diff --git a/module/oc_telegram_shop/upload/catalog/controller/extension/tgshop/handle.php b/module/oc_telegram_shop/upload/catalog/controller/extension/tgshop/handle.php index 231bf83..8420e35 100755 --- a/module/oc_telegram_shop/upload/catalog/controller/extension/tgshop/handle.php +++ b/module/oc_telegram_shop/upload/catalog/controller/extension/tgshop/handle.php @@ -20,7 +20,7 @@ if (is_readable($sysLibPath . '/oc_telegram_shop.phar')) { class Controllerextensiontgshophandle extends Controller { - public function index() + public function index(): void { $app = ApplicationFactory::create([ 'oc_config_tax' => $this->config->get('config_tax'), @@ -79,4 +79,206 @@ class Controllerextensiontgshophandle extends Controller $app->bootAndHandleRequest(); } + + public function cart() { + $this->load->language('checkout/cart'); + + if ($this->cart->hasProducts()) { + if (!$this->cart->hasStock() && (!$this->config->get('config_stock_checkout') || $this->config->get('config_stock_warning'))) { + $data['error_warning'] = $this->language->get('error_stock'); + } elseif (isset($this->session->data['error'])) { + $data['error_warning'] = $this->session->data['error']; + + unset($this->session->data['error']); + } else { + $data['error_warning'] = ''; + } + + if ($this->config->get('config_customer_price') && !$this->customer->isLogged()) { + $data['attention'] = sprintf($this->language->get('text_login'), $this->url->link('account/login'), $this->url->link('account/register')); + } else { + $data['attention'] = ''; + } + + if (isset($this->session->data['success'])) { + $data['success'] = $this->session->data['success']; + + unset($this->session->data['success']); + } else { + $data['success'] = ''; + } + + if ($this->config->get('config_cart_weight')) { + $data['weight'] = $this->weight->format($this->cart->getWeight(), $this->config->get('config_weight_class_id'), $this->language->get('decimal_point'), $this->language->get('thousand_point')); + } else { + $data['weight'] = ''; + } + + $this->load->model('tool/image'); + $this->load->model('tool/upload'); + + $data['products'] = array(); + + $products = $this->cart->getProducts(); + + foreach ($products as $product) { + $product_total = 0; + + foreach ($products as $product_2) { + if ($product_2['product_id'] == $product['product_id']) { + $product_total += $product_2['quantity']; + } + } + + if ($product['minimum'] > $product_total) { + $data['error_warning'] = sprintf($this->language->get('error_minimum'), $product['name'], $product['minimum']); + } + + if ($product['image']) { + $image = $this->model_tool_image->resize($product['image'], $this->config->get('theme_' . $this->config->get('config_theme') . '_image_cart_width'), $this->config->get('theme_' . $this->config->get('config_theme') . '_image_cart_height')); + } else { + $image = ''; + } + + $option_data = array(); + + foreach ($product['option'] as $option) { + if ($option['type'] != 'file') { + $value = $option['value']; + } else { + $upload_info = $this->model_tool_upload->getUploadByCode($option['value']); + + if ($upload_info) { + $value = $upload_info['name']; + } else { + $value = ''; + } + } + + $option_data[] = array( + 'name' => $option['name'], + 'value' => (utf8_strlen($value) > 20 ? utf8_substr($value, 0, 20) . '..' : $value) + ); + } + + // Display prices + if ($this->customer->isLogged() || !$this->config->get('config_customer_price')) { + $unit_price = $this->tax->calculate($product['price'], $product['tax_class_id'], $this->config->get('config_tax')); + + $price = $this->currency->format($unit_price, $this->session->data['currency']); + $total = $this->currency->format($unit_price * $product['quantity'], $this->session->data['currency']); + } else { + $price = false; + $total = false; + } + + $recurring = ''; + + if ($product['recurring']) { + $frequencies = array( + 'day' => $this->language->get('text_day'), + 'week' => $this->language->get('text_week'), + 'semi_month' => $this->language->get('text_semi_month'), + 'month' => $this->language->get('text_month'), + 'year' => $this->language->get('text_year') + ); + + if ($product['recurring']['trial']) { + $recurring = sprintf($this->language->get('text_trial_description'), $this->currency->format($this->tax->calculate($product['recurring']['trial_price'] * $product['quantity'], $product['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']), $product['recurring']['trial_cycle'], $frequencies[$product['recurring']['trial_frequency']], $product['recurring']['trial_duration']) . ' '; + } + + if ($product['recurring']['duration']) { + $recurring .= sprintf($this->language->get('text_payment_description'), $this->currency->format($this->tax->calculate($product['recurring']['price'] * $product['quantity'], $product['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']), $product['recurring']['cycle'], $frequencies[$product['recurring']['frequency']], $product['recurring']['duration']); + } else { + $recurring .= sprintf($this->language->get('text_payment_cancel'), $this->currency->format($this->tax->calculate($product['recurring']['price'] * $product['quantity'], $product['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']), $product['recurring']['cycle'], $frequencies[$product['recurring']['frequency']], $product['recurring']['duration']); + } + } + + $data['products'][] = array( + 'cart_id' => (int)$product['cart_id'], + 'thumb' => $image, + 'name' => $product['name'], + 'model' => $product['model'], + 'option' => $option_data, + 'recurring' => $recurring, + 'quantity' => (int)$product['quantity'], + 'stock' => $product['stock'] ? true : !(!$this->config->get('config_stock_checkout') || $this->config->get('config_stock_warning')), + 'reward' => ($product['reward'] ? sprintf($this->language->get('text_points'), $product['reward']) : ''), + 'price' => $price, + 'total' => $total, + 'href' => $this->url->link('product/product', 'product_id=' . $product['product_id']) + ); + } + + // Totals + $this->load->model('setting/extension'); + + $totals = array(); + $taxes = $this->cart->getTaxes(); + $total = 0; + + // Because __call can not keep var references so we put them into an array. + $total_data = array( + 'totals' => &$totals, + 'taxes' => &$taxes, + 'total' => &$total + ); + + // Display prices + if ($this->customer->isLogged() || !$this->config->get('config_customer_price')) { + $sort_order = array(); + + $results = $this->model_setting_extension->getExtensions('total'); + + foreach ($results as $key => $value) { + $sort_order[$key] = $this->config->get('total_' . $value['code'] . '_sort_order'); + } + + array_multisort($sort_order, SORT_ASC, $results); + + foreach ($results as $result) { + if ($this->config->get('total_' . $result['code'] . '_status')) { + $this->load->model('extension/total/' . $result['code']); + + // We have to put the totals in an array so that they pass by reference. + $this->{'model_extension_total_' . $result['code']}->getTotal($total_data); + } + } + + $sort_order = array(); + + foreach ($totals as $key => $value) { + $sort_order[$key] = $value['sort_order']; + } + + array_multisort($sort_order, SORT_ASC, $totals); + } + + $data['totals'] = array(); + + foreach ($totals as $total) { + $data['totals'][] = array( + 'title' => $total['title'], + 'text' => $this->currency->format($total['value'], $this->session->data['currency']) + ); + } + + $data['total_products_count'] = $this->cart->countProducts(); + } else { + $data['text_error'] = $this->language->get('text_empty'); + $data['totals'] = []; + $data['products'] = []; + $data['total_products_count'] = 0; + unset($this->session->data['success']); + } + + http_response_code(200); + header('Content-Type: application/json'); + header('Access-Control-Allow-Origin: *'); + header('Access-Control-Allow-Methods: GET, POST'); + header('Access-Control-Allow-Headers: Content-Type, Authorization'); + header('Access-Control-Allow-Credentials: true'); + echo json_encode($data); + die(); + } } diff --git a/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Telegram/RequestValidator.php b/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Telegram/RequestValidator.php new file mode 100755 index 0000000..c13fc96 --- /dev/null +++ b/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Telegram/RequestValidator.php @@ -0,0 +1,8 @@ +imageTool = $imageTool; } - public function index(Request $request): JsonResponse - { - return new JsonResponse([ - 'data' => [ - 'products' => $this->getProducts(), - 'count' => $this->cart->countProducts(), - 'total' => $this->cart->getTotal(), - ] - ]); - } - public function checkout(Request $request): JsonResponse { $items = $request->json(); diff --git a/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/CategoriesHandler.php b/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/CategoriesHandler.php index 6b6b5a8..cdb82fc 100755 --- a/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/CategoriesHandler.php +++ b/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/CategoriesHandler.php @@ -10,6 +10,8 @@ use Openguru\OpenCartFramework\QueryBuilder\JoinClause; class CategoriesHandler { + private const THUMB_SIZE = 150; + private Builder $queryBuilder; private ImageToolInterface $ocImageTool; @@ -22,14 +24,11 @@ class CategoriesHandler public function index(Request $request): JsonResponse { $languageId = 1; - $perPage = $request->get('perPage', 10); - $imageWidth = 150; - $imageHeight = 150; - - $categories = $this->queryBuilder->newQuery() + $categoriesFlat = $this->queryBuilder->newQuery() ->select([ 'categories.category_id' => 'id', + 'categories.parent_id' => 'parent_id', 'categories.image' => 'image', 'descriptions.name' => 'name', 'descriptions.description' => 'description', @@ -42,23 +41,48 @@ class CategoriesHandler ->where('descriptions.language_id', '=', $languageId); } ) - ->where('categories.parent_id', '=', 0) ->where('categories.status', '=', 1) + ->orderBy('parent_id') ->orderBy('sort_order') - ->limit($perPage) ->get(); - return new JsonResponse([ - 'data' => array_map(function ($category) use ($imageWidth, $imageHeight) { - $image = $this->ocImageTool->resize($category['image'], $imageWidth, $imageHeight, 'no_image.png'); + $categories = $this->buildCategoryTree($categoriesFlat); + return new JsonResponse([ + 'data' => array_map(static function ($category) { return [ 'id' => (int)$category['id'], - 'image' => $image, + 'image' => $category['image'], 'name' => $category['name'], 'description' => $category['description'], + 'children' => $category['children'], ]; }, $categories), ]); } + + public function buildCategoryTree(array $flat, $parentId = 0): array { + $branch = []; + + foreach ($flat as $category) { + if ((int)$category['parent_id'] === (int)$parentId) { + $children = $this->buildCategoryTree($flat, $category['id']); + if ($children) { + $category['children'] = $children; + } + + $image = $this->ocImageTool->resize($category['image'], self::THUMB_SIZE, self::THUMB_SIZE, 'no_image.png'); + + $branch[] = [ + 'id' => (int)$category['id'], + 'image' => $image, + 'name' => $category['name'], + 'description' => $category['description'], + 'children' => $category['children'] ?? [], + ]; + } + } + + return $branch; + } } diff --git a/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/ProductsHandler.php b/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/ProductsHandler.php index d32efe6..1a9995c 100755 --- a/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/ProductsHandler.php +++ b/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/ProductsHandler.php @@ -44,7 +44,7 @@ class ProductsHandler { $languageId = 1; $page = $request->get('page', 1); - $perPage = 10; + $perPage = 6; $categoryId = (int) $request->get('categoryId', 0); $categoryName = ''; @@ -178,6 +178,8 @@ class ProductsHandler 'product_description.name' => 'product_name', 'product_description.description' => 'product_description', 'products.price' => 'price', + 'products.minimum' => 'minimum', + 'products.quantity' => 'quantity', 'products.image' => 'product_image', 'products.tax_class_id' => 'tax_class_id', 'manufacturer.name' => 'product_manufacturer', @@ -247,6 +249,8 @@ class ProductsHandler 'description' => html_entity_decode($product['product_description']), 'manufacturer' => $product['product_manufacturer'], 'price' => $price, + 'minimum' => $product['minimum'], + 'quantity' => $product['quantity'], 'images' => $images, 'options' => $this->loadProductOptions($product), ]; diff --git a/module/oc_telegram_shop/upload/oc_telegram_shop/src/routes.php b/module/oc_telegram_shop/upload/oc_telegram_shop/src/routes.php index 2643956..66cec69 100755 --- a/module/oc_telegram_shop/upload/oc_telegram_shop/src/routes.php +++ b/module/oc_telegram_shop/upload/oc_telegram_shop/src/routes.php @@ -14,5 +14,4 @@ return [ 'categoriesList' => [CategoriesHandler::class, 'index'], 'checkout' => [CartHandler::class, 'checkout'], - 'cart' => [CartHandler::class, 'index'], ]; diff --git a/spa/src/components/CategoriesInline.vue b/spa/src/components/CategoriesInline.vue index 0daf41a..0b28d95 100644 --- a/spa/src/components/CategoriesInline.vue +++ b/spa/src/components/CategoriesInline.vue @@ -1,13 +1,13 @@ @@ -74,21 +103,25 @@ diff --git a/spa/src/views/Checkout.vue b/spa/src/views/Checkout.vue new file mode 100644 index 0000000..5e242d9 --- /dev/null +++ b/spa/src/views/Checkout.vue @@ -0,0 +1,13 @@ + + + diff --git a/spa/src/views/Product.vue b/spa/src/views/Product.vue index 3cc809f..137cdcf 100644 --- a/spa/src/views/Product.vue +++ b/spa/src/views/Product.vue @@ -15,6 +15,8 @@

{{ product.price }}

+

Кол-во на складе: {{ product.quantity }} шт.

+

Минимальное кол-ва для заказа: {{ product.minimum }}

@@ -67,13 +69,13 @@