From 4561bd68d1b469d1905d1fdac802fe6a50f7535e Mon Sep 17 00:00:00 2001 From: hieutmd Date: Wed, 31 Jan 2024 11:36:25 +0700 Subject: [PATCH 1/2] c --- assets/script/RowExpand.js | 44 ++ data/order/home.php | 62 +- data/product/category.php | 102 ++++ data/product/category_form.php | 18 + inc/Hura8/AppAdmin.php | 4 +- .../Controller/bTrackingController.php | 17 + .../Analytics/Model/TrackDeviceInfo.php | 19 + .../Analytics/Model/TrackRouteInfo.php | 28 + .../Analytics/Model/TrackUserInfo.php | 19 + .../Analytics/Model/TrackingModel.php | 32 + .../AArticleCategoryController.php | 14 + .../AdminController/AArticleController.php | 24 + .../Controller/bArticleCategoryController.php | 35 ++ .../Article/Controller/bArticleController.php | 91 +++ .../Model/ArticleCategoryLanguageModel.php | 21 + .../Article/Model/ArticleCategoryModel.php | 33 ++ .../Article/Model/ArticleLanguageModel.php | 19 + .../Components/Article/Model/ArticleModel.php | 150 +++++ .../Article/Model/ArticleSearchModel.php | 29 + .../Article/Model/UArticleModel.php | 55 ++ .../AdminController/ABannerController.php | 16 + .../ABannerLocationController.php | 26 + .../Banner/Controller/bBannerController.php | 67 +++ .../Banner/Model/BannerLocationModel.php | 30 + .../Components/Banner/Model/BannerModel.php | 90 +++ .../Banner/Model/BannerSearchModel.php | 33 ++ .../AdminController/ABrandController.php | 44 ++ .../Brand/Controller/bBrandController.php | 73 +++ .../Brand/Model/BrandLanguageModel.php | 19 + .../Components/Brand/Model/BrandModel.php | 72 +++ .../AdminController/AComboSetController.php | 15 + .../Controller/bComboSetController.php | 148 +++++ .../ComboSet/Model/ComboSetLanguageModel.php | 17 + .../ComboSet/Model/ComboSetModel.php | 165 ++++++ .../AConfigGroupController.php | 77 +++ .../Controller/bConfigGroupController.php | 24 + .../ConfigGroup/Model/ConfigGroupModel.php | 500 ++++++++++++++++ .../AdminController/ACustomerController.php | 23 + .../ACustomerGroupController.php | 64 ++ .../ACustomerLoyaltyController.php | 9 + .../Controller/bCustomerController.php | 40 ++ .../Controller/bCustomerLoyaltyController.php | 206 +++++++ .../Customer/Model/CustomerAuthModel.php | 79 +++ .../Customer/Model/CustomerGroupModel.php | 213 +++++++ .../Customer/Model/CustomerLoyaltyModel.php | 268 +++++++++ .../Customer/Model/CustomerModel.php | 128 ++++ .../Customer/Model/CustomerSearchModel.php | 34 ++ .../ADealCollectionController.php | 51 ++ .../Deal/AdminController/ADealController.php | 58 ++ .../Deal/Controller/bDealController.php | 48 ++ .../Deal/Model/DealCollectionModel.php | 223 +++++++ inc/Hura8/Components/Deal/Model/DealModel.php | 196 ++++++ .../AdminController/ACouponController.php | 40 ++ .../AdminController/APosterController.php | 26 + .../AProductFeedController.php | 51 ++ .../Controller/bCouponController.php | 46 ++ .../Controller/bProductFeedController.php | 26 + .../Marketing/Model/CouponModel.php | 130 ++++ .../Marketing/Model/PosterModel.php | 33 ++ .../Marketing/Model/ProductFeedModel.php | 126 ++++ .../Marketing/Model/UProductFeedModel.php | 8 + .../AdminController/AItemMediaController.php | 38 ++ .../AMediaCategoryController.php | 14 + .../AdminController/AMediaController.php | 42 ++ .../Media/Controller/bItemMediaController.php | 61 ++ .../Controller/bMediaCategoryController.php | 20 + .../Media/Controller/bMediaController.php | 59 ++ .../Components/Media/Model/ItemMediaModel.php | 76 +++ .../Media/Model/ItemMediaSearchModel.php | 34 ++ .../Media/Model/MediaCategoryModel.php | 20 + .../Components/Media/Model/MediaModel.php | 61 ++ .../Media/Model/MediaSearchModel.php | 32 + .../AdminController/AOrderController.php | 235 ++++++++ .../AOrderStatusController.php | 43 ++ .../Order/Controller/OrderStatus.php | 43 ++ .../Components/Order/Model/OrderModel.php | 557 ++++++++++++++++++ .../Order/Model/OrderSearchModel.php | 30 + .../Order/Model/OrderStatusModel.php | 94 +++ .../Page/AdminController/APageController.php | 50 ++ .../Page/Controller/bPageController.php | 92 +++ .../Page/Model/PageLanguageModel.php | 21 + inc/Hura8/Components/Page/Model/PageModel.php | 76 +++ .../AProductCategoryController.php | 38 +- .../Product/Model/ProductCategoryModel.php | 6 +- .../AdminController/AProvinceController.php | 10 + .../Controller/bProvinceController.php | 151 +++++ .../Province/Model/ProvinceModel.php | 73 +++ .../ClientPermissionController.php | 76 +++ .../AdminController/StaffAdminController.php | 72 +++ .../StaffAdminDepartmentController.php | 44 ++ .../StaffDepartmentPermissionController.php | 98 +++ .../AdminController/StaffLogController.php | 27 + .../StaffPermissionController.php | 180 ++++++ .../Components/Staff/Model/StaffAuthModel.php | 64 ++ .../Staff/Model/StaffDepartmentModel.php | 40 ++ .../Model/StaffDepartmentPermissionModel.php | 29 + .../Components/Staff/Model/StaffLogModel.php | 38 ++ .../Components/Staff/Model/StaffModel.php | 58 ++ .../Staff/Model/StaffPermissionModel.php | 67 +++ .../AdminController/ATemplateController.php | 216 +++++++ .../ATemplateSetController.php | 46 ++ .../Controller/TemplateController.php | 167 ++++++ .../Template/Controller/TemplateFilter.php | 262 ++++++++ .../Template/Model/TemplateModel.php | 132 +++++ .../Template/Model/TemplateSetModel.php | 64 ++ .../AdminController/ANewsletterController.php | 27 + .../AUserCommentController.php | 27 + .../AUserContactController.php | 27 + .../User/AdminController/AUserController.php | 18 + .../AdminController/AUserReviewController.php | 27 + .../User/Controller/bUserController.php | 35 ++ .../User/Controller/bUserReviewController.php | 27 + .../User/Controller/bUserUploadController.php | 41 ++ .../Components/User/Model/NewsletterModel.php | 73 +++ .../User/Model/UserCommentModel.php | 90 +++ .../User/Model/UserCommentReplyModel.php | 96 +++ .../User/Model/UserContactModel.php | 54 ++ inc/Hura8/Components/User/Model/UserModel.php | 58 ++ .../Components/User/Model/UserReviewModel.php | 218 +++++++ .../Components/User/Model/UserUploadModel.php | 63 ++ .../Interfaces/iEntityAdminController.php | 3 - .../AdminEntityBaseControllerTraits.php | 18 + .../AdminEntityCategoryControllerTraits.php | 74 +++ template/product/category.html | 54 ++ template/product/category_form.html | 131 ++++ 125 files changed, 9117 insertions(+), 58 deletions(-) create mode 100644 assets/script/RowExpand.js create mode 100644 data/product/category.php create mode 100644 data/product/category_form.php create mode 100644 inc/Hura8/Components/Analytics/Controller/bTrackingController.php create mode 100644 inc/Hura8/Components/Analytics/Model/TrackDeviceInfo.php create mode 100644 inc/Hura8/Components/Analytics/Model/TrackRouteInfo.php create mode 100644 inc/Hura8/Components/Analytics/Model/TrackUserInfo.php create mode 100644 inc/Hura8/Components/Analytics/Model/TrackingModel.php create mode 100644 inc/Hura8/Components/Article/AdminController/AArticleCategoryController.php create mode 100644 inc/Hura8/Components/Article/AdminController/AArticleController.php create mode 100644 inc/Hura8/Components/Article/Controller/bArticleCategoryController.php create mode 100644 inc/Hura8/Components/Article/Controller/bArticleController.php create mode 100644 inc/Hura8/Components/Article/Model/ArticleCategoryLanguageModel.php create mode 100644 inc/Hura8/Components/Article/Model/ArticleCategoryModel.php create mode 100644 inc/Hura8/Components/Article/Model/ArticleLanguageModel.php create mode 100644 inc/Hura8/Components/Article/Model/ArticleModel.php create mode 100644 inc/Hura8/Components/Article/Model/ArticleSearchModel.php create mode 100644 inc/Hura8/Components/Article/Model/UArticleModel.php create mode 100644 inc/Hura8/Components/Banner/AdminController/ABannerController.php create mode 100644 inc/Hura8/Components/Banner/AdminController/ABannerLocationController.php create mode 100644 inc/Hura8/Components/Banner/Controller/bBannerController.php create mode 100644 inc/Hura8/Components/Banner/Model/BannerLocationModel.php create mode 100644 inc/Hura8/Components/Banner/Model/BannerModel.php create mode 100644 inc/Hura8/Components/Banner/Model/BannerSearchModel.php create mode 100644 inc/Hura8/Components/Brand/AdminController/ABrandController.php create mode 100644 inc/Hura8/Components/Brand/Controller/bBrandController.php create mode 100644 inc/Hura8/Components/Brand/Model/BrandLanguageModel.php create mode 100644 inc/Hura8/Components/Brand/Model/BrandModel.php create mode 100644 inc/Hura8/Components/ComboSet/AdminController/AComboSetController.php create mode 100644 inc/Hura8/Components/ComboSet/Controller/bComboSetController.php create mode 100644 inc/Hura8/Components/ComboSet/Model/ComboSetLanguageModel.php create mode 100644 inc/Hura8/Components/ComboSet/Model/ComboSetModel.php create mode 100644 inc/Hura8/Components/ConfigGroup/AdminController/AConfigGroupController.php create mode 100644 inc/Hura8/Components/ConfigGroup/Controller/bConfigGroupController.php create mode 100644 inc/Hura8/Components/ConfigGroup/Model/ConfigGroupModel.php create mode 100644 inc/Hura8/Components/Customer/AdminController/ACustomerController.php create mode 100644 inc/Hura8/Components/Customer/AdminController/ACustomerGroupController.php create mode 100644 inc/Hura8/Components/Customer/AdminController/ACustomerLoyaltyController.php create mode 100644 inc/Hura8/Components/Customer/Controller/bCustomerController.php create mode 100644 inc/Hura8/Components/Customer/Controller/bCustomerLoyaltyController.php create mode 100644 inc/Hura8/Components/Customer/Model/CustomerAuthModel.php create mode 100644 inc/Hura8/Components/Customer/Model/CustomerGroupModel.php create mode 100644 inc/Hura8/Components/Customer/Model/CustomerLoyaltyModel.php create mode 100644 inc/Hura8/Components/Customer/Model/CustomerModel.php create mode 100644 inc/Hura8/Components/Customer/Model/CustomerSearchModel.php create mode 100644 inc/Hura8/Components/Deal/AdminController/ADealCollectionController.php create mode 100644 inc/Hura8/Components/Deal/AdminController/ADealController.php create mode 100644 inc/Hura8/Components/Deal/Controller/bDealController.php create mode 100644 inc/Hura8/Components/Deal/Model/DealCollectionModel.php create mode 100644 inc/Hura8/Components/Deal/Model/DealModel.php create mode 100644 inc/Hura8/Components/Marketing/AdminController/ACouponController.php create mode 100644 inc/Hura8/Components/Marketing/AdminController/APosterController.php create mode 100644 inc/Hura8/Components/Marketing/AdminController/AProductFeedController.php create mode 100644 inc/Hura8/Components/Marketing/Controller/bCouponController.php create mode 100644 inc/Hura8/Components/Marketing/Controller/bProductFeedController.php create mode 100644 inc/Hura8/Components/Marketing/Model/CouponModel.php create mode 100644 inc/Hura8/Components/Marketing/Model/PosterModel.php create mode 100644 inc/Hura8/Components/Marketing/Model/ProductFeedModel.php create mode 100644 inc/Hura8/Components/Marketing/Model/UProductFeedModel.php create mode 100644 inc/Hura8/Components/Media/AdminController/AItemMediaController.php create mode 100644 inc/Hura8/Components/Media/AdminController/AMediaCategoryController.php create mode 100644 inc/Hura8/Components/Media/AdminController/AMediaController.php create mode 100644 inc/Hura8/Components/Media/Controller/bItemMediaController.php create mode 100644 inc/Hura8/Components/Media/Controller/bMediaCategoryController.php create mode 100644 inc/Hura8/Components/Media/Controller/bMediaController.php create mode 100644 inc/Hura8/Components/Media/Model/ItemMediaModel.php create mode 100644 inc/Hura8/Components/Media/Model/ItemMediaSearchModel.php create mode 100644 inc/Hura8/Components/Media/Model/MediaCategoryModel.php create mode 100644 inc/Hura8/Components/Media/Model/MediaModel.php create mode 100644 inc/Hura8/Components/Media/Model/MediaSearchModel.php create mode 100644 inc/Hura8/Components/Order/AdminController/AOrderController.php create mode 100644 inc/Hura8/Components/Order/AdminController/AOrderStatusController.php create mode 100644 inc/Hura8/Components/Order/Controller/OrderStatus.php create mode 100644 inc/Hura8/Components/Order/Model/OrderModel.php create mode 100644 inc/Hura8/Components/Order/Model/OrderSearchModel.php create mode 100644 inc/Hura8/Components/Order/Model/OrderStatusModel.php create mode 100644 inc/Hura8/Components/Page/AdminController/APageController.php create mode 100644 inc/Hura8/Components/Page/Controller/bPageController.php create mode 100644 inc/Hura8/Components/Page/Model/PageLanguageModel.php create mode 100644 inc/Hura8/Components/Page/Model/PageModel.php create mode 100644 inc/Hura8/Components/Province/AdminController/AProvinceController.php create mode 100644 inc/Hura8/Components/Province/Controller/bProvinceController.php create mode 100644 inc/Hura8/Components/Province/Model/ProvinceModel.php create mode 100644 inc/Hura8/Components/Staff/AdminController/ClientPermissionController.php create mode 100644 inc/Hura8/Components/Staff/AdminController/StaffAdminController.php create mode 100644 inc/Hura8/Components/Staff/AdminController/StaffAdminDepartmentController.php create mode 100644 inc/Hura8/Components/Staff/AdminController/StaffDepartmentPermissionController.php create mode 100644 inc/Hura8/Components/Staff/AdminController/StaffLogController.php create mode 100644 inc/Hura8/Components/Staff/AdminController/StaffPermissionController.php create mode 100644 inc/Hura8/Components/Staff/Model/StaffAuthModel.php create mode 100644 inc/Hura8/Components/Staff/Model/StaffDepartmentModel.php create mode 100644 inc/Hura8/Components/Staff/Model/StaffDepartmentPermissionModel.php create mode 100644 inc/Hura8/Components/Staff/Model/StaffLogModel.php create mode 100644 inc/Hura8/Components/Staff/Model/StaffModel.php create mode 100644 inc/Hura8/Components/Staff/Model/StaffPermissionModel.php create mode 100644 inc/Hura8/Components/Template/AdminController/ATemplateController.php create mode 100644 inc/Hura8/Components/Template/AdminController/ATemplateSetController.php create mode 100644 inc/Hura8/Components/Template/Controller/TemplateController.php create mode 100644 inc/Hura8/Components/Template/Controller/TemplateFilter.php create mode 100644 inc/Hura8/Components/Template/Model/TemplateModel.php create mode 100644 inc/Hura8/Components/Template/Model/TemplateSetModel.php create mode 100644 inc/Hura8/Components/User/AdminController/ANewsletterController.php create mode 100644 inc/Hura8/Components/User/AdminController/AUserCommentController.php create mode 100644 inc/Hura8/Components/User/AdminController/AUserContactController.php create mode 100644 inc/Hura8/Components/User/AdminController/AUserController.php create mode 100644 inc/Hura8/Components/User/AdminController/AUserReviewController.php create mode 100644 inc/Hura8/Components/User/Controller/bUserController.php create mode 100644 inc/Hura8/Components/User/Controller/bUserReviewController.php create mode 100644 inc/Hura8/Components/User/Controller/bUserUploadController.php create mode 100644 inc/Hura8/Components/User/Model/NewsletterModel.php create mode 100644 inc/Hura8/Components/User/Model/UserCommentModel.php create mode 100644 inc/Hura8/Components/User/Model/UserCommentReplyModel.php create mode 100644 inc/Hura8/Components/User/Model/UserContactModel.php create mode 100644 inc/Hura8/Components/User/Model/UserModel.php create mode 100644 inc/Hura8/Components/User/Model/UserReviewModel.php create mode 100644 inc/Hura8/Components/User/Model/UserUploadModel.php create mode 100644 inc/Hura8/Traits/AdminEntityBaseControllerTraits.php create mode 100644 inc/Hura8/Traits/AdminEntityCategoryControllerTraits.php create mode 100644 template/product/category.html create mode 100644 template/product/category_form.html diff --git a/assets/script/RowExpand.js b/assets/script/RowExpand.js new file mode 100644 index 0000000..b81393f --- /dev/null +++ b/assets/script/RowExpand.js @@ -0,0 +1,44 @@ + +const RowExpand = (function (){ + + const $status_expand_all = $("#js-row-expand-all"); + + let track_open_rows = []; + + function open_child_row(child_class_name){ + const $children = $(`.${child_class_name}`); + + if(!track_open_rows.includes(child_class_name)) { + $children.css('display', 'table-row'); + track_open_rows.push(child_class_name); + }else{ + $children.css('display', 'none'); + track_open_rows = [...Util.removeItemFromArray(track_open_rows, child_class_name)]; + } + } + + function open_all_row(){ + if(!track_open_rows.includes('expand_all')) { + $(".row").css('display', 'table-row'); + track_open_rows.push('expand_all'); + + $status_expand_all.html("[-]"); + + }else{ + // collapse all + $(".row").css('display', 'none'); + // open only first parent + $(".parent_0").css('display', 'table-row'); + + track_open_rows = []; + + $status_expand_all.html("[+]"); + } + } + + return { + open_child: open_child_row, + open_all: open_all_row + } + +})(); diff --git a/data/order/home.php b/data/order/home.php index 8416a9c..234d5e1 100644 --- a/data/order/home.php +++ b/data/order/home.php @@ -1,17 +1,55 @@ getRequest('orderCode', ''), + 'q' => getRequest('q', ''), + //'coupon' => getRequest('coupon', ''), + 'cus_id' => getRequest('cus_id', ''), + 'province' => getRequest('province', ''), + //'district' => getRequest('district', ''), + 'folder' => getRequest('folder', ''), + 'view_status' => getRequest('view_status', ''), + 'update_by' => getRequest('update_by', ''), + //'shipping_status' => getRequest('shipping_status', ''), + 'assign_to' => getRequest('assign_to', ''), + 'from_date' => getRequest('from_date', ''), + 'to_date' => getRequest('to_date', ''), + //'from_hour' => getRequest('from_hour', ''), + //'to_hour' => getRequest('to_hour', ''), + 'payment' => getRequest('payment', ''), + 'fullfillment' => getRequest('fullfillment', ''), + 'status' => getRequest('status', ''), + //'excluded_ids' => getRequest('', ''), + //'included_ids' => getRequest('', ''), + 'list' => getRequest('list', ''), + 'numPerPage' => $numPerPage, + 'page' => getPageId(), +); + +$objAOrderController = new AOrderController(); +$totalResults = $objAOrderController->getTotal($conditions); +$item_list = $objAOrderController->getList($conditions); + +debug_var($item_list); + +list($page_collection, $tb_page, $total_pages) = Paging::paging_template($totalResults, $numPerPage); + +return [ + "total" => $totalResults, + "item_list" => $item_list, + "pagination" => [ + 'collection' => $page_collection, + 'html' => $tb_page, + 'total_pages' => $total_pages, + ], + "order_status_list" => OrderStatus::ORDER_STATUS , + "payment_status_list" => OrderStatus::PAYMENT_STATUS, + "fullfillment_status_list" => OrderStatus::FULFILLMENT_STATUS , +]; diff --git a/data/product/category.php b/data/product/category.php new file mode 100644 index 0000000..ef056e6 --- /dev/null +++ b/data/product/category.php @@ -0,0 +1,102 @@ +getAllParent(); + +return [ + 'category_list' => get_category_list(0, getRequest("id"), $level=1, $prefix="", $category_collection ) +]; + + +function get_category_list($parentId=0, $currentCat="",$level=1, $prefix="", $category_collection = array()){ + + $categoryTree = ""; + $extra_space = ""; + for($i = 1; $i < $level; $i++){ + $extra_space .= "      "; + } + + $stt = 0; + if(isset($category_collection[$parentId])) { + + foreach($category_collection[$parentId] as $index => $cat_info){ + $cat_id = $cat_info['id']; + + $stt ++; + $imgUrl = (strlen($cat_info["thumbnail"]) > 2) ? " " : ""; + + if($cat_info["status"]) $status = "Hạ xuống"; + else $status = "Hiển thị"; + + $edit_link ="/admin/product/category-form?id=".$cat_id; + + $hide_this = ($parentId > 0) ? "style='display: none;'" : ''; + + $show_category_name = $cat_info["title"]; + + if(!IS_DEFAULT_LANGUAGE && isset($cat_info["not_translated"]) && $cat_info["not_translated"]) { + $show_category_name = "[Chưa dịch] ".$cat_info["title"]; + } + + if($cat_info['is_parent']) { + $show_category_name = "".$show_category_name.""; + } + + $categoryTree .= " + + + ".$cat_id." + + + + ". $extra_space . $prefix . $stt.". ". $show_category_name . $imgUrl." + + + ".$cat_info['item_count']." - Xem + + + Web + + + + + + + "; + + if(IS_DEFAULT_LANGUAGE) { + $categoryTree .= " + + Thuộc tính (".$cat_info['attribute_count'].") + + + ".$status." | + Sửa lại | + Xóa + + "; + + }else{ + $categoryTree .= " + + Sửa lại + + "; + } + + $categoryTree .= " + + "; + + if($cat_info["is_parent"]) $categoryTree .= get_category_list($cat_id, $currentCat, $level + 1, $prefix . $stt.".", $category_collection); + + } + } + + return $categoryTree; +} + diff --git a/data/product/category_form.php b/data/product/category_form.php new file mode 100644 index 0000000..b202a08 --- /dev/null +++ b/data/product/category_form.php @@ -0,0 +1,18 @@ + 0) ? $objAProductCategoryController->getFullInfo($id) : null; +if(!$item_info) $item_info = $objAProductCategoryController->getEmptyInfo([]); + + +return [ + 'item_info' => $item_info, + 'categoryDropBox' => $objAProductCategoryController->getDropBox( $item_info['parent_id'], 0, 1), + 'update_status' => getRequest("us"), +]; diff --git a/inc/Hura8/AppAdmin.php b/inc/Hura8/AppAdmin.php index 86dfbcb..de59673 100644 --- a/inc/Hura8/AppAdmin.php +++ b/inc/Hura8/AppAdmin.php @@ -53,7 +53,7 @@ class AppAdmin }else{ $data = ['file data '. $module_file .' not found!']; } - + $global_data = [ "module" => $this->current_route_info['module'], "view" => $this->current_route_info['view'], @@ -85,7 +85,7 @@ class AppAdmin } $template_file_path = $this->tpl_path ."/". $this->current_route_info['module']; - $template_file_name = $this->current_route_info['view'].".html"; + $template_file_name = str_replace("-", '_', $this->current_route_info['view']).".html"; $template_file_full_path = $template_file_path."/".$template_file_name; //check exist diff --git a/inc/Hura8/Components/Analytics/Controller/bTrackingController.php b/inc/Hura8/Components/Analytics/Controller/bTrackingController.php new file mode 100644 index 0000000..b52f119 --- /dev/null +++ b/inc/Hura8/Components/Analytics/Controller/bTrackingController.php @@ -0,0 +1,17 @@ +objTrackingModel = new TrackingModel(); + } + +} diff --git a/inc/Hura8/Components/Analytics/Model/TrackDeviceInfo.php b/inc/Hura8/Components/Analytics/Model/TrackDeviceInfo.php new file mode 100644 index 0000000..a0df313 --- /dev/null +++ b/inc/Hura8/Components/Analytics/Model/TrackDeviceInfo.php @@ -0,0 +1,19 @@ +ip_address = $ip_address; + $this->user_agent = $user_agent; + $this->referrer = $referrer; + $this->is_mobile = $is_mobile; + } +} diff --git a/inc/Hura8/Components/Analytics/Model/TrackRouteInfo.php b/inc/Hura8/Components/Analytics/Model/TrackRouteInfo.php new file mode 100644 index 0000000..e68b8bc --- /dev/null +++ b/inc/Hura8/Components/Analytics/Model/TrackRouteInfo.php @@ -0,0 +1,28 @@ +url = $url; + $this->module = $module; + $this->view = $view; + $this->view_id = $view_id; + $this->query = $query; + } + +} diff --git a/inc/Hura8/Components/Analytics/Model/TrackUserInfo.php b/inc/Hura8/Components/Analytics/Model/TrackUserInfo.php new file mode 100644 index 0000000..21243a1 --- /dev/null +++ b/inc/Hura8/Components/Analytics/Model/TrackUserInfo.php @@ -0,0 +1,19 @@ +web_user_id = $web_user_id; + $this->customer_id = $customer_id; + $this->is_crawler = $is_crawler ? 1 : 0; + } + +} diff --git a/inc/Hura8/Components/Analytics/Model/TrackingModel.php b/inc/Hura8/Components/Analytics/Model/TrackingModel.php new file mode 100644 index 0000000..5ec20d0 --- /dev/null +++ b/inc/Hura8/Components/Analytics/Model/TrackingModel.php @@ -0,0 +1,32 @@ +isDefaultLanguage()) { + return $this->iEntityLanguageModel->update($item_id, $new_item_info); + } + + return $this->objArticleModel->updateTableInfo($item_id, $new_item_info); + } + +} diff --git a/inc/Hura8/Components/Article/Controller/bArticleCategoryController.php b/inc/Hura8/Components/Article/Controller/bArticleCategoryController.php new file mode 100644 index 0000000..dbd2202 --- /dev/null +++ b/inc/Hura8/Components/Article/Controller/bArticleCategoryController.php @@ -0,0 +1,35 @@ +objArticleCategoryModel = new ArticleCategoryModel(); + + if(!$this->isDefaultLanguage()) { + + parent::__construct( + $this->objArticleCategoryModel, + new ArticleCategoryLanguageModel() + ); + + } else { + + parent::__construct($this->objArticleCategoryModel); + + } + } + + +} diff --git a/inc/Hura8/Components/Article/Controller/bArticleController.php b/inc/Hura8/Components/Article/Controller/bArticleController.php new file mode 100644 index 0000000..b3ed6be --- /dev/null +++ b/inc/Hura8/Components/Article/Controller/bArticleController.php @@ -0,0 +1,91 @@ + ['width' => 200,] , + 'l' => ['width' => 600,] , + ); + + /* @var ArticleModel $objArticleModel */ + protected $objArticleModel; + + public function __construct() + { + $this->objArticleModel = new ArticleModel(); + + if(!$this->isDefaultLanguage()) { + parent::__construct( + $this->objArticleModel, + new ArticleLanguageModel() + ); + + } else { + parent::__construct($this->objArticleModel); + } + } + + + public function getFullInfo($id) + { + + if(!$id) return null; + + return self::getCache("getFullInfo-".$id."-".$this->view_language, function () use ($id){ + + $info = $this->objArticleModel->getFullInfo($id); + + if($this->iEntityLanguageModel && $info ) { + $item_language_info = $this->iEntityLanguageModel->getInfo($id) ?? ["not_translated" => true]; + return $this->formatItemInfo(array_merge($info, $item_language_info)); + } + + return ($info) ? $this->formatItemInfo($info) : null; + + }); + } + + + protected function formatItemInList(array $item_info) + { + return $this->formatItemInfo($item_info); + } + + + protected function formatItemInfo(array $item_info) + { + if(!$item_info) return null; + + $info = $item_info; + $info['image'] = self::getResizedImageCollection($info['thumbnail']); + + return $info; + } + + + public static function getResizedImageCollection($image_name) { + $image = []; + + $size_in_full = [ + 't' => 'thumb' , + 's' => 'small' , + 'l' => 'large' , + ]; + + foreach (static::$resized_sizes as $size => $value) { + $image[$size_in_full[$size]] = ($image_name) ? STATIC_DOMAIN . "/". static::$image_folder . "/". $size. IMAGE_FILE_SEPARATOR . $image_name : ''; + } + + return $image; + } + +} diff --git a/inc/Hura8/Components/Article/Model/ArticleCategoryLanguageModel.php b/inc/Hura8/Components/Article/Model/ArticleCategoryLanguageModel.php new file mode 100644 index 0000000..8b37216 --- /dev/null +++ b/inc/Hura8/Components/Article/Model/ArticleCategoryLanguageModel.php @@ -0,0 +1,21 @@ +richtext_fields); + } + +} diff --git a/inc/Hura8/Components/Article/Model/ArticleCategoryModel.php b/inc/Hura8/Components/Article/Model/ArticleCategoryModel.php new file mode 100644 index 0000000..c367bed --- /dev/null +++ b/inc/Hura8/Components/Article/Model/ArticleCategoryModel.php @@ -0,0 +1,33 @@ +richtext_fields); + } + +} diff --git a/inc/Hura8/Components/Article/Model/ArticleModel.php b/inc/Hura8/Components/Article/Model/ArticleModel.php new file mode 100644 index 0000000..1c5771f --- /dev/null +++ b/inc/Hura8/Components/Article/Model/ArticleModel.php @@ -0,0 +1,150 @@ +db->runQuery( + "SELECT * FROM `".$this->tb_entity."` basic, `".$this->tb_article_info."` info + WHERE basic.`id` = info.`article_id` AND basic.id = ? + LIMIT 1 ", + ['d'], [$id] + ); + + if( $item_info = $this->db->fetchAssoc($query)){ + return $item_info; + } + + return null; + } + + + protected function _buildQueryConditionExtend(array $filter_condition) : ?array + { + /*$condition = array( + "category" => getRequestInt("category"), + "no_image" => 0,//1 + );*/ + + $catCondition = []; + $bind_types = []; + $bind_values = []; + + //Tim danh muc + if(isset($filter_condition["category"]) && $filter_condition["category"]) { + + $objArticleCategoryModel = new ArticleCategoryModel(); + $category_info = $objArticleCategoryModel->getInfo($filter_condition["category"]); + + if($category_info) { + if($category_info['is_parent']) { + $catCondition[] = " AND `id` IN (SELECT `item_id` FROM `".$this->tb_article_per_category."` WHERE `category_id` IN (".$category_info['child_ids'].") ) "; + //$bind_types[] = 'd'; + //$bind_values[] = $filter_condition["category"]; + }else{ + $catCondition[] = " AND `id` IN (SELECT `item_id` FROM `".$this->tb_article_per_category."` WHERE `category_id` = ? ) "; + $bind_types[] = 'd'; + $bind_values[] = $filter_condition["category"]; + } + } + + } + + + return array( join(" ", $catCondition), $bind_types, $bind_values); + } + + + protected function addArticleToCategory($item_id, array $category_list_id) { + $this->db->runQuery("DELETE FROM `".$this->tb_article_per_category."` WHERE `item_id` = ? ", ['d'], [$item_id]); + + $bulk_inserts = []; + foreach($category_list_id as $cat_id) { + if (! $cat_id) continue; + + $bulk_inserts[] = [ + 'category_id' => $cat_id, + 'item_id' => $item_id, + 'status' => 1, + 'create_time' => CURRENT_TIME, + ]; + } + + if(sizeof($bulk_inserts)) { + $this->db->bulk_insert($this->tb_article_per_category, $bulk_inserts); + } + + // update counter + $objArticleCategoryModel = new ArticleCategoryModel(); + foreach($category_list_id as $cat_id) { + $objArticleCategoryModel->updateItemCount($cat_id); + } + + } + + + public function updateUrl($id, $url_index): bool + { + + $module_routing = ModuleManager::getModuleRouting("article"); + $request_path_config = isset($module_routing["detail"]) ? $module_routing["detail"]['url_manager']['request_path'] : ''; + + if(!$request_path_config) { + return false; + } + + $request_path = UrlManagerController::translateRequestPathConfig($request_path_config, $id, $url_index); + $id_path = UrlManagerController::createIdPath("article", "detail", $id); + + $objUrlManager = new UrlManagerController(); + $new_request_path = $objUrlManager->createUrl("article:detail", $request_path, $id_path, 0); + + if($new_request_path) { + $this->db->update( + $this->tb_entity, + [ + 'request_path' => $new_request_path, + ], + [ + 'id' => $id, + ] + ); + } + + return true; + } + + + +} diff --git a/inc/Hura8/Components/Article/Model/ArticleSearchModel.php b/inc/Hura8/Components/Article/Model/ArticleSearchModel.php new file mode 100644 index 0000000..0daa06c --- /dev/null +++ b/inc/Hura8/Components/Article/Model/ArticleSearchModel.php @@ -0,0 +1,29 @@ + "tb_article.status", + ]; + + private $fulltext_fields = [ + "keywords" => ["tb_article.title", ], + ]; + + + public function __construct() + { + parent::__construct( + "tb_article", + $this->fulltext_fields, + $this->filter_fields + ); + } + +} diff --git a/inc/Hura8/Components/Article/Model/UArticleModel.php b/inc/Hura8/Components/Article/Model/UArticleModel.php new file mode 100644 index 0000000..52d849b --- /dev/null +++ b/inc/Hura8/Components/Article/Model/UArticleModel.php @@ -0,0 +1,55 @@ +db->runQuery(" + ( + SELECT `item_id` + FROM ".$this->tb_article_per_category." + WHERE `category_id` = ? AND `status`=1 AND `item_id` > ? + ORDER BY `item_id` DESC + LIMIT 10 + + ) UNION ALL ( + SELECT `item_id` + FROM ".$this->tb_article_per_category." + WHERE `category_id` = ? AND `status`=1 AND `item_id` < ? + ORDER BY `item_id` DESC + LIMIT 10 + ) + ", + ['d', 'd', 'd', 'd'], + [$category_id, $main_id, $category_id, $main_id] + ); + + $article_list_id = []; + $article_item_info = array(); + $article_item = []; + + foreach ( $this->db->fetchAll($query) as $rs ) { + if(!isset($article_item_info[$rs["item_id"]])) $article_item_info[$rs["item_id"]] = array(); + if(!in_array($rs["item_id"], $article_list_id)) $article_list_id[] = $rs["item_id"]; + + if($rs["item_id"] > $main_id) { + $article_item['new'][$rs["item_id"]] = &$article_item_info[$rs["item_id"]]; + } + else { + $article_item['old'][$rs["item_id"]] = &$article_item_info[$rs["item_id"]]; + } + } + + $list_article_info = $this->getListByIds($article_list_id); + foreach ($article_list_id as $_id) { + if(isset($list_article_info[$_id])) $article_item_info[$_id] = $list_article_info[$_id]; + } + + + return $article_item; + } + +} diff --git a/inc/Hura8/Components/Banner/AdminController/ABannerController.php b/inc/Hura8/Components/Banner/AdminController/ABannerController.php new file mode 100644 index 0000000..ee1196a --- /dev/null +++ b/inc/Hura8/Components/Banner/AdminController/ABannerController.php @@ -0,0 +1,16 @@ + "Toàn bộ website" , + "header" => "Đầu trang" , + "homepage" => "Trang chủ" , + "column_left" => "Cột trái" , + "column_right" => "Cột phải" , + "footer" => "Chân trang" , + "product_detail"=> "Chi tiết sản phẩm" , + "product_list" => "Danh sách & Danh mục sản phẩm" , + "collection_list" => "Bộ sưu tập" , + "article_home" => "Trang chủ tin tức" , + "brand_detail" => "Chi tiết thương hiệu", + ); + + + protected $objBannerModel; + protected $objBannerLocationModel; + + public function __construct() + { + $this->objBannerModel = new BannerModel(); + $this->objBannerLocationModel = new BannerLocationModel(); + + parent::__construct($this->objBannerModel); + } + + + protected function formatItemInList(array $item_info) + { + return self::formatFile($item_info); + } + + protected function formatItemInfo(array $item_info) + { + return self::formatFile($item_info); + } + + + public static function formatFile(array $item_info) + { + + if($item_info['file_url']) { + $item_info['display_file'] = STATIC_DOMAIN ."/". static::$image_folder ."/". $item_info['file_url']; + }else if($item_info['file_external_url']) { + $item_info['display_file'] = $item_info['file_external_url']; + } + + $item_info['html_code'] = "\"".htmlspecialchars($item_info['title'])."\""; + + return $item_info; + } + + +} diff --git a/inc/Hura8/Components/Banner/Model/BannerLocationModel.php b/inc/Hura8/Components/Banner/Model/BannerLocationModel.php new file mode 100644 index 0000000..d3208cb --- /dev/null +++ b/inc/Hura8/Components/Banner/Model/BannerLocationModel.php @@ -0,0 +1,30 @@ +db->runQuery("SELECT * FROM `".$this->tb_entity."` WHERE `tracking_id` = ? LIMIT 1 ", ['s'], [$tracking_id]) ; + if( $item_info = $this->db->fetchAssoc($query)){ + return $this->formatItemInfo($item_info); + } + + return false; + } + + public function getBannerPerTemplate(array $template_list, $numberOfBannerPerTpl=100){ + + $all_bind_types = []; + $all_bind_values = []; + + $view_id = 0; + + $build_query = []; + foreach($template_list as $tpl) { + + list($where_condition, $bind_types, $bind_values) = $this->buildQueryPerTpl($tpl, $view_id, $numberOfBannerPerTpl); + + $build_query[] = " (".$where_condition.") "; + $all_bind_types = array_merge($all_bind_types, $bind_types); + $all_bind_values = array_merge($all_bind_values, $bind_values); + } + + if(!sizeof($build_query)) return []; + + $query = $this->db->runQuery(join(" UNION ALL ", $build_query), $all_bind_types, $all_bind_values); + + return $this->db->fetchAll($query); + } + + protected function _buildQueryConditionExtend(array $filter_condition) : ?array + { + /*$condition = array( + [location] => 2 + [category] => 0 + );*/ + + $catCondition = []; + $bind_types = []; + $bind_values = []; + + if(isset($filter_condition['location']) && $filter_condition['location']) { + $catCondition[] = " AND `location` = ? "; + $bind_types[] = 'd'; + $bind_values[] = $filter_condition['location']; + } + + if(isset($filter_condition['category']) && $filter_condition['category']) { + $catCondition[] = " AND `id` IN ( SELECT `banner_id` FROM `".$this->tb_banner_per_category."` WHERE `category_id` = ? ) "; + $bind_types[] = 'd'; + $bind_values[] = $filter_condition['category']; + } + + return array( join(" ", $catCondition), $bind_types, $bind_values); + } + + +} diff --git a/inc/Hura8/Components/Banner/Model/BannerSearchModel.php b/inc/Hura8/Components/Banner/Model/BannerSearchModel.php new file mode 100644 index 0000000..6fd6b38 --- /dev/null +++ b/inc/Hura8/Components/Banner/Model/BannerSearchModel.php @@ -0,0 +1,33 @@ + "tb_banner.location", + "status" => "tb_banner.status", + ]; + + private $fulltext_fields = [ + "keywords" => ["tb_banner.title",], + ]; + + + public function __construct() + { + parent::__construct( + "tb_banner", + $this->fulltext_fields, + $this->filter_fields + ); + + //$this->createTableSearch(); + } + +} diff --git a/inc/Hura8/Components/Brand/AdminController/ABrandController.php b/inc/Hura8/Components/Brand/AdminController/ABrandController.php new file mode 100644 index 0000000..c56efb1 --- /dev/null +++ b/inc/Hura8/Components/Brand/AdminController/ABrandController.php @@ -0,0 +1,44 @@ +objBrandModel->getGroupByFirstLetter(); + } + + + protected function deleteFileBeforeDeleteItem($item_id): bool + { + // delete thumb files + $item_info = $this->getInfo($item_id); + if($item_info['thumbnail']) { + foreach (static::$resized_sizes as $size => $value) { + $file_local_path = PUBLIC_DIR . "/". static::$image_folder . "/". $size. IMAGE_FILE_SEPARATOR . $item_info['thumbnail']; + unlink($file_local_path); + } + + // remove original file + $file_local_path = PUBLIC_DIR . "/". static::$image_folder . "/". $item_info['thumbnail']; + unlink($file_local_path); + } + + //delete media files? + // todo: + + // ok + return true; + } + + +} diff --git a/inc/Hura8/Components/Brand/Controller/bBrandController.php b/inc/Hura8/Components/Brand/Controller/bBrandController.php new file mode 100644 index 0000000..8376b0e --- /dev/null +++ b/inc/Hura8/Components/Brand/Controller/bBrandController.php @@ -0,0 +1,73 @@ + ['width' => 200,] , + ); + + /* @var BrandModel $objBrandModel */ + protected $objBrandModel; + /* @var BrandLanguageModel $objBrandLanguageModel */ + protected $objBrandLanguageModel; + protected $view_language = ''; + + public function __construct() + { + $this->objBrandModel = new BrandModel(); + + if(!$this->isDefaultLanguage()) { + $this->objBrandLanguageModel = new BrandLanguageModel(); + //$this->objVideoLanguageModel->createTableLang(); + parent::__construct($this->objBrandModel, $this->objBrandLanguageModel); + + }else{ + parent::__construct($this->objBrandModel); + } + } + + public function getInfoByUrl(string $band_index) : ?array + { + return $this->objBrandModel->getInfoByUrl($band_index); + } + + protected function formatItemInList(array $item_info) : array + { + return $this->formatItemInfo($item_info); + } + + + protected function formatItemInfo(array $item_info) : ?array + { + if(!$item_info) return null; + + $info = static::formatItemImage($item_info); + + $info['url'] = "/brand/".$info['brand_index']; + + return $info; + } + + + public static function formatItemImage(array $item_info) { + $info = $item_info; + + foreach (static::$resized_sizes as $size => $value) { + $info['image'][$size] = ($info['thumbnail']) ? STATIC_DOMAIN . "/". static::$image_folder . "/". $size. IMAGE_FILE_SEPARATOR . $info['thumbnail'] : ''; + } + + return $info; + } + + +} diff --git a/inc/Hura8/Components/Brand/Model/BrandLanguageModel.php b/inc/Hura8/Components/Brand/Model/BrandLanguageModel.php new file mode 100644 index 0000000..543df94 --- /dev/null +++ b/inc/Hura8/Components/Brand/Model/BrandLanguageModel.php @@ -0,0 +1,19 @@ +richtext_fields); + } + +} diff --git a/inc/Hura8/Components/Brand/Model/BrandModel.php b/inc/Hura8/Components/Brand/Model/BrandModel.php new file mode 100644 index 0000000..344e4a2 --- /dev/null +++ b/inc/Hura8/Components/Brand/Model/BrandModel.php @@ -0,0 +1,72 @@ +db->runQuery( + "SELECT `letter`, COUNT(*) AS item_count FROM `".$this->tb_entity."` GROUP BY `letter` ORDER BY `letter` ASC " + ); + return $this->db->fetchAll($query); + } + + + protected function _buildQueryConditionExtend(array $filter_condition): ?array + { + /*$condition = array( + "letter" => "", + );*/ + + $catCondition = []; + $bind_types = []; + $bind_values = []; + + + if(isset($filter_condition["letter"]) && strlen($filter_condition["letter"]) == 1){ + $catCondition[] = " AND `letter` = ? "; + $bind_types[] = 's'; + $bind_values[] = $filter_condition["letter"]; + } + + return array( join(" ", $catCondition), $bind_types, $bind_values); + } + + public function getInfoByUrl($brand_index) : ?array + { + $brand_index = preg_replace("/[^a-z0-9\.\-\_]/i", '', $brand_index); + + $query = $this->db->runQuery("SELECT * FROM `".$this->tb_entity."` WHERE `brand_index` = ? LIMIT 1 ", ['s'], [$brand_index]); + if($item_info = $this->db->fetchAssoc($query)){ + return $this->formatItemInfo($item_info); + } + + return null; + } + +} diff --git a/inc/Hura8/Components/ComboSet/AdminController/AComboSetController.php b/inc/Hura8/Components/ComboSet/AdminController/AComboSetController.php new file mode 100644 index 0000000..f64db01 --- /dev/null +++ b/inc/Hura8/Components/ComboSet/AdminController/AComboSetController.php @@ -0,0 +1,15 @@ +objComboSetModel = new ComboSetModel(); + + if(!$this->isDefaultLanguage()) { + $this->objComboSetLanguageModel = new ComboSetLanguageModel(); + //$this->objVideoLanguageModel->createTableLang(); + parent::__construct($this->objComboSetModel, $this->objComboSetLanguageModel); + + }else{ + parent::__construct($this->objComboSetModel); + } + } + + + public function getAllSetIdsForAProduct($product_id) + { + return $this->objComboSetModel->getAllSetIdsForAProduct($product_id); + } + + + public function getTotalProductUseSet($set_id) + { + return $this->objComboSetModel->getTotalProductUseSet($set_id); + } + + + public function getListProductUseSet($set_id, $numPerPage) + { + return $this->objComboSetModel->getListProductUseSet($set_id, $numPerPage); + } + + + + + + public function getProductListInfoInConfig(array $category) { + $product_list_ids = []; + foreach ($category as $index => $_category_info) { + foreach ($_category_info['suggest_list'] as $_proindex => $_pro_info) { + $product_list_ids[] = $_pro_info['real_id']; + } + } + + return array_unique($product_list_ids); + } + + + public function buildConfig( $category, $product) { + + $group_category = []; + + foreach ($category as $category_index => $_category_info) { + $category_product = []; + foreach ($product[$category_index] as $product_index => $_product_info) { + //$_product_info['price'] = clean_price($_product_info['price']); + $category_product[] = $_product_info; + } + + $group_category[] = [ + "title" => $_category_info['title'], + //"type" => "category", + //"real_id" => $_category_info['real_id'], + //"select_type" => $_category_info['select_type'],//checkbox|radio + "suggest_list" => $category_product, + ]; + } + + return $group_category; + } + + + public function decomposeConfig($config) { + $tab = []; + $group = []; + $category = []; + $product = []; + + $group_index = 0; + $category_index = 0; + $product_index = 0; + + foreach ($config as $tab_index => $tab_info) { + //construct tab + $tab[$tab_index] = [ + 'title' => $tab_info['title'], + ]; + + //construct group + foreach ($tab_info['child'] as $child_group) { + $group_index += 1; + + $group[$tab_index][$group_index] = [ + 'title' => $child_group['title'], + ]; + + //construct category + foreach ($child_group['child'] as $child_category) { + $category_index += 1; + + $category[$group_index][$category_index] = [ + 'title' => $child_category['title'], + 'real_id' => $child_category['real_id'], + 'select_type' => $child_category['select_type'], + ]; + + //construct product + foreach ($child_category['suggest_list'] as $child_product) { + $product_index += 1; + + $product[$category_index][$product_index] = [ + 'title' => $child_product['title'], + 'real_id' => $child_product['real_id'], + 'is_default' => $child_product['is_default'], + ]; + } + } + } + } + + return [ + "tab" => $tab, + "group" => $group, + 'category' => $category, + 'product' => $product, + ]; + } + + + + +} diff --git a/inc/Hura8/Components/ComboSet/Model/ComboSetLanguageModel.php b/inc/Hura8/Components/ComboSet/Model/ComboSetLanguageModel.php new file mode 100644 index 0000000..c312404 --- /dev/null +++ b/inc/Hura8/Components/ComboSet/Model/ComboSetLanguageModel.php @@ -0,0 +1,17 @@ +db->runQuery( + " SELECT `set_id` FROM ".$this->tb_set_product." WHERE `product_id` = ? ", + ['d'], [$product_id] + ); + + $item_list = array(); + foreach ( $this->db->fetchAll($query) as $info ) { + $item_list[] = $info['set_id']; + } + + return $item_list; + } + + + public function getTotalProductUseSet($set_id) + { + // search + $keyword = getRequest("q"); + if($keyword) { + $search = new ProductSearchModel(); + $match_result = $search->find($keyword); + $catCondition = (sizeof($match_result) > 0) ? " AND `product_id` IN (".join(",", $match_result).") " : " AND `product_id` = -1 "; + + $query = $this->db->runQuery(" + SELECT COUNT(product_id) AS total_product + FROM ".$this->tb_set_product." + WHERE `set_id` = ? " . $catCondition ." + ", ['d'], [$set_id]); + + if ($info = $this->db->fetchAssoc($query)) { + return $info['total_product']; + } + + return 0; + + } else { + $set_info = $this->getInfo($set_id); + + return $set_info['product_count']; + } + } + + + public function getListProductUseSet($set_id, $numPerPage) + { + $page = getPageId(); + + // search + $catCondition = ""; + $keyword = getRequest("q"); + if($keyword) { + $search = new ProductSearchModel(); + $match_result = $search->find($keyword); + $catCondition = (sizeof($match_result) > 0) ? " AND `product_id` IN (".join(",", $match_result).") " : " AND `product_id` = -1 "; + } + + $query = $this->db->runQuery(" + SELECT `product_id` + FROM ".$this->tb_set_product." + WHERE `set_id` = ? " . $catCondition ." + ORDER BY id desc + LIMIT ".($page - 1) * $numPerPage .", ".$numPerPage." + ", ['d'], [$set_id]); + + $item_list = array(); + foreach ( $this->db->fetchAll($query) as $info ) { + $item_list[] = $info['product_id']; + } + + return $item_list; + } + + + protected function _buildQueryOrderBy(string $sort_by = "new") + { + $order_condition = ""; + + switch ($sort_by) { + case "ordering"; + $order_condition = " `ordering` desc "; + break; + case "old"; + $order_condition = " id asc "; + break; + case "last_show_time"; + $order_condition = " last_show_time ASC "; + break; + } + + return $order_condition; + } + + + protected function formatItemInfo(array $item_info) : array + { + $from_time = $item_info['from_time']; + $from_time_date = ($from_time > 0) ? date("d-m-Y", $from_time) : ''; + $from_time_minute = ($from_time > 0) ? date("H:i", $from_time) : "00:00"; + + $to_time = $item_info['to_time']; + $to_time_date = ($to_time > 0) ? date("d-m-Y", $to_time) : ''; + $to_time_minute = ($to_time > 0) ? date("H:i", $to_time) : "00:00"; + + $item_info['from_time_date'] = $from_time_date; + $item_info['from_time_minute'] = $from_time_minute; + $item_info['to_time_date'] = $to_time_date; + $item_info['to_time_minute'] = $to_time_minute; + + return $item_info; + } + + + + ///--------- + /// + protected function _buildQueryConditionExtend(array $filter_condition) : ?array + { + + $catCondition = ""; + $bind_types = []; + $bind_values = []; + + if(isset($filter_condition["product_id"]) && $filter_condition["product_id"]){ + $catCondition .= " AND `id` IN ( SELECT `set_id` FROM ".$this->tb_set_product." WHERE `product_id` = ? ) "; + + $bind_types[] = 'd'; + $bind_values[] = $filter_condition['product_id']; + } + + return [$catCondition, $bind_types, $bind_values]; + } + + +} diff --git a/inc/Hura8/Components/ConfigGroup/AdminController/AConfigGroupController.php b/inc/Hura8/Components/ConfigGroup/AdminController/AConfigGroupController.php new file mode 100644 index 0000000..177ed0c --- /dev/null +++ b/inc/Hura8/Components/ConfigGroup/AdminController/AConfigGroupController.php @@ -0,0 +1,77 @@ +objConfigGroupModel->deleteAttribute($id, $group_id); + } + + + public function updateAttribute($id, $info) { + $this->objConfigGroupModel->updateAttribute($id, $info) ; + } + + + public function createAttribute($info) { + return $this->objConfigGroupModel->createAttribute($info) ; + } + + + public function createAttributeValue($info) { + $this->objConfigGroupModel->createAttributeValue($info); + } + + + public function deleteAttributeValue($id) { + $this->objConfigGroupModel->deleteAttributeValue($id); + } + + + public function updateAttributeValue($id, $info) { + $this->objConfigGroupModel->updateAttributeValue($id, $info); + } + + + public function createProduct($product_id, $group_id, array $attribute_config) { + $this->objConfigGroupModel->createProduct($product_id, $group_id, $attribute_config); + } + + + public function deleteProduct($product_id, $group_id) { + $this->objConfigGroupModel->deleteProduct($product_id, $group_id); + } + + + public function updateProduct($product_id, $group_id, array $attribute_config, $product_name_in_group = '') { + + return $this->objConfigGroupModel->updateProduct($product_id, $group_id, $attribute_config, $product_name_in_group); + } + + + public function getProductInGroup($group_id){ + return $this->objConfigGroupModel->getProductInGroup($group_id); + } + + + public function getGroupConfig($item_id) { + return $this->objConfigGroupModel->getGroupConfig($item_id); + } + + + protected function deleteFileBeforeDeleteItem($item_id): bool + { + return true; + } + + +} diff --git a/inc/Hura8/Components/ConfigGroup/Controller/bConfigGroupController.php b/inc/Hura8/Components/ConfigGroup/Controller/bConfigGroupController.php new file mode 100644 index 0000000..3f5baff --- /dev/null +++ b/inc/Hura8/Components/ConfigGroup/Controller/bConfigGroupController.php @@ -0,0 +1,24 @@ +objConfigGroupModel = new ConfigGroupModel(); + parent::__construct($this->objConfigGroupModel); + } + + + +} diff --git a/inc/Hura8/Components/ConfigGroup/Model/ConfigGroupModel.php b/inc/Hura8/Components/ConfigGroup/Model/ConfigGroupModel.php new file mode 100644 index 0000000..e149db8 --- /dev/null +++ b/inc/Hura8/Components/ConfigGroup/Model/ConfigGroupModel.php @@ -0,0 +1,500 @@ +tb_config_group = $this->tb_entity; + } + + + protected function extendedFilterOptions() : array + { + return [ + // empty for now + ]; + } + + + protected function updateGroupAttributeCount($group_id) { + $this->db->runQuery( + "UPDATE `".$this->tb_config_group."` SET + `attribute_count` = ( SELECT COUNT(*) FROM `".$this->tb_config_group_attribute."` WHERE `group_id` = ? ) + WHERE `id` = ? LIMIT 1 ", + ['d', 'd'], [ $group_id, $group_id ] + ); + } + + + protected function updateGroupProductCount($group_id) { + $this->db->runQuery( + "UPDATE `".$this->tb_config_group."` SET + `item_count` = ( SELECT COUNT(*) FROM `".$this->tb_config_group_product."` WHERE `group_id` = ? ) + WHERE `id` = ? LIMIT 1 ", + ['d', 'd'], [ $group_id, $group_id ] + ); + } + + + //attribute value + public function deleteAttributeValue($att_value_id) { + + $attr_id = 0; + $query = $this->db->runQuery("SELECT `attr_id` FROM `".$this->tb_config_group_attribute_value."` WHERE `id` = ? LIMIT 1 ", ['d'], [ $att_value_id ]); + if ($info = $this->db->fetchAssoc($query)) { + $attr_id = $info['attr_id']; + } + + $group_id = $this->getGroupIdFromAttribute($attr_id); + + $this->db->runQuery("DELETE FROM `".$this->tb_config_group_attribute_value."` WHERE `id` = ? LIMIT 1 ", ['d'], [ $att_value_id ]); + + $this->resetProductConfigCache($group_id); + + $this->updateAttributeValueCount($attr_id); + } + + + protected function updateAttributeValueCount($attr_id) { + $this->db->runQuery( + "UPDATE `".$this->tb_config_group_attribute."` SET + `value_count` = ( SELECT COUNT(*) FROM `".$this->tb_config_group_attribute_value."` WHERE `attr_id` = ? ) + WHERE `id` = ? LIMIT 1 ", + ['d', 'd'], + [$attr_id, $attr_id ] + ); + } + + + public function updateAttributeValue($id, $info) { + + $updated_info = $info; + + $updated_info['last_update'] = CURRENT_TIME; + $updated_info['last_update_by'] = ADMIN_NAME; + + $this->db->update( + $this->tb_config_group_attribute_value, + $updated_info, + [ + "id" => $id, + ] + ); + + $group_id = $this->getGroupIdFromAttributeValue($id); + $this->resetProductConfigCache($group_id); + } + + + public function createAttributeValue($info) { + $updated_info = $info; + + $updated_info['create_time'] = CURRENT_TIME; + $updated_info['create_by'] = ADMIN_NAME; + $updated_info['last_update'] = CURRENT_TIME; + $updated_info['last_update_by'] = ADMIN_NAME; + + $this->db->insert($this->tb_config_group_attribute_value, $updated_info ); + + $group_id = $this->getGroupIdFromAttribute($info['attr_id']); + $this->resetProductConfigCache($group_id); + + $this->updateAttributeValueCount($info['attr_id']); + } + + //attribute + public function deleteAttribute($id, $group_id = 0) { + if(!$group_id) $group_id = $this->getGroupIdFromAttribute($id); + $this->db->runQuery("DELETE FROM `".$this->tb_config_group_attribute."` WHERE `id` = ? LIMIT 1 ", ['d'], [ $id ]); + $this->db->runQuery("DELETE FROM `".$this->tb_config_group_attribute_value."` WHERE `attr_id` = ? LIMIT 1 ", ['d'], [ $id ]); + + $this->updateGroupAttributeCount($group_id); + + //todo: update for product attribute_config ? + $this->resetProductConfigCache($group_id); + } + + public function updateAttribute($id, $info) { + + $updated_info = $info; + + $updated_info['last_update'] = CURRENT_TIME; + $updated_info['last_update_by'] = ADMIN_NAME; + + $this->db->update( + $this->tb_config_group_attribute, + $updated_info, + [ + 'id' => $id, + ] + ); + + $group_id = $this->getGroupIdFromAttribute($id); + $this->resetProductConfigCache($group_id); + } + + public function createAttribute($info) { + + $updated_info = $info; + + $updated_info['create_time'] = CURRENT_TIME; + $updated_info['create_by'] = ADMIN_NAME; + $updated_info['last_update'] = CURRENT_TIME; + $updated_info['last_update_by'] = ADMIN_NAME; + + $this->db->insert($this->tb_config_group_attribute, $updated_info ); + + $this->resetProductConfigCache($info['group_id']); + + $this->updateGroupAttributeCount($info['group_id']); + + return $this->db->get_insert_id(); + } + + private function getGroupIdFromAttributeValue($att_value_id) { + $attr_id = 0; + $query = $this->db->runQuery("SELECT `attr_id` FROM `".$this->tb_config_group_attribute_value."` WHERE `id` = ? LIMIT 1 ", ['d'], [ $att_value_id ]); + if ($info = $this->db->fetchAssoc($query)) { + $attr_id = $info['attr_id']; + } + + return $this->getGroupIdFromAttribute($attr_id); + } + + private function getGroupIdFromAttribute($attr_id) { + $group_id = 0; + $query = $this->db->runQuery("SELECT `group_id` FROM `".$this->tb_config_group_attribute."` WHERE `id` = ? LIMIT 1 ", ['d'], [ $attr_id ]); + if ($info = $this->db->fetchAssoc($query)) { + $group_id = $info['group_id']; + } + + return $group_id; + } + + //create or update product in a group + public function createProduct($product_id, $group_id, array $attribute_config) { + if($this->isProductInGroup($product_id, $group_id)) { + + $this->updateProduct($product_id, $group_id, $attribute_config); + + }else { + + $updated_info = [ + "product_id" => $product_id, + "group_id" => $group_id, + "attribute_config" => json_encode($attribute_config), + + "create_time" => CURRENT_TIME, + "create_by" => ADMIN_NAME, + "last_update" => CURRENT_TIME, + "last_update_by" => ADMIN_NAME, + ]; + + $this->db->insert($this->tb_config_group_product, $updated_info ); + + $this->updateGroupProductCount($group_id); + + } + + $this->resetProductConfigCache($group_id); + } + + public function deleteProduct($product_id, $group_id) { + $this->db->runQuery( + "DELETE FROM `".$this->tb_config_group_product."` WHERE `product_id` = ? AND `group_id` = ? LIMIT 1 ", + ['d', 'd'], [ $product_id, $group_id ] + ); + + $this->deleteProductConfigCache($product_id); + + $this->updateGroupProductCount($group_id); + } + + public function updateProduct($product_id, $group_id, array $attribute_config, $product_name_in_group = '') { + + $this->db->update( + $this->tb_config_group_product, + [ + "attribute_config" => json_encode($attribute_config), + "product_name_in_group" => substr($product_name_in_group, 0, 140), + "last_update" => CURRENT_TIME, + "last_update_by" => ADMIN_NAME, + ], + [ + "product_id" => $product_id, + "group_id" => $group_id, + ] + ); + + $this->resetProductConfigCache($group_id); + + return true; + } + + + //we want to reset all caches for products in a group + //we need to do this when we make changes to group's attributes, or create new products/ update product in group + protected function resetProductConfigCache($group_id) { + $query = $this->db->runQuery("SELECT `product_id` FROM `".$this->tb_config_group_product."` WHERE `group_id` = ? ", ['d'], [$group_id]) ; + $product_list = array(); + foreach( $this->db->fetchAll($query) as $item ){ + $product_list[] = $item['product_id']; + } + + if(sizeof($product_list)) { + $this->db->query("UPDATE `".$this->tb_config_group_product_cache."` SET + `value` = NULL + WHERE `product_id` IN (".join(",", $product_list).") ") ; + } + } + + + protected function deleteProductConfigCache($product_id) { + $this->db->runQuery("DELETE FROM `".$this->tb_config_group_product_cache."` WHERE `product_id` = ? LIMIT 1 ", ['d'], [$product_id]) ; + } + + + public function saveProductConfigCache($product_id, $value) { + + $query = $this->db->runQuery( + "SELECT `product_id` FROM `".$this->tb_config_group_product_cache."` WHERE `product_id` = ? LIMIT 1 ", + ['d'], [$product_id] + ) ; + + if($this->db->fetchAssoc($query)){ + $this->db->runQuery( + "UPDATE `".$this->tb_config_group_product_cache."` SET + `value` = '".$this->db->escape(json_encode($value))."' + WHERE `product_id` = ? LIMIT 1 ", + ['d'], [$product_id] + ) ; + }else{ + $this->db->runQuery("INSERT INTO `".$this->tb_config_group_product_cache."` (`product_id`, `value`) + VALUES ('". (int) $product_id."', '".$this->db->escape(json_encode($value))."') ") ; + } + } + + + public function getProductConfigCache($product_id) { + $query = $this->db->runQuery("SELECT `value` FROM `".$this->tb_config_group_product_cache."` WHERE `product_id` = ? LIMIT 1 ", ['d'], [$product_id]) ; + if($item_info = $this->db->fetchAssoc($query)){ + return ($item_info['value']) ? \json_decode($item_info['value'], true) : false; + } + + return false; + } + + + //get all group config + public function getGroupConfig($group_id) { + + $query = $this->db->runQuery( + "SELECT + a.id AS attribute_id , + a.name AS attribute_name , + a.ordering AS attr_ordering , + v.id AS value_id , + v.name AS value_name , + v.image AS image , + v.color_code AS color , + v.ordering , + v.description AS description + FROM `".$this->tb_config_group_attribute."` a + LEFT JOIN `".$this->tb_config_group_attribute_value."` v ON a.id = v.attr_id + WHERE a.group_id = ? + ORDER BY attr_ordering DESC, `ordering` DESC + ", + ['d'], [$group_id] + ); + + $group_attribute = array(); + foreach ( $this->db->fetchAll($query) as $info ) { + if(!isset($group_attribute[$info['attribute_id']])) { + $group_attribute[$info['attribute_id']] = array( + 'id' => $info['attribute_id'], + 'name' => $info['attribute_name'], + 'ordering' => $info['attr_ordering'], + 'list' => array(), + ); + } + + if($info['value_id']) { + $group_attribute[$info['attribute_id']]['list'][] = array( + 'id' => $info['value_id'], + 'name' => $info['value_name'], + 'image' => $info['image'], + 'color' => $info['color'], + 'ordering' => $info['ordering'], + 'description' => $info['description'], + ); + } + } + + return $group_attribute; + } + + + public function getProductConfigGroupId($product_id) { + $query = $this->db->runQuery( + "SELECT `group_id` FROM `".$this->tb_config_group_product."` WHERE `product_id` = ? LIMIT 1 ", + ['d'], [$product_id] + ) ; + + if($item_info = $this->db->fetchAssoc($query)){ + return $item_info['group_id']; + } + + return 0; + } + + + public function getProductInGroup($group_id){ + $query = $this->db->runQuery( + "SELECT `product_id`, `product_name_in_group`, `attribute_config` + FROM `".$this->tb_config_group_product."` + WHERE `group_id` = ? + ", + ['d'], [$group_id] + ); + + $product_list = array(); + $product_ids = array(); + + foreach ( $this->db->fetchAll($query) as $info ) { + $product_ids[] = $info['product_id']; + + $product_list[$info['product_id']] = array( + "id" => $info['product_id'], + "name" => "", + "product_name_in_group" => $info['product_name_in_group'], + "attribute" => \json_decode($info['attribute_config'], true), + "url" => "", + "sku" => "", + "price" => 0, + "image" => "", + "status" => "", + ); + } + + //find product urls + if(sizeof($product_ids)) { + $objProductModel = new ProductModel(); + $product_list_info = $objProductModel->getListByIds($product_ids); + + // debug_var($product_list_info); + // update $product_list + foreach ($product_list as $_pro_id => $_info) { + $_pro_info = $product_list_info[$_pro_id] ?? null; + if($_pro_info) { + $product_list[$_pro_id]['name'] = $_pro_info['title']; + $product_list[$_pro_id]['price'] = $_pro_info['price']; + $product_list[$_pro_id]['sku'] = $_pro_info['sku']; + $product_list[$_pro_id]['image'] = $_pro_info['thumbnail']; + $product_list[$_pro_id]['url'] = $_pro_info['request_path']; + $product_list[$_pro_id]['status'] = $_pro_info['status']; + } + } + } + + return $product_list; + } + + + protected function isProductInGroup($product_id, $group_id) { + $query = $this->db->runQuery( + "SELECT * FROM `".$this->tb_config_group_product."` WHERE `product_id` = ? AND `group_id` = ? LIMIT 1 ", + ['d', 'd'], + [$product_id, $group_id] + ) ; + + return ($this->db->fetchAssoc($query)); + } + + + protected function _buildQueryConditionExtend(array $filter_condition) : ?array + { + /*$condition = array( + "q" => "", + "numPerPage" => 20, + "order_by" => '', + );*/ + + $catCondition = ""; + + return [ + $catCondition, + [], + [] + ]; + } + + protected function beforeCreateItem(array $input_info): AppResponse + { + $info = $input_info; + + $info['create_time'] = CURRENT_TIME; + $info['create_by'] = ADMIN_NAME; + $info['last_update'] = CURRENT_TIME; + $info['last_update_by'] = ADMIN_NAME; + + return new AppResponse('ok', null, $info); + } + + protected function afterCreateItem($new_item_id, $new_item_info) + { + // TODO: Implement afterCreateItem() method. + } + + protected function beforeUpdateItem($item_id, $current_item_info, $new_input_info):AppResponse + { + $info = $new_input_info; + + $info['last_update'] = CURRENT_TIME; + $info['last_update_by'] = ADMIN_NAME; + + return new AppResponse('ok', null, $info); + } + + protected function afterUpdateItem($item_id, $old_item_info, $new_item_info) + { + // TODO: Implement afterUpdateItem() method. + } + + protected function beforeDeleteItem($item_id, $item_info):AppResponse + { + return new AppResponse('ok' ); + } + + protected function afterDeleteItem($item_id, $item_info) + { + + $query = $this->db->runQuery("SELECT `id` FROM `".$this->tb_config_group_attribute."` WHERE `group_id` = ? ", ['d'], [$item_id]); + + foreach ( $this->db->fetchAll($query) as $info ) { + $this->deleteAttribute($info['id'], $item_id); + } + + $this->db->runQuery( + "DELETE FROM `".$this->tb_config_group_product_cache."` WHERE `product_id` IN (SELECT product_id FROM config_group_product WHERE `group_id` = ? ) ", + ['d'], [$item_id] + ) ; + + $this->db->runQuery("DELETE FROM `".$this->tb_config_group_product."` WHERE `group_id` = ? ", ['d'], [$item_id]) ; + } +} diff --git a/inc/Hura8/Components/Customer/AdminController/ACustomerController.php b/inc/Hura8/Components/Customer/AdminController/ACustomerController.php new file mode 100644 index 0000000..f01f7f6 --- /dev/null +++ b/inc/Hura8/Components/Customer/AdminController/ACustomerController.php @@ -0,0 +1,23 @@ +objCustomerGroupModel = new CustomerGroupModel(); + parent::__construct($this->objCustomerGroupModel); + } + + + public function getAllGroup() { + return $this->objCustomerGroupModel->getList(["numPerPage" => 1000]); + } + + + public function removeCustomer($customer_id, $group_id) + { + return $this->objCustomerGroupModel->removeCustomer($customer_id, $group_id); + } + + + public function addCustomer($customer_id, $group_id) + { + return $this->objCustomerGroupModel->addCustomer($customer_id, $group_id); + } + + + public function getTotalCustomer($group_id, array $condition = []) + { + return $this->objCustomerGroupModel->getTotalCustomer($group_id, $condition); + } + + + public function getListCustomer($group_id, array $condition = []) { + + $objProvinceController = new AProvinceController(); + + return array_map(function ($item) use ($objProvinceController){ + + $item['province_name'] = $objProvinceController->getProvinceName($item['province']); + + return $item; + + }, $this->objCustomerGroupModel->getListCustomer($group_id, $condition)); + } + + + protected function deleteFileBeforeDeleteItem($item_id): bool + { + // TODO: Implement deleteFileBeforeDeleteItem() method. + return true; + } +} diff --git a/inc/Hura8/Components/Customer/AdminController/ACustomerLoyaltyController.php b/inc/Hura8/Components/Customer/AdminController/ACustomerLoyaltyController.php new file mode 100644 index 0000000..d3eb87c --- /dev/null +++ b/inc/Hura8/Components/Customer/AdminController/ACustomerLoyaltyController.php @@ -0,0 +1,9 @@ +objCustomerModel = new CustomerModel(); + $this->objProvinceController = new AProvinceController(); + parent::__construct($this->objCustomerModel); + } + + + public function formatItemInList(array $item_info) + { + return $this->formatItemInfo($item_info); + } + + + public function formatItemInfo(array $item_info) + { + $info = $item_info; + $info['province_name'] = $this->objProvinceController->getProvinceName($item_info['province']); + + return $info; + } + +} diff --git a/inc/Hura8/Components/Customer/Controller/bCustomerLoyaltyController.php b/inc/Hura8/Components/Customer/Controller/bCustomerLoyaltyController.php new file mode 100644 index 0000000..8ca17ce --- /dev/null +++ b/inc/Hura8/Components/Customer/Controller/bCustomerLoyaltyController.php @@ -0,0 +1,206 @@ +objCustomerLoyaltyModel = new CustomerLoyaltyModel(); + + // import settings + //$new_info_file = "../config/build/customer_point.php" ; + //$config_file = ROOT_DIR . "/config/build/customer_point.php"; + if(@file_exists($this->point_setting_config_file)) { + $this->point_setting = include $this->point_setting_config_file; + } + + // customer level based on point gain + if( defined("ENABLE_CUSTOMER_POINT") && ENABLE_CUSTOMER_POINT ) { + if(@file_exists($this->level_setting_config_file)) { + $this->level_setting = include $this->level_setting_config_file; + } + } + + // default is point + $this->level_by = (defined('CHANGE_CUSTOMER_LEVEL_BY')) ? CHANGE_CUSTOMER_LEVEL_BY : 'point'; + + $this->objUserLoyaltyPointCalculation = new UserLoyaltyPointCalculation($this->point_setting); + + } + + + public function getPointSettingConfigFile() { + return $this->point_setting_config_file; + } + + public function getPointSetting() { + return $this->point_setting; + } + + public function getLevelSetting(){ + return $this->level_setting; + } + + // show estimate cart point + public function getEstimateCartPoint($cart_value){ + $conversion_rate = (isset($this->point_setting['reward']['buy']['rate'])) ? $this->point_setting['reward']['buy']['rate'] : 0; + return ($conversion_rate) ? round($cart_value / $conversion_rate) : 0; + } + + public function getUserPoint($user_id, array $condition, $return_type) + { + return $this->objCustomerLoyaltyModel->getUserPoint($user_id, $condition, $return_type); + } + + // remove rewarded point i.e. reward for successfull order and now order is marked canceled + public function reclaimRewardedPoint($user_id, $activity_type_tracker){ + // todo: + } + + public function usePoint($user_id, $use_point, $activity_type, $activity_type_tracker, $reason = '', $point_args = ['order_value' => 0]){ + // no user or no config + if(!$user_id || !ENABLE_CUSTOMER_POINT) return false; + + $result = $this->objUserLoyaltyPointCalculation->calculateUsePoint($user_id, $use_point, $activity_type, $activity_type_tracker, $point_args); + + $this->pointOp('use', $user_id, $result['use_point'], $activity_type, $activity_type_tracker, $reason); + + return $result; + } + + + public function rewardPoint($user_id, $activity_type, $activity_type_tracker, $reason = '', $point_args = ['order_id' => 0]){ + // no user or no config + if(!$user_id || !ENABLE_CUSTOMER_POINT) return false; + + $point = $this->objUserLoyaltyPointCalculation->calculateRewardPoint($user_id, $activity_type, $activity_type_tracker, $point_args); + + $this->pointOp('reward', $user_id, $point, $activity_type, $activity_type_tracker, $reason); + + return $point; + } + + // $operation: reward|use + // $change_point: positive (reward) or nagative (use) + protected function pointOp($operation, $user_id, $change_point, $activity_type, $activity_type_tracker, $reason = '') { + + if(!$change_point) return false; + + $reason_prefix = ($operation == 'use') ? 'Sử dụng' : 'Thưởng'; + if($activity_type == 'return') $reason_prefix = 'Hoàn lại'; + $full_reason = join(" ", [$reason_prefix, $change_point, static::$POINT_NAME, ":", $reason]); + + if($operation == 'use') $change_point = -1 * $change_point; + + // security: hash the row to avoid editing point directly in the database + $hash_value = sha1(join(".", [ + $operation, + $user_id, + $change_point, + $activity_type, + $activity_type_tracker, + CURRENT_TIME, + 'ass@ss' + ])); + + $new_id = $this->db->insert( + $this->tb_point , + [ + 'customer_id' => $user_id , + 'activity_type' => $activity_type, + 'activity_type_tracker' => $activity_type_tracker , + 'operation' => $operation, + 'point' => $change_point, + 'create_time' => CURRENT_TIME, + 'reason' => substr($full_reason, 0, 200), + 'referer_url' => substr(REFERER_URL, 0, 150) , + 'hash_value' => $hash_value , + ] + ); + + //update user reward balance + if($new_id) { + $this->updateStat($user_id, $change_point); + } + + return $new_id; + } + + protected function updateStat($user_id, $changed_point, $changed_order_value=0) { + return $this->objCustomerLoyaltyModel->updateStat($user_id, $changed_point, $changed_order_value); + } + + private function calculateLevelByPoint($point) { + //if the point in between -> return the lowest level + $all_level = array_keys($this->level_setting); + + foreach ( $all_level as $level) { + $next_level = $level + 1; + if(!in_array($next_level, $all_level)) $next_level = 0; + + if($next_level) { + if( $point >= $this->level_setting[$level]["point_require"] + && $point < $this->level_setting[$next_level]["point_require"] ) { + return $level; + } + }else{ + if($point >= $this->level_setting[$level]["point_require"]) { + return $level; + } + } + } + + return 0; + } + + private function calculateLevelByOrderValue($aggregate_purchase_value = 0) { + + //if the point in between -> return the lowest level + $all_level = array_keys($this->level_setting); + + //tinh hang thanh vien theo so tien tich luy + foreach ( $all_level as $level ) { + $next_level = $level + 1; + if(!in_array($next_level, $all_level)) $next_level = 0; + + if($next_level) { + if( $aggregate_purchase_value >= $this->level_setting[$level]["total_order_value"] && + $aggregate_purchase_value < $this->level_setting[$next_level]["total_order_value"] + ) { + return $level; + } + }else{ + if( $aggregate_purchase_value >= $this->level_setting[$level]["total_order_value"]) { + return $level; + } + } + } + + return 0; + } + + +} diff --git a/inc/Hura8/Components/Customer/Model/CustomerAuthModel.php b/inc/Hura8/Components/Customer/Model/CustomerAuthModel.php new file mode 100644 index 0000000..3360bad --- /dev/null +++ b/inc/Hura8/Components/Customer/Model/CustomerAuthModel.php @@ -0,0 +1,79 @@ +tb_customer_login, $this->tb_customer_access_code); + } + + + public function getLoginListByIds(array $staff_ids) { + if(!sizeof($staff_ids)) { + return []; + } + + list($parameterized_ids, $bind_types) = create_bind_sql_parameter_from_value_list($staff_ids, 'int'); + + $bind_values = $staff_ids; + + $query = $this->db->runQuery( + "SELECT `user_id`, `last_login_time`, `last_login_ip`, `last_login_device`, `last_login_browser` + FROM ".$this->tb_customer_login." + WHERE `user_id` IN (".$parameterized_ids.") ", + $bind_types, + $bind_values + ); + + $item_list = []; + foreach ($this->db->fetchAll($query) as $item) { + $item_list[$item['user_id']] = $item; + } + + return $item_list; + } + + + public function getLoginLog(array $conditions = []) { + $bind_types = []; + $bind_values = []; + + $query = $this->db->runQuery( + "SELECT * FROM ".$this->tb_customer_login_log." WHERE 1 ORDER BY `id` DESC LIMIT 100 ", + $bind_types, + $bind_values + ); + + return $this->db->fetchAll($query) ; + } + + + /** + * @param $email + * @param string $login_status ok or error + * @param string $login_msg + */ + public function logLogin($email, $login_status, $login_msg) { + $this->db->insert( + $this->tb_customer_login_log, + [ + "email" => substr($email, 0, 45), + "login_status" => $login_status, + "login_msg" => substr($login_msg, 0, 45), + "ip_address" => substr(USER_IP, 0, 45), + "user_agent" => substr(USER_AGENT, 0, 99), + "create_time" => CURRENT_TIME, + ] + ); + } + +} diff --git a/inc/Hura8/Components/Customer/Model/CustomerGroupModel.php b/inc/Hura8/Components/Customer/Model/CustomerGroupModel.php new file mode 100644 index 0000000..ee243fd --- /dev/null +++ b/inc/Hura8/Components/Customer/Model/CustomerGroupModel.php @@ -0,0 +1,213 @@ +db->runQuery( + "UPDATE `".$this->tb_entity."` SET + `customer_count` = (SELECT COUNT(*) AS total FROM `".$this->tb_customer_per_group."` WHERE `group_id` = ? ) + WHERE `id` = ? LIMIT 1 + ", + ['d', 'd'], [$group_id, $group_id] + ); + } + + + public function getTotalCustomer($group_id, array $condition = []) + { + $query = $this->db->runQuery( + " SELECT COUNT(*) as total FROM `".$this->tb_customer_per_group."` WHERE `group_id` = ? ", + ['d'], [$group_id] + ); + + $total = 0; + if ($rs = $this->db->fetchAssoc($query)) { + $total = $rs['total']; + } + + return $total; + } + + + public function getListCustomer($group_id, array $condition = []) + { + $numPerPage = (isset($condition['numPerPage']) && $condition['numPerPage'] > 0 ) ? intval($condition['numPerPage']) : 20 ; + $page = (isset($condition['page']) && $condition['page'] > 0 ) ? intval($condition['page']) : 1 ; + $order_by = " `id` DESC"; + + $query = $this->db->runQuery( + "SELECT `customer_id` FROM ".$this->tb_customer_per_group." WHERE `group_id` = ? + ORDER BY ".$order_by." + LIMIT ".(($page-1) * $numPerPage).", ".$numPerPage , + ['d'], [$group_id] + ) ; + + $item_list_ids = array_map(function ($item){ return $item['customer_id'];}, $this->db->fetchAll($query)); + + $objCustomerModel = new CustomerModel(); + $list_info = $objCustomerModel->getListByIds($item_list_ids); + + // final list + $final_list = []; + foreach ($item_list_ids as $_id) { + $final_list[] = $list_info[$_id] ?? null; + } + + return $final_list; + } + + + public function removeCustomerFromAllGroup($customer_id) + { + $this->db->runQuery( + "DELETE FROM `".$this->tb_customer_per_group."` WHERE `customer_id` = ?", + ['d'], [$customer_id] + ); + + return true; + } + + + public function removeCustomer($customer_id, $group_id) + { + $this->db->runQuery( + "DELETE FROM `".$this->tb_customer_per_group."` WHERE `group_id` =? AND `customer_id` = ? LIMIT 1 ", + ['d', 'd'], + [$group_id, $customer_id] + ); + + $this->updateItemCount($group_id); + + return true; + } + + + public function addCustomer($customer_id, $group_id) + { + $query = $this->db->runQuery( + " SELECT * FROM `".$this->tb_customer_per_group."` WHERE `group_id` = ? AND `customer_id` = ? LIMIT 1 ", + ['d', 'd'], + [$group_id, $customer_id] + ); + + if ($this->db->fetchAssoc($query)) { + return false; + } + + $this->db->insert( + $this->tb_customer_per_group, + [ + "group_id" => $group_id, + "customer_id" => $customer_id, + ] + ); + + $this->updateItemCount($group_id); + + return true; + } + + + protected function _buildQueryConditionExtend(array $filter_condition): ?array + { + /*$condition = array( + "q" => "", + "status" => 0, + );*/ + + $catCondition = []; + $bind_types = []; + $bind_values = []; + + return array( join(" ", $catCondition), $bind_types, $bind_values); + } + + + protected function beforeCreateItem(array $input_info) : AppResponse + { + $info = $input_info; + + if(!$info['group_code']) $info['group_code'] = $info['title']; + $info['group_code'] = $this->createUniqueCode(0, $info['group_code']); + + $info['create_time'] = CURRENT_TIME; + $info['create_by'] = ADMIN_NAME; + + return new AppResponse('ok', null, $info); + } + + + protected function afterCreateItem($new_item_id, $new_item_info) + { + + } + + protected function beforeUpdateItem($item_id, $current_item_info, $new_input_info): AppResponse + { + $info = $new_input_info; + + if(isset($info['group_code'])) { + if(!$info['group_code']) $info['group_code'] = $info['title']; + $info['group_code'] = $this->createUniqueCode($item_id, $info['group_code']); + } + + $info['last_update'] = CURRENT_TIME; + $info['last_update_by'] = ADMIN_NAME; + + return new AppResponse('ok', null, $info); + } + + + protected function createUniqueCode($current_item_id, $wanted_code){ + + $clean_code = UrlManagerController::create_url_index($wanted_code); + + //if exist and belong other id, create a new one + $query = $this->db->runQuery("SELECT `id` FROM `".$this->tb_entity."` WHERE `group_code` = ? LIMIT 1 ", ['s'], [$clean_code]) ; + if($info = $this->db->fetchAssoc($query)){ + if($info['id'] != $current_item_id) { + $new_code = $clean_code."-".IDGenerator::createStringId(3); + return $this->createUniqueCode($current_item_id, $new_code); + } + } + + return $clean_code; + } + + + protected function afterUpdateItem($item_id, $old_item_info, $new_item_info) + { + + } + + protected function beforeDeleteItem($item_id, $item_info) : AppResponse + { + return new AppResponse('ok'); + } + + protected function afterDeleteItem($item_id, $item_info) + { + + } + + protected function extendedFilterOptions(): array + { + return []; + } +} diff --git a/inc/Hura8/Components/Customer/Model/CustomerLoyaltyModel.php b/inc/Hura8/Components/Customer/Model/CustomerLoyaltyModel.php new file mode 100644 index 0000000..a10b3ea --- /dev/null +++ b/inc/Hura8/Components/Customer/Model/CustomerLoyaltyModel.php @@ -0,0 +1,268 @@ +db = get_db("", ENABLE_DB_DEBUG); + + // import settings + //$new_info_file = "../config/build/customer_point.php" ; + //$config_file = ROOT_DIR . "/config/build/customer_point.php"; + if(@file_exists($this->point_setting_config_file)) { + $this->point_setting = include $this->point_setting_config_file; + } + + // customer level based on point gain + if( defined("ENABLE_CUSTOMER_POINT") && ENABLE_CUSTOMER_POINT ) { + if(@file_exists($this->level_setting_config_file)) { + $this->level_setting = include $this->level_setting_config_file; + } + } + + // default is point + $this->level_by = (defined('CHANGE_CUSTOMER_LEVEL_BY')) ? CHANGE_CUSTOMER_LEVEL_BY : 'point'; + + $this->objUserLoyaltyPointCalculation = new UserLoyaltyPointCalculation($this->point_setting); + } + + + public function getPointSettingConfigFile() { + return $this->point_setting_config_file; + } + + public function getPointSetting() { + return $this->point_setting; + } + + public function getLevelSetting(){ + return $this->level_setting; + } + + // show estimate cart point + public function getEstimateCartPoint($cart_value){ + $conversion_rate = (isset($this->point_setting['reward']['buy']['rate'])) ? $this->point_setting['reward']['buy']['rate'] : 0; + return ($conversion_rate) ? round($cart_value / $conversion_rate) : 0; + } + + public function getUserPoint($user_id, array $condition, $return_type) + { + + if($return_type == "total") { + //Lay tong so + $query = $this->db->runQuery("SELECT COUNT(*) AS total FROM `". $this->tb_point ."` WHERE `customer_id` = ? " , ['d'], [$user_id]); + if($resultTotal = $this->db->fetchAssoc($query)){ + return $resultTotal['total']; + } + return 0; + + } else { + + $numPerPage = (isset($condition['numPerPage'])) ? intval($condition['numPerPage']) : 50; + $page = getPageId(); + + $query = $this->db->runQuery(" + SELECT * FROM `". $this->tb_point ."` + WHERE `customer_id` = ? + ORDER BY id DESC + LIMIT ".($page - 1) * $numPerPage .", ".$numPerPage." " , ['d'], [$user_id]); + + $result = array(); + $i = ($page - 1) * $numPerPage; + foreach ( $this->db->fetchAll($query) as $rs){ + $i++; + $rs['counter'] = $i; + $rs['activity_type_name'] = (isset($this->point_setting[$rs['operation']][$rs['activity_type']])) ? $this->point_setting[$rs['operation']][$rs['activity_type']]['name'] : '--'; + $result[] = $rs; + } + + return $result; + } + + } + + + public function usePoint($user_id, $use_point, $activity_type, $activity_type_tracker, $reason = '', $point_args = ['order_value' => 0]){ + // no user or no config + if(!$user_id || !ENABLE_CUSTOMER_POINT) return false; + + $result = $this->objUserLoyaltyPointCalculation->calculateUsePoint($user_id, $use_point, $activity_type, $activity_type_tracker, $point_args); + + $this->pointOp('use', $user_id, $result['use_point'], $activity_type, $activity_type_tracker, $reason); + + return $result; + } + + + public function rewardPoint($user_id, $activity_type, $activity_type_tracker, $reason = '', $point_args = ['order_id' => 0]){ + // no user or no config + if(!$user_id || !ENABLE_CUSTOMER_POINT) return false; + + $point = $this->objUserLoyaltyPointCalculation->calculateRewardPoint($user_id, $activity_type, $activity_type_tracker, $point_args); + + $this->pointOp('reward', $user_id, $point, $activity_type, $activity_type_tracker, $reason); + + return $point; + } + + + // $operation: reward|use + // $change_point: positive (reward) or nagative (use) + protected function pointOp($operation, $user_id, $change_point, $activity_type, $activity_type_tracker, $reason = '') { + + if(!$change_point) return false; + + $reason_prefix = ($operation == 'use') ? 'Sử dụng' : 'Thưởng'; + if($activity_type == 'return') $reason_prefix = 'Hoàn lại'; + $full_reason = join(" ", [$reason_prefix, $change_point, static::$POINT_NAME, ":", $reason]); + + if($operation == 'use') $change_point = -1 * $change_point; + + // security: hash the row to avoid editing point directly in the database + $hash_value = sha1(join(".", [ + $operation, + $user_id, + $change_point, + $activity_type, + $activity_type_tracker, + CURRENT_TIME, + 'ass@ss' + ])); + + $new_id = $this->db->insert( + $this->tb_point , + [ + 'customer_id' => $user_id , + 'activity_type' => $activity_type, + 'activity_type_tracker' => $activity_type_tracker , + 'operation' => $operation, + 'point' => $change_point, + 'create_time' => CURRENT_TIME, + 'reason' => substr($full_reason, 0, 200), + 'referer_url' => substr(REFERER_URL, 0, 150) , + 'hash_value' => $hash_value , + ] + ); + + //update user reward balance + if($new_id) { + $this->updateStat($user_id, $change_point); + } + + return $new_id; + } + + + public function updateStat($user_id, $changed_point, $changed_order_value=0) { + $user_id = intval($user_id); + + $query = $this->db->runQuery("SELECT + `loyalty_point`, + `loyalty_level`, + `total_value_success` + FROM ".$this->tb_customer." + WHERE `id` = ? + LIMIT 1 " , ['d'], [$user_id]); + + if($current = $this->db->fetchAssoc($query)){ + $new_point = $current['loyalty_point'] + $changed_point; + $new_purchase_value = $current['total_value_success'] + $changed_order_value; + + $level = $current['loyalty_level']; + if($this->level_by == 'point' && $changed_point != 0) $level = $this->calculateLevelByPoint($new_point); + else if($changed_order_value) $level = $this->calculateLevelByOrderValue($new_purchase_value); + + $this->db->update( + $this->tb_customer , + [ + 'loyalty_point' => $new_point, + 'loyalty_level' => $level, + 'total_value_success' => $new_purchase_value, + ], + [ + 'id' => $user_id, + ], + 1 + ); + } + + return true; + } + + + private function calculateLevelByPoint($point) { + //if the point in between -> return the lowest level + $all_level = array_keys($this->level_setting); + + foreach ( $all_level as $level) { + $next_level = $level + 1; + if(!in_array($next_level, $all_level)) $next_level = 0; + + if($next_level) { + if( $point >= $this->level_setting[$level]["point_require"] + && $point < $this->level_setting[$next_level]["point_require"] ) { + return $level; + } + }else{ + if($point >= $this->level_setting[$level]["point_require"]) { + return $level; + } + } + } + + return 0; + } + + private function calculateLevelByOrderValue($aggregate_purchase_value = 0) { + + //if the point in between -> return the lowest level + $all_level = array_keys($this->level_setting); + + //tinh hang thanh vien theo so tien tich luy + foreach ( $all_level as $level ) { + $next_level = $level + 1; + if(!in_array($next_level, $all_level)) $next_level = 0; + + if($next_level) { + if( $aggregate_purchase_value >= $this->level_setting[$level]["total_order_value"] && + $aggregate_purchase_value < $this->level_setting[$next_level]["total_order_value"] + ) { + return $level; + } + }else{ + if( $aggregate_purchase_value >= $this->level_setting[$level]["total_order_value"]) { + return $level; + } + } + } + + return 0; + } +} diff --git a/inc/Hura8/Components/Customer/Model/CustomerModel.php b/inc/Hura8/Components/Customer/Model/CustomerModel.php new file mode 100644 index 0000000..3257c7c --- /dev/null +++ b/inc/Hura8/Components/Customer/Model/CustomerModel.php @@ -0,0 +1,128 @@ + "Chưa đăng ký", + "register" => "Đăng ký thành viên", + ]; + + /* @var iSearch $objSearchModel */ + protected $objSearchModel; + + public function __construct() { + $this->objSearchModel = new CustomerSearchModel(); + + parent::__construct( + EntityType::CUSTOMER, + "", + $this->objSearchModel + ); + } + + + protected function extendedFilterOptions() : array + { + return [ + 'province' => 0, + 'user_type' => '', + ]; + } + + + public function getInfoByCRMCode($code) + { + $query = $this->db->runQuery("SELECT * FROM `".$this->tb_entity."` WHERE `crm_code` = ? LIMIT 1 ", ['s'], [$code]) ; + if( $item_info = $this->db->fetchAssoc($query)){ + return $this->formatItemInfo($item_info); + } + + return false; + } + + + public function getInfoByEmail($email, $user_type='register') + { + $query = $this->db->runQuery( + "SELECT * FROM `".$this->tb_entity."` WHERE `email` = ? AND `type` = ? LIMIT 1 ", + ['s', 's'], [$email, $user_type] + ) ; + + if( $item_info = $this->db->fetchAssoc($query)){ + return $this->formatItemInfo($item_info); + } + + return null; + } + + + public function getInfoByVerifiedEmail($email) + { + $info = $this->getInfoByEmail($email); + if($info && $info['is_email_verify']) { + return $info; + } + + return null; + } + + + protected function _buildQueryConditionExtend(array $filter_condition): ?array + { + /*$condition = array( + "user_type" => '' + "q" => "", + "status" => 0, + );*/ + + $catCondition = []; + $bind_types = []; + $bind_values = []; + + + if(isset($filter_condition["province"]) && $filter_condition["province"]) { + $catCondition[] = " AND `province` = ? "; + $bind_types[] = 'd'; + $bind_values[] = $filter_condition["province"]; + } + + // user_type + if(isset($filter_condition["user_type"]) && array_key_exists($filter_condition["user_type"], $this->user_types) ){ + $catCondition[] = " AND `type` = ? "; + $bind_types[] = 's'; + $bind_values[] = $filter_condition["user_type"]; + } + + + return array( join(" ", $catCondition), $bind_types, $bind_values); + } + + + protected function formatItemInfo(array $item_info): array + { + if($item_info["birth_day"] && $item_info["birth_year"]) { + $item_info["birth_day"] = $item_info["birth_day"]."-".$item_info["birth_year"]; + } + + return $item_info; + } + + + protected function createWebCRMCode($input_code = '') { + return $input_code ?: "Web-".IDGenerator::createStringId(8); + } + + +} diff --git a/inc/Hura8/Components/Customer/Model/CustomerSearchModel.php b/inc/Hura8/Components/Customer/Model/CustomerSearchModel.php new file mode 100644 index 0000000..42e9bcd --- /dev/null +++ b/inc/Hura8/Components/Customer/Model/CustomerSearchModel.php @@ -0,0 +1,34 @@ + "tb_customer.type", + "province" => "tb_customer.province", + "is_email_verify" => "tb_customer.is_email_verify", + "total_value" => "tb_customer.total_value", + ]; + + private $fulltext_fields = [ + "keywords" => ["tb_customer.name", "tb_customer.crm_code", "tb_customer.email","tb_customer.mobile",], + ]; + + + public function __construct() + { + parent::__construct( + "tb_customer", + $this->fulltext_fields, + $this->filter_fields + ); + } + +} diff --git a/inc/Hura8/Components/Deal/AdminController/ADealCollectionController.php b/inc/Hura8/Components/Deal/AdminController/ADealCollectionController.php new file mode 100644 index 0000000..6cc7b73 --- /dev/null +++ b/inc/Hura8/Components/Deal/AdminController/ADealCollectionController.php @@ -0,0 +1,51 @@ +objDealCollectionModel = new DealCollectionModel(); + parent::__construct($this->objDealCollectionModel); + } + + public function getAllProductIdInCollection($collection_id) { + return $this->objDealCollectionModel->getAllProductIdInCollection($collection_id); + } + + public function getAllDealIdInCollection($collection_id) { + return $this->objDealCollectionModel->getAllDealIdInCollection($collection_id); + } + + public function updateAllDealInCollection($collection_id, $price, $time){ + return $this->objDealCollectionModel->updateAllDealInCollection($collection_id, $price, $time); + } + + public function addProductToCollection($product_id, $collection_id){ + return $this->objDealCollectionModel->addProductToCollection($product_id, $collection_id); + } + + public function removeFromCollection($deal_id, $collection_id){ + $this->objDealCollectionModel->removeFromCollection($deal_id, $collection_id); + } + + public function addToCollection($deal_id, $collection_id){ + $this->objDealCollectionModel->addToCollection($deal_id, $collection_id); + } + + public function updateCollectionView($id){ + $this->objDealCollectionModel->updateCollectionView($id); + } + + protected function deleteFileBeforeDeleteItem($item_id): bool + { + return true; + } +} diff --git a/inc/Hura8/Components/Deal/AdminController/ADealController.php b/inc/Hura8/Components/Deal/AdminController/ADealController.php new file mode 100644 index 0000000..4ed9df7 --- /dev/null +++ b/inc/Hura8/Components/Deal/AdminController/ADealController.php @@ -0,0 +1,58 @@ +objDealModel->getAllAutoRenewableDeal(); + + //then renew & log history + foreach ($deal_list as $info) { + $this->renewDeal($info['id'], $info['from_time'], $info['to_time'], $info['auto_renew_history']); + } + } + + protected function renewDeal($id, $from_time, $to_time, array $auto_renew_history) { + /*$obj_from_date = new \DateTime(date("Y-m-d", $from_time)); + $obj_to_date = new \DateTime(date("Y-m-d", $to_time)); + $day_diff = $obj_to_date->diff($obj_from_date)->format('%a'); + + $obj_to_date->add(new \DateInterval('P'.$day_diff.'D')); + $new_date = $obj_to_date->format('Y-m-d'); + + $current_date = date("Y-m-d"); + $from_time_minute = ($from_time > 0) ? date("H:i", $from_time) : "00:00"; + $to_time_minute = ($to_time > 0) ? date("H:i", $to_time) : "00:00";*/ + + $to_time_new = CURRENT_TIME + ($to_time - $from_time); + + $auto_renew_history[] = [ + "renew_time" => show_datetime_from_unix(CURRENT_TIME), + "from_time" => show_datetime_from_unix(CURRENT_TIME), + "to_time" => show_datetime_from_unix($to_time_new), + ]; + + return $this->updateFields( $id, + [ + 'from_time' => CURRENT_TIME, + 'to_time' => $to_time_new, + 'auto_renew_history' => serialize($auto_renew_history), + ] + ); + } + + + protected function deleteFileBeforeDeleteItem($item_id): bool + { + return true; + } +} diff --git a/inc/Hura8/Components/Deal/Controller/bDealController.php b/inc/Hura8/Components/Deal/Controller/bDealController.php new file mode 100644 index 0000000..8f714d2 --- /dev/null +++ b/inc/Hura8/Components/Deal/Controller/bDealController.php @@ -0,0 +1,48 @@ +objDealModel = new DealModel(); + parent::__construct($this->objDealModel); + } + + + public function getList(array $condition) : array + { + $deal_list = parent::getList($condition); + + $product_list_info = []; + $product_list_ids = []; + $final_list = []; + foreach ($deal_list as $item) { + if(!isset($product_list_info[$item['pro_id']])) { + $product_list_info[$item['pro_id']]= null; + $product_list_ids[] = $item['pro_id']; + } + + $copy = $item; + $copy['product_info'] = &$product_list_info[$item['pro_id']]; + $final_list[] = $copy; + } + + $objAProductController = new AProductController(); + foreach ($objAProductController->getListByIds($product_list_ids) as $pro_id => $info) { + $product_list_info[$pro_id] = $info; + } + + return $final_list; + } + + +} diff --git a/inc/Hura8/Components/Deal/Model/DealCollectionModel.php b/inc/Hura8/Components/Deal/Model/DealCollectionModel.php new file mode 100644 index 0000000..446d3f7 --- /dev/null +++ b/inc/Hura8/Components/Deal/Model/DealCollectionModel.php @@ -0,0 +1,223 @@ +getAllDealIdInCollection($collection_id); + + if(!sizeof($deal_id_list)) return array(); + + $query = $this->db->runQuery("SELECT `pro_id` FROM `".$this->tb_deal."` WHERE `id` IN (". join(',', $deal_id_list).") "); + + return array_map(function ($item){ + return $item['pro_id']; + }, $this->db->fetchAll($query)); + } + + public function getAllDealIdInCollection($collection_id) { + $query = $this->db->runQuery("SELECT `deal_id` FROM `".$this->tb_collection_item."` WHERE `collection_id` = ? ", ['d'], [$collection_id]); + + return array_map(function ($item){ + return $item['deal_id']; + }, $this->db->fetchAll($query)); + } + + public function updateAllDealInCollection($collection_id, $price, $time){ + + $from_time = ($time['from_date'] != '') ? strtotime(TimeManager::convert_date_from_javascript($time['from_date'])." ".$time['from_time_minute'].":00") : 0; + $to_time = ($time['to_date'] != '') ? strtotime(TimeManager::convert_date_from_javascript($time['to_date'])." ".$time['to_time_minute'].":00") : 0; + + $deal_id_list = $this->getAllDealIdInCollection($collection_id); + + if(!sizeof($deal_id_list)) return false; + + $query = $this->db->runQuery("SELECT `id`, `pro_id` FROM `".$this->tb_deal."` WHERE `id` IN (". join(',', $deal_id_list).") "); + $product_list_id = array(); + foreach ( $this->db->fetchAll($query) as $info ) { + $product_list_id[$info['pro_id']] = $info['id']; + } + + //get product prices + $query = $this->db->runQuery(" + SELECT `id`, price FROM ".TableName::PRODUCT." + WHERE `id` IN (". join(',', array_keys($product_list_id)) .") + "); + + $objDealModel = new DealModel(); + + foreach ( $this->db->fetchAll($query) as $_info ) { + $product_id = $_info['id']; + $product_price = $_info['price']; + $deal_price = ($price['type'] == 'percent') ? round($product_price * (100 - $price['value']) / 100) : ($product_price - $price['value']); + + //update + $objDealModel->updatePriceAndTime( + $product_list_id[$product_id], + array( + "price" => $deal_price, + "from_time" => $from_time, + "to_time" => $to_time, + ) + ); + } + + return true; + } + + public function addProductToCollection($product_id, $collection_id){ + + $objAProductController = new AProductController(); + $product_info = $objAProductController->getInfo($product_id); + + if($product_info){ + + $objDealModel = new DealModel(); + + $deal_id = $objDealModel->create(array( + "pro_id" => $product_id, + "title" => $product_info['title'], + "price" => $product_info['price'], + "quantity" => $product_info['quantity'], + "min_purchase" => 1, + "from_time" => 0, + "to_time" => 0, + "ordering" => $product_info[''], + "description" => '', + )); + + $this->addToCollection($deal_id, $collection_id); + + return $deal_id; + } + + return 0; + } + + public function removeFromCollection($deal_id, $collection_id){ + $this->db->runQuery( + "DELETE FROM `".$this->tb_collection_item."` WHERE `deal_id` = ? AND `collection_id` = ? ", + ['d', 'd'], + [$deal_id, $collection_id] + ); + + $this->updateCollectionCount($collection_id); + } + + public function addToCollection($deal_id, $collection_id){ + $query = $this->db->runQuery( + "SELECT `deal_id` FROM `".$this->tb_collection_item."` WHERE `deal_id`= ? AND `collection_id` = ? LIMIT 1 ", + ['d', 'd'], [$deal_id, $collection_id] + ); + + if( ! $this->db->fetchAssoc($query) ){ + $this->db->insert( + $this->tb_collection_item , + [ + 'collection_id' => $collection_id , + 'deal_id' => $deal_id, + 'create_by' => ADMIN_ID, + 'create_time' => CURRENT_TIME, + ] + ); + + $this->updateCollectionCount($collection_id); + } + } + + protected function updateCollectionCount($collection_id){ + $this->db->runQuery( + "UPDATE `".$this->tb_entity."` SET + `deal_count` = (SELECT COUNT(*) FROM `".$this->tb_collection_item."` WHERE `collection_id` = ? ) + WHERE `id` = ? LIMIT 1 ", + ['d', 'd'], + [$collection_id, $collection_id] + ); + } + + public function updateCollectionView($id){ + $this->db->runQuery("UPDATE `".$this->tb_entity."` SET `visit` = `visit` + 1 WHERE `id` = ? LIMIT 1 ", ['d'], [ $id ]); + } + + + protected function beforeCreateItem(array $input_info) : AppResponse + { + $info = $input_info; + + $info['create_time'] = CURRENT_TIME; + $info['create_by'] = ADMIN_NAME; + $info['last_update'] = CURRENT_TIME; + $info['last_update_by'] = ADMIN_NAME; + + return new AppResponse('ok', null, $info); + } + + protected function afterCreateItem($new_item_id, $new_item_info) + { + // TODO: Implement afterCreateItem() method. + } + + protected function beforeUpdateItem($item_id, $current_item_info, $new_input_info) : AppResponse + { + $info = $new_input_info; + + $info['last_update'] = CURRENT_TIME; + $info['last_update_by'] = ADMIN_NAME; + + return new AppResponse('ok', null, $info); + } + + protected function afterUpdateItem($item_id, $old_item_info, $new_item_info) + { + // TODO: Implement afterUpdateItem() method. + } + + protected function beforeDeleteItem($item_id, $item_info) : AppResponse + { + return new AppResponse('ok'); + } + + protected function afterDeleteItem($item_id, $item_info) + { + // TODO: Implement afterDeleteItem() method. + } + + +} diff --git a/inc/Hura8/Components/Deal/Model/DealModel.php b/inc/Hura8/Components/Deal/Model/DealModel.php new file mode 100644 index 0000000..9bdb007 --- /dev/null +++ b/inc/Hura8/Components/Deal/Model/DealModel.php @@ -0,0 +1,196 @@ +db->runQuery( + "SELECT `id`, `from_time`, `to_time` FROM `". $this->tb_entity ."` + WHERE `to_time` < '".CURRENT_TIME."' AND `to_time` > 0 AND `auto_renew` = 1 " + ); + + return $this->db->fetchAll($query); + } + + protected function _buildQueryConditionExtend(array $filter_condition) : ?array + { + + $where_clause = []; + $bind_types = []; + $bind_values = []; + + $limit_by_time = false; + $limit_by_time_condition = ''; + + // get deal by start time + // require format: YY-mm-dd h:m:i or YY-mm-dd h:m or timestamp + $datetime_pattern = '/^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}\s[0-9]{1,2}:[0-9]{1,2}(:[0-9]{1,2})?$/i'; + + if(isset($filter_condition['start_time']) && $filter_condition['start_time'] ) { + $limit_by_time = true; + if(preg_match($datetime_pattern, trim($filter_condition['start_time']))) { + $check_time = strtotime($filter_condition['start_time']); + }else{ + $check_time = intval($filter_condition['start_time']); + } + + $limit_by_time_condition .= " AND `from_time` >= '".$check_time."' "; + + $bind_types[] = 'd'; + $bind_values[] = $check_time; + } + + // get deal by end time + // require format: YY-mm-dd h:m:i or YY-mm-dd h:m or timestamp + if(isset($filter_condition['end_time']) && $filter_condition['end_time'] ) { + $limit_by_time = true; + if(preg_match($datetime_pattern, trim($filter_condition['end_time']))) { + $check_time = strtotime($filter_condition['end_time']); + }else{ + $check_time = intval($filter_condition['end_time']); + } + + $limit_by_time_condition .= " AND `to_time` <= '".$check_time."' "; + $bind_types[] = 'd'; + $bind_values[] = $check_time; + } + + if($limit_by_time) { + $where_clause[] = " AND `status`= 1 ".$limit_by_time_condition; + } + + //type expire + if(isset($filter_condition['type']) && $filter_condition['type'] == 'expire' ) { + $where_clause[] = "AND `status`= 1 AND `to_time` < ? "; + $bind_types[] = 'd'; + $bind_values[] = CURRENT_TIME; + } + + //type active: might not have begun yet + if(isset($filter_condition['type']) && $filter_condition['type'] == 'active' && !$limit_by_time ) { + $where_clause[] = " AND `status` = 1 AND `to_time` >= ? "; + $bind_types[] = 'd'; + $bind_values[] = CURRENT_TIME; + } + + // Đang bắt đầu + if(isset($filter_condition['type']) && $filter_condition['type'] == 'started' && !$limit_by_time ) { + $where_clause[] = " AND `status` = 1 AND `to_time` >= ? AND from_time < ? "; + $bind_types[] = 'd'; + $bind_values[] = CURRENT_TIME; + $bind_types[] = 'd'; + $bind_values[] = CURRENT_TIME; + } + + // Chưa bắt đầu + if(isset($filter_condition['type']) && $filter_condition['type'] == 'coming' && !$limit_by_time ) { + $where_clause[] = " AND `status` = 1 AND `from_time` >= ? "; + $bind_types[] = 'd'; + $bind_values[] = CURRENT_TIME; + } + + //deal collection + if(isset($filter_condition['collection_id']) && $filter_condition['collection_id'] > 0) { + $where_clause[] = " AND `id` IN ( SELECT `deal_id` FROM `".$this->tb_collection_item."` WHERE `collection_id` = ? ) "; + $bind_types[] = 'd'; + $bind_values[] = $filter_condition['collection_id']; + } + + // exclude from collection + if(isset($filter_condition['add_to_collection']) && $filter_condition['add_to_collection'] > 0) { + $where_clause[] = " AND `id` NOT IN ( SELECT `deal_id` FROM `".$this->tb_collection_item."` WHERE `collection_id` = ? ) "; + $bind_types[] = 'd'; + $bind_values[] = $filter_condition['add_to_collection']; + } + + // by word filter + $filter = $filter_condition['filter'] ?? ''; + switch ($filter) { + case "not-started": // Chưa bắt đầu + $where_clause[] = " AND ( ? - `from_time` ) < 0 "; + $bind_types[] = 'd'; + $bind_values[] = CURRENT_TIME; + break; + + case "started": // Đang bắt đầu + $where_clause[] = " AND ( ? - `from_time` ) > 0 AND ( `to_time` - ?) > 0 "; + $bind_types[] = 'd'; + $bind_types[] = 'd'; + $bind_values[] = CURRENT_TIME; + $bind_values[] = CURRENT_TIME; + break; + + case "ended": // Hết thời gian + $where_clause[] = " AND (`to_time` - ?) < 0 "; + $bind_types[] = 'd'; + $bind_values[] = CURRENT_TIME; + break; + + case "hidden": // Ẩn hiển thị + $where_clause[] = " AND `status` = 0 "; + break; + + case "featured": // Đang nổi bật + $where_clause[] = " AND `is_featured` = 1 "; + break; + } + + + return [ + join(" ", $where_clause), + $bind_types, + $bind_values + ]; + } + + + protected function formatItemInList(array $item_info): array + { + $copy = $item_info; + + $copy['deal_time_happen'] = CURRENT_TIME - $item_info['from_time']; + $copy['deal_time_left'] = $item_info['to_time'] - CURRENT_TIME; + $copy['is_start'] = (CURRENT_TIME - $item_info['from_time'] > 0) ? 1 : 0; + $copy['is_end'] = ($item_info['to_time'] - CURRENT_TIME > 0) ? 0 : 1; + + return $copy; + } + + protected function formatItemInfo(array $item_info): array + { + $copy = $item_info; + + $copy['deal_time_happen'] = CURRENT_TIME - $item_info['from_time']; + $copy['deal_time_left'] = $item_info['to_time'] - CURRENT_TIME; + $copy['is_start'] = (CURRENT_TIME - $item_info['from_time'] > 0) ? 1 : 0; + $copy['is_end'] = ($item_info['to_time'] - CURRENT_TIME > 0) ? 0 : 1; + + return $copy; + } + + + +} diff --git a/inc/Hura8/Components/Marketing/AdminController/ACouponController.php b/inc/Hura8/Components/Marketing/AdminController/ACouponController.php new file mode 100644 index 0000000..9b569d0 --- /dev/null +++ b/inc/Hura8/Components/Marketing/AdminController/ACouponController.php @@ -0,0 +1,40 @@ +objCouponModel->updateProduct($product_id, $coupon_id, $info); + } + + + public function removeProduct($product_id, $coupon_id) + { + return $this->objCouponModel->removeProduct($product_id, $coupon_id); + } + + + public function addProduct($product_id, $coupon_id, $ordering=0) + { + return $this->objCouponModel->addProduct($product_id, $coupon_id, $ordering); + } + + + protected function deleteFileBeforeDeleteItem($item_id): bool + { + // TODO: Implement deleteFileBeforeDeleteItem() method. + return true; + } + + +} diff --git a/inc/Hura8/Components/Marketing/AdminController/APosterController.php b/inc/Hura8/Components/Marketing/AdminController/APosterController.php new file mode 100644 index 0000000..bad0fd4 --- /dev/null +++ b/inc/Hura8/Components/Marketing/AdminController/APosterController.php @@ -0,0 +1,26 @@ +objPosterModel = new PosterModel(); + parent::__construct($this->objPosterModel); + } + + + protected function deleteFileBeforeDeleteItem($item_id): bool + { + // TODO: Implement deleteFileBeforeDeleteItem() method. + return true; + } +} diff --git a/inc/Hura8/Components/Marketing/AdminController/AProductFeedController.php b/inc/Hura8/Components/Marketing/AdminController/AProductFeedController.php new file mode 100644 index 0000000..e390b22 --- /dev/null +++ b/inc/Hura8/Components/Marketing/AdminController/AProductFeedController.php @@ -0,0 +1,51 @@ +objProductFeedModel->getAllCategories(); + } + + public function getAllProductListIds( $list_id){ + return $this->objProductFeedModel->getAllProductListIds($list_id); + } + + public function getProductListTotal($list_id) { + return $this->objProductFeedModel->getProductListTotal($list_id); + } + + public function getProductList($list_id, $page = 1, $numPerPage = 30) { + return $this->objProductFeedModel->getProductList($list_id, $page, $numPerPage); + } + + public function deleteAllProductFromList($list_id) { + $this->objProductFeedModel->deleteAllProductFromList($list_id); + } + + //remove product from a list + public function deleteProductFromList($pro_list, $list_id){ + return $this->objProductFeedModel->deleteProductFromList($pro_list, $list_id); + } + + //add product to a list + public function addProductToList($pro_list, $list_id){ + return $this->objProductFeedModel->addProductToList($pro_list, $list_id); + } + + protected function deleteFileBeforeDeleteItem($item_id): bool + { + return true; + } +} diff --git a/inc/Hura8/Components/Marketing/Controller/bCouponController.php b/inc/Hura8/Components/Marketing/Controller/bCouponController.php new file mode 100644 index 0000000..96c2fda --- /dev/null +++ b/inc/Hura8/Components/Marketing/Controller/bCouponController.php @@ -0,0 +1,46 @@ + "Tặng sản phẩm", + 'cash' => "Tặng tiền mặt", + 'priceoff' => "Giảm giá %", + 'other' => "Khác" + ); + + + /* @var CouponModel $objCouponModel */ + protected $objCouponModel; + + public function __construct() + { + $this->objCouponModel = new CouponModel(); + parent::__construct($this->objCouponModel); + } + + + public function getTotalProduct($coupon_id, array $condition = []) + { + return $this->objCouponModel->getTotalProduct($coupon_id, $condition); + } + + + public function getListProduct($coupon_id, array $condition = []) { + return $this->objCouponModel->getListProduct($coupon_id, $condition); + } + + + public function getTypeList() { + return $this->type_list; + } + + +} diff --git a/inc/Hura8/Components/Marketing/Controller/bProductFeedController.php b/inc/Hura8/Components/Marketing/Controller/bProductFeedController.php new file mode 100644 index 0000000..7dfdb6d --- /dev/null +++ b/inc/Hura8/Components/Marketing/Controller/bProductFeedController.php @@ -0,0 +1,26 @@ +objProductFeedModel = new ProductFeedModel(); + parent::__construct($this->objProductFeedModel); + } + + + public function getInfoByPublicId($public_id) + { + return $this->objProductFeedModel->getInfoByPublicId($public_id); + } + + +} diff --git a/inc/Hura8/Components/Marketing/Model/CouponModel.php b/inc/Hura8/Components/Marketing/Model/CouponModel.php new file mode 100644 index 0000000..8d1896a --- /dev/null +++ b/inc/Hura8/Components/Marketing/Model/CouponModel.php @@ -0,0 +1,130 @@ +db->runQuery( + " SELECT COUNT(*) as total FROM `".$this->tb_coupon_product."` WHERE `coupon_id` = ? ", + ['d'], [$coupon_id] + ); + + $total = 0; + if ($rs = $this->db->fetchAssoc($query)) { + $total = $rs['total']; + } + + return $total; + } + + + public function getListProduct($coupon_id, array $condition = []) + { + $numPerPage = (isset($condition['numPerPage']) && $condition['numPerPage'] > 0 ) ? intval($condition['numPerPage']) : 20 ; + $page = (isset($condition['page']) && $condition['page'] > 0 ) ? intval($condition['page']) : 1 ; + $order_by = " `ordering` DESC, `id` DESC"; + + $query = $this->db->runQuery( + "SELECT `product_id` FROM ".$this->tb_coupon_product." WHERE `coupon_id` = ? + ORDER BY ".$order_by." + LIMIT ".(($page-1) * $numPerPage).", ".$numPerPage , + ['d'], [$coupon_id] + ) ; + + $item_list = array(); + $counter = ($page-1) * $numPerPage; + foreach ( $this->db->fetchAll($query) as $item ) { + $counter += 1; + + $item_list[$item['product_id']] = [ + 'counter' => $counter, + ]; + } + + $objProductModel = new ProductModel(); + $product_list_info = $objProductModel->getListByIds(array_keys($item_list)); + + // final list + $final_list = []; + foreach ($item_list as $_pro_id => $_pro_info_in_collection) { + $pro_basic = $product_list_info[$_pro_id] ?? null; + if($pro_basic) { + $final_list[] = array_merge($pro_basic, $_pro_info_in_collection); + } + } + + return $final_list; + } + + + protected function _buildQueryConditionExtend(array $filter_condition) : ?array + { + /*$condition = array( + "q" => getRequest("q", ''), + "featured" => (int) getRequest("featured"), + "status" => (int) getRequest("status"), + );*/ + + $catCondition = []; + $bind_types = []; + $bind_values = []; + + + if(isset($filter_condition["letter"]) && strlen($filter_condition["letter"]) == 1){ + $catCondition[] = " AND `letter` = ? "; + $bind_types[] = 's'; + $bind_values[] = $filter_condition["letter"]; + } + + return array( join(" ", $catCondition), $bind_types, $bind_values); + } + + + protected function createUniqueCode($current_item_id, $wanted_code = ''){ + if(!$wanted_code) $wanted_code = IDGenerator::createStringId(10); + + $clean_code = DataClean::makeInputSafe($wanted_code, DataType::ID); + $clean_code = strtoupper($clean_code); + + //if exist and belong other id, create a new one + $query = $this->db->runQuery("SELECT `id` FROM `".$this->tb_entity."` WHERE `code` = ? LIMIT 1 ", ['s'], [$clean_code]) ; + if($info = $this->db->fetchAssoc($query)){ + if($info['id'] != $current_item_id) { + $new_code = IDGenerator::createStringId(6); + return $this->createUniqueCode($current_item_id, $new_code); + } + } + + return $clean_code; + } + + +} diff --git a/inc/Hura8/Components/Marketing/Model/PosterModel.php b/inc/Hura8/Components/Marketing/Model/PosterModel.php new file mode 100644 index 0000000..151133b --- /dev/null +++ b/inc/Hura8/Components/Marketing/Model/PosterModel.php @@ -0,0 +1,33 @@ +all_brands = $this->buildAllBrands(); + //$this->all_categories = $this->buildAllCategories(); + } + + + protected function extendedFilterOptions() : array + { + return [ + // empty for now + ]; + } + + + public function getInfoByPublicId($public_id) + { + $query = $this->db->runQuery("SELECT * FROM `".$this->tb_entity."` WHERE `public_id` = ? LIMIT 1 ", ['s'], [$public_id]) ; + if( $item_info = $this->db->fetchAssoc($query)){ + return $this->formatItemInfo($item_info); + } + + return false; + } + + public function getProductListTotal($list_id) { + $query = $this->db->runQuery( + " SELECT COUNT(*) AS total FROM `".$this->tb_feed_product."` WHERE `list_id` = ? ", + ['d'], [$list_id] + ); + + $total = 0; + if ($info = $this->db->fetchAssoc($query)) { + $total = $info['total']; + } + + return $total; + } + + public function getProductList($list_id, $page = 1, $numPerPage = 30) { + + $query = $this->db->runQuery( + " SELECT `pro_id` FROM `".$this->tb_feed_product."` + WHERE `list_id` = ? + ORDER BY `id` DESC + LIMIT ".( ($page - 1) * $numPerPage ).", ".$numPerPage, + ['d'], [$list_id] + ); + + $product_list_ids = array_map(function ($item) { return $item['pro_id'];}, $this->db->fetchAll($query)); + + $objAProductController = new AProductController(); + + $stt = ($page - 1) * $numPerPage; + $item_list = []; + foreach ($objAProductController->getListByIds($product_list_ids) as $_id => $info) { + $stt++; + $info["counter"] = $stt; + $item_list[] = $info; + } + + return $item_list; + } + + //-------------------- + + public function getAllCategories() { + return $this->all_categories; + } + + + public function getAllProductListIds( $list_id){ + if(!$list_id) return []; + + $query = $this->db->runQuery("SELECT `pro_id` FROM `".$this->tb_feed_product."` WHERE `list_id` = ? ", ['d'], [ $list_id ]); + + $item_list = array(); + foreach ( $this->db->fetchAll($query) as $rs ) { + $item_list[] = $rs['pro_id']; + } + + return $item_list; + } + + + //-------------------- + + + protected function _buildQueryConditionExtend(array $filter_condition) : ?array + { + /*$condition = array( + "letter" => "", + );*/ + + $catCondition = []; + $bind_types = []; + $bind_values = []; + + + if(isset($filter_condition["letter"]) && strlen($filter_condition["letter"]) == 1){ + $catCondition[] = " AND `letter` = ? "; + $bind_types[] = 's'; + $bind_values[] = $filter_condition["letter"]; + } + + return array( join(" ", $catCondition), $bind_types, $bind_values); + } + + + +} diff --git a/inc/Hura8/Components/Marketing/Model/UProductFeedModel.php b/inc/Hura8/Components/Marketing/Model/UProductFeedModel.php new file mode 100644 index 0000000..0883921 --- /dev/null +++ b/inc/Hura8/Components/Marketing/Model/UProductFeedModel.php @@ -0,0 +1,8 @@ +getInfo($item_id); + if(!$item_info['file_url']) { + return true; + } + + $file_name = $item_info['file_url']; + + foreach (static::$resized_sizes as $size => $value) { + $file_local_path = PUBLIC_DIR . "/". static::$image_folder . "/". $size. IMAGE_FILE_SEPARATOR . $file_name; + @unlink($file_local_path); + } + + // remove original file + $file_local_path = PUBLIC_DIR . "/". static::$image_folder . "/". $file_name; + @unlink($file_local_path); + + return true; + } + +} diff --git a/inc/Hura8/Components/Media/AdminController/AMediaCategoryController.php b/inc/Hura8/Components/Media/AdminController/AMediaCategoryController.php new file mode 100644 index 0000000..6fd0203 --- /dev/null +++ b/inc/Hura8/Components/Media/AdminController/AMediaCategoryController.php @@ -0,0 +1,14 @@ +getInfo($item_id); + if(!$item_info['file_url']) { + return true; + } + + list($sub_folder, $file_name) = explode("/", $item_info['file_url']); // format: Y-m-d/file_name + + foreach (static::$resized_sizes as $size => $value) { + $file_local_path = PUBLIC_DIR . "/". static::$image_folder . "/" . $sub_folder . "/". $size. IMAGE_FILE_SEPARATOR . $file_name; + @unlink($file_local_path); + } + + // remove original file + $file_local_path = PUBLIC_DIR . "/". static::$image_folder . "/" . $sub_folder . "/". $file_name; + @unlink($file_local_path); + + return true; + } + +} diff --git a/inc/Hura8/Components/Media/Controller/bItemMediaController.php b/inc/Hura8/Components/Media/Controller/bItemMediaController.php new file mode 100644 index 0000000..d370ea3 --- /dev/null +++ b/inc/Hura8/Components/Media/Controller/bItemMediaController.php @@ -0,0 +1,61 @@ + ['width' => 300,] + ); + + /* @var ItemMediaModel $objItemMediaModel */ + protected $objItemMediaModel; + + protected $item_type; + protected $item_id; + + public function __construct(string $item_type = '', $item_id = 0) + { + $this->objItemMediaModel = new ItemMediaModel($item_type, $item_id); + parent::__construct($this->objItemMediaModel); + } + + + protected function formatItemInList(array $item_info) : array + { + return $this->formatItemInfo($item_info); + } + + + protected function formatItemInfo(array $item_info) : ?array + { + if(!$item_info) return null; + + $item_info['display_file'] = STATIC_DOMAIN . "/". static::$image_folder. "/". $item_info['file_url']; + $item_info['image'] = self::getResizedImageCollection($item_info['file_url']); + + return $item_info; + } + + + public static function getResizedImageCollection($image_name) { + $image = []; + + $size_in_full = [ + 's' => 'small' , + ]; + + foreach (static::$resized_sizes as $size => $value) { + $image[$size_in_full[$size]] = ($image_name) ? STATIC_DOMAIN . "/". static::$image_folder . "/". $size. IMAGE_FILE_SEPARATOR . $image_name : ''; + } + + return $image; + } + +} diff --git a/inc/Hura8/Components/Media/Controller/bMediaCategoryController.php b/inc/Hura8/Components/Media/Controller/bMediaCategoryController.php new file mode 100644 index 0000000..6ac394e --- /dev/null +++ b/inc/Hura8/Components/Media/Controller/bMediaCategoryController.php @@ -0,0 +1,20 @@ +objMediaCategoryModel = new MediaCategoryModel(); + parent::__construct($this->objMediaCategoryModel); + } + +} diff --git a/inc/Hura8/Components/Media/Controller/bMediaController.php b/inc/Hura8/Components/Media/Controller/bMediaController.php new file mode 100644 index 0000000..637ab9e --- /dev/null +++ b/inc/Hura8/Components/Media/Controller/bMediaController.php @@ -0,0 +1,59 @@ + ['width' => 300,] + ); + + protected $objMediaModel; + + + public function __construct() + { + $this->objMediaModel = new MediaModel(); + parent::__construct($this->objMediaModel); + } + + + protected function formatItemInList(array $item_info) : array + { + return $this->formatItemInfo($item_info); + } + + + protected function formatItemInfo(array $item_info) : ?array + { + if(!$item_info) return null; + + $item_info['display_file'] = STATIC_DOMAIN . "/". static::$image_folder. "/". $item_info['file_url']; + $item_info['image'] = ($item_info['file_type'] == 'image') ? self::getResizedImageCollection($item_info['file_url']) : null; + + return $item_info; + } + + + public static function getResizedImageCollection($image_name) { + $image = []; + + $size_in_full = [ + 's' => 'small' , + ]; + + foreach (static::$resized_sizes as $size => $value) { + $image[$size_in_full[$size]] = ($image_name) ? STATIC_DOMAIN . "/". static::$image_folder . "/". $size. IMAGE_FILE_SEPARATOR . $image_name : ''; + } + + return $image; + } + +} diff --git a/inc/Hura8/Components/Media/Model/ItemMediaModel.php b/inc/Hura8/Components/Media/Model/ItemMediaModel.php new file mode 100644 index 0000000..57d2a59 --- /dev/null +++ b/inc/Hura8/Components/Media/Model/ItemMediaModel.php @@ -0,0 +1,76 @@ +item_type = $item_type; + $this->item_id = $item_id; + } + + + protected function extendedFilterOptions() : array + { + return [ + // empty for now + ]; + } + + + protected function _buildQueryConditionExtend(array $filter_condition) : ?array + { + + $catCondition = []; + $bind_types = []; + $bind_values = []; + + if($this->item_type) { + $catCondition[] = " AND `item_type` = ? "; + $bind_types[] = 's'; + $bind_values[] = $this->item_type; + } + + if($this->item_id) { + $catCondition[] = " AND `item_id` = ? "; + $bind_types[] = 'd'; + $bind_values[] = $this->item_id; + } + + if(isset($filter_condition["item_type"]) && $filter_condition["item_type"]){ + $catCondition[] = " AND `item_type` = ? "; + $bind_types[] = 's'; + $bind_values[] = $filter_condition["item_type"]; + } + + if(isset($filter_condition["item_id"]) && $filter_condition["item_id"]){ + $catCondition[] = " AND `item_id` = ? "; + $bind_types[] = 's'; + $bind_values[] = $filter_condition["item_id"]; + } + + if(isset($filter_condition["file_type"]) && $filter_condition["file_type"]){ + $catCondition[] = " AND `file_type` = ? "; + $bind_types[] = 's'; + $bind_values[] = $filter_condition["file_type"]; + } + + return array( join(" ", $catCondition), $bind_types, $bind_values); + } + + + + +} diff --git a/inc/Hura8/Components/Media/Model/ItemMediaSearchModel.php b/inc/Hura8/Components/Media/Model/ItemMediaSearchModel.php new file mode 100644 index 0000000..f92f5e2 --- /dev/null +++ b/inc/Hura8/Components/Media/Model/ItemMediaSearchModel.php @@ -0,0 +1,34 @@ + "tb_item_media.item_type", + 'item_id' => "tb_item_media.item_id", + 'file_type' => "tb_item_media.file_type", + ]; + + private $fulltext_fields = [ + "keywords" => ["tb_item_media.title",], + ]; + + + public function __construct() + { + parent::__construct( + "tb_item_media", + $this->fulltext_fields, + $this->filter_fields + ); + + //$this->createTableSearch(); + } + +} diff --git a/inc/Hura8/Components/Media/Model/MediaCategoryModel.php b/inc/Hura8/Components/Media/Model/MediaCategoryModel.php new file mode 100644 index 0000000..86cd5cd --- /dev/null +++ b/inc/Hura8/Components/Media/Model/MediaCategoryModel.php @@ -0,0 +1,20 @@ + getRequestInt("category"), + "file_type" => '', + );*/ + + $catCondition = []; + $bind_types = []; + $bind_values = []; + + + //Tim danh muc + if(isset($filter_condition["category"]) && $filter_condition["category"]){ + $catCondition[] = " AND `id` IN (SELECT `item_id` FROM `".$this->tb_media_per_category."` WHERE `category_id` = ?) "; + $bind_types[] = 'd'; + $bind_values[] = $filter_condition["category"]; + } + + if(isset($filter_condition["file_type"]) && $filter_condition["file_type"]){ + $catCondition[] = " AND `file_type` = ? "; + $bind_types[] = 's'; + $bind_values[] = $filter_condition["file_type"]; + } + + + return array( join(" ", $catCondition), $bind_types, $bind_values); + } + + + +} diff --git a/inc/Hura8/Components/Media/Model/MediaSearchModel.php b/inc/Hura8/Components/Media/Model/MediaSearchModel.php new file mode 100644 index 0000000..45c3890 --- /dev/null +++ b/inc/Hura8/Components/Media/Model/MediaSearchModel.php @@ -0,0 +1,32 @@ + "tb_media.file_type", + ]; + + private $fulltext_fields = [ + "keywords" => ["tb_media.title",], + ]; + + + public function __construct() + { + parent::__construct( + "tb_media", + $this->fulltext_fields, + $this->filter_fields + ); + + //$this->createTableSearch(); + } + +} diff --git a/inc/Hura8/Components/Order/AdminController/AOrderController.php b/inc/Hura8/Components/Order/AdminController/AOrderController.php new file mode 100644 index 0000000..1e3b86c --- /dev/null +++ b/inc/Hura8/Components/Order/AdminController/AOrderController.php @@ -0,0 +1,235 @@ +objAOrderStatusController = new AOrderStatusController(); + $this->objOrderModel = new OrderModel(); + parent::__construct($this->objOrderModel); + } + + public function updateOrderFulfillmentStatus($order_id, $new_status, $comment, $payment_data = []) { + + if(!array_key_exists($new_status, OrderStatus::FULFILLMENT_STATUS)) { + return [ + "status" => 'error', + 'message' => '', + ]; + } + + $this->objAOrderStatusController->createHistory($order_id, 'fulfillment', $new_status, $comment, $payment_data ); + + //cap nhat don hang + $this->objOrderModel->update( $order_id, [ + 'fulfillment_status' => $new_status + ]); + + $this->updateDerivedOrderStatus($order_id); + + return [ + "status" => 'success', + 'message' => 'Cập nhật thành công', + ]; + } + + public function updateOrderPaymentStatus($order_id, $new_status, $comment, $payment_data = []) { + + if(!array_key_exists($new_status, OrderStatus::PAYMENT_STATUS)) { + return [ + "status" => 'error', + 'message' => '', + ]; + } + + $this->objAOrderStatusController->createHistory($order_id, 'payment', $new_status, $comment, $payment_data ); + + //cap nhat don hang + $this->objOrderModel->update( $order_id, [ + 'payment_status' => $new_status + ]); + + $this->updateDerivedOrderStatus($order_id); + + return [ + "status" => 'success', + 'message' => 'Cập nhật thành công', + ]; + } + + protected function updateDerivedOrderStatus($order_id) { + + $current_info = $this->getInfo($order_id); + + // order must be success + if( + $current_info['payment_status'] == OrderStatus::PAYMENT_STATUS['paid']['id'] && + $current_info['fulfillment_status'] == OrderStatus::FULFILLMENT_STATUS['fulfilled']['id'] + ) { + + return $this->objOrderModel->update($order_id, [ + 'order_status' => OrderStatus::ORDER_STATUS['success']['id'] + ]); + + } + + + // update processing + return $this->objOrderModel->update($order_id, [ + 'order_status' => OrderStatus::ORDER_STATUS['processing']['id'] + ]); + + } + + public function updateOrderStatus($order_id, $status, $comment) { + + $current_info = $this->getInfo($order_id); + + // cannot update if order has: success or cancel + if(in_array($current_info['order_status'], [ + OrderStatus::ORDER_STATUS['success']['id'], + OrderStatus::ORDER_STATUS['canceled']['id'], + ])) { + return [ + "status" => 'error', + 'message' => '', + ]; + } + + if(!array_key_exists($status, OrderStatus::ORDER_STATUS)) { + return [ + "status" => 'error', + 'message' => '', + ]; + } + + $this->objAOrderStatusController->createHistory($order_id, 'order', $status, $comment ); + + $this->objOrderModel->update($order_id, [ + 'order_status' => $status + ]); + + // dispatch + $objOrderEvent = new OrderEvent(); + $objOrderEvent->setUpdateOrderInfo([ + 'orderId' => $order_id, + 'order_status' => $status, + 'old_status' => $current_info['order_status'] + ]); + get_dispatcher()->dispatch(EventName::ORDER['updated_status'], $objOrderEvent); + + return [ + "status" => 'success', + 'message' => 'Cập nhật thành công', + ]; + } + + + protected function formatItemInList(array $order_info ) { + + $rs = $order_info; + + $rs["order_date"] = date("d-m-Y", $rs['order_time']); + $rs["order_hour"] = date("h:i a", $rs['order_time']); + + if($rs['order_discount']) $rs['order_discount'] = \json_decode($rs['order_discount'], true); + + $rs["payment_status_name"] = (array_key_exists($rs["payment_status"], OrderStatus::PAYMENT_STATUS)) ? OrderStatus::PAYMENT_STATUS[$rs["payment_status"]]['title'] : ''; + + $rs["fulfillment_status_name"] = (array_key_exists($rs["fulfillment_status"], OrderStatus::FULFILLMENT_STATUS)) ? OrderStatus::FULFILLMENT_STATUS[$rs["fulfillment_status"]]['title'] : ''; + + $rs["order_status_name"] = (array_key_exists($rs["order_status"], OrderStatus::ORDER_STATUS)) ? OrderStatus::ORDER_STATUS[$rs["order_status"]]['title'] : ''; + + return $rs; + } + + protected function getListFilterCondition($list_id) { + + if($list_id == 'mine') { + return [ + 'assign_to' => ADMIN_ID, + ]; + } + + if($list_id == 'new') { + return [ + 'status' => 'new', + ]; + } + + if($list_id == 'unpaid') { + return [ + 'payment' => 'unpaid', + ]; + } + + if($list_id == 'partially-paid') { + return [ + 'payment' => 'partially-paid', + ]; + } + + if($list_id == 'unfulfilled') { + return [ + 'fullfillment' => 'unfulfilled', + ]; + } + + if($list_id == 'partially-fulfilled') { + return [ + 'fullfillment' => 'partially-fulfilled', + ]; + } + + return null; + } + + public function getStatusHistory($orderId){ + + return $this->objAOrderStatusController->getStatusHistory($orderId); + + } + + public function getItemsForOrderList(array $list_ids, $fields = "*") { + + return $this->objOrderModel->getItemsForOrderList($list_ids, $fields); + + } + + public static function createId($order_id){ + $key_length = strlen($order_id); + + $order_keys = []; + for($i=0; $i < 9 - $key_length; $i++){ + $order_keys[] = "0"; + } + $order_keys[] = $order_id; + + $order_eles = str_split(join("", $order_keys), 3); + + return join("-", $order_eles); + } + + + protected function deleteFileBeforeDeleteItem($item_id): bool + { + return true; + } + +} diff --git a/inc/Hura8/Components/Order/AdminController/AOrderStatusController.php b/inc/Hura8/Components/Order/AdminController/AOrderStatusController.php new file mode 100644 index 0000000..a4773f4 --- /dev/null +++ b/inc/Hura8/Components/Order/AdminController/AOrderStatusController.php @@ -0,0 +1,43 @@ +objOrderStatusModel = new OrderStatusModel(); + } + + public function getStatusHistory($orderId){ + return $this->objOrderStatusModel->getStatusHistory($orderId); + } + + public function createHistory($order_id, $status_type = 'order', $system_status = '', $comment = '', array $data= [], array $other_info = []) { + return $this->objOrderStatusModel->createHistory($order_id, $status_type , $system_status , $comment, $data, $other_info); + } + + public function getInfo($status_id) { + return $this->objOrderStatusModel->getInfo($status_id); + } + + public function getAll() { + return $this->objOrderStatusModel->getAll(); + } + + public function delete($id) { + return $this->objOrderStatusModel->delete($id); + } + + public function update($id, array $info) { + return $this->objOrderStatusModel->update($id, $info); + } + + public function create(array $info) { + return $this->objOrderStatusModel->create($info); + } +} diff --git a/inc/Hura8/Components/Order/Controller/OrderStatus.php b/inc/Hura8/Components/Order/Controller/OrderStatus.php new file mode 100644 index 0000000..69aefe3 --- /dev/null +++ b/inc/Hura8/Components/Order/Controller/OrderStatus.php @@ -0,0 +1,43 @@ + ['id' => 'new', 'title' => 'Mới'],// 'Mới', // + 'processing' => ['id' => 'processing', 'title' => 'Đang xử lý'],// 'Đang xử lý', // + 'success' => ['id' => 'success', 'title' => 'Thành công'],// 'Thành công', // + 'closed' => ['id' => 'closed', 'title' => 'Đóng lại'],// 'Đóng lại', // + //'archived' => 'Lưu kho', // + 'canceled' => ['id' => 'canceled', 'title' => 'Hủy'],// 'Hủy', // + ]; + + const PAYMENT_STATUS = [ + 'pending' => ['id' => 'pending', 'title' => 'Chờ'],// 'Chờ', // Orders have the Payment pending status for one of the following reasons: During checkout, You create an order, Manual payment methods, such as Cash On Delivery + 'authorized' => ['id' => 'authorized', 'title' => 'Đã xác nhận'],// 'Đã xác nhận', // The payment provider validated your customer’s payment information. The order is created, customers can complete their checkout, and inventory is reserved. + 'overdue' => ['id' => 'overdue', 'title' => 'Quá hạn'],// 'Quá hạn', // Payment wasn't captured before the due date that was set in the payment terms on an order that had the Payment pending status. + 'expiring' => ['id' => 'expiring', 'title' => 'Sắp hết hạn'],// 'Sắp hết hạn', // Expiring isn't a payment status, but the Expiring badge is displayed two days before the deadline for capturing payment on orders that have the Authorized payment status. + 'expired' => ['id' => 'expired', 'title' => 'Hết hạn'],// 'Hết hạn', // Payment wasn't captured before the date that was set by the payment provider on an order that had the Authorized payment status. + 'paid' => ['id' => 'paid', 'title' => 'Đã thanh toán'],// 'Đã thanh toán', // Payment was automatically or manually captured, or the order was marked as paid. + 'refunded' => ['id' => 'refunded', 'title' => 'Đã hoàn lại'],// 'Đã hoàn lại', // The full amount that the customer paid for an order was returned to the customer. + 'partially-refunded' => ['id' => 'partially-refunded', 'title' => 'Hoàn lại 1 phần'],// 'Hoàn lại 1 phần', // The amount that was returned to a customer is less than the full amount that the customer paid for an order. + 'partially-paid' => ['id' => 'partially-paid', 'title' => 'Thanh toán 1 phần'],// 'Thanh toán 1 phần', // You manually captured payment for the order and specified less than the full order value as the payment amount. + 'voided' => ['id' => 'voided', 'title' => 'Hủy'],// 'Hủy', // An unpaid order was manually canceled. + 'unpaid' => ['id' => 'unpaid', 'title' => 'Chưa thanh toán'],// 'Chưa thanh toán', // Unpaid payment status includes orders that are in Authorized, Pending, Expired, and Partially paid payment status. + ]; + + const FULFILLMENT_STATUS = [ + 'fulfilled' => ['id' => 'fulfilled', 'title' => 'Đã chuyển hết'],// 'Đã chuyển hết', // When you've shipped all the items in an order, it is Fulfilled. + 'unfulfilled' => ['id' => 'unfulfilled', 'title' => 'Chưa chuyển'],// 'Chưa chuyển', // When an order is placed, it has an Unfulfilled fulfillment status, unless you have selected to automatically capture the payment and automatically fulfill all of the order's line items in the checkout settings. + 'partially-fulfilled' => ['id' => 'partially-fulfilled', 'title' => 'Chuyển 1 phần'],// 'Chuyển 1 phần', // If you have shipped some, but not all, of the items in an order, then the order has a Partially fulfilled fulfillment status. + 'scheduled' => ['id' => 'scheduled', 'title' => 'Đã lên kế hoạch'],// 'Đã lên kế hoạch', // Prepaid subscription orders have a Scheduled status until the fulfillment date is reached + 'onhold ' => ['id' => 'onhold', 'title' => 'Giữ hàng'],// 'Giữ hàng', // When upsell offers are presented to customers at checkout, the order fulfillment status is set to On hold temporarily. When a fulfillment is On hold you can reserve inventory for the order, but you can't fulfill the order until the fulfillment hold is released, and the order fulfillment status changes to Unfulfilled. + ]; + +} + diff --git a/inc/Hura8/Components/Order/Model/OrderModel.php b/inc/Hura8/Components/Order/Model/OrderModel.php new file mode 100644 index 0000000..0803480 --- /dev/null +++ b/inc/Hura8/Components/Order/Model/OrderModel.php @@ -0,0 +1,557 @@ +objSearchModel = new OrderSearchModel(); + + parent::__construct(EntityType::ORDER, '', $this->objSearchModel); + } + + + protected function extendedFilterOptions() : array + { + return [ + // empty for now + ]; + } + + + public function getItems($orderId, $fields = "*") { + $query = $this->db->runQuery( + " SELECT ".$fields." FROM `".$this->tb_order_detail."` WHERE `order_id` = ? ", + ['d'], [ $orderId ]); + + $order_item = array(); + foreach ( $this->db->fetchAll($query) as $info ) { + + $item_info = ($info["item_info"]) ? \json_decode($info["item_info"], true) : false; + $in_cart = ($info["in_cart"]) ? \json_decode($info["in_cart"], true) : false; + + + $info['item_info'] = $item_info; + $info['in_cart'] = $in_cart; + + $order_item[] = $info; + } + + return $order_item; + } + + //since we save the entire cart-structure for item_info, we need to re-construct it to make it easier to read and for various reporting/ email etc.. + protected function buildOrderItemInfo($item_type, array $item_info) { + $new_info = []; + + if($item_type == 'product') { + + $new_info = System::stripProperty(array($item_info['info']), [ + "variant_option", + 'id', + 'productId', + 'priceUnit', + 'price', + 'currency', + 'lastUpdate', + 'warranty', + 'productName', + 'productUrl', + 'productModel', + 'productSummary', + 'marketPrice', + 'productImage', + 'brand', + 'visit', + 'rating', + 'reviewCount', + 'quantity', + 'productSKU', + 'hasVAT', + 'condition', + 'specialOffer', + 'specialOfferGroup', + 'productType', + 'thum_poster', + 'promotion_price', + 'addon' + ])[0]; + + //find variants bought + if($new_info['config_count'] > 0) { + + foreach ($item_info['in_cart'] as $_variant) { + $new_info['variants'][] = array( + "id" => $_variant['id'], + "sku" => $_variant['sku'], + "title" => $_variant['name'], + "image" => ($_variant['image']) ? $_variant['image'] : $item_info['info']['productImage']["medium"], + "url" => $item_info['info']['productUrl'], + "attribute" => $_variant['attribute'], + "price" => $_variant['price'], + "addon_total" => 0, + "currency" => $item_info['info']['currency'], + "priceUnit" => $item_info['info']['priceUnit'], + "quantity" => $_variant['quantity'], + "buyer_note" => $_variant['buyer_note'], + "addon" => [], + "promotion" => [ + "list" => $item_info['info']['specialOffer'], + "group" => (isset($_variant['promotion'])) ? $this->buildPromotionFromGroup( $item_info['info']['specialOfferGroup'], $_variant['promotion']) : $this->buildPromotionFromGroup( $item_info['info']['specialOfferGroup'], array() ), + ], + //..any other + ); + } + + }else{ + + //product does not have variant + $build_addon = []; + $total_addon_price = 0; + if(isset($item_info['info']['addon']) && isset($item_info['in_cart'][0]['addon'])) { + $build_addon = $this->getSelectedAddon($item_info['info']['addon'], $item_info['in_cart'][0]['addon']); + foreach ($build_addon as $addon) { + $total_addon_price += $addon['price'] * $addon['quantity']; + } + } + + $variant_in_cart = (isset($item_info['in_cart'][0])) ? $item_info['in_cart'][0] : false; + + $new_info['variants'][] = array( + "id" => 0, + "sku" => $item_info['info']['productSKU'], + "title" => $item_info['info']['productName'], + "image" => $item_info['info']['productImage']["medium"], + "url" => $item_info['info']['productUrl'], + "attribute" => [], + "price" => $item_info['info']['price'], + "addon_total" => $total_addon_price, + "currency" => $item_info['info']['currency'], + "priceUnit" => $item_info['info']['priceUnit'], + "quantity" => $variant_in_cart['quantity'], + "buyer_note" => $variant_in_cart['buyer_note'], + "addon" => $build_addon, + "promotion" => [ + "list" => $item_info['info']['specialOffer'], + "group" => (isset($variant_in_cart['promotion'])) ? $this->buildPromotionFromGroup( $item_info['info']['specialOfferGroup'], $variant_in_cart['promotion']) : $this->buildPromotionFromGroup( $item_info['info']['specialOfferGroup'], array() ), + ], + //..any other + ); + } + + // + return $new_info; + } + + if($item_type == 'combo') { + + $new_info = [ + "price" => $item_info['info']['sale_price'], + "quantity" => $item_info['in_cart']['quantity'], + "buyer_note" => $item_info['in_cart']['buyer_note'], + "url" => '', + ]; + + $new_info['product_list'] = System::stripProperty($item_info['info']['product_list'], [ + "variant_option", + 'id', + 'productId', + 'priceUnit', + 'price', + 'currency', + 'lastUpdate', + 'warranty', + //'productName', + //'productUrl', + //'productModel', + 'productSummary', + 'marketPrice', + 'productImage', + 'brand', + 'visit', + 'rating', + 'reviewCount', + 'config_count', + 'quantity', + //'productSKU', + 'hasVAT', + 'condition', + 'specialOffer', + 'specialOfferGroup', + 'productType', + 'thum_poster', + 'promotion_price', + 'addon', + 'imageCollection', + 'variants' + ]); + + return $new_info; + } + + if($item_type == 'deal') { + + $new_info = [ + "price" => $item_info['info']['price'], + "quantity" => $item_info['in_cart']['quantity'], + "buyer_note" => $item_info['in_cart']['buyer_note'], + "url" => '/deal/'.$item_info['info']['id'], + ]; + + return $new_info; + } + + return $new_info; + } + + protected function getSelectedAddon($all_product_addons, $in_cart) { + + if(!is_array($all_product_addons) || !is_array($in_cart)) return []; + + $result = []; + foreach ($all_product_addons as $item) { + foreach ($in_cart as $selected) { + if($item['addon_id'] == $selected['id']) { + $result[] = [ + "id" => $selected['id'], + "title" => $item['title'], + "price" => $item['price'], + "quantity" => (isset($selected['quantity'])) ? intval($selected['quantity']) : 1, + "related_article_url" => $item['related_article_url'], + ]; + } + } + } + + return $result; + } + + protected function buildPromotionFromGroup( $offer_group, $selected_one_promotion) { + + if(!is_array($offer_group) && !is_array($selected_one_promotion)) return false; + + $promotion = []; + + foreach ($offer_group as $group) { + if($group['type'] == 'one') { + + $selected_promotion = []; + foreach ($group['promotion'] as $promo) { + foreach ($selected_one_promotion as $selected) { + if($selected['promotion_id'] == $promo['id'] && $selected['group_id'] == $group['id']) { + $selected_promotion[] = $promo; + } + } + } + + $promotion[] = [ + "id" => $group['id'], + "title" => $group['title'], + "note" => $group['note'], + "promotion" => $selected_promotion, + ]; + + + }else{ + $promotion[] = [ + "id" => $group['id'], + "title" => $group['title'], + "note" => $group['note'], + "promotion" => $group['promotion'], + ]; + } + } + + return $promotion; + + } + + + protected function getListFilterCondition($list_id) { + + if($list_id == 'mine') { + return [ + 'assign_to' => ADMIN_ID, + ]; + } + + if($list_id == 'new') { + return [ + 'status' => 'new', + ]; + } + + if($list_id == 'unpaid') { + return [ + 'payment' => 'unpaid', + ]; + } + + if($list_id == 'partially-paid') { + return [ + 'payment' => 'partially-paid', + ]; + } + + if($list_id == 'unfulfilled') { + return [ + 'fullfillment' => 'unfulfilled', + ]; + } + + if($list_id == 'partially-fulfilled') { + return [ + 'fullfillment' => 'partially-fulfilled', + ]; + } + + return null; + } + + public function getStatusHistory($orderId){ + $query = $this->db->runQuery(" + select * from ".TB_ORDER_STATUS_HISTORY." + WHERE order_id = ? + order by id desc + limit 100 + ", ['d'], [ $orderId ] ) ; + + return $this->db->fetchAll($query); + } + + public function getItemsForOrderList(array $list_ids, $fields = "*") { + + if(!sizeof($list_ids)) return []; + + list($parameterized_ids, $bind_types) = create_bind_sql_parameter_from_value_list($list_ids, 'int'); + + $query = $this->db->runQuery(" + SELECT ".$fields." FROM `".$this->tb_order_detail."` + WHERE `order_id` IN (".$parameterized_ids.") + ", $bind_types, $list_ids); + + $result = array(); + foreach ( $this->db->fetchAll($query) as $rs ) { + + $item_info = unserialize($rs['item_info']); + if( isset($item_info["info"]) && isset($item_info["in_cart"])) { + $rs['item_info'] = $this->buildOrderItemInfo($rs['item_type'], $item_info ); + } else { + $rs['item_info'] = null; + } + + $result[$rs['order_id']][] = $rs; + } + + return $result; + } + + protected function _buildQueryConditionExtend(array $conditions) : ?array + { + $catCondition = []; + $bind_types = []; + $bind_values = []; + + /* + $conditions = array( + 'orderCode' => '', + 'query' => '', + 'coupon' => '', + 'cus_id' => '', + 'province' => '', + 'district' => '', + 'folder' => '', + 'view_status' => '', + 'update_by' => '', + 'shipping_status' => '', + 'assign_to' => '', + 'from_date' => '', + 'to_date' => '', + 'from_hour' => '', + 'to_hour' => '', + 'excluded_ids' => '', + 'included_ids' => '', + 'payment' => '', + 'fullfillment' => '', + 'list' => '', + );*/ + + + // merge with special list + if(isset($conditions['list']) && $conditions['list']) { + $list_condition = $this->getListFilterCondition($conditions['list']); + if($list_condition) { + // update and over-write any key in $conditions if exist + foreach ($list_condition as $key => $value) { + $conditions[$key] = $value; + } + } + } + + if(isset($conditions['orderCode']) && $conditions['orderCode']) { + $orderCode = DataClean::makeInputSafe($conditions['orderCode'],DataType::INTEGER); + $catCondition[] = " AND `orderId` LIKE '".$orderCode."%' "; + } + + if(isset($conditions['coupon']) && $conditions['coupon']) { + $coupon = preg_replace("/[^a-z0-9_\-\.]/i","", $conditions['coupon']); + if($coupon) $catCondition[] = " AND ( LENGTH(`order_discount`) > 10 AND `order_discount` LIKE '%".$coupon."%' ) "; + } + + if(isset($conditions['cus_id']) && $conditions['cus_id']) { + $catCondition[] = " AND buyerId = '".intval($conditions['cus_id'])."'"; + } + + if(isset($conditions['province']) && $conditions['province']) { + $catCondition[] = " AND province = '".intval($conditions['province'])."'"; + } + + if(isset($conditions['district']) && $conditions['district']) { + $catCondition[] = " AND district = '".intval($conditions['district'])."'"; + } + + if(isset($conditions['folder']) && $conditions['folder']) { + $catCondition[] = " AND `folder` = '". preg_replace("/[^a-z0-9_\-\.]/i", "", $conditions['folder'])."' "; + } + + if(isset($conditions['payment']) && array_key_exists($conditions['payment'], OrderStatus::PAYMENT_STATUS ) ) { + $catCondition[] = " AND `payment_status` = '". $this->db->escape($conditions['payment'])."' "; + } + + if(isset($conditions['fullfillment']) && array_key_exists($conditions['fullfillment'], OrderStatus::FULFILLMENT_STATUS) ) { + $catCondition[] = " AND `fulfillment_status` = '". $this->db->escape($conditions['fullfillment'])."' "; + } + + if(isset($conditions['status']) && array_key_exists($conditions['status'], OrderStatus::ORDER_STATUS) ) { + $catCondition[] = " AND `order_status` = '". $this->db->escape($conditions['status'])."' "; + } + + if(isset($conditions['view_status']) && $conditions['view_status']) { + if($conditions['view_status'] == 'no-status') { + $catCondition[] = " AND `status_id` = 0 "; + } else { + $catCondition[] = " AND `status_id` = '". intval($conditions['view_status'])."' "; + } + } + + if(isset($conditions['update_by']) && $conditions['update_by']) { + $catCondition[] = " AND `status_update_by` = '". $this->db->escape($conditions['update_by'])."' "; + } + + if(isset($conditions['shipping_status']) && $conditions['shipping_status']) { + $catCondition[] = " AND `admin_shipping_status` = '". preg_replace("/[^a-z0-9_\-\.]/i", "", $conditions['shipping_status'])."' "; + } + + if(isset($conditions['assign_to']) && $conditions['assign_to']) { + $catCondition[] = " AND `assign_to` = '". intval($conditions['assign_to'])."' "; + } + + //filter by date + if(isset($conditions['from_date']) && $conditions['from_date']) { + $catCondition[] = " AND order_time >= '". intval(strtotime(TimeManager::convert_date_from_javascript($conditions['from_date'])." 00:00"))."' "; + } + + if(isset($conditions['to_date']) && $conditions['to_date']) { + $catCondition[] = " AND order_time <= '".strtotime(TimeManager::convert_date_from_javascript($conditions['to_date'])." 23:59")."' "; + } + + //filter by hour + if(isset($conditions['from_hour']) && $conditions['from_hour']) { + $catCondition[] = " AND `order_hour` >= '".intval($conditions['from_hour'])."' "; + } + if(isset($conditions['to_hour']) && $conditions['to_hour']) { + $catCondition[] = " AND `order_hour` <= '".intval($conditions['to_hour'])."' "; + } + + if(isset($conditions["excluded_ids"]) && $conditions["excluded_ids"] ){ + $list_ids = filterNumber(explode(",", $conditions["excluded_ids"])); + if(sizeof($list_ids)) $catCondition[] = " AND `orderId` NOT IN (".join(',', $list_ids ).") "; + } + + if(isset($conditions["included_ids"]) && $conditions["included_ids"] ){ + $list_ids = filterNumber(explode(",", $conditions["included_ids"])); + if(sizeof($list_ids)) $catCondition[] = " AND `orderId` IN (".join(',', $list_ids ).") "; + } + + + return array( join(" ", $catCondition), $bind_types, $bind_values); + } + + + protected function beforeCreateItem(array $input_info) : AppResponse + { + $info = $input_info; + + if(isset($info['file_external_url'])) { + if($info['file_external_url'] && !Url::isUrlValid($info['file_external_url'])) { + $info['file_external_url'] = ''; + } + } + + + $info['create_time'] = CURRENT_TIME; + $info['create_by'] = ADMIN_NAME; + $info['last_update'] = CURRENT_TIME; + $info['last_update_by'] = ADMIN_NAME; + + return new AppResponse('ok', null, $info); + } + + + protected function beforeUpdateItem($item_id, $current_item_info, $new_input_info) : AppResponse + { + $info = $new_input_info; + + unset($info['id']); + + if(isset($info['file_external_url']) && $info['file_external_url'] && !Url::isUrlValid($info['file_external_url'])) { + $info['file_external_url'] = ''; + } + + $info['last_update'] = CURRENT_TIME; + $info['last_update_by'] = ADMIN_NAME; + + return new AppResponse('ok', null, $info); + } + + protected function beforeDeleteItem($item_id, $item_info) : AppResponse + { + return new AppResponse('ok'); + } + + protected function afterDeleteItem($item_id, $item_info) + { + + } + + + protected function afterCreateItem($new_item_id, $new_item_info) + { + + } + + protected function afterUpdateItem($item_id, $old_item_info, $new_item_info) + { + + } + +} diff --git a/inc/Hura8/Components/Order/Model/OrderSearchModel.php b/inc/Hura8/Components/Order/Model/OrderSearchModel.php new file mode 100644 index 0000000..305670b --- /dev/null +++ b/inc/Hura8/Components/Order/Model/OrderSearchModel.php @@ -0,0 +1,30 @@ + "tb_order.price", + ]; + + private $fulltext_fields = [ + "keywords" => ["tb_order.buyerName", ], + ]; + + + public function __construct() + { + parent::__construct( + "tb_order", + $this->fulltext_fields, + $this->filter_fields + ); + } + +} diff --git a/inc/Hura8/Components/Order/Model/OrderStatusModel.php b/inc/Hura8/Components/Order/Model/OrderStatusModel.php new file mode 100644 index 0000000..aae45f0 --- /dev/null +++ b/inc/Hura8/Components/Order/Model/OrderStatusModel.php @@ -0,0 +1,94 @@ +db = get_db('', ENABLE_DB_DEBUG); + } + + public function getStatusHistory($orderId){ + $query = $this->db->runQuery(" + select * from ".$this->tb_status_history." + WHERE order_id = ? + order by id desc + limit 100 + ", ['d'], [ $orderId ] ) ; + + return $this->db->fetchAll($query); + } + + public function createHistory($order_id, $status_type = 'order', $system_status = '', $comment = '', array $data= [], array $other_info = []) { + + $info = $other_info; + + $info['order_id'] = $order_id; + $info['status_type'] = $status_type; + $info['system_status'] = $system_status; + $info['data'] = \json_encode($data); + $info['comment'] = substr($comment, 0, 150); + $info['create_time'] = CURRENT_TIME; + $info['create_by'] = (defined('ADMIN_NAME')) ? ADMIN_NAME : ''; + + return $this->db->insert($this->tb_status_history, $info); + } + + public function getCustomerCancelStatusId() { + $info = $this->db->select($this->tb_status, ['id'], [ + "system_status" => ["=", "cancel"], + 'message' => 'Khách hàng hủy', + ], '', 1); + + if($info) { + return $info['id']; + } + + // create and return + return $this->create([ + 'message' => 'Khách hàng hủy', + 'system_status' => "cancel", + 'create_time' => CURRENT_TIME, + 'create_by' => 'System', + ]); + } + + + public function getInfo($status_id) { + return $this->db->getItemInfo($this->tb_status, $status_id, 'id'); + } + + public function getAll() { + $query = $this->db->runQuery(" select * from ".$this->tb_status." order by `id` desc ") ; + $item_list = array(); + foreach ( $this->db->fetchAll($query) as $rs ) { + if(!$rs['system_status']) $rs['system_status'] = 'new'; + //$rs['system_order_status'] = System::$ORDER_STATUS[$rs['system_status']]; + $item_list[] = $rs; + } + + return $item_list; + } + + public function delete($id) { + return $this->db->runQuery("DELETE FROM ".$this->tb_status." WHERE `id` = ? limit 1 ", ['d'], [ $id ]) ; + } + + public function update($id, array $info) { + return $this->db->update($this->tb_status, $info, ['id' => $id]); + } + + public function create(array $info) { + return $this->db->insert($this->tb_status, $info); + } + +} diff --git a/inc/Hura8/Components/Page/AdminController/APageController.php b/inc/Hura8/Components/Page/AdminController/APageController.php new file mode 100644 index 0000000..48b10ff --- /dev/null +++ b/inc/Hura8/Components/Page/AdminController/APageController.php @@ -0,0 +1,50 @@ +objPageModel->updateTableInfo($item_id, $new_item_info); + } + + + protected function deleteFileBeforeDeleteItem($item_id): bool + { + // delete thumb files + $item_info = $this->getInfo($item_id); + $this->deleteThumbnailFile($item_info['thumbnail']); + + //delete media files? + // todo: + + return true; + } + + + protected function deleteThumbnailFile($file_name): bool + { + if(!$file_name) { + return false; + } + + foreach (self::$resized_sizes as $size => $value) { + $file_local_path = PUBLIC_DIR . "/". self::$image_folder . "/". $size. IMAGE_FILE_SEPARATOR . $file_name; + unlink($file_local_path); + } + + // remove original file + $file_local_path = PUBLIC_DIR . "/". self::$image_folder . "/". $file_name; + return unlink($file_local_path); + } + +} diff --git a/inc/Hura8/Components/Page/Controller/bPageController.php b/inc/Hura8/Components/Page/Controller/bPageController.php new file mode 100644 index 0000000..00a3629 --- /dev/null +++ b/inc/Hura8/Components/Page/Controller/bPageController.php @@ -0,0 +1,92 @@ + ['width' => 200,] , + 'l' => ['width' => 600,] , + ); + + + protected $objPageModel; + + + public function __construct() + { + $this->objPageModel = new PageModel(); + + if(!$this->isDefaultLanguage()) { + //$this->objPageLanguageModel->createTableLang(); + parent::__construct($this->objPageModel, new PageLanguageModel()); + }else{ + parent::__construct($this->objPageModel); + } + } + + + // get full info- basic with description + public function getFullInfo($id) : ?array + { + if(!$id) return null; + + return self::getCache("getFullInfo-".$id."-".$this->view_language, function () use ($id){ + + $info = $this->objPageModel->getFullInfo($id); + + if($this->iEntityLanguageModel && $info ) { + $item_language_info = $this->iEntityLanguageModel->getInfo($id); + if($item_language_info) { + return $this->formatItemInfo(array_merge($info, $item_language_info)); + } + } + + return $this->formatItemInfo($info); + + }); + } + + + protected function formatItemInfo(array $item_info) + { + if(!$item_info) return null; + + $info = $item_info; + $info['image'] = self::getResizedImageCollection($info['thumbnail']); + + return $info; + } + + + protected function formatItemInList(array $item_info) + { + return $this->formatItemInfo($item_info); + } + + + public static function getResizedImageCollection($image_name) { + $image = []; + + $size_in_full = [ + 't' => 'thumb' , + 's' => 'small' , + 'l' => 'large' , + ]; + + foreach (static::$resized_sizes as $size => $value) { + $image[$size_in_full[$size]] = ($image_name) ? STATIC_DOMAIN . "/". static::$image_folder . "/". $size. IMAGE_FILE_SEPARATOR . $image_name : ''; + } + + return $image; + } + +} diff --git a/inc/Hura8/Components/Page/Model/PageLanguageModel.php b/inc/Hura8/Components/Page/Model/PageLanguageModel.php new file mode 100644 index 0000000..5098c36 --- /dev/null +++ b/inc/Hura8/Components/Page/Model/PageLanguageModel.php @@ -0,0 +1,21 @@ +richtext_fields); + } + + +} diff --git a/inc/Hura8/Components/Page/Model/PageModel.php b/inc/Hura8/Components/Page/Model/PageModel.php new file mode 100644 index 0000000..9f72300 --- /dev/null +++ b/inc/Hura8/Components/Page/Model/PageModel.php @@ -0,0 +1,76 @@ +richtext_fields); + } + + + protected function extendedFilterOptions() : array + { + return [ + // empty for now + ]; + } + + + public function getFullInfo($id) : ?array + { + $query = $this->db->runQuery( + "SELECT * FROM `".$this->tb_entity."` basic, `".$this->tb_page_info."` info + WHERE basic.`id` = info.`page_id` AND basic.id = ? + LIMIT 1 ", + ['d'], [$id] + ); + + if( $item_info = $this->db->fetchAssoc($query)){ + return $item_info; + } + + return null; + } + + protected function _buildQueryConditionExtend(array $filter_condition): ?array + { + /*$condition = array( + "q" => "", + "status" => 0, + );*/ + + /*$condition = array( + "letter" => "", + );*/ + + $catCondition = []; + $bind_types = []; + $bind_values = []; + + /*if(isset($filter_condition["letter"]) && strlen($filter_condition["letter"]) == 1){ + $catCondition[] = " AND `letter` = ? "; + $bind_types[] = 's'; + $bind_values[] = $filter_condition["letter"]; + }*/ + + return array( join(" ", $catCondition), $bind_types, $bind_values); + } + + +} diff --git a/inc/Hura8/Components/Product/AdminController/AProductCategoryController.php b/inc/Hura8/Components/Product/AdminController/AProductCategoryController.php index 1d56fe9..8e7da59 100644 --- a/inc/Hura8/Components/Product/AdminController/AProductCategoryController.php +++ b/inc/Hura8/Components/Product/AdminController/AProductCategoryController.php @@ -3,52 +3,16 @@ namespace Hura8\Components\Product\AdminController; use Hura8\Components\Product\Controller\bProductCategoryController; -use Hura8\Interfaces\AppResponse; -use Hura8\Components\Product\Model\ProductCategoryInfoModel; -use Hura8\Interfaces\iEntityAdminCategoryController; use Hura8\Traits\AdminEntityCategoryControllerTraits; -class AProductCategoryController extends bProductCategoryController implements iEntityAdminCategoryController +class AProductCategoryController extends bProductCategoryController { use AdminEntityCategoryControllerTraits; - - public function updateItemCount($id) { - $this->objProductCategoryModel->updateItemCount($id); - } - - public function getAttributeList($catId) { return $this->objProductCategoryModel->getAttributeList($catId); } - - public function create(array $info) : AppResponse - { - $res = parent::create($info); - - if($res->getStatus() == 'ok') { - $objProductCategoryInfoModel = new ProductCategoryInfoModel(); - $objProductCategoryInfoModel->createInfo($res->getData(), $info); - } - - return $res; - } - - - public function update($id, array $info) : AppResponse - { - if(!$this->isDefaultLanguage()) { - return parent::update($id, $info); - } - - // update info - $objProductCategoryInfoModel = new ProductCategoryInfoModel(); - $objProductCategoryInfoModel->updateInfo($id, $info); - - return parent::update($id, $info); - } - } diff --git a/inc/Hura8/Components/Product/Model/ProductCategoryModel.php b/inc/Hura8/Components/Product/Model/ProductCategoryModel.php index 794a625..fe67f3a 100644 --- a/inc/Hura8/Components/Product/Model/ProductCategoryModel.php +++ b/inc/Hura8/Components/Product/Model/ProductCategoryModel.php @@ -3,14 +3,12 @@ namespace Hura8\Components\Product\Model; -use Hura8\Interfaces\AppResponse; -use Hura8\System\Controller\UrlManagerController; +use Hura8\Interfaces\iEntityCategoryModel; use Hura8\System\Model\aCategoryBaseModel; -use Hura8\System\ModuleManager; use Hura8\Interfaces\EntityType; -class ProductCategoryModel extends aCategoryBaseModel +class ProductCategoryModel extends aCategoryBaseModel implements iEntityCategoryModel { static $url_module = "product"; static $url_view = "category"; diff --git a/inc/Hura8/Components/Province/AdminController/AProvinceController.php b/inc/Hura8/Components/Province/AdminController/AProvinceController.php new file mode 100644 index 0000000..d8589b7 --- /dev/null +++ b/inc/Hura8/Components/Province/AdminController/AProvinceController.php @@ -0,0 +1,10 @@ +objProvinceModel = new ProvinceModel(); + } + + + public function getProvinceName($id) { + return self::getCache("getProvinceName-".$id, function () use ($id) { + $info = $this->objProvinceModel->getProvinceInfo($id, 'name'); + return ($info) ? $info['name'] : ''; + }); + } + + public function getDistrictName($id) { + return self::getCache("getDistrictName-".$id, function () use ($id) { + $info = $this->objProvinceModel->getDistrictInfo($id, 'name'); + return ($info) ? $info['name'] : ''; + }); + } + + public function getWardName($id) { + return self::getCache("getWardName-".$id, function () use ($id) { + $info = $this->objProvinceModel->getWardInfo($id, 'name'); + return ($info) ? $info['name'] : ''; + }); + } + + + public function getProvinceList($field="*") { + return self::getCache("getProvinceList-", function () use ($field) { + return $this->objProvinceModel->getProvinceList($field); + //$pick_keys = ['id', 'api_id', 'name']; + + /*return array_map(function ($item) use($pick_keys){ + return pick_return_array_key($item, $pick_keys); + }, $province_list);*/ + }); + } + + public function getProvinceDistrictList($province_id, $field="*") { + + return self::getCache("getProvinceDistrictList-".$province_id, function () use ($province_id) { + return $this->objProvinceModel->getProvinceDistrictList($province_id); + //$pick_keys = ['id', 'api_id', 'name']; + + /*return array_map(function ($item) use($pick_keys){ + return pick_return_array_key($item, $pick_keys); + }, $province_list);*/ + }); + } + + public function getAllDistrictList() { + return self::getCache("getAllDistrictList", function (){ + return $this->objProvinceModel->getAllDistrictList(); + }); + } + + + public function getDistrictWardList($district_id, $field="*") { + return self::getCache("getDistrictWardList-".$district_id, function () use ($district_id) { + return $this->objProvinceModel->getDistrictWardList($district_id); + }); + } + + // these are kept for old time sake + /*public static $province_list = array( + "1" => "Hà Nội", + "2" => "TP HCM", + "5" => "Hải Phòng" , + "4" => "Đà Nẵng" , + "6" => "An Giang" , + "7" => "Bà Rịa-Vũng Tàu", + "13" => "Bình Dương" , + "15" => "Bình Phước" , + "16" => "Bình Thuận" , + "14" => "Bình Định" , + "8" => "Bạc Liêu", + "10" => "Bắc Giang" , + "9" => "Bắc Kạn", + "11" => "Bắc Ninh", + "12" => "Bến Tre", + "18" => "Cao Bằng", + "17" => "Cà Mau", + "3" => "Cần Thơ", + "24" => "Gia Lai", + "25" => "Hà Giang", + "26" => "Hà Nam", + "27" => "Hà Tĩnh", + "30" => "Hòa Bình", + "28" => "Hải Dương", + "29" => "Hậu Giang", + "31" => "Hưng Yên", + "32" => "Khánh Hòa", + "33" => "Kiên Giang", + "34" => "Kon Tum", + "35" => "Lai Châu", + "38" => "Lào Cai", + "36" => "Lâm Đồng", + "37" => "Lạng Sơn", + "39" => "Long An", + "40" => "Nam Định", + "41" => "Nghệ An", + "42" => "Ninh Bình", + "43" => "Ninh Thuận", + "44" => "Phú Thọ", + "45" => "Phú Yên", + "46" => "Quảng Bình", + "47" => "Quảng Nam", + "48" => "Quảng Ngãi", + "49" => "Quảng Ninh", + "50" => "Quảng Trị", + "51" => "Sóc Trăng", + "52" => "Sơn La", + "53" => "Tây Ninh", + "56" => "Thanh Hóa", + "54" => "Thái Bình", + "55" => "Thái Nguyên", + "57" => "Thừa Thiên-Huế", + "58" => "Tiền Giang", + "59" => "Trà Vinh", + "60" => "Tuyên Quang", + "61" => "Vĩnh Long", + "62" => "Vĩnh Phúc", + "63" => "Yên Bái", + "19" => "Đắk Lắk", + "22" => "Đồng Nai", + "23" => "Đồng Tháp", + "21" => "Điện Biên", + "20" => "Đăk Nông", + ); + + public static function getName($id) { + return (isset(static::$province_list[$id])) ? static::$province_list[$id] : ''; + }*/ + +} diff --git a/inc/Hura8/Components/Province/Model/ProvinceModel.php b/inc/Hura8/Components/Province/Model/ProvinceModel.php new file mode 100644 index 0000000..5d37f81 --- /dev/null +++ b/inc/Hura8/Components/Province/Model/ProvinceModel.php @@ -0,0 +1,73 @@ +db = get_db(); + } + + public function getProvinceInfo($id, $field="*") { + if(!$id) return null; + + $query = $this->db->runQuery("SELECT ".$field." FROM `".$this->tb_province."` WHERE `id` = ? LIMIT 1 ", ['d'], [ $id ]); + return $this->db->fetchAssoc($query); + } + + public function getDistrictInfo($id, $field="*") { + if(!$id) return null; + + $query = $this->db->runQuery("SELECT ".$field." FROM `".$this->tb_province_district."` WHERE `id` = ? LIMIT 1 ", ['d'], [ $id ]); + return $this->db->fetchAssoc($query); + } + + public function getWardInfo($id, $field="*") { + if(!$id) return null; + + $query = $this->db->runQuery("SELECT ".$field." FROM `".$this->tb_province_ward."` WHERE `id` = ? LIMIT 1 ", ['d'], [ $id ]); + return $this->db->fetchAssoc($query); + } + + public function getProvinceList($field="*") { + $query = $this->db->runQuery("SELECT ".$field." FROM `".$this->tb_province."` ORDER BY `id` ASC "); + return $this->db->fetchAll($query); + } + + public function getProvinceDistrictList($province_id, $field="*") { + $query = $this->db->runQuery( + "SELECT ".$field." FROM `".$this->tb_province_district."` WHERE `province_id` = ? ORDER BY `ordering` DESC ", + ['d'], [ $province_id ] + ); + + return $this->db->fetchAll($query); + } + + public function getAllDistrictList() { + $query = $this->db->runQuery("SELECT * FROM `".$this->tb_province_district."` WHERE 1 ORDER BY id ASC "); + return $this->db->fetchAll($query); + } + + public function getDistrictWardList($district_id, $field="*") { + $query = $this->db->runQuery( + "SELECT ".$field." FROM `".$this->tb_province_ward."` WHERE `district_id` = ? ORDER BY `ordering` DESC ", + ['d'], + [ $district_id ] + ); + + return $this->db->fetchAll($query); + } + +} diff --git a/inc/Hura8/Components/Staff/AdminController/ClientPermissionController.php b/inc/Hura8/Components/Staff/AdminController/ClientPermissionController.php new file mode 100644 index 0000000..30936aa --- /dev/null +++ b/inc/Hura8/Components/Staff/AdminController/ClientPermissionController.php @@ -0,0 +1,76 @@ +getClientEntityPermission_raw(); + }); + } + + protected function getClientEntityPermission_raw() { + + $system_file = ROOT_DIR. "/config/system/admin.entity.permission.php"; + $entity_group = include $system_file; + + $client_allowed_entities = Permission::getClientEntities(); + + $final_config = []; + foreach ($entity_group as $_group) { + + $settings = include ROOT_DIR. "/config/system/entity_permission/".$_group.".php"; + + $children_match = []; + foreach ($settings['children'] as $_entity => $_p) { + if(in_array($_entity, $client_allowed_entities)) { + $children_match[$_entity] = $_p; + } + } + + if(sizeof($children_match)) { + $final_config[$_group] = [ + 'title' => $settings['title'], + 'children' => $children_match, + ]; + } + } + + + return $final_config; + } + + + public function getClientMenu() { + return static::getCache("getClientMenu", function (){ + $menu_config_file = ROOT_DIR. "/config/client/admin/admin.menu.php"; + + $header_admin_config = []; + $menu_group = include $menu_config_file; + foreach ($menu_group as $_group) { + $content = include ROOT_DIR. "/config/client/admin/admin_menu/".$_group.".php"; + $enabled_menu_item = array_filter($content['menu'], function ($item){ return $item['enable'];}); + + if(sizeof($enabled_menu_item) > 0) { + $header_admin_config[$_group] = [ + 'enable' => $content['enable'], + 'name' => $content['name'], + 'url' => $content['url'], + 'menu' => $enabled_menu_item, + ]; + } + } + + return $header_admin_config; + }); + } + + +} diff --git a/inc/Hura8/Components/Staff/AdminController/StaffAdminController.php b/inc/Hura8/Components/Staff/AdminController/StaffAdminController.php new file mode 100644 index 0000000..314a63a --- /dev/null +++ b/inc/Hura8/Components/Staff/AdminController/StaffAdminController.php @@ -0,0 +1,72 @@ +objStaffAuthModel = new StaffAuthModel(); + $this->objStaffModel = new StaffModel(); + } + + public function getLoginListByIds(array $staff_ids) : array + { + return $this->objStaffAuthModel->getLoginListByIds($staff_ids); + } + + public function getList(array $conditions) : array + { + return $this->objStaffModel->getList($conditions); + } + + public function getInfo($id) : ?array + { + return $this->objStaffModel->getInfo($id); + } + + public function getEmptyInfo(array $additional_fields = []) : array + { + return $this->objStaffModel->getEmptyInfo($additional_fields); + } + + public function update($id, array $input_info) : AppResponse + { + // change password + if(isset($input_info['password']) && strlen($input_info['password']) > 5) { + $this->objStaffAuthModel->createOrUpdatePassword($id, $input_info['password']); + } + + return $this->objStaffModel->update($id, $input_info); + } + + public function create(array $input_info, $password = "") : AppResponse + { + $db_res = $this->objStaffModel->create($input_info); + + if($db_res->getStatus() == 'ok') { + + $new_id = $db_res->getData(); + + if(!$password) $password = IDGenerator::createStringId(6); + + $this->objStaffAuthModel->createOrUpdatePassword($new_id, $password); + + return new AppResponse('ok', '', ["id" => $new_id, "password" => $password]); + } + + return new AppResponse('error', 'Cannot create'); + } + + +} diff --git a/inc/Hura8/Components/Staff/AdminController/StaffAdminDepartmentController.php b/inc/Hura8/Components/Staff/AdminController/StaffAdminDepartmentController.php new file mode 100644 index 0000000..54ffdc5 --- /dev/null +++ b/inc/Hura8/Components/Staff/AdminController/StaffAdminDepartmentController.php @@ -0,0 +1,44 @@ +objStaffDepartmentModel = new StaffDepartmentModel(); + } + + public function getList(array $conditions) { + return $this->objStaffDepartmentModel->getList($conditions); + } + + public function getInfo($id) { + return self::getCache("getInfo-".$id, function () use ($id){ + return $this->objStaffDepartmentModel->getInfo($id); + }); + } + + public function getEmptyInfo(array $additional_fields = []) + { + return $this->objStaffDepartmentModel->getEmptyInfo($additional_fields); + } + + public function update($id, array $input_info) { + return $this->objStaffDepartmentModel->update($id, $input_info); + } + + public function create(array $input_info) { + return $this->objStaffDepartmentModel->create($input_info); + } + +} diff --git a/inc/Hura8/Components/Staff/AdminController/StaffDepartmentPermissionController.php b/inc/Hura8/Components/Staff/AdminController/StaffDepartmentPermissionController.php new file mode 100644 index 0000000..d54830d --- /dev/null +++ b/inc/Hura8/Components/Staff/AdminController/StaffDepartmentPermissionController.php @@ -0,0 +1,98 @@ +objStaffDepartmentPermissionModel = new StaffDepartmentPermissionModel(); + } + + + public function getDepartmentMenuPermissionSetting($department_id) { + + $current_permission = $this->getDepartmentMenuPermission($department_id); + + $user_menu_settings = []; + foreach ($this->getClientMenu() as $group_id => $group_info) { + + $rebuild_menu = []; + foreach ($group_info['menu'] as $index => $menu) { + $rebuild_menu[$index] = $menu; + + $rebuild_menu[$index]['is_user_permitted'] = (in_array($menu['id'], $current_permission)) ? 1 : 0; + } + + $user_menu_settings[$group_id] = $group_info; + $user_menu_settings[$group_id]['menu'] = $rebuild_menu; + } + + return $user_menu_settings; + } + + + public function saveDepartmentMenuPermission($department_id, array $new_permission) { + $this->objStaffDepartmentPermissionModel->saveDepartmentMenuPermission($department_id, $new_permission); + } + + + public function getDepartmentMenuPermission($department_id) { + return $this->objStaffDepartmentPermissionModel->getDepartmentMenuPermission($department_id); + } + + + public function getDepartmentEntityPermissionSetting($department_id) { + + $current_permission = $this->getDepartmentEntityPermission($department_id); + + $_settings = []; + foreach ($this->getClientEntityPermission() as $group_id => $group_info) { + + $rebuild_children = []; + foreach ($group_info['children'] as $entity => $info) { + + $actions = []; + foreach ($info['action'] as $action_key => $action_title) { + $actions[] = [ + 'action' => $action_key, + 'title' => $action_title, + 'is_user_permitted' => (isset($current_permission[$group_id]) && isset($current_permission[$group_id][$entity]) && isset($current_permission[$group_id][$entity][$action_key])) ? $current_permission[$group_id][$entity][$action_key] : false , + ]; + } + + $rebuild_children[$entity] = [ + 'title' => $info['title'], + 'action_list' => $actions, + ]; + + } + + $_settings[$group_id] = $group_info; + $_settings[$group_id]['children'] = $rebuild_children; + } + + return $_settings; + } + + + public function saveDepartmentEntityPermission($department_id, array $new_permission) { + $this->objStaffDepartmentPermissionModel->saveDepartmentEntityPermission( + $department_id, $new_permission + ); + } + + + public function getDepartmentEntityPermission($department_id) { + return static::getCache("getDepartmentEntityPermission-".$department_id, function () use ($department_id){ + return $this->objStaffDepartmentPermissionModel->getDepartmentEntityPermission($department_id); + }) ; + } + +} diff --git a/inc/Hura8/Components/Staff/AdminController/StaffLogController.php b/inc/Hura8/Components/Staff/AdminController/StaffLogController.php new file mode 100644 index 0000000..f1f7e80 --- /dev/null +++ b/inc/Hura8/Components/Staff/AdminController/StaffLogController.php @@ -0,0 +1,27 @@ +objStaffLogModel = new StaffLogModel(); + } + + public function getList(array $conditions) { + return $this->objStaffLogModel->getList($conditions); + } + + public function getTotal(array $conditions) { + return $this->objStaffLogModel->getTotal($conditions); + } + + public function create(array $input_info) { + + } +} diff --git a/inc/Hura8/Components/Staff/AdminController/StaffPermissionController.php b/inc/Hura8/Components/Staff/AdminController/StaffPermissionController.php new file mode 100644 index 0000000..d87f2ca --- /dev/null +++ b/inc/Hura8/Components/Staff/AdminController/StaffPermissionController.php @@ -0,0 +1,180 @@ +objStaffPermissionModel = new StaffPermissionModel(); + } + + /** + * @param $entity_group + * @param $entity + * @param string $action valid values in PermissionType:: + * @return bool + */ + public function checkEntityActionPermission($is_super_user, $entity_group, $entity, $action ) : bool { + + // super is allowed by default + if($is_super_user) { + return true; + } + + $current_permission = $this->getCurrentUserEntityPermission(); + + if ( + isset($current_permission[$entity_group]) && + isset($current_permission[$entity_group][$entity]) && + isset($current_permission[$entity_group][$entity][$action]) + ) { + return $current_permission[$entity_group][$entity][$action] ; + } + + return false; + } + + + public function getUserProductMenuList() { + + return self::getCache("getUserProductMenuList", function (){ + $menu_list = include CONFIG_DIR. '/client/admin/product_menu.php'; + + $final_list = []; + foreach (array_filter($menu_list, function ($item){ return $item['enabled'];}) as $key => $value) { + + // check if the current staff can see + // todo + // ... + + $final_list[$key] = $value; + } + + return $final_list; + }); + + } + + + public function saveUserMenuPermission($admin_id, array $new_permission) { + $this->objStaffPermissionModel->saveUserMenuPermission($admin_id, $new_permission); + } + + + public function saveUserEntityPermission($admin_id, array $new_permission) { + $this->objStaffPermissionModel->saveUserEntityPermission($admin_id, $new_permission); + } + + /* + * get menu for currently logged-in user + */ + public function getUserMenu($is_super_user) { + + // super can see all + if($is_super_user) { + return $this->getClientMenu(); + } + + $current_permission = $this->getCurrentUserMenuPermission(); + + $user_menu_settings = []; + foreach ($this->getClientMenu() as $group_id => $group_info) { + + $rebuild_menu = []; + foreach ($group_info['menu'] as $index => $menu) { + if(!in_array($menu['id'], $current_permission)) continue; + + $rebuild_menu[$index] = $menu; + } + + if(sizeof($rebuild_menu)) { + $user_menu_settings[$group_id] = $group_info; + $user_menu_settings[$group_id]['menu'] = $rebuild_menu; + } + } + + return $user_menu_settings; + } + + + public function getCurrentUserMenuPermission() { + $current_staff_id = StaffLoginController::getLoggedInStaffId(); + return $this->objStaffPermissionModel->getUserMenuPermission($current_staff_id); + } + + + public function getCurrentUserEntityPermission() { + $current_staff_id = StaffLoginController::getLoggedInStaffId(); + return $this->objStaffPermissionModel->getUserEntityPermission($current_staff_id); + } + + + public function getUserMenuPermissionSetting($admin_id) { + + $current_permission = $this->objStaffPermissionModel->getUserMenuPermission($admin_id); + + $user_menu_settings = []; + foreach ($this->getClientMenu() as $group_id => $group_info) { + + $rebuild_menu = []; + foreach ($group_info['menu'] as $index => $menu) { + $rebuild_menu[$index] = $menu; + + $rebuild_menu[$index]['is_user_permitted'] = (in_array($menu['id'], $current_permission)) ? 1 : 0; + } + + $user_menu_settings[$group_id] = $group_info; + $user_menu_settings[$group_id]['menu'] = $rebuild_menu; + } + + return $user_menu_settings; + } + + + public function getUserEntityPermissionSetting($admin_id) { + + $current_permission = $this->objStaffPermissionModel->getUserEntityPermission($admin_id); + + $_settings = []; + + foreach ($this->getClientEntityPermission() as $group_id => $group_info) { + + $rebuild_children = []; + foreach ($group_info['children'] as $entity => $info) { + + $actions = []; + foreach ($info['action'] as $action_key => $action_title) { + $actions[] = [ + 'action' => $action_key, + 'title' => $action_title, + 'is_user_permitted' => ( + isset($current_permission[$group_id]) && + isset($current_permission[$group_id][$entity]) && + isset($current_permission[$group_id][$entity][$action_key]) + ) ? $current_permission[$group_id][$entity][$action_key] : false , + ]; + } + + $rebuild_children[$entity] = [ + 'title' => $info['title'], + 'action_list' => $actions, + ]; + + } + + $_settings[$group_id] = $group_info; + $_settings[$group_id]['children'] = $rebuild_children; + } + + return $_settings; + } + +} diff --git a/inc/Hura8/Components/Staff/Model/StaffAuthModel.php b/inc/Hura8/Components/Staff/Model/StaffAuthModel.php new file mode 100644 index 0000000..8430a6d --- /dev/null +++ b/inc/Hura8/Components/Staff/Model/StaffAuthModel.php @@ -0,0 +1,64 @@ +tb_staff_login, $this->tb_staff_access_code); + } + + + public function getLoginListByIds(array $staff_ids) { + if(!sizeof($staff_ids)) { + return []; + } + + list($parameterized_ids, $bind_types) = create_bind_sql_parameter_from_value_list($staff_ids, 'int'); + + $bind_values = $staff_ids; + + $query = $this->db->runQuery( + "SELECT `user_id`, `last_login_time`, `last_login_ip`, `last_login_device`, `last_login_browser` + FROM ".$this->tb_staff_login." + WHERE `user_id` IN (".$parameterized_ids.") ", + $bind_types, + $bind_values + ); + + $item_list = []; + foreach ($this->db->fetchAll($query) as $item) { + $item_list[$item['user_id']] = $item; + } + + return $item_list; + } + + + public function getLoginLog(array $conditions = []) { + $bind_types = []; + $bind_values = []; + + $query = $this->db->runQuery( + "SELECT * FROM ".$this->tb_staff_login_log." WHERE 1 ORDER BY `id` DESC LIMIT 100 ", + $bind_types, + $bind_values + ); + + return $this->db->fetchAll($query) ; + } + + + +} diff --git a/inc/Hura8/Components/Staff/Model/StaffDepartmentModel.php b/inc/Hura8/Components/Staff/Model/StaffDepartmentModel.php new file mode 100644 index 0000000..1e15000 --- /dev/null +++ b/inc/Hura8/Components/Staff/Model/StaffDepartmentModel.php @@ -0,0 +1,40 @@ +objStaffDepartmentModel = new StaffDepartmentModel(); + } + + + public function getDepartmentMenuPermission($department_id) { + $_info = $this->objStaffDepartmentModel->getInfo($department_id); + + return ($_info['menu_permission']) ? \json_decode($_info['menu_permission'], true) : []; + } + + + + public function getDepartmentEntityPermission($department_id) { + $_info = $this->objStaffDepartmentModel->getInfo($department_id); + + return ($_info['entity_permission']) ? \json_decode($_info['entity_permission'], true) : []; + } + +} diff --git a/inc/Hura8/Components/Staff/Model/StaffLogModel.php b/inc/Hura8/Components/Staff/Model/StaffLogModel.php new file mode 100644 index 0000000..087b6a8 --- /dev/null +++ b/inc/Hura8/Components/Staff/Model/StaffLogModel.php @@ -0,0 +1,38 @@ +tb_staff = $this->tb_entity; + } + + + protected function extendedFilterOptions() : array + { + return [ + // empty for now + ]; + } + + + public function getInfoByEmail($email) : ?array + { + $query = $this->db->runQuery("SELECT * FROM `".$this->tb_entity."` WHERE `email` = ? LIMIT 1 ", ['s'], [$email]) ; + if( $item_info = $this->db->fetchAssoc($query)){ + return $this->formatItemInfo($item_info); + } + + return null; + } + + + protected function _buildQueryConditionExtend(array $condition) : ?array + { + /*$condition = array( + "letter" => "", + );*/ + + $catCondition = []; + $bind_types = []; + $bind_values = []; + + + if(isset($filter_condition["letter"]) && strlen($filter_condition["letter"]) == 1){ + $catCondition[] = " AND `letter` = ? "; + $bind_types[] = 's'; + $bind_values[] = $filter_condition["letter"]; + } + + return array( join(" ", $catCondition), $bind_types, $bind_values); + } + +} diff --git a/inc/Hura8/Components/Staff/Model/StaffPermissionModel.php b/inc/Hura8/Components/Staff/Model/StaffPermissionModel.php new file mode 100644 index 0000000..f9f9049 --- /dev/null +++ b/inc/Hura8/Components/Staff/Model/StaffPermissionModel.php @@ -0,0 +1,67 @@ +objStaffModel = new StaffModel(); + } + + + public function getUserEntityPermission($admin_id) { + + /*return [ + // entity group => entity + 'product' => [ + 'item' => [ + 'view' => true, + 'create' => false, + 'delete' => true, + 'update' => false, + ], + ], + + 'article' => [ + 'item' => [ + 'view' => true, + 'create' => false, + 'delete' => false, + 'update' => true, + ], + ] + ];*/ + + $admin_info = $this->objStaffModel->getInfo($admin_id); + + if($admin_info['entity_permission']) { + $entity_permission = \json_decode($admin_info['entity_permission'], true); + + if(sizeof($entity_permission) > 0) { + return $entity_permission; + } + } + + // else use department + if($admin_info['department']) { + $objStaffDepartmentPermissionModel = new StaffDepartmentPermissionModel(); + $department_entity_permission = $objStaffDepartmentPermissionModel->getDepartmentEntityPermission($admin_info['department']); + + return $department_entity_permission; + } + + return []; + } + + + public function getUserMenuPermission($admin_id) { + $admin_info = $this->objStaffModel->getInfo($admin_id); + return ($admin_info['menu_permission']) ? \json_decode($admin_info['menu_permission'], true) : []; + } + +} diff --git a/inc/Hura8/Components/Template/AdminController/ATemplateController.php b/inc/Hura8/Components/Template/AdminController/ATemplateController.php new file mode 100644 index 0000000..06d12a8 --- /dev/null +++ b/inc/Hura8/Components/Template/AdminController/ATemplateController.php @@ -0,0 +1,216 @@ +objTemplateModel = new TemplateModel($template_set); + $this->template_set = $template_set; + + $this->checkAndCreateDirectory(); + } + + public function checkFileExist($file_name, $f_type ) { + return $this->objTemplateModel->checkFileExist($file_name, $f_type); + } + + public function getInfo($id) { + return $this->objTemplateModel->getInfo($id); + } + + public function getEmptyInfo($addition_field_value = []) { + return $this->objTemplateModel->getEmptyInfo($addition_field_value); + } + + public function getModuleList() { + return $this->objTemplateModel->getModuleList(); + } + + + /** + * @description full tpl file name has this format: language_layout_base-name + * language is omitted if language = 'vnd' + * layout is omitted if layout = 'pc' + Example: + * for vn/pc: + - index + - product_detail + * for vn/mobile: + - mobile_index + - mobile_product_detail + * for en/pc: + - en_index + - en_product_detail + * for en/mobile: + - en_mobile_index + - en_mobile_product_detail + * @description contruct a full tpl file name to store in folder filesystem + * @param string $language vn or en + * @param string $layout pc or mobile + * @param string $base_name should not contain reserved keywords used for language (i.e en) & layout (i.e mobile) + * @return string + * @test + debug_var(\Hura8\Admin\ATemplate::buildFullTplFileName("product_detail", "vn", "pc")); + debug_var(\Hura8\Admin\ATemplate::buildFullTplFileName("product_detail", "vn", "mobile")); + debug_var(\Hura8\Admin\ATemplate::buildFullTplFileName("product_detail", "en", "pc")); + debug_var(\Hura8\Admin\ATemplate::buildFullTplFileName("product_detail", "en", "mobile")); + */ + public static function buildFullTplFileName(string $base_name, string $language=DEFAULT_LANGUAGE, string $layout='pc') { + if($language == DEFAULT_LANGUAGE) { + return ($layout == 'pc') ? $base_name : join("_", [$layout, $base_name]); + } + + return ($layout == 'pc') ? join("_", [$language, $base_name]) : join("_", [$language, $layout, $base_name]); + } + + /** + * @description extract $language, $layout, $base_name from $full_tpl_file + * @param string $full_tpl_file + * @return array + * @test + debug_var(\Hura8\Admin\ATemplate::extractFullTplFileName("product_detail")); + debug_var(\Hura8\Admin\ATemplate::extractFullTplFileName("mobile_product_detail")); + debug_var(\Hura8\Admin\ATemplate::extractFullTplFileName("en_product_detail")); + debug_var(\Hura8\Admin\ATemplate::extractFullTplFileName("en_mobile_product_detail")); + */ + public static function extractFullTplFileName(string $full_tpl_file) { + $language = DEFAULT_LANGUAGE; + $layout = "pc"; + + // check for different language + if(substr($full_tpl_file, 0, 3) == "en_") { + $language = "en"; + } + + // check for different layout + $clean_file = str_replace($language."_", "", $full_tpl_file); + if(substr($clean_file, 0, 7) == "mobile_") { + $layout = "mobile"; + } + + $base_name = str_replace($layout."_", "", $clean_file); + + return [ $language, $layout, $base_name ]; + } + + protected function checkAndCreateDirectory() { + // check and create directory + if (!is_dir($this->web_template_path)) { + mkdir($this->web_template_path, 0755, true); + } + + if (!is_dir($this->assets_template_path)) { + mkdir($this->assets_template_path, 0755, true); + mkdir(join(DIRECTORY_SEPARATOR, [$this->assets_template_path, 'script']), 0755, true); + mkdir(join(DIRECTORY_SEPARATOR, [$this->assets_template_path, 'images']), 0755, true); + } + } + + public function getFiles(array $conditions = []) { + + $conditions['numPerPage'] = 2000; + + return $this->objTemplateModel->getList($conditions); + } + + + public function getVersionHistory($module, $tpl_file) { + return $this->objTemplateModel->getVersionHistory($module, $tpl_file); + } + + public function getVersionContent($module, $tpl_file, $version) { + return $this->objTemplateModel->getVersionContent($module, $tpl_file, $version); + + } + + public function getFileContent($tpl_file, $folder, $is_setting = false) { + $ext = strrchr($tpl_file, "."); + if ($ext) $tpl_file = str_replace($ext, "", $tpl_file); + + switch ($ext) { + // css or js files + case ".script": + $full_file_path = join(DIRECTORY_SEPARATOR, [$this->assets_template_path, "script", $tpl_file]); + $content = (@file_exists($full_file_path)) ? @file_get_contents($full_file_path) : ''; + $real_ext = strrchr($tpl_file, "."); + $editor_mode = ($real_ext == ".js") ? 'text/javascript' : 'text/css'; + + return "
+ + +
+ "; + + + case ".image": + + $full_file_path = join(DIRECTORY_SEPARATOR, [$this->assets_template_path, "images", $tpl_file]); + return "
+ +
"; + + + default; + + $full_file_path = ($folder != 'index') ? + join(DIRECTORY_SEPARATOR, [$this->web_template_path, $folder, $tpl_file.".html"]) : + join(DIRECTORY_SEPARATOR, [$this->web_template_path, $tpl_file.".html"]) ; + + $content = (@file_exists($full_file_path)) ? @file_get_contents($full_file_path) : ''; + + return " + +
+ +
+ + "; + + } + } + +} diff --git a/inc/Hura8/Components/Template/AdminController/ATemplateSetController.php b/inc/Hura8/Components/Template/AdminController/ATemplateSetController.php new file mode 100644 index 0000000..509b532 --- /dev/null +++ b/inc/Hura8/Components/Template/AdminController/ATemplateSetController.php @@ -0,0 +1,46 @@ +objTemplateSetModel = new TemplateSetModel(); + } + + + // get empty/default item for form + public function getEmptyInfo($addition_field_value = []) { + return $this->objTemplateSetModel->getEmptyInfo($addition_field_value); + } + + public function checkSetExist($set_name) + { + return $this->objTemplateSetModel->getInfoBySet($set_name); + } + + public function getActivatedSet() { + return $this->objTemplateSetModel->getActivatedSet(); + } + + public function getList(array $condition) + { + return $this->objTemplateSetModel->getList($condition); + } + + public function getInfo($id): ?array + { + return $this->objTemplateSetModel->getInfo($id); + } + +} diff --git a/inc/Hura8/Components/Template/Controller/TemplateController.php b/inc/Hura8/Components/Template/Controller/TemplateController.php new file mode 100644 index 0000000..a9ef656 --- /dev/null +++ b/inc/Hura8/Components/Template/Controller/TemplateController.php @@ -0,0 +1,167 @@ +template_set = $template_set; + $this->web_template_path = self::TEMPLATE_DIR . $template_set; + $this->assets_template_path = self::TEMPLATE_ASSETS_DIR . $template_set; + $this->assets_public_path = join('/', ['', 'static', 'assets', $template_set]) ; + } + + + /** + * @param string $language_prefix + * @param string $layout + * @param $routing array + * @return string + */ + public static function getPublicTemplateFile($language_prefix="", $layout="pc", array $routing=[]): string{ + $tpl_file = str_replace('-', '_', $routing['view']). '.html'; + if($layout != 'pc') $tpl_file = $layout.'_'.$tpl_file; + + if($language_prefix) $tpl_file = $language_prefix."_".$tpl_file; + + return join( DIRECTORY_SEPARATOR, [ + $routing['module'], + $tpl_file + ]); + } + + + /** + * @param string $language_prefix + * @param string $layout + * @return string + */ + public static function getSiteThemeFile($language_prefix="", $layout = 'pc'): string + { + $tpl_file = "index.html"; + if($layout != 'pc') $tpl_file = $layout.'_'.$tpl_file; + + if($language_prefix) return $language_prefix."_".$tpl_file; + + return $tpl_file; + } + + + public static function flushCache() { + try { + + $cache = new File([ + 'cache_dir' => self::$cache_dir + ]); + + $cache->flush(); + + }catch (\Exception $exception) { + + } + } + + /* + * 2 ways to render a html template + * 1. Use $html_to_parse, which requires no dependencies + * Example: + * Template::parse(null, 'Age = {{age}}', ['age' => 21], ''); + * + * 2. Use $template_file_path, which requires dependency $path + * Template::parse(Template::$setting_template_path, null, ['age' => 21], 'email/test'); + * + * */ + public static function parse($path = null, $html_to_parse = null, array $data = [], $template_file_path = '') { + + if(!$html_to_parse && !$template_file_path) { + return 'Nothing to parse'; + } + + //output to html + Liquid::set('INCLUDE_SUFFIX', 'html'); + Liquid::set('INCLUDE_PREFIX', ''); + //Liquid::set('INCLUDE_ALLOW_EXT', true); + Liquid::set('ESCAPE_BY_DEFAULT', false); + + $enable_cache = false; // default = true, turn this on-off to disable cache while working on local mode + //$enable_cache = true; + + //catch exception and print friendly notice + try { + + $objLiquidTemplate = new LiquidTemplate( $path ); + $objLiquidTemplate->registerFilter( TemplateFilter::class ); + if($enable_cache) { + $objLiquidTemplate->setCache(new File([ + 'cache_dir' => self::$cache_dir + ])); + } + + if($html_to_parse) { + $objLiquidTemplate->parse($html_to_parse); + }elseif ($template_file_path) { + $objLiquidTemplate->parseFile($template_file_path); + } + + return $objLiquidTemplate->render($data); + + } catch (\Exception $e) { + $result = []; + do { + //printf("%s:%d %s (%d) [%s]\n", $e->getFile(), $e->getLine(), $e->getMessage(), $e->getCode(), get_class($e)); + //echo $e->getTraceAsString(); + //$code = $e->getTrace()[0]['args'][0]; + //if(is_array($code)) $code = serialize($code); + $result[] = sprintf( + " +Lỗi code trong file template html:
+- Chi tiết lỗi: %s
+- File template: %s
+- Cache Dir: %s
+- Hướng dẫn xử lý: Tách từng phần html để kiểm tra và nhấn F5 mỗi lần. Nếu không xuất hiện thông báo này nghĩa là phần đó không tạo lỗi +", + $e->getMessage(), + substr($template_file_path, strrpos($template_file_path, DIRECTORY_SEPARATOR) + 1 ), + static::$cache_dir + ); + + } while($e = $e->getPrevious()); + + return join(" - ", $result); + } + } + + + public function getWebTemplatePath() { + return $this->web_template_path; + } + + public function getWebPublicAssetsUrl() { + return $this->assets_public_path; + } + + public function getWebTemplateAssetsPath() { + return $this->assets_template_path; + } + +} diff --git a/inc/Hura8/Components/Template/Controller/TemplateFilter.php b/inc/Hura8/Components/Template/Controller/TemplateFilter.php new file mode 100644 index 0000000..b164647 --- /dev/null +++ b/inc/Hura8/Components/Template/Controller/TemplateFilter.php @@ -0,0 +1,262 @@ + '', 'value' => ] from [key1 => value1, key2=>value2, ...] + * + * @param array $key_values [key1 => value1, key2=>value2] + * + * @return array [['key' => 'key1', 'value' => value1], ['key' => 'key2', 'value' => value2]] + */ + public static function to_array(array $key_values) { + $result = []; + foreach ($key_values as $key => $value) { + $result[] = [ + 'key' => $key, + 'value' => $value, + ]; + } + + return $result; + } + + + /** + * split a s by line to create array + * + * @param string $txt + * + * @return array + */ + public static function get_line($txt) { + + if(is_array($txt)) { + return $txt; + } + + $txt = trim($txt); + if( ! $txt ) return []; + + return preg_split("/\n/", $txt); + } + + /** + * Implement strlen + * + * @param string $str + * + * @return int + */ + public static function length($str) { + return strlen(trim($str)); + } + + + /** + * Make number easier to read: 1000 -> 1.000 + * + * @param string $number + * + * @return string + */ + public static function format_number($number) { + if(!$number) return ''; + $number = floatval($number); + + $number = number_format($number, 0, ",", "."); //Vietnamese format with decimals by a coma + + return $number; + } + + public static function format_price($p_price, $currency = ''){ + if(!$p_price) return ''; + if(!$currency) $currency = (defined("DEFAULT_CURRENCY")) ? DEFAULT_CURRENCY : "vnd"; + //if(is_string($p_price)) return 0; + if($currency == 'usd') { + return number_format($p_price,2,".",","); + }else { + return number_format($p_price,0,",","."); + } + } + + public static function global_asset_url($file_name = '') + { + return GLOBAL_ASSETS_PATH . $file_name; + } + + /** + * + * Description: get the shop's full asset url for template's images/js/css + * + * //Returns the URL of a file in the "assets" folder of a theme. + // {{ 'shop.css' | asset_url : 'arg1', 'arg2' ...}} -> //cdn.shopify.com/s/files/1/0087/0462/t/394/assets/shop.css?28253 + * + * @param string $file_name + * + * @return string + */ + public static function asset_url($file_name = '') + { + if( !$file_name ) return ''; + + $file_ext = strtolower(strrchr($file_name, ".")); + + // script tags + if(in_array($file_ext, ['.js', '.css'])) return TEMPLATE_ASSET_SCRIPT . $file_name; + + // default image + return TEMPLATE_ASSET_IMAGE . $file_name; + } + + + /** + * + * Description: construct a full html tag for images/js/css file + * + * @param string $file_path domain.com/static/style.css?v=3.1.1 + * + * @return string + */ + public static function script_tag($file_path) { + if( ! $file_path ) return ''; + + //check for ? + if(strpos($file_path, "?") !== false) { + $file_ext = str_replace(strrchr($file_path, "?"), "", $file_path); + $file_ext = strtolower(strrchr($file_ext, ".")); + } else { + $file_ext = strtolower(strrchr($file_path, ".")); + } + + $tag_config = [ + ".css" => "", + ".js" => "", + ".jpg" => "\"n\"/", + ".jpeg" => "\"\"/", + ".gif" => "\"\"/", + ".png" => "\"\"/", + ]; + + return (isset($tag_config[$file_ext])) ? $tag_config[$file_ext] : ''; + } + + /** + * {{ product_info.main_image | img_url: '300x300' }} => https://cdn.shopify.com/s/files/1/1183/1048/products/boat-shoes_300x300.jpeg?1459175177 + * @param string $full_path + * @param string $modifier + * $modifier: + * - must be in format: NumberxNumber or Numberx where Number must within 10 -> 9999 + * - or be one of these: small | medium | large + * @return string + */ + public static function img_url($full_path, $modifier) + { + $clean_modifier = ($modifier) ? trim($modifier) : ""; + + // verify $modifier + // must be in format: NumberxNumber or Numberx where Number must within 10 -> 9999 + if($clean_modifier + && !preg_match("/^[0-9]{2,4}x([0-9]{2,4})?$/i", $clean_modifier) + && !in_array($clean_modifier, ["small", "medium", "large"]) + ) { + $clean_modifier = ""; + } + + // return if no valid modifier + if( ! $clean_modifier ) { + return $full_path; + } + + $last_dot_position = strrpos($full_path, "."); + if( ! $last_dot_position ) return $full_path . $clean_modifier; + + return join("", [ + substr($full_path, 0, $last_dot_position), + "_", + $clean_modifier, + substr($full_path, $last_dot_position) + ]); + } + + /** + * //Returns the URL of a file in the Files page of the admin. + //{{ 'size-chart.pdf' | file_url }} -> //cdn.shopify.com/s/files/1/0087/0462/files/size-chart.pdf?28261 + * + * @param string $input + * @param string $string + * + * @return string + */ + public static function file_url($input, $string) + { + return strtoupper($input) . " = " . $string; + } + + /** + * //Returns the asset URL of an image in the Files page of the admin. file_img_url accepts an image size parameter. + //{{ 'logo.png' | file_img_url: '1024x768' }} -> //cdn.shopify.com/s/files/1/0246/0527/files/logo_1024x768.png?42 + * + * @param string $input + * @param string $string + * + * @return string + */ + public static function file_img_url($input, $string) + { + return ''; + } + + + /** + * Show all content of a variable, useful for template development + * + * @param string + * + * @return string + */ + public static function print_r($input) + { + @ob_start(); + print_r($input); + $content = ob_get_contents(); + @ob_end_clean(); + + return join("\r", ['']) ; + } + + /** + * Show all content of a variable, useful for template development + * + * @param string + * + * @return string + */ + public static function show_var($input) + { + @ob_start(); + print_r($input); + $content = ob_get_contents(); + @ob_end_clean(); + + return join("\r", ['']) ; + } +} diff --git a/inc/Hura8/Components/Template/Model/TemplateModel.php b/inc/Hura8/Components/Template/Model/TemplateModel.php new file mode 100644 index 0000000..da07a12 --- /dev/null +++ b/inc/Hura8/Components/Template/Model/TemplateModel.php @@ -0,0 +1,132 @@ +template_set = $template_set; + $this->tb_template = $this->tb_entity; + } + + + protected function extendedFilterOptions() : array + { + return [ + // empty for now + ]; + } + + + public function getModuleList() { + $query = $this->db->runQuery( + " select distinct `module` from `".$this->tb_template."` where `set_name` = ? order by `module` asc ", + [ 's' ], + [ $this->template_set ] + ) ; + + $item_list = []; + foreach ($this->db->fetchAll($query) as $item) { + if($item['module']) $item_list[] = $item['module']; + } + + return $item_list; + } + + + public function checkFileExist($file_name, $f_type ) { + $query = $this->db->runQuery( + "SELECT * FROM ".$this->tb_template." WHERE `file_name` = ? AND `file_type` = ? AND `set_name` = ? LIMIT 1 ", + [ 's', 's' , 's' ], + [ $file_name, $f_type, $this->template_set ] + ); + + return $this->db->fetchAssoc($query); + } + + + public function getVersionHistory($module, $tpl_file) { + + if(!$tpl_file) return []; + + $history_tpl_file = $this->historyFile($module, $tpl_file); + + $query = $this->db->runQuery( + "SELECT tpl_version, last_update, last_update_by FROM ".$this->tb_template_history." + WHERE `template` = ? AND `set_name` = ? ORDER BY `tpl_version` DESC LIMIT 30 ", + [ 's', 's' ], + [ $history_tpl_file, $this->template_set ] + ); + + return $this->db->fetchAll($query); + } + + + public function getVersionContent($module, $tpl_file, $version) { + + $history_tpl_file = $this->historyFile($module, $tpl_file); + + $query = $this->db->runQuery( + "SELECT `content` FROM ".$this->tb_template_history." + WHERE `template`= ? AND `set_name` = ? AND `tpl_version` = ? + LIMIT 1 ", + [ 's', 's', 'd' ], + [ $history_tpl_file, $this->template_set, $version ] + ); + + if ($rs = $this->db->fetchAssoc($query)) { + return $rs['content']; + } + + return ''; + } + + protected function historyFile($module, $tpl_file) { + return join("/", [$module, $tpl_file]); + } + + + protected function _buildQueryConditionExtend(array $conditions) : ?array + { + + /*$conditions = [ + 'file_folder' => '', + 'not_image' => true, + ];*/ + + $where_clause = [ " AND `set_name` = ? "]; + $bind_types = ['s']; + $bind_values = [$this->template_set]; + + if(isset($conditions['file_folder']) && in_array($conditions['file_folder'], ['layout', 'images', 'script']) ) { + $where_clause[] = " AND `file_folder` = ? "; + $bind_types[] = 's'; + $bind_values[] = $conditions['file_folder']; + } + + if(isset($conditions['not_image']) && $conditions['not_image']) { + $where_clause[] = " AND `file_folder` != 'images' "; + } + + return [ + join(" ", $where_clause), + $bind_types, + $bind_values + ]; + } + + +} diff --git a/inc/Hura8/Components/Template/Model/TemplateSetModel.php b/inc/Hura8/Components/Template/Model/TemplateSetModel.php new file mode 100644 index 0000000..f7733ac --- /dev/null +++ b/inc/Hura8/Components/Template/Model/TemplateSetModel.php @@ -0,0 +1,64 @@ +db->runQuery("SELECT * FROM `". $this->tb_entity ."` WHERE `folder_name` = ? LIMIT 1 ", ['s'], [$set_name]); + if($item_info = $this->db->fetchAssoc($query)){ + return $item_info; + } + + return false; + } + + + public function getActivatedSet() { + $query = $this->db->runQuery("SELECT `folder_name` FROM `". $this->tb_entity ."` WHERE `is_activated` = 1 LIMIT 1 "); + if($item_info = $this->db->fetchAssoc($query)){ + return $item_info['folder_name']; + } + + return 'default'; + } + + + protected function _buildQueryConditionExtend(array $condition) : ?array + { + $where_clause = ""; + $bind_types = []; + $bind_values = []; + + return [ + $where_clause, + $bind_types, + $bind_values + ]; + } + + + +} diff --git a/inc/Hura8/Components/User/AdminController/ANewsletterController.php b/inc/Hura8/Components/User/AdminController/ANewsletterController.php new file mode 100644 index 0000000..d208f8f --- /dev/null +++ b/inc/Hura8/Components/User/AdminController/ANewsletterController.php @@ -0,0 +1,27 @@ +objNewsletterModel = new NewsletterModel(); + parent::__construct($this->objNewsletterModel); + } + + + protected function deleteFileBeforeDeleteItem($item_id): bool + { + // TODO: Implement deleteFileBeforeDeleteItem() method. + return true; + } + + +} diff --git a/inc/Hura8/Components/User/AdminController/AUserCommentController.php b/inc/Hura8/Components/User/AdminController/AUserCommentController.php new file mode 100644 index 0000000..5f854bf --- /dev/null +++ b/inc/Hura8/Components/User/AdminController/AUserCommentController.php @@ -0,0 +1,27 @@ +objUserCommentModel = new UserCommentModel(); + parent::__construct($this->objUserCommentModel); + } + + + protected function deleteFileBeforeDeleteItem($item_id): bool + { + // TODO: Implement deleteFileBeforeDeleteItem() method. + return true; + } + +} diff --git a/inc/Hura8/Components/User/AdminController/AUserContactController.php b/inc/Hura8/Components/User/AdminController/AUserContactController.php new file mode 100644 index 0000000..05ea5b2 --- /dev/null +++ b/inc/Hura8/Components/User/AdminController/AUserContactController.php @@ -0,0 +1,27 @@ +objUserContactModel = new UserContactModel(); + parent::__construct($this->objUserContactModel); + } + + + protected function deleteFileBeforeDeleteItem($item_id): bool + { + // TODO: Implement deleteFileBeforeDeleteItem() method. + return true; + } + +} diff --git a/inc/Hura8/Components/User/AdminController/AUserController.php b/inc/Hura8/Components/User/AdminController/AUserController.php new file mode 100644 index 0000000..bd6eba4 --- /dev/null +++ b/inc/Hura8/Components/User/AdminController/AUserController.php @@ -0,0 +1,18 @@ +objUserReviewModel = new UserReviewModel(); + parent::__construct($this->objUserReviewModel); + } + + + protected function deleteFileBeforeDeleteItem($item_id): bool + { + // TODO: Implement deleteFileBeforeDeleteItem() method. + return true; + } + +} diff --git a/inc/Hura8/Components/User/Controller/bUserController.php b/inc/Hura8/Components/User/Controller/bUserController.php new file mode 100644 index 0000000..becf701 --- /dev/null +++ b/inc/Hura8/Components/User/Controller/bUserController.php @@ -0,0 +1,35 @@ +web_user_id = self::getWebUserId(); + $this->objUserModel = new UserModel($this->web_user_id ); + parent::__construct($this->objUserModel); + } + + + /** + * @description this value is set by hura.js for anonymous web users + * @return string + */ + public static function getWebUserId() { + return Cookie::get("uID", ''); + } + + + +} diff --git a/inc/Hura8/Components/User/Controller/bUserReviewController.php b/inc/Hura8/Components/User/Controller/bUserReviewController.php new file mode 100644 index 0000000..d08bc58 --- /dev/null +++ b/inc/Hura8/Components/User/Controller/bUserReviewController.php @@ -0,0 +1,27 @@ +web_user_id = UUserController::getWebUserId(); + + $this->objUserReviewModel = new UserReviewModel($item_type, $item_id); + + parent::__construct($this->objUserReviewModel); + } + + + +} diff --git a/inc/Hura8/Components/User/Controller/bUserUploadController.php b/inc/Hura8/Components/User/Controller/bUserUploadController.php new file mode 100644 index 0000000..731c7e3 --- /dev/null +++ b/inc/Hura8/Components/User/Controller/bUserUploadController.php @@ -0,0 +1,41 @@ +web_user_id = AUserController::getWebUserId(); + $this->customer_id = UCustomerLoginController::getLoggedInCustomerId(); + + $this->item_type = $item_type; + $this->item_id = $item_id; + + parent::__construct(new UserUploadModel($this->web_user_id, $this->customer_id, $item_type, $item_id)); + } + + protected function deleteFileBeforeDeleteItem($item_id): bool + { + // delete thumb files + $item_info = $this->getInfo($item_id); + + if($item_info['file_path']) { + $file_local_path = PUBLIC_DIR . "/". $item_info['file_path']; + @unlink($file_local_path); + } + + // ok + return true; + } + +} diff --git a/inc/Hura8/Components/User/Model/NewsletterModel.php b/inc/Hura8/Components/User/Model/NewsletterModel.php new file mode 100644 index 0000000..4e25fff --- /dev/null +++ b/inc/Hura8/Components/User/Model/NewsletterModel.php @@ -0,0 +1,73 @@ + "", + "status" => 0, + );*/ + + $catCondition = []; + $bind_types = []; + $bind_values = []; + + return array( join(" ", $catCondition), $bind_types, $bind_values); + } + + + protected function beforeCreateItem(array $input_info) : AppResponse + { + $info = $input_info; + + $info['create_time'] = CURRENT_TIME; + + return new AppResponse('ok', null, $info); + } + + protected function afterCreateItem($new_item_id, $new_item_info) + { + // TODO: Implement afterCreateItem() method. + } + + protected function beforeUpdateItem($item_id, $current_item_info, $new_input_info) : AppResponse + { + return new AppResponse('ok', null, $new_input_info); + } + + protected function afterUpdateItem($item_id, $old_item_info, $new_item_info) + { + // TODO: Implement afterUpdateItem() method. + } + + protected function beforeDeleteItem($item_id, $item_info) : AppResponse + { + return new AppResponse('ok'); + } + + protected function afterDeleteItem($item_id, $item_info) + { + // TODO: Implement afterDeleteItem() method. + } +} diff --git a/inc/Hura8/Components/User/Model/UserCommentModel.php b/inc/Hura8/Components/User/Model/UserCommentModel.php new file mode 100644 index 0000000..7a18f1c --- /dev/null +++ b/inc/Hura8/Components/User/Model/UserCommentModel.php @@ -0,0 +1,90 @@ + "", + "status" => 0, + 'read' => 1,-1 + );*/ + + $catCondition = []; + $bind_types = []; + $bind_values = []; + + + if(isset($condition["read"]) && $condition["read"]){ + $catCondition[] = " AND `is_read` = ? "; + $bind_types[] = 'd'; + $bind_values[] = ($condition["read"] == 1) ? 1 : 0; + } + + return array( join(" ", $catCondition), $bind_types, $bind_values); + } + + + protected function beforeCreateItem(array $input_info) : AppResponse + { + $info = $input_info; + + $info['create_time'] = CURRENT_TIME; + $info['create_by'] = ADMIN_NAME; + + return new AppResponse('ok', null, $info); + } + + protected function afterCreateItem($new_item_id, $new_item_info) + { + + } + + protected function beforeUpdateItem($item_id, $current_item_info, $new_input_info) : AppResponse + { + $info = $new_input_info; + + $info['last_update'] = CURRENT_TIME; + $info['last_update_by'] = ADMIN_NAME; + + return new AppResponse('ok', null, $info); + } + + protected function afterUpdateItem($item_id, $old_item_info, $new_item_info) + { + + } + + protected function beforeDeleteItem($item_id, $item_info) : AppResponse + { + return new AppResponse('ok'); + } + + protected function afterDeleteItem($item_id, $item_info) + { + + } + +} diff --git a/inc/Hura8/Components/User/Model/UserCommentReplyModel.php b/inc/Hura8/Components/User/Model/UserCommentReplyModel.php new file mode 100644 index 0000000..d21dc50 --- /dev/null +++ b/inc/Hura8/Components/User/Model/UserCommentReplyModel.php @@ -0,0 +1,96 @@ + "", + "status" => 0, + 'read' => 1,-1 + );*/ + + $catCondition = []; + $bind_types = []; + $bind_values = []; + + + if(isset($condition["read"]) && $condition["read"]){ + $catCondition[] = " AND `is_read` = ? "; + $bind_types[] = 'd'; + $bind_values[] = ($condition["read"] == 1) ? 1 : 0; + } + + return array( join(" ", $catCondition), $bind_types, $bind_values); + } + + protected function _buildQueryOrderBy($sort_by = "new") + { + return parent::_buildQueryOrderBy($sort_by); + } + + + protected function beforeCreateItem(array $input_info) : AppResponse + { + $info = $input_info; + + $info['create_time'] = CURRENT_TIME; + $info['create_by'] = ADMIN_NAME; + + return new AppResponse('ok', null, $info); + } + + protected function afterCreateItem($new_item_id, $new_item_info) + { + + } + + protected function beforeUpdateItem($item_id, $current_item_info, $new_input_info) : AppResponse + { + $info = $new_input_info; + + $info['last_update'] = CURRENT_TIME; + $info['last_update_by'] = ADMIN_NAME; + + return new AppResponse('ok', null, $info); + } + + protected function afterUpdateItem($item_id, $old_item_info, $new_item_info) + { + + } + + protected function beforeDeleteItem($item_id, $item_info) : AppResponse + { + return new AppResponse('ok'); + } + + protected function afterDeleteItem($item_id, $item_info) + { + + } + +} diff --git a/inc/Hura8/Components/User/Model/UserContactModel.php b/inc/Hura8/Components/User/Model/UserContactModel.php new file mode 100644 index 0000000..bbde4b3 --- /dev/null +++ b/inc/Hura8/Components/User/Model/UserContactModel.php @@ -0,0 +1,54 @@ + "", + "status" => 0, + 'read' => 1,-1 + );*/ + + $catCondition = []; + $bind_types = []; + $bind_values = []; + + if(isset($condition["read"]) && $condition["read"]){ + $catCondition[] = " AND `is_read` = ? "; + $bind_types[] = 'd'; + $bind_values[] = ($condition["read"] == 1) ? 1 : 0; + } + + return array( join(" ", $catCondition), $bind_types, $bind_values); + } + + protected function _buildQueryOrderBy($sort_by = "new") + { + return parent::_buildQueryOrderBy($sort_by); + } + +} diff --git a/inc/Hura8/Components/User/Model/UserModel.php b/inc/Hura8/Components/User/Model/UserModel.php new file mode 100644 index 0000000..63881aa --- /dev/null +++ b/inc/Hura8/Components/User/Model/UserModel.php @@ -0,0 +1,58 @@ +web_user_id = $web_user_id; + $this->user_db_id = $user_db_id; + + parent::__construct('web_user_info'); + } + + + protected function extendedFilterOptions() : array + { + return [ + // empty for now + ]; + } + + + protected function _buildQueryConditionExtend(array $condition) : ?array + { + /*$condition = array( + "q" => "", + "status" => 0, + );*/ + + /*$condition = array( + "letter" => "", + );*/ + + $catCondition = []; + $bind_types = []; + $bind_values = []; + + + if(isset($filter_condition["letter"]) && strlen($filter_condition["letter"]) == 1){ + $catCondition[] = " AND `letter` = ? "; + $bind_types[] = 's'; + $bind_values[] = $filter_condition["letter"]; + } + + return array( join(" ", $catCondition), $bind_types, $bind_values); + } + + +} diff --git a/inc/Hura8/Components/User/Model/UserReviewModel.php b/inc/Hura8/Components/User/Model/UserReviewModel.php new file mode 100644 index 0000000..336df9c --- /dev/null +++ b/inc/Hura8/Components/User/Model/UserReviewModel.php @@ -0,0 +1,218 @@ + true, + 'auto-approve-message' => false, + 'detect-spam-before-create' => true, + ]; + + protected $item_type = ''; + protected $item_id = 0; + + /* @var ?iEntityStatistic $iEntityStatisticModel */ + protected $iEntityStatisticModel; + + public function __construct($item_type, $item_id = 0) { + + $this->item_type = $item_type; + $this->item_id = $item_id; + + $this->iEntityStatisticModel = get_statistic_model_instance($this->item_type); + + // todo: overwrite default rules by client + + parent::__construct("user-review"); + } + + + protected function extendedFilterOptions() : array + { + return [ + // empty for now + ]; + } + + + public function getSummary(array $conditions = []) + { + $where_conditions = []; + $bind_types = []; + $bind_values = []; + + //item_type + $where_conditions[] = " AND `item_type` = ? "; + $bind_types[] = 's'; + $bind_values[] = $this->item_type; + + + //item_id + $where_conditions[] = " AND `item_id` = ? "; + $bind_types[] = 's'; + $bind_values[] = $this->item_id; + + + //approved + if(isset($conditions["approved"]) ){ + $where_conditions[] = " AND `approved` = ? "; + $bind_types[] = 'd'; + $bind_values[] = ($conditions["approved"] == 1) ? 1 : 0; + } + + $query = $this->db->runQuery( + "SELECT AVG(`rate`) AS avgRate, COUNT(*) AS total FROM `". $this->tb_entity ."` WHERE 1 ".join(" ", $where_conditions), + $bind_types, $bind_values + ); + + if ( $info = $this->db->fetchAssoc($query) ) { + return [ + "avgRate" => $info['avgRate'], + "total" => $info['total'], + ]; + } + + return [ + "avgRate" => 0, + "total" => 0, + ]; + } + + + protected function _buildQueryConditionExtend(array $condition) : ?array + { + /*$condition = array( + "q" => "", + "status" => 0, + 'read' => 1,-1 + );*/ + + $catCondition = []; + $bind_types = []; + $bind_values = []; + + if(isset($condition["read"]) && $condition["read"]){ + $catCondition[] = " AND `is_read` = ? "; + $bind_types[] = 'd'; + $bind_values[] = ($condition["read"] == 1) ? 1 : 0; + } + + return array( join(" ", $catCondition), $bind_types, $bind_values); + } + + + protected function beforeCreateItem(array $input_info) : AppResponse + { + //todo: check user's authentication and authorization + if($this->rules['require-user-login'] && !UCustomerLoginController::getLoggedInCustomerId()) { + return new AppResponse('error', "Login required"); + } + + $info = $input_info; + + $info['item_type'] = $this->item_type; + $info['item_id'] = $this->item_id; + + $info['item_title'] = DataClean::limitLengthFullWords($input_info['item_title'], 50); + $info['title'] = DataClean::limitLengthFullWords($input_info['title'], 50); + $info['content'] = DataClean::limitLengthFullWords($input_info['content'], 500); + + $info['user_id'] = ''; + $info['user_email'] = DataClean::makeInputSafe($input_info['user_email'], DataType::EMAIL); + $info['user_name'] = DataClean::limitLengthFullWords($input_info['user_name'], 50); + + // todo: check files actually exists and belong to this user + $info['files'] = (is_array($input_info['files'])) ? DataClean::makeListOfInputSafe($input_info['files'], DataType::INTEGER) : null; + + //$info['approved'] = (CONFIG_AUTO_APPROVE_REVIEW) ? 1 : 0; + $info['rate'] = (in_array($info['rate'], [1,2,3,4,5])) ? $info['rate'] : 0; + $info['ip_address'] = USER_IP; + $info['user_agent'] = substr(USER_AGENT, 0, 200); + + /* + "item_type" => $post_info['item_type'], + "item_id" => $post_info['item_id'], + "item_title" => $post_info['item_title'], + "is_user_admin" => $post_info['is_user_admin'], + "user_id" => USER_ID, + "user_email" => $post_info['user_email'], + "user_name" => $post_info['user_name'], + "user_avatar" => $post_info['user_avatar'], + "user_note" => $post_info['user_note'], + "rate" => (int) $post_info['rate'], + "title" => $post_info['title'], + "content" => $post_info['content'], + "files" => $post_info['files'], + "approved" => (CONFIG_AUTO_APPROVE_REVIEW) ? 1 : 0, + "post_time" => CURRENT_TIME, + "ip_address" => USER_IP, + "user_agent" => substr(USER_AGENT, 0, 200),*/ + + $info['create_time'] = CURRENT_TIME; + + return new AppResponse('ok', null, $info); + } + + + protected function afterCreateItem($new_item_id, $new_item_info) + { + // update summary for item + $this->updateItemReviewCount(); + } + + + protected function beforeUpdateItem($item_id, $current_item_info, $new_input_info) : AppResponse + { + //todo: check user's authentication and authorization + + $info = $new_input_info; + + $info['last_update'] = CURRENT_TIME; + $info['last_update_by'] = ''; + + return new AppResponse('ok', null, $info); + } + + + protected function afterUpdateItem($item_id, $old_item_info, $new_item_info) + { + + } + + + protected function beforeDeleteItem($item_id, $item_info) : AppResponse + { + //todo: check user's authentication and authorization + + return new AppResponse('ok'); + } + + + protected function afterDeleteItem($item_id, $item_info) + { + // update summary for item + $this->updateItemReviewCount(); + } + + + protected function updateItemReviewCount() + { + // update summary for item + if($this->iEntityStatisticModel) { + $summary = $this->getSummary([]); + $this->iEntityStatisticModel->updateReviewCount($this->item_id, $summary['total'], $summary['avgRate']); + } + } +} diff --git a/inc/Hura8/Components/User/Model/UserUploadModel.php b/inc/Hura8/Components/User/Model/UserUploadModel.php new file mode 100644 index 0000000..08032c2 --- /dev/null +++ b/inc/Hura8/Components/User/Model/UserUploadModel.php @@ -0,0 +1,63 @@ +web_user_id = $web_user_id; + $this->customer_id = $customer_id; + $this->item_id = $item_id; + $this->item_type = $item_type; + } + + protected function extendedFilterOptions() : array + { + return [ + // empty for now + ]; + } + + protected function _buildQueryConditionExtend(array $condition) : ?array + { + /*$condition = array( + "q" => "", + "status" => 0, + 'read' => 1,-1 + );*/ + + $catCondition = []; + $bind_types = []; + $bind_values = []; + + if(isset($condition["type"]) && $condition["type"]){ + $catCondition[] = " AND `type` = ? "; + $bind_types[] = 's'; + $bind_values[] = $condition["type"]; + } + + if(isset($condition["approved"]) && $condition["approved"]){ + $catCondition[] = " AND `approved` = ? "; + $bind_types[] = 'd'; + $bind_values[] = ($condition["approved"] == 1) ? 1 : 0; + } + + return array( join(" ", $catCondition), $bind_types, $bind_values); + } + +} diff --git a/inc/Hura8/Interfaces/iEntityAdminController.php b/inc/Hura8/Interfaces/iEntityAdminController.php index 095316c..bd63dca 100644 --- a/inc/Hura8/Interfaces/iEntityAdminController.php +++ b/inc/Hura8/Interfaces/iEntityAdminController.php @@ -4,8 +4,5 @@ namespace Hura8\Interfaces; interface iEntityAdminController extends iEntityController { - public function create(array $info) : AppResponse; - public function update($id, array $info) : AppResponse; - public function delete($id) : AppResponse; public function getEmptyInfo(array $additional_fields = []): array; } diff --git a/inc/Hura8/Traits/AdminEntityBaseControllerTraits.php b/inc/Hura8/Traits/AdminEntityBaseControllerTraits.php new file mode 100644 index 0000000..195649c --- /dev/null +++ b/inc/Hura8/Traits/AdminEntityBaseControllerTraits.php @@ -0,0 +1,18 @@ +iEntityModel->getEmptyInfo($additional_fields); + } + +} diff --git a/inc/Hura8/Traits/AdminEntityCategoryControllerTraits.php b/inc/Hura8/Traits/AdminEntityCategoryControllerTraits.php new file mode 100644 index 0000000..14dd8d4 --- /dev/null +++ b/inc/Hura8/Traits/AdminEntityCategoryControllerTraits.php @@ -0,0 +1,74 @@ +getAllParent([]); + + $extra_space = ""; + for($i = 1; $i < $level; $i++){ + $extra_space .= "     "; + } + + $result = ""; + + if(isset($all_categories[$categoryParentId])) { + foreach($all_categories[$categoryParentId] as $cat_info){ + $cat_id = $cat_info['id']; + + if($selectedId == $cat_id) { + $result .= ""; + } + else { + $result .= ""; + } + + if($cat_info['is_parent']) { + $result .= $this->getDropBox($selectedId, $cat_id, $level+1); + } + } + } + + return $result; + } + + + public function categorySelectBox(array $array_selected, $categoryParentId, $level=1){ + + $all_categories = $this->getAllParent([]); + + if(!isset($all_categories[$categoryParentId])) return ''; + + $extra_space = ""; + for($i = 1; $i < $level; $i++){ + $extra_space .= "     "; + } + + $result = ''; + + foreach ( $all_categories[$categoryParentId] as $item ) { + + $checked = (in_array($item['id'], $array_selected)) ? "checked" : ""; + + if($item['is_parent']) { + $result .= $extra_space ." ". $item['title']."
"; + $result .= $this->categorySelectBox( $array_selected, $item['id'], $level+1); + }else{ + if(!$checked) { + $result .= $extra_space . "
"; + }else{ + $result .= $extra_space . "
"; + } + } + + } + + return $result; + } + +} diff --git a/template/product/category.html b/template/product/category.html new file mode 100644 index 0000000..600929a --- /dev/null +++ b/template/product/category.html @@ -0,0 +1,54 @@ + + + + + +
[+] Xem hết
+ + + + + + + + + + + + + {{page.category_list}} + +
IDTên gọiSản phẩmWebThứ tự hiển thịThuộc tínhSửa lại
+ +

+ Lưu ý: Tổng sản phẩm ở danh mục mẹ được tính là tổng sản phẩm sản phẩm của các danh mục con và danh mục mẹ. Bộ đếm không loại trừ sản phẩm trùng nhau (v.d. trường hợp 1 sản phẩm thuộc cả 2 danh mục con thì sẽ được đếm 2 lần) +

+ + + + + + + + + diff --git a/template/product/category_form.html b/template/product/category_form.html new file mode 100644 index 0000000..de17866 --- /dev/null +++ b/template/product/category_form.html @@ -0,0 +1,131 @@ +{if="$item_info.id > 0"} +{$language_selector} +
+{/if} + + + +{if="$update_status == 'success'"} +

Cập nhật thành công

+{/if} + + +
+ + + +
+
+
+
+
+ + + + {if="$item_info.id > 0"} +
+
(* thay đổi giá trị này sẽ thay đổi link truy cập)
+ {/if} + +
(nếu có)
+
+ + + +
+ +
+
+ +
+ +
+
+ + {if="strlen($item_info.icon) > 3"} + + {/if} + + +
+ +
+
+ (Nhập từng giá cách nhau dấu ;)
+ ví dụ: 300000;800000;1500000 có nghĩa là tạo ra 4 khoảng giá cho khách hàng lọc, đó là:
+ - Dưới 300.000,
+ - Từ 300.000 đến 800.000,
+ - Từ 800.000 đến 1.500.000
+ - Trên 1.500.000 +
+ +
+
+
+ +
+
+ +
+
+ +
+ {$display_template = isset($item_info.settings.display_template) ? $item_info.settings.display_template : ''} +
(v.d. landing_page/special_deal_11_2023 - cấu trúc file trong template)
+ +
+ {$number_display = isset($item_info.settings.number_display) ? $item_info.settings.number_display : 0} +
(để = 0 nếu mặc định theo hệ thống cài đặt chung)
+ +
+
(cao xếp trước)
+ +
+
+ + + + + + + + + +
Url canonical + * để trống sẽ dùng link mặc định của hệ thống
Meta Title
Meta Keywords
Meta Description + +
+ (Khuyến nghị: 160 ký tự) + * nếu để trống sẽ dùng tóm tắt danh mục +
+
+ +
+
+ {$set_display = 1} + {if="$item_info.id > 0"} + {$set_display = $item_info.status} + {/if} + + +
+ +
+ +
+
+ + hoặc Hủy bỏ +
+
+ +
From 37e4278d539c7a2d8895e83a8c33b7f87c8ef673 Mon Sep 17 00:00:00 2001 From: Tieptk Date: Wed, 31 Jan 2024 11:59:25 +0700 Subject: [PATCH 2/2] search --- assets/script/pc_style.css | 32 ++++- assets/script/pc_style.css.map | 6 +- assets/script/pc_style.scss | 43 ++++-- template/javascript/global.html | 8 ++ template/javascript/product_list.html | 190 ++++++++++++++++++-------- template/theme.html | 14 +- 6 files changed, 213 insertions(+), 80 deletions(-) diff --git a/assets/script/pc_style.css b/assets/script/pc_style.css index d8b79e3..3e73a2a 100644 --- a/assets/script/pc_style.css +++ b/assets/script/pc_style.css @@ -794,13 +794,13 @@ input[type=radio]:focus:before { .order-page-table .icons { width: 30px; height: 30px; - border: 1px solid #ECECEC; - background-color: #F9F9F9; + border: 1px solid #ececec; + background-color: #f9f9f9; border-radius: 5px; } .order-page-table .icon-edit { - border: 1px solid #0041E8; - background-color: #F5F7FF; + border: 1px solid #0041e8; + background-color: #f5f7ff; background-position: -108px -82px; margin-right: 6px; } @@ -867,4 +867,28 @@ input[type=radio]:focus:before { .table-brand td { padding: 7px 6px; border: 1px solid #ececec; +} + +.autocomplete-suggestions .item { + padding: 12px 0; + border-bottom: 1px solid #ededed; +} +.autocomplete-suggestions .item .info { + width: calc(100% - 108px); + margin-right: 48px; +} +.autocomplete-suggestions .item img { + width: 60px; + display: block; +} +.autocomplete-suggestions .item .name { + font-weight: 600; + line-height: 20px; +} +.autocomplete-suggestions .item .price { + font-weight: 600; + color: #fb4e4e; + line-height: 20px; + display: block; + margin-top: 5px; }/*# sourceMappingURL=pc_style.css.map */ \ No newline at end of file diff --git a/assets/script/pc_style.css.map b/assets/script/pc_style.css.map index 9da40ec..63d5c21 100644 --- a/assets/script/pc_style.css.map +++ b/assets/script/pc_style.css.map @@ -1,5 +1 @@ -<<<<<<< HEAD -{"version":3,"sources":["pc_style.css","pc_style.scss"],"names":[],"mappings":"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","file":"pc_style.css"} -======= -{"version":3,"sources":["pc_style.css","pc_style.scss"],"names":[],"mappings":"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","file":"pc_style.css"} ->>>>>>> 36c52953bd3cedfda1d619bacfc1b45c7decb17e +{"version":3,"sources":["pc_style.css","pc_style.scss"],"names":[],"mappings":"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","file":"pc_style.css"} \ No newline at end of file diff --git a/assets/script/pc_style.scss b/assets/script/pc_style.scss index 8fb4760..53a7f46 100644 --- a/assets/script/pc_style.scss +++ b/assets/script/pc_style.scss @@ -48,7 +48,7 @@ img { max-width: 100%; height: auto; } -table{ +table { width: 100%; } a { @@ -304,13 +304,14 @@ a { align-items: center; transition: 0.3s all; position: relative; - &:hover, &.current{ + &:hover, + &.current { background: #81b5e4; .icons { filter: brightness(100); } } - &:hover { + &:hover { .sub-menu { left: calc(100% + 8px); opacity: 1; @@ -770,7 +771,7 @@ input[type="radio"] { &:nth-child(10) { text-align: left; } - } + } } } .order-page-table { @@ -812,13 +813,13 @@ input[type="radio"] { .icons { width: 30px; height: 30px; - border: 1px solid #ECECEC; - background-color: #F9F9F9; + border: 1px solid #ececec; + background-color: #f9f9f9; border-radius: 5px; } .icon-edit { - border: 1px solid #0041E8; - background-color: #F5F7FF; + border: 1px solid #0041e8; + background-color: #f5f7ff; background-position: -108px -82px; margin-right: 6px; } @@ -888,3 +889,29 @@ input[type="radio"] { border: 1px solid #ececec; } } + +.autocomplete-suggestions { + .item { + padding: 12px 0; + border-bottom: 1px solid #ededed; + .info { + width: calc(100% - 108px); + margin-right: 48px; + } + img { + width: 60px; + display: block; + } + .name { + font-weight: 600; + line-height: 20px; + } + .price { + font-weight: 600; + color: #fb4e4e; + line-height: 20px; + display: block; + margin-top: 5px; + } + } +} diff --git a/template/javascript/global.html b/template/javascript/global.html index 10f61bf..848f824 100644 --- a/template/javascript/global.html +++ b/template/javascript/global.html @@ -33,4 +33,12 @@ localStorage.setItem(hideMenuBig ? 'menu_big' : 'menu_small', 'hidden'); localStorage.removeItem(hideMenuBig ? 'menu_small' : 'menu_big'); } + + + function formatCurrency(a) { + var b = parseFloat(a).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, "$1.").toString(); + var len = b.length; + b = b.substring(0, len - 3); + return b; + } \ No newline at end of file diff --git a/template/javascript/product_list.html b/template/javascript/product_list.html index 03e8cc4..60da000 100644 --- a/template/javascript/product_list.html +++ b/template/javascript/product_list.html @@ -1,69 +1,139 @@ \ No newline at end of file diff --git a/template/theme.html b/template/theme.html index 5e539bf..dcde647 100644 --- a/template/theme.html +++ b/template/theme.html @@ -220,11 +220,19 @@