From 1667606036f26f9c874078c7dc6f58752327780a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=A4=80=ED=9D=A0?= Date: Fri, 17 May 2024 16:08:27 +0900 Subject: [PATCH] vhost init...3 --- app/Cells/BoardCell.php | 4 +- app/Cells/ProductCell.php | 36 ++++++- app/Controllers/Admin/DeviceController.php | 6 +- app/Controllers/Admin/ProductController.php | 94 +++++++++++++++--- app/Controllers/BaseController.php | 83 ++++++++-------- app/Controllers/Front/ProductController.php | 2 +- app/Database/base.sql | 40 ++++---- app/Entities/BoardEntity.php | 4 + app/Entities/DeviceEntity.php | 22 ++-- app/Entities/ProductEntity.php | 13 +++ app/Entities/SitepageEntity.php | 4 + app/Helpers/Device_helper.php | 2 +- app/Helpers/Product_helper.php | 12 +-- app/Language/ko/Category.php | 14 +-- app/Language/ko/Device.php | 4 +- app/Language/ko/Product.php | 9 +- app/Language/ko/User.php | 14 +-- app/Models/BaseHierarchyModel.php | 8 +- app/Models/BaseModel.php | 39 ++++---- app/Models/BillingModel.php | 8 -- app/Models/BoardModel.php | 13 +-- app/Models/CategoryModel.php | 21 ++-- app/Models/DeviceModel.php | 25 +++-- app/Models/OrderModel.php | 8 -- app/Models/ProductDeviceModel.php | 50 ++++++++++ app/Models/ProductModel.php | 9 +- app/Models/SitepageModel.php | 5 +- app/Models/UserModel.php | 3 +- app/Models/UserSNSModel.php | 9 +- app/Views/admin/product/insert.php | 13 --- .../cell => cells/board}/information.php | 0 app/Views/cells/product/beremetal.php | 24 +++++ .../cells/product/beremetal_calculator.php | 82 +++++++++++++++ .../product/virtual.php} | 0 .../1715920446_a395357eca0ed080d201.jpg | Bin 0 -> 27995 bytes .../large_1715920446_a395357eca0ed080d201.jpg | Bin 0 -> 6572 bytes ...middle_1715920446_a395357eca0ed080d201.jpg | Bin 0 -> 2858 bytes .../small_1715920446_a395357eca0ed080d201.jpg | Bin 0 -> 1557 bytes 38 files changed, 454 insertions(+), 226 deletions(-) create mode 100644 app/Models/ProductDeviceModel.php rename app/Views/{front/board/cell => cells/board}/information.php (100%) create mode 100644 app/Views/cells/product/beremetal.php create mode 100644 app/Views/cells/product/beremetal_calculator.php rename app/Views/{front/product/cell/virtual_calculator.php => cells/product/virtual.php} (100%) create mode 100644 public/upload_images/1715920446_a395357eca0ed080d201.jpg create mode 100644 public/upload_images/large_1715920446_a395357eca0ed080d201.jpg create mode 100644 public/upload_images/middle_1715920446_a395357eca0ed080d201.jpg create mode 100644 public/upload_images/small_1715920446_a395357eca0ed080d201.jpg diff --git a/app/Cells/BoardCell.php b/app/Cells/BoardCell.php index e20ec0a..883f89f 100644 --- a/app/Cells/BoardCell.php +++ b/app/Cells/BoardCell.php @@ -15,13 +15,11 @@ class BoardCell extends BaseCell public function information(array $viewDatas): string { helper('Board'); - $viewDatas['currentCategory'] = $this->getCategoryModel()->getEntity([$this->getCategoryModel()->getPrimaryKey() => __FUNCTION__]); - $viewDatas['cellDatas'] = array(); $viewDatas['cellDatas']['entitys'] = $this->getBoardModel()->getEntitys([ 'category' => __FUNCTION__ ]); return view( - 'Views/front/board/cell/' . __FUNCTION__, + 'Views/cells/board/' . __FUNCTION__, ['viewDatas' => $viewDatas] ); } diff --git a/app/Cells/ProductCell.php b/app/Cells/ProductCell.php index 1416c21..e6af540 100644 --- a/app/Cells/ProductCell.php +++ b/app/Cells/ProductCell.php @@ -3,14 +3,46 @@ namespace App\Cells; use App\Cells\BaseCell; +use App\Models\DeviceModel; class ProductCell extends BaseCell { - public function virtual_calculator(array $viewDatas): string + private $_deviceModel = null; + final protected function getDeviceModel(): DeviceModel + { + return $this->_deviceModel = $this->_deviceModel ?: new DeviceModel(); + } + + public function virtual(array $viewDatas): string { $viewDatas['cellDatas'] = array(); return view( - 'Views/front/product/cell/' . __FUNCTION__, + 'Views/cells/product/' . __FUNCTION__, + ['viewDatas' => $viewDatas] + ); + } + + public function beremetal(array $viewDatas): string + { + $viewDatas['cellDatas'] = []; + $viewDatas['cellDatas']['device'] = []; + $viewDatas['cellDatas']['device']['categorys'] = ['server', 'cpu', 'memory', 'disk', 'nic', 'publicip', 'os']; + $viewDatas['cellDatas']['device']['options'] = $this->getDeviceModel()->getOptions(); + return view( + 'Views/cells/product/' . __FUNCTION__, + ['viewDatas' => $viewDatas] + ); + } + + public function beremetal_calulator(array $viewDatas): string + { + $viewDatas['cellDatas'] = []; + $viewDatas['cellDatas']['device'] = []; + $viewDatas['cellDatas']['device']['categorys'] = ['server', 'cpu', 'memory', 'disk', 'nic', 'publicip', 'os']; + $viewDatas['cellDatas']['device']['options'] = $this->getDeviceModel()->getOptions(); + + return view( + 'Views/cells/product/' . __FUNCTION__, ['viewDatas' => $viewDatas] ); } diff --git a/app/Controllers/Admin/DeviceController.php b/app/Controllers/Admin/DeviceController.php index 65df63b..73aef2e 100644 --- a/app/Controllers/Admin/DeviceController.php +++ b/app/Controllers/Admin/DeviceController.php @@ -22,11 +22,11 @@ class DeviceController extends AdminController public function getFields(string $action = ""): array { - $fields = ["type", "name", "cost", "price", "sale", "stock", "status", "content",]; + $fields = ["category", "name", "cost", "price", "status",]; switch ($action) { case "index": case "excel": - return ["type", "name", "cost", "price", "sale", "stock", "status", "created_at"]; + return ["category", "name", "cost", "price", "status", "created_at"]; break; case "view": return [...$fields, "created_at"]; @@ -38,7 +38,7 @@ class DeviceController extends AdminController } public function getFieldFilters(): array { - return ["type", "status"]; + return ["category", "status"]; } public function getFieldBatchFilters(): array { diff --git a/app/Controllers/Admin/ProductController.php b/app/Controllers/Admin/ProductController.php index d817e36..a885dfa 100644 --- a/app/Controllers/Admin/ProductController.php +++ b/app/Controllers/Admin/ProductController.php @@ -24,18 +24,13 @@ class ProductController extends AdminController helper($this->_viewDatas['className']); } - final protected function getDeviceModel(): DeviceModel - { - return $this->_deviceModel = $this->_deviceModel ?: new DeviceModel(); - } - public function getFields(string $action = ""): array { - $fields = ["category_uid", 'type', 'name', "photo", "cost", "sale", "stock", "view_cnt", "status", "content",]; + $fields = ["category", 'type', 'name', "photo", "device", "cost", "sale", "stock", "view_cnt", "status", "content",]; switch ($action) { case "index": case "excel": - return ["category_uid", "user_uid", 'type', 'name', "cost", "sale", "price", "stock", "view_cnt", "status", "created_at"]; + return ["category", "user_uid", 'type', 'name', "cost", "sale", "price", "stock", "view_cnt", "status", "created_at"]; break; case "view": return [...$fields, "created_at"]; @@ -47,7 +42,7 @@ class ProductController extends AdminController } public function getFieldFilters(): array { - return ["category_uid", "user_uid", 'type', "status"]; + return ["category", "user_uid", 'type', "status"]; } public function getFieldBatchFilters(): array { @@ -84,12 +79,82 @@ class ProductController extends AdminController return $this->_viewDatas['fieldDatas']['cost'] - $this->_viewDatas['fieldDatas']['sale']; } - protected function action_init(array $action_datas): void + //가상서버 + protected function virtual_process() { - parent::action_init($action_datas); - $this->_viewDatas['device'] = []; - $this->_viewDatas['device']['fields'] = ['server', 'cpu', 'memory', 'disk', 'nic', 'publicip', 'os']; - $this->_viewDatas['device']['options'] = $this->getDeviceModel()->getOptions(); + //가상서버정보 + $protudctDatas = array( + 'category' => 'virtual', + 'name' => '', + 'content' => '', + 'cost' => $this->_viewDatas['fieldDatas']['price'], + 'price' => $this->_viewDatas['fieldDatas']['price'], + 'sale' => 0, + 'stock' => 1, + 'view_cnt' => 1, + 'status' => 'use', + ); + //서버부품정보검증 + $titles = array('가상서버'); + //foreach (Product['parts']['virtual']['category'] as $category => $attrs) { + foreach ([] as $category => $attrs) { + if (!$this->_viewDatas['fieldDatas'][$category]) { + throw new \Exception($category . "의 값이 지정되지 않았습니다."); + } else { + $protudctDatas[$category . "_model"] = $attrs['label']; + $protudctDatas[$category . "_cnt"] = $this->_viewDatas['fieldDatas'][$category]; + array_push( + $titles, + sprintf( + "%s * %s%s,", + $protudctDatas[$category . "_model"], + $protudctDatas[$category . "_cnt"], + $attrs['unit'], + ), + ); + } + } + $protudctDatas['name'] = implode(" ", $titles); + $protudctDatas['content'] = implode("\n", $titles); + $product = $this->_model->create($protudctDatas); + //return $this->add_procedure($product, 1, $this->_viewDatas['fieldDatas']['paymentday']); + } + //실서버 + protected function beremetal_process() + { + //상품정보가져오기 + $product = $this->_model->getEntity([$this->_model->getPrimaryKey() => $this->_viewDatas['fieldDatas']['product_uid']]); + //재고수 비교 + if ($product->stock < $this->_viewDatas['fieldDatas']['quantity']) { + throw new \Exception("구매수량이 너무 많습니다.\n구매수량:{$this->_viewDatas['fieldDatas']['quantity']}개, 남은 재고수량:{$product->stock}개"); + } + //구매 금액 비교 + $price = $product->price * $this->_viewDatas['fieldDatas']['quantity']; + if ($price != $this->_viewDatas['fieldDatas']['price']) { + throw new \Exception("실 상품금액{$price} 와 구매금액{$this->_viewDatas['fieldDatas']['price']}이 서로 다릅니다."); + } + //결제방식이 월이용권이면 결제일 확인 + $paymentDay = null; + if ($product->type == 'rental') { + $paymentDay = $this->request->getVar('paymentday') ?: throw new \Exception("월이용권 상품의 경우는 매월 결제일을 지정해주셔야합니다."); + } + //return $this->add_procedure($product, $this->_viewDatas['fieldDatas']['quantity'], $paymentDay); + } + + //주문처리 + protected function device_process() + { + switch ($this->_viewDatas['fieldDatas']['category']) { + case 'virtual': + return $this->virtual_process(); + break; + case 'beremetal': + return $this->beremetal_process(); + break; + default: + throw new \Exception($this->_viewDatas['fieldDatas']['category'] . "는 알수없는 상품 구분입니다. 다시 확인 부탁드립니다."); + break; + } } //Insert관련 @@ -97,13 +162,12 @@ class ProductController extends AdminController { parent::insert_validate(); } - protected function insert_process() { + $this->device_process(); $this->_viewDatas['fieldDatas']['price'] = $this->calculate_price(); return parent::insert_process(); } - //Update관련 protected function update_process($entity) { diff --git a/app/Controllers/BaseController.php b/app/Controllers/BaseController.php index f750880..1a54b42 100644 --- a/app/Controllers/BaseController.php +++ b/app/Controllers/BaseController.php @@ -530,28 +530,38 @@ abstract class BaseController extends Controller protected function index_condition() { //조건절 처리 - $filterFields = array(); foreach ($this->_viewDatas['fieldFilters'] as $field) { - if ($this->request->getVar($field) != DEFAULTS['EMPTY']) { - $filterFields[$field] = $this->request->getVar($field); - } + $value = $this->request->getVar($field); + $this->_model->setIndexFieldFilter($field, $this->request->getVar($field) ?: DEFAULTS['EMPTY']); } - $this->_viewDatas['word'] = $this->request->getVar('word') ?: ''; - $this->_viewDatas['start'] = $this->request->getVar('start') ?: ''; - $this->_viewDatas['end'] = $this->request->getVar('end') ?: ''; - $this->_viewDatas['order_field'] = $this->request->getVar('order_field') ?: 'created_at'; - $this->_viewDatas['order_value'] = $this->request->getVar('order_value') ?: 'DESC'; - $this->_model->setCondition( - $filterFields, - $this->_viewDatas['word'], - $this->_viewDatas['start'], - $this->_viewDatas['end'], - $this->_viewDatas['order_field'], - $this->_viewDatas['order_value'] - ); + //검색어 처리 + $this->_viewDatas['word'] = $this->request->getVar('word') ?: DEFAULTS['EMPTY']; + $this->_model->setIndexWordFilter($this->_viewDatas['word']); + //검색일 처리 + $this->_viewDatas['start'] = $this->request->getVar('start') ?: DEFAULTS['EMPTY']; + $this->_viewDatas['end'] = $this->request->getVar('end') ?: DEFAULTS['EMPTY']; + $this->_model->setIndexDateFilter($this->_viewDatas['start'], $this->_viewDatas['end']); } - private function index_pagination($pager_group = 'default', int $segment = 0, $template = 'bootstrap_full'): string + //Totalcount 처리 + protected function index_total(): int { + $this->index_process(); + $this->index_condition(); + $total = $this->_model->countAllResults(); + // echo dd($this->_model->getLastQuery()); + return $total; + } + //PageNation 처리 + protected function index_pagination($pager_group = 'default', int $segment = 0, $template = 'bootstrap_full'): string + { + //Page, Per_page필요부분 + $this->_viewDatas['page'] = (int)$this->request->getVar('page') ?: 1; + $this->_viewDatas['per_page'] = (int)$this->request->getVar('per_page') ?: $this->_per_page; + //줄수 처리용 + $this->_viewDatas['pageOptions'] = array("" => "줄수선택"); + for ($i = 10; $i <= $this->_viewDatas['total_count'] + $this->_viewDatas['per_page']; $i += 10) { + $this->_viewDatas['pageOptions'][$i] = $i; + } // 1.Views/Pagers/에 bootstrap_full.php,bootstrap_simple.php 생성 // 2.app/Config/Pager.php/$templates에 'bootstrap_full => 'Pagers\bootstrap_full', // 'bootstrap_simple' => 'Pagers\bootstrap_simple', 추가 @@ -569,49 +579,42 @@ abstract class BaseController extends Controller $this->_viewDatas['total_page'] = $pager->getPageCount($pager_group); return $pager->links($pager_group, $template); } - private function index_entitys(): array + protected function index_entitys(): array { $this->index_condition(); if (array_key_exists('page', $this->_viewDatas)) { - return $this->_model->findAll( + $this->_model->limit( $this->_viewDatas['per_page'], $this->_viewDatas['page'] * $this->_viewDatas['per_page'] - $this->_viewDatas['per_page'] ); } - return $this->_model->findAll(); + //Sorting 처리 + $this->_viewDatas['order_field'] = $this->request->getVar('order_field') ?: DEFAULTS['EMPTY']; + $this->_viewDatas['order_value'] = $this->request->getVar('order_value') ?: DEFAULTS['EMPTY']; + $orderBy = []; + if ($this->_viewDatas['order_field'] && $this->_viewDatas['order_value']) { + $orderBy = ["{$this->_viewDatas['order_field']} {$this->_viewDatas['order_value']}"]; + } + return $this->_model->getEntitys([], $orderBy); } public function index() { try { + helper(['form']); $this->action_init(['action' => __FUNCTION__]); foreach ($this->_viewDatas['fieldFilters'] as $field) { $this->_viewDatas[$field] = $this->request->getVar($field) ?: DEFAULTS['EMPTY']; } - $this->index_process(); - //Totalcount 처리 - $this->index_condition(); - $this->_viewDatas['total_count'] = $this->_model->countAllResults(); - // echo $this->_model->getLastQuery(); - // echo "
"; - // log_message("debug", __METHOD__ . "에서 TotalCount 호출:" . $this->_model->getLastQuery()); - //Page, Per_page필요부분 - $this->_viewDatas['page'] = (int)$this->request->getVar('page') ?: 1; - $this->_viewDatas['per_page'] = (int)$this->request->getVar('per_page') ?: $this->_per_page; + //URL처리 $this->_viewDatas['uri'] = $this->request->getUri(); - //줄수 처리용 - $this->_viewDatas['pageOptions'] = array("" => "줄수선택"); - for ($i = 10; $i <= $this->_viewDatas['total_count'] + $this->_viewDatas['per_page']; $i += 10) { - $this->_viewDatas['pageOptions'][$i] = $i; - } + //total 처리 + $this->_viewDatas['total_count'] = $this->index_total(); //pagenation 처리 $this->_viewDatas['pagination'] = $this->index_pagination(); //모델 처리 $this->_viewDatas['entitys'] = $this->index_entitys(); - // echo $this->_model->getLastQuery(); - // exit; - // log_message("debug", __METHOD__ . "에서 findAll 호출:" . $this->_model->getLastQuery()); + // dd($this->_model->getLastQuery()); //setting return_url to session flashdata - helper(['form']); $this->_session->setFlashdata(SESSION_NAMES['RETURN_URL'], current_url() . '?' . $this->request->getUri()->getQuery() ?: ""); return view($this->_viewPath . '/index' . $this->request->getVar('v') ?: '', ['viewDatas' => $this->_viewDatas]); } catch (\Exception $e) { diff --git a/app/Controllers/Front/ProductController.php b/app/Controllers/Front/ProductController.php index 8174464..82ff850 100644 --- a/app/Controllers/Front/ProductController.php +++ b/app/Controllers/Front/ProductController.php @@ -68,7 +68,7 @@ class ProductController extends FrontController //Category 및 Status 조건추가 protected function index_condition() { - $this->_model->where("category_uid", $this->_viewDatas['currentCategory']->getPrimaryKey()); + $this->_model->where("category", $this->_viewDatas['currentCategory']->getPrimaryKey()); $this->_model->where("status", DEFAULTS['STATUS']); parent::index_condition(); } diff --git a/app/Database/base.sql b/app/Database/base.sql index f2a0ba3..48e5477 100644 --- a/app/Database/base.sql +++ b/app/Database/base.sql @@ -104,16 +104,30 @@ CREATE TABLE vhost.tw_sitepage ( created_at timestamp NOT NULL DEFAULT current_timestamp(), deleted_at timestamp NULL DEFAULT NULL, PRIMARY KEY (uid), - KEY category_uid (category_uid), KEY user_uid (user_uid), CONSTRAINT tw_sitepage_ibfk_1 FOREIGN KEY (user_uid) REFERENCES tw_user (uid) ) ENGINE = InnoDB CHARSET = utf8 COLLATE = utf8_general_ci COMMENT '사이트페이지'; +DROP TABLE IF EXISTS vhost.tw_device; + +CREATE TABLE vhost.tw_device ( + uid varchar(36) NOT NULL, + category varchar(20) NOT NULL COMMENT '형식:server(HP,KVM,Container),cpu,memory,disk(ssd,nvme),os(linux,windows),공인ip등등', + name varchar(255) NOT NULL, + cost int(10) unsigned NOT NULL DEFAULT 0 COMMENT '원가', + price int(10) unsigned NOT NULL DEFAULT 0 COMMENT '판매가', + status varchar(10) NOT NULL DEFAULT 'use' COMMENT 'use: 판매중 unuse: 판매중지, soldout:매진, outofstock:재고부족 등등', + updated_at timestamp NULL DEFAULT NULL, + created_at timestamp NOT NULL DEFAULT current_timestamp(), + deleted_at timestamp NULL DEFAULT NULL, + PRIMARY KEY (uid) +) ENGINE = InnoDB CHARSET = utf8 COLLATE = utf8_general_ci COMMENT '장비 정보'; + DROP TABLE IF EXISTS vhost.tw_product; CREATE TABLE vhost.tw_product ( uid varchar(36) NOT NULL, - category_uid varchar(50) NOT NULL COMMENT '범주_UID', + category varchar(20) NOT NULL COMMENT '범주_UID', user_uid varchar(36) DEFAULT NULL COMMENT '생산자 정보', type varchar(10) NOT NULL DEFAULT 'rental' COMMENT 'rental: 월임대, onetime:판매,일회성', name varchar(255) NOT NULL COMMENT '상품명', @@ -129,30 +143,10 @@ CREATE TABLE vhost.tw_product ( created_at timestamp NOT NULL DEFAULT current_timestamp(), deleted_at timestamp NULL DEFAULT NULL, PRIMARY KEY (uid), - KEY category_uid (category_uid), KEY user_uid (user_uid), - CONSTRAINT tw_product_ibfk_1 FOREIGN KEY (category_uid) REFERENCES tw_category (uid), - CONSTRAINT tw_product_ibfk_2 FOREIGN KEY (user_uid) REFERENCES tw_user (uid) + CONSTRAINT tw_product_ibfk_1 FOREIGN KEY (user_uid) REFERENCES tw_user (uid) ) ENGINE = InnoDB CHARSET = utf8 COLLATE = utf8_general_ci COMMENT = '상품 정보'; -DROP TABLE IF EXISTS vhost.tw_device; - -CREATE TABLE vhost.tw_device ( - uid varchar(36) NOT NULL, - type varchar(20) NOT NULL COMMENT '형식:server(HP,KVM,Container),cpu,memory,disk(ssd,nvme),os(linux,windows),공인ip등등', - name varchar(255) NOT NULL, - cost int(10) unsigned NOT NULL DEFAULT 0 COMMENT '원가', - price int(10) unsigned NOT NULL DEFAULT 0 COMMENT '판매가', - sale int(10) unsigned NOT NULL DEFAULT 0 COMMENT '할인가', - stock int(5) unsigned NOT NULL DEFAULT 1 COMMENT '재고수량', - content text NOT NULL COMMENT '장비내용', - status varchar(10) NOT NULL DEFAULT 'use' COMMENT 'use: 판매중 unuse: 판매중지, soldout:매진, outofstock:재고부족 등등', - updated_at timestamp NULL DEFAULT NULL, - created_at timestamp NOT NULL DEFAULT current_timestamp(), - deleted_at timestamp NULL DEFAULT NULL, - PRIMARY KEY (uid) -) ENGINE = InnoDB CHARSET = utf8 COLLATE = utf8_general_ci COMMENT '장비 정보'; - DROP TABLE IF EXISTS vhost.tw_product_device; CREATE TABLE vhost.tw_product_device ( diff --git a/app/Entities/BoardEntity.php b/app/Entities/BoardEntity.php index 09f5b2f..0ce620c 100644 --- a/app/Entities/BoardEntity.php +++ b/app/Entities/BoardEntity.php @@ -18,6 +18,10 @@ class BoardEntity extends BaseHierarchyEntity { return $this->attributes['passwd']; } + public function getCategory(): string + { + return $this->attributes['category']; + } //파일관련 Field전용 final public function getFileDownload($url, $field = "upload_file") { diff --git a/app/Entities/DeviceEntity.php b/app/Entities/DeviceEntity.php index 610c890..1281a99 100644 --- a/app/Entities/DeviceEntity.php +++ b/app/Entities/DeviceEntity.php @@ -13,19 +13,19 @@ class DeviceEntity extends BaseEntity { return $this->attributes['name']; } - //추가기능 - public function getType(): string + public function getCategory(): string { - return $this->attributes['type']; + return $this->attributes['category']; } - - //판매금액표시용 - public function getSalePrice(array $options = []): string + public function getPrice(): int { - $price = $this->attributes['price'] - $this->attributes['sale']; - if (array_key_exists('format', $options)) { - $price = sprintf($options['format'], number_format($price)); - } - return $price; + return $this->attributes['price']; + } + //추가기능 + //판매금액표시용 + public function getTitleWithPrice(array $attrs = []): string + { + $format = array_key_exists('format', $attrs) ? $attrs['format'] : "%s원 %s"; + return sprintf($format, number_format($this->getPrice()), $this->getTitle()); } } diff --git a/app/Entities/ProductEntity.php b/app/Entities/ProductEntity.php index e49cee6..2806df8 100644 --- a/app/Entities/ProductEntity.php +++ b/app/Entities/ProductEntity.php @@ -13,6 +13,10 @@ class ProductEntity extends BaseEntity { return $this->attributes['name']; } + public function getCategory(): string + { + return $this->attributes['category']; + } //추가기능 //이미지관련 Field전용 final public function getFileImage($size = false, $field = "photo") @@ -28,4 +32,13 @@ class ProductEntity extends BaseEntity $files[0] ); } + //판매금액표시용 + public function getSalePrice(array $options = []): string + { + $price = $this->attributes['price'] - $this->attributes['sale']; + if (array_key_exists('format', $options)) { + $price = sprintf($options['format'], number_format($price)); + } + return $price; + } } diff --git a/app/Entities/SitepageEntity.php b/app/Entities/SitepageEntity.php index e8e289a..a533795 100644 --- a/app/Entities/SitepageEntity.php +++ b/app/Entities/SitepageEntity.php @@ -13,5 +13,9 @@ class SitepageEntity extends BaseEntity { return $this->attributes['title']; } + public function getCategory(): string + { + return $this->attributes['category']; + } //추가기능 } diff --git a/app/Helpers/Device_helper.php b/app/Helpers/Device_helper.php index 9346552..6dd5fb2 100644 --- a/app/Helpers/Device_helper.php +++ b/app/Helpers/Device_helper.php @@ -36,7 +36,7 @@ function getFieldForm_DeviceHelper($field, $value, array $viewDatas, array $attr return form_textarea($field, html_entity_decode($value), ['class' => 'editor', 'rows' => '20', 'cols' => '100']); break; case "status": - case "type": + case "category": $viewDatas['fieldFormOptions'][$field] = [DEFAULTS['EMPTY'] => lang("{$viewDatas['className']}.label.{$field}") . " 선택", ...$viewDatas['fieldFormOptions'][$field]]; return form_dropdown($field, $viewDatas['fieldFormOptions'][$field], $value, $attributes); break; diff --git a/app/Helpers/Product_helper.php b/app/Helpers/Product_helper.php index 9741cf5..f2b5a91 100644 --- a/app/Helpers/Product_helper.php +++ b/app/Helpers/Product_helper.php @@ -26,15 +26,8 @@ function getFieldForm_ProductHelper($field, $value, array $viewDatas, array $att // } // return implode(" ", $checkboxs); break; - case 'server': - case 'cpu': - case 'memory': - case 'disk': - case 'nic': - case 'os': - case 'publicip': - $viewDatas['fieldFormOptions'][$field] = [DEFAULTS['EMPTY'] => lang("Device.TYPE.label.{$field}") . " 선택", ...$viewDatas['device']['options'][$field]]; - return form_dropdown($field, $viewDatas['fieldFormOptions'][$field], $value, [...$attributes, 'style' => 'width:200px']); + case 'device': + return sprintf("
%s
", view_cell('ProductCell::beremetal', $viewDatas)); break; case 'title': case 'name': @@ -61,6 +54,7 @@ function getFieldForm_ProductHelper($field, $value, array $viewDatas, array $att case 'view_cnt': return form_input($field, $value, ['type' => 'number']); break; + case "category": case "status": case "type": $viewDatas['fieldFormOptions'][$field] = [DEFAULTS['EMPTY'] => lang("{$viewDatas['className']}.label.{$field}") . " 선택", ...$viewDatas['fieldFormOptions'][$field]]; diff --git a/app/Language/ko/Category.php b/app/Language/ko/Category.php index 7dee6a8..4dd1ec1 100644 --- a/app/Language/ko/Category.php +++ b/app/Language/ko/Category.php @@ -3,25 +3,25 @@ $roles = []; foreach (ROLES as $role) { switch ($role) { case 'guest': - $roles[] = '비회원'; + $roles[$role] = '비회원'; break; case 'user': - $roles[] = '일반회원'; + $roles[$role] = '일반회원'; break; case 'vip': - $roles[] = 'VIP회원'; + $roles[$role] = 'VIP회원'; break; case 'manager': - $roles[] = '관리자'; + $roles[$role] = '관리자'; break; case 'cloudflare': - $roles[] = 'Cloudflare'; + $roles[$role] = 'Cloudflare'; break; case 'director': - $roles[] = '감독자'; + $roles[$role] = '감독자'; break; case 'master': - $roles[] = '마스터'; + $roles[$role] = '마스터'; break; } } diff --git a/app/Language/ko/Device.php b/app/Language/ko/Device.php index 10a4b98..5827b0e 100644 --- a/app/Language/ko/Device.php +++ b/app/Language/ko/Device.php @@ -3,7 +3,7 @@ return [ 'title' => "장비 정보", 'label' => [ 'uid' => "번호", - 'type' => '형식', + 'category' => '형식', 'name' => "모델명", 'cost' => "판매원가", 'price' => "판매금액", @@ -14,7 +14,7 @@ return [ 'updated_at' => "수정일", 'created_at' => "생성일" ], - "TYPE" => [ + "CATEGORY" => [ 'server' => '서버', 'cpu' => 'CPU', 'memory' => 'Memory', diff --git a/app/Language/ko/Product.php b/app/Language/ko/Product.php index 54df923..eab777e 100644 --- a/app/Language/ko/Product.php +++ b/app/Language/ko/Product.php @@ -3,7 +3,7 @@ return [ 'title' => "상품 정보", 'label' => [ 'uid' => "번호", - 'category_uid' => "분류", + 'category' => "분류", 'user_uid' => "판매자", 'type' => '형식', 'name' => "상품명", @@ -16,7 +16,12 @@ return [ 'content' => "상품정보", 'status' => "상태", 'updated_at' => "수정일", - 'created_at' => "생성일" + 'created_at' => "생성일", + 'device' => "기본장비" + ], + "CATEGORY" => [ + 'beremetal' => '단독서버', + 'vpc' => '가상서버', ], "TYPE" => [ "rental" => "월이용권", diff --git a/app/Language/ko/User.php b/app/Language/ko/User.php index 3f6b295..e0de1bf 100644 --- a/app/Language/ko/User.php +++ b/app/Language/ko/User.php @@ -3,25 +3,25 @@ $roles = []; foreach (ROLES as $role) { switch ($role) { case 'guest': - $roles[] = '비회원'; + $roles[$role] = '비회원'; break; case 'user': - $roles[] = '일반회원'; + $roles[$role] = '일반회원'; break; case 'vip': - $roles[] = 'VIP회원'; + $roles[$role] = 'VIP회원'; break; case 'manager': - $roles[] = '관리자'; + $roles[$role] = '관리자'; break; case 'cloudflare': - $roles[] = 'Cloudflare'; + $roles[$role] = 'Cloudflare'; break; case 'director': - $roles[] = '감독자'; + $roles[$role] = '감독자'; break; case 'master': - $roles[] = '마스터'; + $roles[$role] = '마스터'; break; } } diff --git a/app/Models/BaseHierarchyModel.php b/app/Models/BaseHierarchyModel.php index 9f8ea88..2a35880 100644 --- a/app/Models/BaseHierarchyModel.php +++ b/app/Models/BaseHierarchyModel.php @@ -15,9 +15,15 @@ abstract class BaseHierarchyModel extends BaseModel } abstract public function getContentField(); abstract public function reply($parent_entity, array $formDatas): BaseEntity; + + public function getEntitys(array $conditions = array(), array $orderBys = array()): array + { + $orderBys = ["grpno DESC", "grporder ASC", ...$orderBys]; + return parent::getEntitys($conditions, $orderBys); + } public function getSiblingEntitys($entity) { - return $this->getEntitys(['grpno' => $entity->getHierarchy_No()]); + return parent::getEntitys(['grpno' => $entity->getHierarchy_No()]); } public function getFieldRule(string $field, array $rules, string $action = ""): array { diff --git a/app/Models/BaseModel.php b/app/Models/BaseModel.php index 6125a79..6ecc7c8 100644 --- a/app/Models/BaseModel.php +++ b/app/Models/BaseModel.php @@ -85,8 +85,12 @@ abstract class BaseModel extends Model { return $this->primaryKey; } - public function getEntitys(array $conditions = array()): array + public function getEntitys(array $conditions = array(), array $orderBys = array()): array { + //dd($orderBys); + foreach ($orderBys as $orderBy) { + $this->orderBy($orderBy); + } return $this->where($conditions)->findAll(); } final public function getUUID() @@ -270,27 +274,26 @@ abstract class BaseModel extends Model } //Index관련 - public function setIndexWordFilter(string $word) + public function setIndexFieldFilter(string $field, $value): void { - } - public function setIndexDateFilter($start, $end) - { - if ($start !== DEFAULTS['EMPTY'] && $end !== DEFAULTS['EMPTY']) { - $this->where("created_at >=", $start); - $this->where("created_at <=", $end); + if ($value !== DEFAULTS['EMPTY']) { + $this->where($field, $value); } } - public function setIndexOrderBy(string $field, string $order) + public function setIndexWordFilter(string $word): void + { + if ($word !== DEFAULTS['EMPTY']) { + $this->orLike($this->getTitleField(), $word, "both"); + } + } + public function setIndexDateFilter($start, $end): void + { + if ($start !== DEFAULTS['EMPTY'] && $end !== DEFAULTS['EMPTY']) { + $this->where(["created_at >={$start}", "created_at <={$end}"]); + } + } + public function setIndexOrderBy(string $field, string $order): void { $this->orderBy($field, $order); } - final public function setCondition(array $filterFields, $word, $start, $end, $order_field, $order_value) - { - foreach ($filterFields as $field => $value) { - $this->where($field, $value); - } - $this->setIndexWordFilter($word); - $this->setIndexDateFilter($start, $end); - $this->setIndexOrderBy($order_field, $order_value); - } } diff --git a/app/Models/BillingModel.php b/app/Models/BillingModel.php index 2193cd8..2f2dca8 100644 --- a/app/Models/BillingModel.php +++ b/app/Models/BillingModel.php @@ -75,12 +75,4 @@ class BillingModel extends BaseModel { return $this->modify_process($entity, $formDatas); } - //Index관련 - public function setIndexWordFilter(string $word) - { - if ($word !== DEFAULTS['EMPTY']) { - parent::setIndexWordFilter($word); - $this->orLike($this->getTitleField(), $word, "both"); - } - } } diff --git a/app/Models/BoardModel.php b/app/Models/BoardModel.php index 626dd7b..c379742 100644 --- a/app/Models/BoardModel.php +++ b/app/Models/BoardModel.php @@ -70,23 +70,14 @@ class BoardModel extends BaseHierarchyModel } //Index관련 - public function setIndexWordFilter(string $word) + public function setIndexWordFilter(string $word): void { if ($word !== DEFAULTS['EMPTY']) { parent::setIndexWordFilter($word); - $this->orLike($this->getTitleField(), $word, "both"); - $this->orLike("content", $word, "both"); //befor , after , both + $this->orLike("content", $word, "both"); } } - public function setIndexOrderBy(?string $field, ?string $order) - { - //계단식의 경우는 먼저 다른것보다 먼저 orderBy가 수행되어야 하므로 - $this->orderBy("grpno", "DESC"); - $this->orderBy("grporder", "DESC"); - parent::setIndexOrderBy($field, $order); - } - //조회수 올리기 final public function addViewCount(BoardEntity $entity, int $view_cnt = 1): BoardEntity { diff --git a/app/Models/CategoryModel.php b/app/Models/CategoryModel.php index 8a7eb19..16d2579 100644 --- a/app/Models/CategoryModel.php +++ b/app/Models/CategoryModel.php @@ -119,14 +119,6 @@ class CategoryModel extends BaseHierarchyModel { return $this->where($conditions)->first() ?: throw new \Exception(__FUNCTION__ . "에서 {$this->getClassName()}의 해당 데이터가 없습니다."); } - public function getEntitys(array $conditions = array()): array - { - $this->where($conditions); - $this->orderBy("grpno", "DESC"); - $this->orderBy("grporder", "ASC"); - return $this->findAll(); - } - public function create(array $formDatas): CategoryEntity { return $this->create_process(new CategoryEntity(), $formDatas); @@ -141,14 +133,15 @@ class CategoryModel extends BaseHierarchyModel } //Index관련 - public function setIndexWordFilter(string $word) + public function setIndexWordFilter(string $word): void { - parent::setIndexWordFilter($word); - $this->orLike($this->getTitleField(), $word, "both"); - $this->orLike("head", $word, "both"); //befor , after , both - $this->orLike("tail", $word, "both"); //befor , after , both + if ($word !== DEFAULTS['EMPTY']) { + parent::setIndexWordFilter($word); + $this->orLike("head", $word, "both"); + $this->orLike("tail", $word, "both"); + } } - public function setIndexOrderBy(?string $field, ?string $order) + public function setIndexOrderBy(?string $field, ?string $order): void { //계단식의 경우는 먼저 다른것보다 먼저 orderBy가 수행되어야 하므로 $this->orderBy("grpno", "DESC"); diff --git a/app/Models/DeviceModel.php b/app/Models/DeviceModel.php index 65c04c4..683beb6 100644 --- a/app/Models/DeviceModel.php +++ b/app/Models/DeviceModel.php @@ -17,8 +17,7 @@ class DeviceModel extends BaseModel parent::__construct('Device'); $this->allowedFields = [ ...$this->allowedFields, - 'type', 'name', "cost", "price", "sale", - "stock", "content", "status" + 'category', 'name', "cost", "price", "status" ]; $this->validationRules = [...$this->validationRules, ...$this->getFieldRules($this->allowedFields),]; } @@ -33,7 +32,7 @@ class DeviceModel extends BaseModel case $this->getTitleField(): $rules[$field] = "required|trim|string"; break; - case 'type': + case 'category': $rules[$field] = "required|string"; break; case 'photo': @@ -62,14 +61,10 @@ class DeviceModel extends BaseModel { //대분류 부분은 선택이 되지 않게 하기위해 따로 만듬 (form_dropdown의 optgroup 기능) foreach ($this->getEntitys($conditions) as $entity) { - if (!array_key_exists($entity->getType(), $options)) { - $options[$entity->getType()] = []; + if (!array_key_exists($entity->getCategory(), $options)) { + $options[$entity->getCategory()] = []; } - $options[$entity->getType()][$entity->getPrimaryKey()] = sprintf( - "%s %s", - $entity->getSalePrice(['format' => "%s원"]), - $entity->getTitle() - ); + $options[$entity->getCategory()][$entity->getPrimaryKey()] = $entity->getTitle(); } return $options; } @@ -78,6 +73,11 @@ class DeviceModel extends BaseModel { return $this->where($conditions)->first() ?: throw new \Exception(__FUNCTION__ . "에서 {$this->getClassName()}의 해당 데이터가 없습니다."); } + public function getEntitys(array $conditions = array(), array $orderBys = array()): array + { + $orderBys = ["category ASC", "price DESC", ...$orderBys]; + return parent::getEntitys($conditions, $orderBys); + } public function create(array $formDatas): DeviceEntity { return $this->create_process(new DeviceEntity(), $formDatas); @@ -88,12 +88,11 @@ class DeviceModel extends BaseModel } //Index관련 - public function setIndexWordFilter(string $word) + public function setIndexWordFilter(string $word): void { if ($word !== DEFAULTS['EMPTY']) { parent::setIndexWordFilter($word); - $this->orLike($this->getTitleField(), $word, "both"); - $this->orLike("content", $word, "both"); //befor , after , both + $this->orLike("content", $word, "both"); } } } diff --git a/app/Models/OrderModel.php b/app/Models/OrderModel.php index de88d1c..34a1d3d 100644 --- a/app/Models/OrderModel.php +++ b/app/Models/OrderModel.php @@ -84,14 +84,6 @@ class OrderModel extends BaseModel { return $this->modify_process($entity, $formDatas); } - //Index관련 - public function setIndexWordFilter(string $word) - { - if ($word !== DEFAULTS['EMPTY']) { - parent::setIndexWordFilter($word); - $this->orLike($this->getTitleField(), $word, "both"); - } - } //장바구니에 넣기() final public function addCart(ProductEntity $product, int $quantity, string $type, $paymentDay = null): OrderEntity diff --git a/app/Models/ProductDeviceModel.php b/app/Models/ProductDeviceModel.php new file mode 100644 index 0000000..a9a982e --- /dev/null +++ b/app/Models/ProductDeviceModel.php @@ -0,0 +1,50 @@ +allowedFields = [ + ...$this->allowedFields, "order_uid", "billing_uid" + ]; + $this->validationRules = [...$this->validationRules, ...$this->getFieldRules($this->allowedFields),]; + } + final public function getTitleField(): string + { + return 'billing_uid'; + } + public function getFieldRule(string $field, array $rules, string $action = ""): array + { + switch ($field) { + case "order_uid": + $rules[$field] = $this->getUUIDFieldRule('required'); + break; + case 'billing_uid': + $rules[$field] = "required|numeric"; + break; + default: + $rules = parent::getFieldRule($field, $rules, $action); + break; + } + return $rules; + } + public function getEntity($conditions): OrderBillingEntity + { + return $this->where($conditions)->first() ?: throw new \Exception(__FUNCTION__ . "에서 {$this->getClassName()}의 해당 데이터가 없습니다."); + } + public function create(array $formDatas): OrderBillingEntity + { + return $this->create_process(new OrderBillingEntity(), $formDatas); + } + public function modify(OrderBillingEntity $entity, array $formDatas): OrderBillingEntity + { + return $this->modify_process($entity, $formDatas); + } +} diff --git a/app/Models/ProductModel.php b/app/Models/ProductModel.php index 7ddcc93..0c2ec30 100644 --- a/app/Models/ProductModel.php +++ b/app/Models/ProductModel.php @@ -17,7 +17,7 @@ class ProductModel extends BaseModel parent::__construct('Product'); $this->allowedFields = [ ...$this->allowedFields, - "category_uid", "user_uid", + "category", "user_uid", 'type', 'name', "photo", "cost", "price", "sale", "stock", "view_cnt", "content", "status" ]; @@ -31,7 +31,7 @@ class ProductModel extends BaseModel public function getFieldRule(string $field, array $rules, string $action = ""): array { switch ($field) { - case "category_uid": + case "category": $rules[$field] = "required|string"; break; case "user_uid": @@ -78,12 +78,11 @@ class ProductModel extends BaseModel } //Index관련 - public function setIndexWordFilter(string $word) + public function setIndexWordFilter(string $word): void { if ($word !== DEFAULTS['EMPTY']) { parent::setIndexWordFilter($word); - $this->orLike($this->getTitleField(), $word, "both"); - $this->orLike("content", $word, "both"); //befor , after , both + $this->orLike("content", $word, "both"); } } diff --git a/app/Models/SitepageModel.php b/app/Models/SitepageModel.php index 630f88c..cd6ef03 100644 --- a/app/Models/SitepageModel.php +++ b/app/Models/SitepageModel.php @@ -61,12 +61,11 @@ class SitepageModel extends BaseModel } //Index관련 - public function setIndexWordFilter(string $word) + public function setIndexWordFilter(string $word): void { if ($word !== DEFAULTS['EMPTY']) { parent::setIndexWordFilter($word); - $this->orLike($this->getTitleField(), $word, "both"); - $this->orLike("content", $word, "both"); //befor , after , both + $this->orLike("content", $word, "both"); } } } diff --git a/app/Models/UserModel.php b/app/Models/UserModel.php index 3c5a1f8..585c514 100644 --- a/app/Models/UserModel.php +++ b/app/Models/UserModel.php @@ -89,11 +89,10 @@ class UserModel extends BaseModel } //Index관련 - public function setIndexWordFilter(string $word) + public function setIndexWordFilter(string $word): void { if ($word !== DEFAULTS['EMPTY']) { parent::setIndexWordFilter($word); - $this->orLike($this->getTitleField(), $word, "both"); //befor , after , both $this->orLike("id", $word, "both"); } } diff --git a/app/Models/UserSNSModel.php b/app/Models/UserSNSModel.php index 0f68c50..1f57fdb 100644 --- a/app/Models/UserSNSModel.php +++ b/app/Models/UserSNSModel.php @@ -61,10 +61,11 @@ class UserSNSModel extends BaseModel } //Index관련 - public function setIndexWordFilter(string $word) + public function setIndexWordFilter(string $word): void { - parent::setIndexWordFilter($word); - $this->orLike($this->getTitleField(), $word, "both"); - $this->orLike("email", $word, "both"); //befor , after , both + if ($word !== DEFAULTS['EMPTY']) { + parent::setIndexWordFilter($word); + $this->orLike("email", $word, "both"); + } } } diff --git a/app/Views/admin/product/insert.php b/app/Views/admin/product/insert.php index 0c35f5b..4bae07f 100644 --- a/app/Views/admin/product/insert.php +++ b/app/Views/admin/product/insert.php @@ -5,19 +5,6 @@ - - - -
기본장비 - -
- - - - -
- -
diff --git a/app/Views/front/board/cell/information.php b/app/Views/cells/board/information.php similarity index 100% rename from app/Views/front/board/cell/information.php rename to app/Views/cells/board/information.php diff --git a/app/Views/cells/product/beremetal.php b/app/Views/cells/product/beremetal.php new file mode 100644 index 0000000..3eb0b15 --- /dev/null +++ b/app/Views/cells/product/beremetal.php @@ -0,0 +1,24 @@ + + + + + + + + + + + +
+ $category, + 'size' => "6", + 'class' => 'vhost_cellDatas', + 'onChange' => "calculator()" + ] + ) ?> +
\ No newline at end of file diff --git a/app/Views/cells/product/beremetal_calculator.php b/app/Views/cells/product/beremetal_calculator.php new file mode 100644 index 0000000..b0e5e46 --- /dev/null +++ b/app/Views/cells/product/beremetal_calculator.php @@ -0,0 +1,82 @@ + + +
+ 'post', + "onsubmit" => 'return calculator()' + ]) ?> + + + + + + + + + + + getPrimaryKey()] = $entity->getTitleWithPrice(); + } + ?> + + + + + + + + + + + + + + +
가상서버 견적 계산기
+ $category, + 'class' => 'vhost_cellDatas', + 'onChange' => "calculator()" + ] + ) ?> +
결제일 + "결제일 선택"]; + for ($i = 1; $i <= 28; $i++) { + $paymentDayOptions[$i] = "매월 {$i}일"; + } + ?> + 'paymentday']); + ?> +
주문금액 + 0원 + "btn btn-outline btn-primary")); ?> +
+ + + getFlashdata('return_message') ? alert_CommonHelper($viewDatas['session']->getFlashdata('return_message')) : "" ?> +
\ No newline at end of file diff --git a/app/Views/front/product/cell/virtual_calculator.php b/app/Views/cells/product/virtual.php similarity index 100% rename from app/Views/front/product/cell/virtual_calculator.php rename to app/Views/cells/product/virtual.php diff --git a/public/upload_images/1715920446_a395357eca0ed080d201.jpg b/public/upload_images/1715920446_a395357eca0ed080d201.jpg new file mode 100644 index 0000000000000000000000000000000000000000..14e59149a797c773d94377c1f88e3654e10ec521 GIT binary patch literal 27995 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�aKKQGEPB6 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 literal 0 HcmV?d00001 diff --git a/public/upload_images/middle_1715920446_a395357eca0ed080d201.jpg b/public/upload_images/middle_1715920446_a395357eca0ed080d201.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5ee17d5b2c9ac7f42673b9ace3e35e00f017d71f GIT binary patch literal 2858 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 PG0R>!f?A)pDQE2ORKzuN literal 0 HcmV?d00001 diff --git a/public/upload_images/small_1715920446_a395357eca0ed080d201.jpg b/public/upload_images/small_1715920446_a395357eca0ed080d201.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4f884e4f2118118c6905f87ed99ba1806cd6ecd2 GIT binary patch literal 1557 zcmbW!XH=6{7zgk-c@r`rydhzU5*Z@HKqN6h86pM%7(fW1BB00tELNzS zDyYagh#--nhBAVJl$5XoiVP8~G6WSgl7_a&p3_fl|M$6{?sM;Xe&@;u<<9|CH)pmp z0E5AR-HHXsSAnmbJXwz3-+9_lq9eBKJs25HNu*IND4P>_-2KrMwwnvZ&7I{!Nwl&s zHlxHPaALXf$rL+^wFOo_3^)NG9KKeHAQXi}BasLM5{p79q48Ke9*4!@lvRkT$|{fw z4yUTF3aOFEWHO$hp{Y*NB$CLawMSr};tm3dK_W3EWt=kUKS%yE0HFabAR2_}0dNQg zLNIwNpbG#nq=LGp{VOoIVn!tt8iU0t8U(5U90r1L1h_V}qB~7-4j>>TaU;!9NzH?U z(u*T)O)t2L*56UpME2~SH?RylbR2_K*U;3`Hr!;i+1P~6*v7Q7wsG3Ya&~cLyLoy0 z`1<(=1cpaMMn&)8?&ZZNBpyym=4WJPoj93&D(B1(XA6sdJa_)WwUW~7H*S{QDzCm< zBe+*vSKrXw(kg0u^tio4($m}5KQK5X9UGsRd@=QMdgj%_+r_1K?>{WBd|Y$E0Ps)N z7ui2tkirE=AV36a%>{!WR%{SLAUD#Kh>jj8PMn(F)^s#!N5R#qCXBwN=R7&=P&ZcH zfIeoputxhs_U~ZF|Cj6w>~EJ8z=JTw=YbI50LY%yeqW?nF>D%eqYWnFH3a=MLb0<9 z`85B?WtbOU)`aIh*{9c8^;o6fgqM*YCps+omapI0>XWz5nk3wi3M>qW9F1gpLY?|P zqQgV`$rGw+w(VM8_Cvq$i%xyQ$#{9a#o%ROqx7DG>`1*BN-A!(p>Yl*mrL7V!(?Fv z-J`PG4=GX0Mvl=3*{RY>?1CSH@kr zq%$!cV`H9kVUn3uY0lvG?C;i&vE1Cne@lqXneorv>01>#(D}Rwhw*v(jjVAjH#ED! zxnzt$4B|@f6~|p4Z5~WXIoDyaWM$|0+65&rKf$mzzn(AMwr=E&mKB+hV;i?gz=J0QX@(TP5#2x-j zgicx0dahTcp=nKU5M5`Vdi)i7_v})m;Vk~B5OKR5gmM$Wn;!iSCVbBxW2NabMWKXO z4TUchSOPusZqd4=u)6}N4GIqctHRZYvk}VmiHq8BO*p~4T;@KXe{n3UhtRTbTS`r? zGs8GCyK``RBXib*m+#t=+Uca!0Gd LXd)qt