diff --git a/README.md b/README.md index e97ec48..9587f61 100755 --- a/README.md +++ b/README.md @@ -195,7 +195,7 @@ You can copy a clean menu documents without comments from here: `/examples/arang "style": { // The `style` attribute "order": 0 }, - "class": {}, + "class": "", "icon": { // Icon from `/themes/default/css/icons` "style": { // The `style` attribute "rotate": "-135deg" @@ -228,6 +228,17 @@ You can copy a clean settings document without comments from here: `/examples/ar "offer": false, // Display the data of a public offer in the footer? (bool) (does not affect the `/offer` page generation) "sim": null, // Examples: "+7 000 000-00-00", "70000000000" (string|null) (if `null` it will not be displayed) "mail": null // Example: "name@domain.zone" (string|null) (if `null` it will not be displayed) + }, + "search": { + "enabled": true, // Enable the search input field? + "position": "fixed" // Values: "fixed", "relative" + }, + "cart": { + "enabled": true // Enable the cart button? + }, + "css": { + "catalog-button-cart-background": "#40a7e3", + "product-button-cart-background": "#40a7e3" } } ``` diff --git a/composer.json b/composer.json index 3eaedec..7b8e3d0 100755 --- a/composer.json +++ b/composer.json @@ -33,7 +33,8 @@ "avadim/fast-excel-reader": "^2.19", "ttatpuot/cdek-sdk2.0": "^1.2", "guzzlehttp/guzzle": "^7.9", - "php-http/guzzle7-adapter": "^1.0" + "php-http/guzzle7-adapter": "^1.0", + "react/async": "^4.3" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 91b7350..b8ddbb7 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d59bfe9a2623bc1b6bd95caaf90e9127", + "content-hash": "0c66c5ef998a3ccf4d0738e41bf2a3d3", "packages": [ { "name": "avadim/fast-excel-helper", @@ -2687,6 +2687,81 @@ }, "time": "2019-03-08T08:55:37+00:00" }, + { + "name": "react/async", + "version": "v4.3.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/async.git", + "reference": "635d50e30844a484495713e8cb8d9e079c0008a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/async/zipball/635d50e30844a484495713e8cb8d9e079c0008a5", + "reference": "635d50e30844a484495713e8cb8d9e079c0008a5", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "react/event-loop": "^1.2", + "react/promise": "^3.2 || ^2.8 || ^1.2.1" + }, + "require-dev": { + "phpstan/phpstan": "1.10.39", + "phpunit/phpunit": "^9.6" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "React\\Async\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async utilities and fibers for ReactPHP", + "keywords": [ + "async", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/async/issues", + "source": "https://github.com/reactphp/async/tree/v4.3.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-06-04T14:40:02+00:00" + }, { "name": "react/cache", "version": "v1.2.0", diff --git a/examples/arangodb/collections/menu/account.json b/examples/arangodb/collections/menu/account.json new file mode 100644 index 0000000..f6bf44a --- /dev/null +++ b/examples/arangodb/collections/menu/account.json @@ -0,0 +1,19 @@ +{ + "urn": "/account", + "name": { + "en": "Account", + "ru": "Аккаунт" + }, + "identifier": "account", + "style": { + "order": 1 + }, + "class": "", + "icon": { + "style": {}, + "class": "loading spinner animated" + }, + "image": { + "storage": null + } +} diff --git a/examples/arangodb/collections/menu/cart.json b/examples/arangodb/collections/menu/cart.json index 4e6a160..22a1d98 100644 --- a/examples/arangodb/collections/menu/cart.json +++ b/examples/arangodb/collections/menu/cart.json @@ -5,9 +5,9 @@ "ru": "Корзина" }, "style": { - "order": 1 + "order": 999 }, - "class": {}, + "class": "cart", "icon": { "style": {}, "class": "shopping cart" diff --git a/examples/arangodb/collections/menu/index.json b/examples/arangodb/collections/menu/index.json index 3173e77..82ee3d5 100644 --- a/examples/arangodb/collections/menu/index.json +++ b/examples/arangodb/collections/menu/index.json @@ -7,7 +7,7 @@ "style": { "order": 0 }, - "class": {}, + "class": "", "icon": { "style": {}, "class": "house" diff --git a/examples/arangodb/collections/settings.json b/examples/arangodb/collections/settings.json index 4d0eeb6..7fa48fc 100644 --- a/examples/arangodb/collections/settings.json +++ b/examples/arangodb/collections/settings.json @@ -1,16 +1,27 @@ { - "status": "active", - "project": { - "name": "PROJECT" - }, - "language": "en", - "currency": "usd", - "company": { - "identifier": null, - "tax": null, - "name": null, - "offer": false, - "sim": null, - "mail": null - } + "status": "active", + "project": { + "name": "PROJECT" + }, + "language": "en", + "currency": "usd", + "company": { + "identifier": null, + "tax": null, + "name": null, + "offer": false, + "sim": null, + "mail": null + }, + "search": { + "enabled": true, + "position": "fixed" + }, + "cart": { + "enabled": true + }, + "css": { + "catalog-button-cart-background": "#40a7e3", + "product-button-cart-background": "#40a7e3" + } } diff --git a/examples/nginx/server.conf b/examples/nginx/server.conf index 53b8d07..b2fffb0 100644 --- a/examples/nginx/server.conf +++ b/examples/nginx/server.conf @@ -14,7 +14,7 @@ server { ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; location / { - try_files $uri $uri/ /index.php; + try_files $uri $uri/ /index.php?$query_string; } location /api/cdek { diff --git a/mirzaev/huesos/system/controllers/api/acquirings/robokassa.php b/mirzaev/huesos/system/controllers/api/acquirings/robokassa.php new file mode 100755 index 0000000..9fd648b --- /dev/null +++ b/mirzaev/huesos/system/controllers/api/acquirings/robokassa.php @@ -0,0 +1,375 @@ + + */ +final class robokassa extends core +{ + /** + * Errors + * + * @var array $errors Registry of errors + */ + protected array $errors = [ + 'session' => [], + 'account' => [], + 'order' => [], + 'robokassa' => [] + ]; + + /** + * Result + * + * @param null + */ + public function result( + ?string $OutSum = null, + ?string $InvId = null, + ?string $SignatureValue = null, + ?string $PaymentMethod = null, + ?string $IncSum = null, + ?string $IncCurrLabel = null, + ?string $IsTest = null, + ?string $EMail = null, + ?string $Fee = null, + string ...$other + ): null { + // Searching for the order + $order = order::_read( + filter: 'd._key == @_key && d.paid != true', + sort: 'd.created DESC, d._key DESC', + amount: 1, + parameters: ['_key' => $InvId], + errors: $this->errors['robokassa'] + ); + + if ($order instanceof order) { + // Initialized the order + + if (model::result(identifier: (int) $InvId, cost: $OutSum, hash: $SignatureValue, test: (bool) $IsTest, errors: $this->errors['robokassa'])) { + // Verified the payment + + // Initializing the cart + $cart = $order->cart(); + + if ($cart instanceof cart) { + // Initialized the cart + + if ((float) ($cart->cost() + ($cart->buffer['delivery']['cost'] ?? 0)) === (float) $OutSum) { + // Full payment received + + // Writing that the order being been paid + $order->paid = true; + /* $order->term = null; */ + + if (document::update($order->__document(), errors: $this->errors['order'])) { + // Writed into ArangoDB + + // Initializing identifier of the order + $identifier = $order->__document()->getKey(); + + // Initializing the customer account + $customer = $order->account(); + + $config = new config(); + $config->setParseMode(config::PARSE_MODE_MARKDOWN); + $config->useReactFileSystem(true); + /* $config->setLoop(loop::get()); */ + + $robot = new zanzara(TELEGRAM_KEY, $config); + + // Sending the message + $robot->getTelegram()->sendMessage("✅ *Заказ \#$identifier оплачен*", ['chat_id' => $customer->identifier]) + ->then(function ($message) use ($robot, $cart, $order, $identifier, $customer) { + // Sended the message + + // Initializing the chats for sending registry + $chats = []; + + foreach ($this->settings->chats as $chat) { + // Iteration over chats + + if ($chat['orders']) { + // Authorized to receive orders + + // Writing into the chats for sending registry + $chats[] = $chat['id']; + } + } + + if (count($chats) > 0) { + // Initialized chats + + // Declaring the formatted list of products for message + $list = ''; + + // Declaring total cost of products + $cost = $cart->cost($list); + + // Escaping the formatted list of products for the message + $list = telegram::unmarkdown($list); + + // Initializing currency symbol + $symbol = ($account->currency ?? currency::rub)->symbol(); + + // Declaring delivery texts + $delivery_cost = $delivery_days = $delivery_address = ''; + + if (!empty($cart->buffer['delivery'])) { + // Initialized delibery data + + // Initializing delivery cost for message + $delivery_cost = telegram::unmarkdown((string) $cart->buffer['delivery']['cost']); + + // Initializing delivery days for message + $delivery_days = telegram::unmarkdown((string) $cart->buffer['delivery']['days']); + + // Initializing delivery address for message + $delivery_address = telegram::unmarkdown($cart->buffer['delivery']['location']['name'] . ', ' . $cart->buffer['delivery']['street']); + } + + // Initializing receiver domain for the message + $domain = telegram::unmarkdown($customer->domain); + + // Initializing receiver SIM for the message + $sim = telegram::unmarkdown((string) $customer->receiver['sim']); + + // Initializing receiver name for the message + $name = telegram::unmarkdown($customer->receiver['name']); + + // Initializing receiver address for the message + $address = telegram::unmarkdown($customer->receiver['address']); + + // Initializing the message cost part + $part_cost = "*Стоимость:* $cost$symbol"; + if (!empty($delivery_cost)) $part_cost .= " \+ $delivery_cost$symbol"; + if (!empty($delivery_days)) $part_cost .= " \($delivery_days дней\)"; + + // Initializing the message delivery part + $part_delivery = ''; + if (!empty($delivery_address)) $part_delivery .= "*Адрес доставки:* $delivery_address"; + if (!empty($part_delivery)) $part_delivery = "\n$part_delivery"; + + // Initializing the message receiver part + $part_receiver = "*Получатель:* @$domain"; + if (!empty($sim)) $part_receiver .= " $sim"; + if (!empty($name)) $part_receiver .= "\n*$name*"; + if (!empty($address)) $part_receiver .= "\n\n*Адрес:* $address"; + + // Initializing the message commentary part + $part_commentary = ''; + if (!empty($order->commentary)) $part_commentary .= "\n\n*Комментарий:* " . $order->commentary; + + // Sending messages + $robot->getTelegram()->sendBulkMessage( + $chats, + << [ + 'inline_keyboard' => [ + [ + ['text' => '✉️ Чат с покупателем', 'url' => 'https://t.me/' . $customer->domain] + ] + ], + 'disable_notification' => true + ] + ] + ); + } + }); + + // Sending response + $this->response + ->start() + ->clean() + ->sse() + ->write("OK$identifier") + ->validate($this->request) + ?->body() + ->end(); + } else throw new exception('Failed to update the order'); + } + } + } + } + + // Exit (success/fail) + return null; + } + + /** + * Success + * + * @return null + */ + public function success( + ?string $OutSum = null, + ?string $InvId = null, + ?string $SignatureValue = null, + ?string $IsTest = null, + ?string $Culture = null, + string ...$other + ): null { + // Searching for the order + $order = order::_read( + filter: 'd._key == @_key', + sort: 'd.created DESC, d._key DESC', + amount: 1, + parameters: ['_key' => $InvId], + errors: $this->errors['robokassa'] + ); + + if ($order instanceof order) { + // Initialized the order + + if (model::success(identifier: (int) $InvId, cost: $OutSum, hash: $SignatureValue, test: (bool) $IsTest, errors: $this->errors['robokassa'])) { + // Verified the payment + + if ($IsTest == 1) { + // Enabled the test mode + + // Initializing a paragraph abount the test mode + $this->view->test = $this->language === language::ru ? 'Тестовый режим' : 'Test mode'; + } + + // Render page + $page = $this->view->render('api/acquirings/robokassa/success.html', [ + 'h2' => $this->language === language::ru ? 'Заказ #' . $order->getKey() . ' оплачен' : 'Order #' . $order->getKey() . ' paid', + 'identifier' => $order->getKey(), + 'closing' => [ + 'title' => $this->language === language::ru ? 'Закрытие окна' : 'Window closing', + 'iterator' => 30 + ] + ]); + + // Sending response + $this->response + ->start() + ->clean() + ->sse() + ->write($page) + ->validate($this->request) + ?->body() + ->end(); + + // Deinitializing rendered page + unset($page); + } + } + + // Exit (success/fail) + return null; + } + + /** + * Fail + * + * @return null + */ + public function fail( + ?string $OutSum = null, + ?string $InvId = null, + ?string $IsTest = null, + ?string $Culture = null, + string ...$other + ): null { + // Searching for the order + $order = order::_read( + filter: 'd._key == @_key', + sort: 'd.created DESC, d._key DESC', + amount: 1, + parameters: ['_key' => $InvId], + errors: $this->errors['robokassa'] + ); + + if ($order instanceof order) { + // Initialized the order + + if ($IsTest == 1) { + // Enabled the test mode + + // Initializing a paragraph abount the test mode + $this->view->test = $this->language === language::ru ? 'Тестовый режим' : 'Test mode'; + } + + // Render page + $page = $this->view->render('api/acquirings/robokassa/fail.html', [ + 'h2' => $this->language === language::ru ? 'Заказ #' . $order->getKey() . ' не оплачен' : 'Order #' . $order->getKey() . ' not paid', + 'identifier' => $order->getKey(), + 'closing' => [ + 'title' => $this->language === language::ru ? 'Закрытие окна' : 'Window closing', + 'iterator' => 30 + ] + ]); + + // Sending response + $this->response + ->start() + ->clean() + ->sse() + ->write($page) + ->validate($this->request) + ?->body() + ->end(); + + // Deinitializing rendered page + unset($page); + } + + // Exit (success/fail) + return null; + } +} diff --git a/mirzaev/huesos/system/controllers/cart.php b/mirzaev/huesos/system/controllers/cart.php index 3c45ce8..a5263aa 100755 --- a/mirzaev/huesos/system/controllers/cart.php +++ b/mirzaev/huesos/system/controllers/cart.php @@ -9,12 +9,23 @@ use mirzaev\huesos\controllers\core, mirzaev\huesos\models\cart as model, mirzaev\huesos\models\product, mirzaev\huesos\models\menu, + mirzaev\huesos\models\telegram, + mirzaev\huesos\models\enumerations\currency, mirzaev\huesos\models\enumerations\language; // Framework for PHP use mirzaev\minimal\http\enumerations\content, mirzaev\minimal\http\enumerations\status; +// Framework for Telegram +use Zanzara\Zanzara as zanzara, + Zanzara\Context as context, + Zanzara\Config as config, + Zanzara\Telegram\Type\Message as message; + +// Event manager for PHP +use React\EventLoop\Loop as loop; + /** * Controller of cart * @@ -113,12 +124,26 @@ final class cart extends core $this->view->formatted = $formatted; } - // Initializing types of avaiabld deliveries - $this->view->deliveries = [ - 'cdek' => [ - 'label' => 'CDEK' - ] - ]; + if (array_search('address', $this->settings->input['deliveries']['site'], true) !== false) { + // The deliveries input is enabled for the site + + // Declaring the deliveries list + $deliveries = []; + + foreach ($this->settings->deliveries as $key => $value) { + // Iterating over deliveries + + if ($value['enabled']) { + // The delivery is enabled + + // Writing into the deliveries list + $deliveries[$key] = ['label' => $value['label']]; + } + } + + // Writing the deliveries list into the templater variables + $this->view->deliveries = $deliveries; + } if (str_contains($this->request->headers['accept'], content::json->value)) { // Request for JSON response @@ -444,85 +469,147 @@ final class cart extends core } /** - * Pay + * Attach * - * Pay for the cart + * Attach the cart * * @return null + * + * @todo кажется я сделал хуйню */ - public function pay(): null + public function attach(?string $share = null): null { if (str_contains($this->request->headers['accept'], content::json->value)) { // Request for JSON response - // Initializing the cart - $this->cart ??= $this->account?->cart() ?? $this->session?->cart(); + if ($this->account) { + // Initialized the account - if ($this->cart instanceof model) { - // Initialized the cart + $config = new config(); + $config->setParseMode(config::PARSE_MODE_MARKDOWN); + $config->useReactFileSystem(true); + /* $config->setLoop(loop::get()); */ - if ($share = $this->cart->share ?? $this->cart->share()) { - // The cart is available for sharing + $robot = new zanzara(TELEGRAM_KEY, $config); - // Sending response - $this->response - ->start() - ->clean() - ->sse() - ->json([ - 'share' => $share, - 'errors' => $this->errors - ]) - ->validate($this->request) - ?->body() - ->end(); - } + // Initializing cart + $cart = model::_read( + filter: 'd.share == @share', + sort: 'd.updated DESC, d.created DESC, d._key DESC', + amount: 1, + page: 1, + parameters: ['share' => $share] + ); // Deinitializing unnecessary variables - unset($hash); + unset($share); + + if ($cart instanceof model) { + // Initialized the cart + + // Unsharing the cart + $cart->unshare(); + + // Connecting the cart to the account + $edge = $this->account->connect($cart); + + if (!empty($edge)) { + // Connected the cart to the account + + // Initializing products in the cart + $products = $cart->products(language: $this->account->language ?? language::ru, currency: $this->account->currency ?? currency::rub); + + if (!empty($products)) { + // Initialized products in the cart + + // Declaring the formatted list of products for message + $list = ''; + + // Declaring total cost of products + $cost = $cart->cost($list); + + // Escaping the formatted list of products for the message + $list = telegram::unmarkdown($list); + + // Deinitializing unnecessary variables + unset($products, $product, $row); + + // Initializing identifier of the cart + $identifier = $cart->getKey(); + + // Initializing currency symbol + $symbol = ($this->account->currency ?? currency::rub)->symbol(); + + // Declaring delivery texts + $delivery_cost = $delivery_days = $delivery_address = ''; + + if (!empty($cart->buffer['delivery'])) { + // Initialized delibery data + + // Initializing delivery cost for message + $delivery_cost = telegram::unmarkdown((string) $cart->buffer['delivery']['cost']); + + // Initializing delivery days for message + $delivery_days = telegram::unmarkdown((string) $cart->buffer['delivery']['days']); + + // Initializing delivery address for message + $delivery_address = telegram::unmarkdown($cart->buffer['delivery']['location']['name'] . ', ' . $cart->buffer['delivery']['street']); + } + + // Initializing the message cost part + $part_cost = "*Стоимость:* $cost$symbol"; + if (!empty($delivery_cost)) $part_cost .= " \+ $delivery_cost$symbol"; + if (!empty($delivery_days)) $part_cost .= " \($delivery_days дней\)"; + + // Initializing the message delivery part + $part_delivery = ''; + if (!empty($delivery_address)) $part_cost .= "*Адрес доставки:* $delivery_address"; + if (!empty($part_delivery)) $part_delivery = "\n$part_delivery"; + + $robot->getTelegram()->sendMessage( + << $this->account->identifier, + 'reply_markup' => [ + 'inline_keyboard' => [ + [ + ['text' => '🚚 Оформить доставку', 'callback_data' => 'cart_delivery'], + ], + ], + 'disable_notification' => true + ] + ] + ); + } + } + + // Deinitializing unnecessary variables + unset($cart, $list); + } } - } - // Exit (success/fail) - return null; - } + // Deinitializing unnecessary variables + unset($cart); - /** - * Robokassa - * - * HTML-document with robokassa iframe - * - * @param null - * - * @todo THIS MUST BE A PAYMENT OF ORDER IN THE FUTURE, NOT CART - */ - public function robokassa(): null - { - // Initializing the cart - $this->cart ??= $this->account?->cart() ?? $this->session?->cart(); - - // Initializing the cart data - $this->view->cart = $this->cart; - $this->view->summary = $this->cart?->summary(currency: $this->currency); - - if (str_contains($this->request->headers['accept'], content::any->value)) { - // Request for any response - - // Render page - $page = $this->view->render('iframes/robokassa.html'); + $robot->getLoop()->run(); // Sending response $this->response ->start() ->clean() ->sse() - ->write($page) + ->json([ + 'success' => true, + 'errors' => $this->errors + ]) ->validate($this->request) ?->body() ->end(); - - // Deinitializing rendered page - unset($page); } // Exit (success/fail) diff --git a/mirzaev/huesos/system/controllers/catalog.php b/mirzaev/huesos/system/controllers/catalog.php index 3d88018..3091975 100755 --- a/mirzaev/huesos/system/controllers/catalog.php +++ b/mirzaev/huesos/system/controllers/catalog.php @@ -52,7 +52,8 @@ final class catalog extends core 'session' => [], 'account' => [], 'menu' => [], - 'catalog' => [] + 'catalog' => [], + 'cart' => [] ]; /** @@ -80,9 +81,13 @@ final class catalog extends core // Initializing the cart $this->cart ??= $this->account?->cart() ?? $this->session?->cart(); + // Initializing summary data of the cart + $summary = $this->cart?->summary(currency: $this->currency, errors: $this->errors['cart']); + // Initializing the cart data $this->view->cart = [ - 'products' => $this->cart?->products(language: $this->language, currency: $this->currency) + 'products' => $this->cart?->products(language: $this->language, currency: $this->currency), + 'summary' => $summary ]; // Validating received product identifier @@ -113,6 +118,7 @@ final class catalog extends core 'cart' => [ 'amount' => $this->view->cart['products'][$this->view->product->getId()]['amount'] ?? 0, 'text' => [ + 'cart' => $this->language === language::ru ? 'Корзина' : 'Cart', 'add' => $this->language === language::ru ? 'Добавить в корзину' : 'Add to the cart', 'added' => $this->language === language::ru ? 'Добавлено в корзину' : 'Added to the cart' ] @@ -231,7 +237,7 @@ final class catalog extends core // search for root ascendants categories $this->view->categories = entry::ascendants( descendant: new category, - return: 'DISTINCT MERGE(ascendant, { name: ascendant.name.@language})', + return: 'DISTINCT MERGE(d, { name: d.name.@language})', parameters: ['language' => $this->language->name], errors: $this->errors['catalog'] ) ?? null; @@ -298,7 +304,7 @@ final class catalog extends core if ($this->view->menu instanceof _document) $this->view->menu = [$this->view->menu]; } - if (str_contains($this->request->headers['accept'], content::json->value)) { + if (str_contains($this->request->headers['accept'] ?? [], content::json->value)) { // Request for JSON response // Initializing the response body buffer diff --git a/mirzaev/huesos/system/controllers/delivery.php b/mirzaev/huesos/system/controllers/delivery.php index 150f0f5..d932d38 100755 --- a/mirzaev/huesos/system/controllers/delivery.php +++ b/mirzaev/huesos/system/controllers/delivery.php @@ -87,294 +87,331 @@ final class delivery extends core 'ready' => false ]; - if (isset($company)) { - // Received company name + if (array_search('address', $this->settings->input['deliveries']['site'], true) !== false) { + // The deliveries address input is enabled for the site - if (mb_strlen($company) < 65) { - // Validated company name + if (isset($company)) { + // Received company name - // Declating variable for normalized value of company namme - $normalized = ''; + if (mb_strlen($company) < 65) { + // Validated company name - // Normalizing company name - if (preg_match('/[\w]+/u', urldecode($company), $matches)) $normalized = $matches[0] ?? ''; + // Declating variable for normalized value of company namme + $normalized = ''; - // Deinitializing unnecessary variables - unset($matches); - - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: ['delivery_company' => $normalized])); - - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: ['delivery_company' => $normalized])); - - // Writing to the buffer of the response - /* $response['company'] = $normalized; */ - - // Initializing the cart - $this->cart ??= $this->account?->cart() ?? $this->session?->cart(); - - if ($this->cart instanceof cart) { - // Initialized the cart - - // Initializing products in the cart - $products = $this->cart->products(language: $this->language, currency: $this->currency); - - // Declaring buffer of formatted products - $formatted = []; - - if (!empty($products)) { - // Initialized products - - foreach ($products as $product) { - // Iterating over products - - // Formatting products - for ($i = 0; $i < $product['amount']; ++$i) { - $formatted[] = [ - 'weight' => $product['document']['weight'] ?? 0, - ...$product['document']['dimensions'] - ]; - } - } - } + // Normalizing company name + if (preg_match('/[\w]+/u', urldecode($company), $matches)) $normalized = $matches[0] ?? ''; // Deinitializing unnecessary variables - unset($product); + unset($matches); - // Writing delivery section to the buffer of the response (@todo add check for exists) - $response['delivery'] = [ - 'html' => $this->view->render('cart/elements/deliveries/' . $normalized . '/section.html'), - 'javascript' => match ($normalized) { - 'cdek' => [ - [ - 'code' => $this->view->render('cart/elements/deliveries/' . $normalized . '/javascript.html', [ - 'formatted' => $formatted - ]) - ] - ], - default => null - } - ]; - } + if ($this->settings->deliveries[$normalized]['enabled']) { + // The delivery found and enabled - // Initialization buffer of delivery parameters - $delivery = $this->account?->buffer['delivery'] ?? $this->session?->buffer['delivery'] ?? []; + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: ['delivery_company' => $normalized])); - // Writing readiness status to the buffer of the response - $response['ready'] = $this->model::ready(company::{$normalized}, $delivery[$normalized] ?? []); + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: ['delivery_company' => $normalized])); - if ($response['ready']) { - // Initialized required parameters + // Writing to the buffer of the response + /* $response['company'] = $normalized; */ - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $normalized . '_ready' => true])); + // Initializing the cart + $this->cart ??= $this->account?->cart() ?? $this->session?->cart(); - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => true])); + if ($this->cart instanceof cart) { + // Initialized the cart - // Deinitializing unnecessary variables - unset($name); - } else { - // Not initialized required parameters + // Initializing products in the cart + $products = $this->cart->products(language: $this->language, currency: $this->currency); - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [ - $name_ready = 'delivery_' . $normalized . '_ready' => false, - $name_cost = 'delivery_' . $normalized . '_cost' => null, - $name_days = 'delivery_' . $normalized . '_days' => null - ])); + // Declaring buffer of formatted products + $formatted = []; - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [ - $name_ready => false, - $name_cost => null, - $name_days => null - ])); + if (!empty($products)) { + // Initialized products - // Deinitializing unnecessary variables - unset($name_ready, $name_cost, $name_days); - } + foreach ($products as $product) { + // Iterating over products - // Deinitializing unnecessary variables - unset($delivery, $normalized); - - // Writing status of execution to the buffer of the response - $response['status'] = 'success'; - } - } else if (isset($location)) { - // Received location name - - if (mb_strlen($location) < 257) { - // Validated location name - - // Declating variable for result value of location name - $result = ''; - - // Declating variable for separated values of location name - $separated = ''; - - // Separating location name - if (preg_match_all('/[^\W][\w\s\-]+/u', trim(urldecode($location)), $matches)) $separated = $matches[0]; - - // Deinitializing unnecessary variables - unset($matches); - - // Initialization buffer of delivery parameters - $delivery = $this->account?->buffer['delivery'] ?? $this->session?->buffer['delivery'] ?? []; - - if (!empty($delivery['company'])) { - // Initialized delivery company - - if (!empty($separated)) { - // Serapated location name - - // Declaring variable for normalized separated values of location name - $normalized = []; - - // Normalizing location name - foreach ($separated as $value) $normalized[] = mb_ucfirst($value); - /* foreach ($separated as $value) $normalized[] = $value; */ - - // Deinitializing unnecessary variables - unset($separated, $value); - - // Reinitializing result value of location name - $result = $normalized[0]; - - // Declaring of universalized locations buffer - $locations = null; - - if ($delivery['company'] === 'cdek') { - // CDEK - - // Searching for locations by name (first part with spaces before first comma or any non word symbol) - $cdek = cdek::location($normalized[0], $this->errors['delivery'])?->items; - - foreach ($cdek ?? [] as $location) { - // Iterating over found locations - - // Initializing structure - $structure = [$location->country]; - - // Initializing additional instances in the structure - if (!empty($location->region) && $location->region !== $location->city) - $structure[] = $location->region; - if (!empty($location->sub_region) && $location->sub_region !== $location->region && $location->sub_region !== $location->city) - $structure[] = $location->sub_region; - - // Universalizing and writing to locations buffer - $locations[] = [ - 'identifier' => $location->code, - 'name' => $location->city, - 'structure' => $structure, - 'longitude' => $location->longitude, - 'latitude' => $location->latitude, - 'data' => $location - ]; - } - - // Deinitializing of response data from CDEK - unset($cdek); - } - - if (!empty($locations)) { - // Found locations - - // Declaring buffer of validated locations by input values - $buffer = []; - - // Initialization of 80% of received input values (required minimum to match location characteristics) - $minimum = count($normalized) * 80 / 100; - - foreach ($locations as $_location) { - // Iterating over locations - - // Declaring variable with score of matching input values with location characteristics - $score = 0; - - foreach ([$_location['name'], ...$_location['structure']] as $value) { - // Iterating over location characteristics - - foreach ($normalized as $_value) { - // Iterating over normalized parts of location name - - // Match normalized parts of location name with location characteristics using the Levenshtein algorithm - $match = levenshtein($value, $_value); - - if ($match < 3) { - // The values are approximately the same - - if (++$score > $minimum) { - // More than $minimum matches found - - // Writing to buffer of validated locations by normalized parts of location name - $buffer[] = $_location; - - // Exit from iteration of location characteristics - break 2; - } - } + // Formatting products + for ($i = 0; $i < $product['amount']; ++$i) { + $formatted[] = [ + 'weight' => $product['document']['weight'] ?? 0, + ...$product['document']['dimensions'] + ]; } - - // Deinitializing unnecessary variables - unset($_value); } - - // Deinitializing unnecessary variables - unset($value); } // Deinitializing unnecessary variables - unset($_location); + unset($product); - // Reinitializating locations from buffer of validated locations by input values - $locations = $buffer; + // Writing delivery section to the buffer of the response (@todo add check for exists) + $response['delivery'] = [ + 'html' => $this->view->render('cart/elements/deliveries/' . $normalized . '/section.html'), + 'javascript' => match ($normalized) { + 'cdek' => [ + [ + 'code' => $this->view->render('cart/elements/deliveries/' . $normalized . '/javascript.html', [ + 'formatted' => $formatted + ]) + ] + ], + default => null + } + ]; + } - /* if (count($locations) === 1) */ - if (count($locations) > 0) { - // Identificated location + // Initialization buffer of delivery parameters + $delivery = $this->account?->buffer['delivery'] ?? $this->session?->buffer['delivery'] ?? []; - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_location' => $locations[0]])); + // Writing readiness status to the buffer of the response + $response['ready'] = $this->model::ready(company::{$normalized}, $delivery[$normalized] ?? []); - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => $locations[0]])); + if ($response['ready']) { + // Initialized required parameters + + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $normalized . '_ready' => true])); + + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => true])); + + // Deinitializing unnecessary variables + unset($name); + } else { + // Not initialized required parameters + + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [ + $name_ready = 'delivery_' . $normalized . '_ready' => false, + $name_cost = 'delivery_' . $normalized . '_cost' => null, + $name_days = 'delivery_' . $normalized . '_days' => null + ])); + + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [ + $name_ready => false, + $name_cost => null, + $name_days => null + ])); + + // Deinitializing unnecessary variables + unset($name_ready, $name_cost, $name_days); + } + + // Deinitializing unnecessary variables + unset($delivery, $normalized); + + // Writing status of execution to the buffer of the response + $response['status'] = 'success'; + } + } + } else if (isset($location)) { + // Received location name + + if (mb_strlen($location) < 257) { + // Validated location name + + // Declating variable for result value of location name + $result = ''; + + // Declating variable for separated values of location name + $separated = ''; + + // Separating location name + if (preg_match_all('/[^\W][\w\s\-]+/u', trim(urldecode($location)), $matches)) $separated = $matches[0]; + + // Deinitializing unnecessary variables + unset($matches); + + // Initialization buffer of delivery parameters + $delivery = $this->account?->buffer['delivery'] ?? $this->session?->buffer['delivery'] ?? []; + + if (!empty($delivery['company'])) { + // Initialized delivery company + + if (!empty($separated)) { + // Serapated location name + + // Declaring variable for normalized separated values of location name + $normalized = []; + + // Normalizing location name + foreach ($separated as $value) $normalized[] = mb_ucfirst($value); + /* foreach ($separated as $value) $normalized[] = $value; */ + + // Deinitializing unnecessary variables + unset($separated, $value); + + // Reinitializing result value of location name + $result = $normalized[0]; + + // Declaring of universalized locations buffer + $locations = null; + + if ($delivery['company'] === 'cdek') { + // CDEK + + // Searching for locations by name (first part with spaces before first comma or any non word symbol) + $cdek = cdek::location($normalized[0], $this->errors['delivery'])?->items; + + foreach ($cdek ?? [] as $location) { + // Iterating over found locations + + // Initializing structure + $structure = [$location->country]; + + // Initializing additional instances in the structure + if (!empty($location->region) && $location->region !== $location->city) + $structure[] = $location->region; + if (!empty($location->sub_region) && $location->sub_region !== $location->region && $location->sub_region !== $location->city) + $structure[] = $location->sub_region; + + // Universalizing and writing to locations buffer + $locations[] = [ + 'identifier' => $location->code, + 'name' => $location->city, + 'structure' => $structure, + 'longitude' => $location->longitude, + 'latitude' => $location->latitude, + 'data' => $location + ]; + } + + // Deinitializing of response data from CDEK + unset($cdek); + } + + if (!empty($locations)) { + // Found locations + + // Declaring buffer of validated locations by input values + $buffer = []; + + // Initialization of 80% of received input values (required minimum to match location characteristics) + $minimum = count($normalized) * 80 / 100; + + foreach ($locations as $_location) { + // Iterating over locations + + // Declaring variable with score of matching input values with location characteristics + $score = 0; + + foreach ([$_location['name'], ...$_location['structure']] as $value) { + // Iterating over location characteristics + + foreach ($normalized as $_value) { + // Iterating over normalized parts of location name + + // Match normalized parts of location name with location characteristics using the Levenshtein algorithm + $match = levenshtein($value, $_value); + + if ($match < 3) { + // The values are approximately the same + + if (++$score > $minimum) { + // More than $minimum matches found + + // Writing to buffer of validated locations by normalized parts of location name + $buffer[] = $_location; + + // Exit from iteration of location characteristics + break 2; + } + } + } + + // Deinitializing unnecessary variables + unset($_value); + } + + // Deinitializing unnecessary variables + unset($value); + } // Deinitializing unnecessary variables - unset($name); + unset($_location); - // Writing result value of location name - $result = $locations[0]['name'] . ', ' . implode(', ', array_reverse($locations[0]['structure'])); + // Reinitializating locations from buffer of validated locations by input values + $locations = $buffer; - // Writing to the actual buffer copy - $delivery[$delivery['company']]['location'] = $result; + /* if (count($locations) === 1) */ + if (count($locations) > 0) { + // Identificated location - // Writing location data to the buffer of the response - /* $response['location'] = [ + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_location' => $locations[0]])); + + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => $locations[0]])); + + // Deinitializing unnecessary variables + unset($name); + + // Writing result value of location name + $result = $locations[0]['name'] . ', ' . implode(', ', array_reverse($locations[0]['structure'])); + + // Writing to the actual buffer copy + $delivery[$delivery['company']]['location'] = $result; + + // Writing location data to the buffer of the response + /* $response['location'] = [ 'identifier' => $locations[0]['identifier'], 'input' => $result ]; */ - // Writing readiness status to the buffer of the response - $response['ready'] = $this->model::ready(company::{$delivery['company']}, $delivery[$delivery['company']] ?? []); + // Writing readiness status to the buffer of the response + $response['ready'] = $this->model::ready(company::{$delivery['company']}, $delivery[$delivery['company']] ?? []); - if ($response['ready']) { - // Initialized required parameters + if ($response['ready']) { + // Initialized required parameters - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_ready' => true])); + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_ready' => true])); - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => true])); + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => true])); + + // Deinitializing unnecessary variables + unset($name); + } else { + // Not initialized required parameters + + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [ + $name_ready = 'delivery_' . $delivery['company'] . '_ready' => false, + $name_cost = 'delivery_' . $delivery['company'] . '_cost' => null, + $name_days = 'delivery_' . $delivery['company'] . '_days' => null + ])); + + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [ + $name_ready => false, + $name_cost => null, + $name_days => null + ])); + + // Deinitializing unnecessary variables + unset($name_ready, $name_cost, $name_days); + } // Deinitializing unnecessary variables - unset($name); + unset($delivery); + + // Writing locations into response buffer + $response['locations'] = []; + + // Writing status of execution to the buffer of the response + $response['status'] = 'success'; } else { - // Not initialized required parameters + // Not identificated location // Writing to the session buffer $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [ + $name_location = 'delivery_' . $delivery['company'] . '_location' => $result, $name_ready = 'delivery_' . $delivery['company'] . '_ready' => false, $name_cost = 'delivery_' . $delivery['company'] . '_cost' => null, $name_days = 'delivery_' . $delivery['company'] . '_days' => null @@ -382,29 +419,46 @@ final class delivery extends core // Writing to the account buffer $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [ + $name_location => $result, $name_ready => false, $name_cost => null, $name_days => null ])); // Deinitializing unnecessary variables - unset($name_ready, $name_cost, $name_days); + unset($name_location, $name_ready, $name_cost, $name_days); + + // Writing status of execution to the buffer of the response (???) + $response['status'] = 'success'; + + // Declaring buffer of data to send + $buffer = []; + + foreach ($locations as $_location) { + // Iterating over locations + + // Writing to buffer of data to send + $buffer[] = [ + 'name' => $_location['name'], + 'structure' => $_location['structure'] + ]; + } + + // Deinitializing unnecessary variables + unset($_location); + + // Writing locations into response buffer + $response['locations'] = $buffer; + + // Deinitializing buffer of data to send + unset($buffer); } - - // Deinitializing unnecessary variables - unset($delivery); - - // Writing locations into response buffer - $response['locations'] = []; - - // Writing status of execution to the buffer of the response - $response['status'] = 'success'; } else { - // Not identificated location + // Not found locations // Writing to the session buffer $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [ - $name_location = 'delivery_' . $delivery['company'] . '_location' => $result, + $name_location = 'delivery_' . $delivery['company'] . '_location' => null, $name_ready = 'delivery_' . $delivery['company'] . '_ready' => false, $name_cost = 'delivery_' . $delivery['company'] . '_cost' => null, $name_days = 'delivery_' . $delivery['company'] . '_days' => null @@ -412,7 +466,7 @@ final class delivery extends core // Writing to the account buffer $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [ - $name_location => $result, + $name_location => null, $name_ready => false, $name_cost => null, $name_days => null @@ -420,34 +474,14 @@ final class delivery extends core // Deinitializing unnecessary variables unset($name_location, $name_ready, $name_cost, $name_days); - - // Writing status of execution to the buffer of the response (???) - $response['status'] = 'success'; - - // Declaring buffer of data to send - $buffer = []; - - foreach ($locations as $_location) { - // Iterating over locations - - // Writing to buffer of data to send - $buffer[] = [ - 'name' => $_location['name'], - 'structure' => $_location['structure'] - ]; - } - - // Deinitializing unnecessary variables - unset($_location); - - // Writing locations into response buffer - $response['locations'] = $buffer; - - // Deinitializing buffer of data to send - unset($buffer); } + + // Deinitializing unnecessary variables + unset($normalized); } else { - // Not found locations + // Value is empty after separating + + // Not initialized required parameters // Writing to the session buffer $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [ @@ -468,563 +502,542 @@ final class delivery extends core // Deinitializing unnecessary variables unset($name_location, $name_ready, $name_cost, $name_days); } + } + + // Deinitializing unnecessary variables + unset($delivery, $normalized); + + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: ['delivery_location' => $result])); + + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: ['delivery_location' => $result])); + + // Deinitializing unnecessary variables + unset($location, $result, $normalized); + } + } else if (isset($street)) { + // Received sreet + + if (mb_strlen($street) < 129) { + // Validated street + + // Declating variable for normalized value of the parameter + $normalized = ''; + + // Normalizing street + if (preg_match('/[\w\d\s\.\,\-]+/u', urldecode($street), $matches)) $normalized = mb_ucfirst($matches[0] ?? ''); + + // Deinitializing unnecessary variables + unset($matches); + + // Initialization buffer of delivery parameters + $delivery = $this->account?->buffer['delivery'] ?? $this->session?->buffer['delivery'] ?? []; + + if (isset($delivery['company'])) { + // Initialized delivery company + + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_street' => $normalized])); + + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => $normalized])); + + // Deinitializing unnecessary variables + unset($name); + + // Writing to the actual buffer copy + $delivery[$delivery['company']]['street'] = $normalized; + + // Writing readiness status to the buffer of the response + $response['ready'] = $this->model::ready(company::{$delivery['company']}, $delivery[$delivery['company']] ?? []); + + if ($response['ready']) { + // Initialized required parameters + + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_ready' => true])); + + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => true])); + + // Deinitializing unnecessary variables + unset($name); + } else { + // Not initialized required parameters + + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [ + $name_ready = 'delivery_' . $delivery['company'] . '_ready' => false, + $name_cost = 'delivery_' . $delivery['company'] . '_cost' => null, + $name_days = 'delivery_' . $delivery['company'] . '_days' => null + ])); + + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [ + $name_ready => false, + $name_cost => null, + $name_days => null + ])); + + // Deinitializing unnecessary variables + unset($name_ready, $name_cost, $name_days); + } + + // Deinitializing unnecessary variables + unset($delivery); + + // Writing status of execution to the buffer of the response + $response['status'] = 'success'; + } + + // Deinitializing unnecessary variables + unset($delivery); + + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: ['delivery_street' => $normalized])); + + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: ['delivery_street' => $normalized])); + + // Writing street to the buffer of the response + /* $response['street'] = $normalized; */ + + // Deinitializing unnecessary variables + unset($normalized); + } + } else if (isset($type)) { + // Received delivery type + + if (mb_strlen($type) < 30) { + // Validated delivery type + + // Declating variable for result value of delivery type + $result = ''; + + // Declating variable for normalized value of delivery type + $normalized = ''; + + // Normalizing delivery type + if (preg_match('/[\w]+/', trim(urldecode($type)), $matches)) $normalized = $matches[0]; + + // Deinitializing unnecessary variables + unset($matches); + + // Initialization buffer of delivery parameters + $delivery = $this->account?->buffer['delivery'] ?? $this->session?->buffer['delivery'] ?? []; + + if (isset($delivery['company'])) { + // Initialized delivery company + + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_type' => $normalized])); + + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => $normalized])); + + // Deinitializing unnecessary variables + unset($name); + + // Writing to the actual buffer copy + $delivery[$delivery['company']]['type'] = $normalized; + + // Writing result value of delivery type + $result = $normalized; // Deinitializing unnecessary variables unset($normalized); - } else { - // Value is empty after separating - // Not initialized required parameters + // Writing readiness status to the buffer of the response + $response['ready'] = $this->model::ready(company::{$delivery['company']}, $delivery[$delivery['company']] ?? []); - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [ - $name_location = 'delivery_' . $delivery['company'] . '_location' => null, - $name_ready = 'delivery_' . $delivery['company'] . '_ready' => false, - $name_cost = 'delivery_' . $delivery['company'] . '_cost' => null, - $name_days = 'delivery_' . $delivery['company'] . '_days' => null - ])); + if ($response['ready']) { + // Initialized required parameters - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [ - $name_location => null, - $name_ready => false, - $name_cost => null, - $name_days => null - ])); + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_ready' => true])); + + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => true])); + + // Deinitializing unnecessary variables + unset($name); + } else { + // Not initialized required parameters + + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [ + $name_ready = 'delivery_' . $delivery['company'] . '_ready' => false, + $name_cost = 'delivery_' . $delivery['company'] . '_cost' => null, + $name_days = 'delivery_' . $delivery['company'] . '_days' => null + ])); + + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [ + $name_ready => false, + $name_cost => null, + $name_days => null + ])); + + // Deinitializing unnecessary variables + unset($name_ready, $name_cost, $name_days); + } // Deinitializing unnecessary variables - unset($name_location, $name_ready, $name_cost, $name_days); + unset($delivery); + + // Writing status of execution to the buffer of the response + $response['status'] = 'success'; } - } - - // Deinitializing unnecessary variables - unset($delivery, $normalized); - - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: ['delivery_location' => $result])); - - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: ['delivery_location' => $result])); - - // Deinitializing unnecessary variables - unset($location, $result, $normalized); - } - } else if (isset($street)) { - // Received sreet - - if (mb_strlen($street) < 129) { - // Validated street - - // Declating variable for normalized value of the parameter - $normalized = ''; - - // Normalizing street - if (preg_match('/[\w\d\s\.\,\-]+/u', urldecode($street), $matches)) $normalized = mb_ucfirst($matches[0] ?? ''); - - // Deinitializing unnecessary variables - unset($matches); - - // Initialization buffer of delivery parameters - $delivery = $this->account?->buffer['delivery'] ?? $this->session?->buffer['delivery'] ?? []; - - if (isset($delivery['company'])) { - // Initialized delivery company - - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_street' => $normalized])); - - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => $normalized])); // Deinitializing unnecessary variables - unset($name); + unset($delivery, $result, $normalized); + } + } else if (isset($tariff)) { + // Received delivery tariff - // Writing to the actual buffer copy - $delivery[$delivery['company']]['street'] = $normalized; + if ((is_string($tariff) && mb_strlen($tariff) < 30) || (is_int($tariff && $tariff < 10000))) { + // Validated delivery tariff - // Writing readiness status to the buffer of the response - $response['ready'] = $this->model::ready(company::{$delivery['company']}, $delivery[$delivery['company']] ?? []); + // Declating variable for result value of delivery tariff + $result = ''; - if ($response['ready']) { - // Initialized required parameters + // Declating variable for normalized value of delivery tariff + $normalized = ''; + + // Normalizing delivery tariff + if (preg_match('/[\w\d]+/', trim(urldecode($tariff)), $matches)) $normalized = $matches[0]; + + // Deinitializing unnecessary variables + unset($matches); + + // Initialization buffer of delivery parameters + $delivery = $this->account?->buffer['delivery'] ?? $this->session?->buffer['delivery'] ?? []; + + if (isset($delivery['company'])) { + // Initialized delivery company // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_ready' => true])); + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_tariff' => $normalized])); // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => true])); + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => $normalized])); // Deinitializing unnecessary variables unset($name); - } else { - // Not initialized required parameters - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [ - $name_ready = 'delivery_' . $delivery['company'] . '_ready' => false, - $name_cost = 'delivery_' . $delivery['company'] . '_cost' => null, - $name_days = 'delivery_' . $delivery['company'] . '_days' => null - ])); + // Writing to the actual buffer copy + $delivery[$delivery['company']]['tariff'] = $normalized; - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [ - $name_ready => false, - $name_cost => null, - $name_days => null - ])); + // Writing result value of delivery tariff + $result = $normalized; // Deinitializing unnecessary variables - unset($name_ready, $name_cost, $name_days); + unset($normalized); + + // Writing readiness status to the buffer of the response + $response['ready'] = $this->model::ready(company::{$delivery['company']}, $delivery[$delivery['company']] ?? []); + + if ($response['ready']) { + // Initialized required parameters + + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_ready' => true])); + + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => true])); + + // Deinitializing unnecessary variables + unset($name); + } else { + // Not initialized required parameters + + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [ + $name_ready = 'delivery_' . $delivery['company'] . '_ready' => false, + $name_cost = 'delivery_' . $delivery['company'] . '_cost' => null, + $name_days = 'delivery_' . $delivery['company'] . '_days' => null + ])); + + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [ + $name_ready => false, + $name_cost => null, + $name_days => null + ])); + + // Deinitializing unnecessary variables + unset($name_ready, $name_cost, $name_days); + } + + // Deinitializing unnecessary variables + unset($delivery); + + // Writing status of execution to the buffer of the response + $response['status'] = 'success'; } // Deinitializing unnecessary variables - unset($delivery); - - // Writing status of execution to the buffer of the response - $response['status'] = 'success'; + unset($delivery, $result, $normalized); } + } else if (isset($longitude)) { + // Received delivery receiver longitude - // Deinitializing unnecessary variables - unset($delivery); - - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: ['delivery_street' => $normalized])); - - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: ['delivery_street' => $normalized])); - - // Writing street to the buffer of the response - /* $response['street'] = $normalized; */ - - // Deinitializing unnecessary variables - unset($normalized); - } - } else if (isset($type)) { - // Received delivery type - - if (mb_strlen($type) < 30) { - // Validated delivery type - - // Declating variable for result value of delivery type + // Declating variable for result value of delivery receiver longitude $result = ''; - // Declating variable for normalized value of delivery type + // Declating variable for normalized value of delivery receiver longitude $normalized = ''; - // Normalizing delivery type - if (preg_match('/[\w]+/', trim(urldecode($type)), $matches)) $normalized = $matches[0]; + // Normalizing receiver longitude + $normalized = filter_var($longitude, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); - // Deinitializing unnecessary variables - unset($matches); + if ($normalized >= -180 && $normalized <= 180) { + // Validated delivery receiver longitude - // Initialization buffer of delivery parameters - $delivery = $this->account?->buffer['delivery'] ?? $this->session?->buffer['delivery'] ?? []; + // Initialization buffer of delivery parameters + $delivery = $this->account?->buffer['delivery'] ?? $this->session?->buffer['delivery'] ?? []; - if (isset($delivery['company'])) { - // Initialized delivery company - - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_type' => $normalized])); - - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => $normalized])); - - // Deinitializing unnecessary variables - unset($name); - - // Writing to the actual buffer copy - $delivery[$delivery['company']]['type'] = $normalized; - - // Writing result value of delivery type - $result = $normalized; - - // Deinitializing unnecessary variables - unset($normalized); - - // Writing readiness status to the buffer of the response - $response['ready'] = $this->model::ready(company::{$delivery['company']}, $delivery[$delivery['company']] ?? []); - - if ($response['ready']) { - // Initialized required parameters + if (isset($delivery['company'])) { + // Initialized delivery company // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_ready' => true])); + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_longitude' => $normalized])); // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => true])); + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => $normalized])); // Deinitializing unnecessary variables unset($name); - } else { - // Not initialized required parameters - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [ - $name_ready = 'delivery_' . $delivery['company'] . '_ready' => false, - $name_cost = 'delivery_' . $delivery['company'] . '_cost' => null, - $name_days = 'delivery_' . $delivery['company'] . '_days' => null - ])); + // Writing to the actual buffer copy + $delivery[$delivery['company']]['longitude'] = $normalized; - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [ - $name_ready => false, - $name_cost => null, - $name_days => null - ])); + // Writing result value of delivery receiver longitude + $result = $normalized; // Deinitializing unnecessary variables - unset($name_ready, $name_cost, $name_days); + unset($normalized); + + // Writing readiness status to the buffer of the response + $response['ready'] = $this->model::ready(company::{$delivery['company']}, $delivery[$delivery['company']] ?? []); + + if ($response['ready']) { + // Initialized required parameters + + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_ready' => true])); + + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => true])); + + // Deinitializing unnecessary variables + unset($name); + } else { + // Not initialized required parameters + + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [ + $name_ready = 'delivery_' . $delivery['company'] . '_ready' => false, + $name_cost = 'delivery_' . $delivery['company'] . '_cost' => null, + $name_days = 'delivery_' . $delivery['company'] . '_days' => null + ])); + + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [ + $name_ready => false, + $name_cost => null, + $name_days => null + ])); + + // Deinitializing unnecessary variables + unset($name_ready, $name_cost, $name_days); + } + + // Deinitializing unnecessary variables + unset($delivery); + + // Writing status of execution to the buffer of the response + $response['status'] = 'success'; } // Deinitializing unnecessary variables - unset($delivery); - - // Writing status of execution to the buffer of the response - $response['status'] = 'success'; + unset($delivery, $result, $normalized); } + } else if (isset($latitude)) { + // Received delivery receiver latitude - // Deinitializing unnecessary variables - unset($delivery, $result, $normalized); - } - } else if (isset($tariff)) { - // Received delivery tariff - - if ((is_string($tariff) && mb_strlen($tariff) < 30) || (is_int($tariff && $tariff < 10000))) { - // Validated delivery tariff - - // Declating variable for result value of delivery tariff + // Declating variable for result value of delivery receiver latitude $result = ''; - // Declating variable for normalized value of delivery tariff + // Declating variable for normalized value of delivery receiver latitude $normalized = ''; - // Normalizing delivery tariff - if (preg_match('/[\w\d]+/', trim(urldecode($tariff)), $matches)) $normalized = $matches[0]; + // Normalizing receiver latitude + $normalized = filter_var($latitude, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); - // Deinitializing unnecessary variables - unset($matches); + if ($normalized >= -90 && $normalized <= 90) { + // Validated delivery receiver latitude - // Initialization buffer of delivery parameters - $delivery = $this->account?->buffer['delivery'] ?? $this->session?->buffer['delivery'] ?? []; + // Initialization buffer of delivery parameters + $delivery = $this->account?->buffer['delivery'] ?? $this->session?->buffer['delivery'] ?? []; - if (isset($delivery['company'])) { - // Initialized delivery company - - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_tariff' => $normalized])); - - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => $normalized])); - - // Deinitializing unnecessary variables - unset($name); - - // Writing to the actual buffer copy - $delivery[$delivery['company']]['tariff'] = $normalized; - - // Writing result value of delivery tariff - $result = $normalized; - - // Deinitializing unnecessary variables - unset($normalized); - - // Writing readiness status to the buffer of the response - $response['ready'] = $this->model::ready(company::{$delivery['company']}, $delivery[$delivery['company']] ?? []); - - if ($response['ready']) { - // Initialized required parameters + if (isset($delivery['company'])) { + // Initialized delivery company // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_ready' => true])); + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_latitude' => $normalized])); // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => true])); + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => $normalized])); // Deinitializing unnecessary variables unset($name); - } else { - // Not initialized required parameters - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [ - $name_ready = 'delivery_' . $delivery['company'] . '_ready' => false, - $name_cost = 'delivery_' . $delivery['company'] . '_cost' => null, - $name_days = 'delivery_' . $delivery['company'] . '_days' => null - ])); + // Writing to the actual buffer copy + $delivery[$delivery['company']]['latitude'] = $normalized; - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [ - $name_ready => false, - $name_cost => null, - $name_days => null - ])); + // Writing result value of delivery receiver latitude + $result = $normalized; // Deinitializing unnecessary variables - unset($name_ready, $name_cost, $name_days); + unset($normalized); + + // Writing readiness status to the buffer of the response + $response['ready'] = $this->model::ready(company::{$delivery['company']}, $delivery[$delivery['company']] ?? []); + + if ($response['ready']) { + // Initialized required parameters + + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_ready' => true])); + + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => true])); + + // Deinitializing unnecessary variables + unset($name); + } else { + // Not initialized required parameters + + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [ + $name_ready = 'delivery_' . $delivery['company'] . '_ready' => false, + $name_cost = 'delivery_' . $delivery['company'] . '_cost' => null, + $name_days = 'delivery_' . $delivery['company'] . '_days' => null + ])); + + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [ + $name_ready => false, + $name_cost => null, + $name_days => null + ])); + + // Deinitializing unnecessary variables + unset($name_ready, $name_cost, $name_days); + } + + // Deinitializing unnecessary variables + unset($delivery); + + // Writing status of execution to the buffer of the response + $response['status'] = 'success'; } // Deinitializing unnecessary variables - unset($delivery); - - // Writing status of execution to the buffer of the response - $response['status'] = 'success'; + unset($delivery, $result, $normalized); } + } else if (isset($apartament)) { + // Received delivery receiver apartament - // Deinitializing unnecessary variables - unset($delivery, $result, $normalized); - } - } else if (isset($longitude)) { - // Received delivery receiver longitude + // Declating variable for result value of delivery receiver apartament + $result = ''; - // Declating variable for result value of delivery receiver longitude - $result = ''; + // Declating variable for normalized value of delivery receiver apartament + $normalized = ''; - // Declating variable for normalized value of delivery receiver longitude - $normalized = ''; + // Normalizing receiver apartament + $normalized = filter_var($apartament, FILTER_SANITIZE_NUMBER_INT, FILTER_FLAG_ALLOW_FRACTION); - // Normalizing receiver longitude - $normalized = filter_var($longitude, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); + if ($normalized > 0 && $normalized <= 1000) { + // Validated delivery receiver apartament - if ($normalized >= -180 && $normalized <= 180) { - // Validated delivery receiver longitude + // Initialization buffer of delivery parameters + $delivery = $this->account?->buffer['delivery'] ?? $this->session?->buffer['delivery'] ?? []; - // Initialization buffer of delivery parameters - $delivery = $this->account?->buffer['delivery'] ?? $this->session?->buffer['delivery'] ?? []; - - if (isset($delivery['company'])) { - // Initialized delivery company - - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_longitude' => $normalized])); - - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => $normalized])); - - // Deinitializing unnecessary variables - unset($name); - - // Writing to the actual buffer copy - $delivery[$delivery['company']]['longitude'] = $normalized; - - // Writing result value of delivery receiver longitude - $result = $normalized; - - // Deinitializing unnecessary variables - unset($normalized); - - // Writing readiness status to the buffer of the response - $response['ready'] = $this->model::ready(company::{$delivery['company']}, $delivery[$delivery['company']] ?? []); - - if ($response['ready']) { - // Initialized required parameters + if (isset($delivery['company'])) { + // Initialized delivery company // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_ready' => true])); + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_apartament' => $normalized])); // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => true])); + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => $normalized])); // Deinitializing unnecessary variables unset($name); - } else { - // Not initialized required parameters - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [ - $name_ready = 'delivery_' . $delivery['company'] . '_ready' => false, - $name_cost = 'delivery_' . $delivery['company'] . '_cost' => null, - $name_days = 'delivery_' . $delivery['company'] . '_days' => null - ])); + // Writing to the actual buffer copy + $delivery[$delivery['company']]['apartment'] = $normalized; - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [ - $name_ready => false, - $name_cost => null, - $name_days => null - ])); + // Writing result value of delivery receiver apartament + $result = $normalized; // Deinitializing unnecessary variables - unset($name_ready, $name_cost, $name_days); + unset($normalized); + + // Writing readiness status to the buffer of the response + $response['ready'] = $this->model::ready(company::{$delivery['company']}, $delivery[$delivery['company']] ?? []); + + if ($response['ready']) { + // Initialized required parameters + + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_ready' => true])); + + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => true])); + + // Deinitializing unnecessary variables + unset($name); + } else { + // Not initialized required parameters + + // Writing to the session buffer + $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [ + $name_ready = 'delivery_' . $delivery['company'] . '_ready' => false, + $name_cost = 'delivery_' . $delivery['company'] . '_cost' => null, + $name_days = 'delivery_' . $delivery['company'] . '_days' => null + ])); + + // Writing to the account buffer + $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [ + $name_ready => false, + $name_cost => null, + $name_days => null + ])); + + // Deinitializing unnecessary variables + unset($name_ready, $name_cost, $name_days); + } + + // Deinitializing unnecessary variables + unset($delivery); + + // Writing status of execution to the buffer of the response + $response['status'] = 'success'; } // Deinitializing unnecessary variables - unset($delivery); - - // Writing status of execution to the buffer of the response - $response['status'] = 'success'; + unset($delivery, $location, $result, $normalized); } - - // Deinitializing unnecessary variables - unset($delivery, $result, $normalized); } - } else if (isset($latitude)) { - // Received delivery receiver latitude + } else { + // The deliveries input is not enabled for the site - // Declating variable for result value of delivery receiver latitude - $result = ''; - - // Declating variable for normalized value of delivery receiver latitude - $normalized = ''; - - // Normalizing receiver latitude - $normalized = filter_var($latitude, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); - - if ($normalized >= -90 && $normalized <= 90) { - // Validated delivery receiver latitude - - // Initialization buffer of delivery parameters - $delivery = $this->account?->buffer['delivery'] ?? $this->session?->buffer['delivery'] ?? []; - - if (isset($delivery['company'])) { - // Initialized delivery company - - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_latitude' => $normalized])); - - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => $normalized])); - - // Deinitializing unnecessary variables - unset($name); - - // Writing to the actual buffer copy - $delivery[$delivery['company']]['latitude'] = $normalized; - - // Writing result value of delivery receiver latitude - $result = $normalized; - - // Deinitializing unnecessary variables - unset($normalized); - - // Writing readiness status to the buffer of the response - $response['ready'] = $this->model::ready(company::{$delivery['company']}, $delivery[$delivery['company']] ?? []); - - if ($response['ready']) { - // Initialized required parameters - - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_ready' => true])); - - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => true])); - - // Deinitializing unnecessary variables - unset($name); - } else { - // Not initialized required parameters - - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [ - $name_ready = 'delivery_' . $delivery['company'] . '_ready' => false, - $name_cost = 'delivery_' . $delivery['company'] . '_cost' => null, - $name_days = 'delivery_' . $delivery['company'] . '_days' => null - ])); - - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [ - $name_ready => false, - $name_cost => null, - $name_days => null - ])); - - // Deinitializing unnecessary variables - unset($name_ready, $name_cost, $name_days); - } - - // Deinitializing unnecessary variables - unset($delivery); - - // Writing status of execution to the buffer of the response - $response['status'] = 'success'; - } - - // Deinitializing unnecessary variables - unset($delivery, $result, $normalized); - } - } else if (isset($apartament)) { - // Received delivery receiver apartament - - // Declating variable for result value of delivery receiver apartament - $result = ''; - - // Declating variable for normalized value of delivery receiver apartament - $normalized = ''; - - // Normalizing receiver apartament - $normalized = filter_var($apartament, FILTER_SANITIZE_NUMBER_INT, FILTER_FLAG_ALLOW_FRACTION); - - if ($normalized > 0 && $normalized <= 1000) { - // Validated delivery receiver apartament - - // Initialization buffer of delivery parameters - $delivery = $this->account?->buffer['delivery'] ?? $this->session?->buffer['delivery'] ?? []; - - if (isset($delivery['company'])) { - // Initialized delivery company - - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_apartament' => $normalized])); - - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => $normalized])); - - // Deinitializing unnecessary variables - unset($name); - - // Writing to the actual buffer copy - $delivery[$delivery['company']]['apartment'] = $normalized; - - // Writing result value of delivery receiver apartament - $result = $normalized; - - // Deinitializing unnecessary variables - unset($normalized); - - // Writing readiness status to the buffer of the response - $response['ready'] = $this->model::ready(company::{$delivery['company']}, $delivery[$delivery['company']] ?? []); - - if ($response['ready']) { - // Initialized required parameters - - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_ready' => true])); - - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => true])); - - // Deinitializing unnecessary variables - unset($name); - } else { - // Not initialized required parameters - - // Writing to the session buffer - $this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [ - $name_ready = 'delivery_' . $delivery['company'] . '_ready' => false, - $name_cost = 'delivery_' . $delivery['company'] . '_cost' => null, - $name_days = 'delivery_' . $delivery['company'] . '_days' => null - ])); - - // Writing to the account buffer - $this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [ - $name_ready => false, - $name_cost => null, - $name_days => null - ])); - - // Deinitializing unnecessary variables - unset($name_ready, $name_cost, $name_days); - } - - // Deinitializing unnecessary variables - unset($delivery); - - // Writing status of execution to the buffer of the response - $response['status'] = 'success'; - } - - // Deinitializing unnecessary variables - unset($delivery, $location, $result, $normalized); - } + // Reinitializing the ready status + $response['ready'] = true; } // Sending response @@ -1057,7 +1070,7 @@ final class delivery extends core */ public function calculate(): null { - if (str_contains($this->request->headers['accept'], content::json->value)) { + if (str_contains($this->request->headers['accept'] ?? '', content::json->value)) { // Request for JSON response // Initialization buffer of delivery parameters diff --git a/mirzaev/huesos/system/controllers/session.php b/mirzaev/huesos/system/controllers/session.php index e3fcd63..42b1a2f 100755 --- a/mirzaev/huesos/system/controllers/session.php +++ b/mirzaev/huesos/system/controllers/session.php @@ -53,6 +53,7 @@ final class session extends core * @param ?string $auth_date * @param ?string $hash * @param ?string $query_id + * @param ?string $signature * * @return null */ @@ -62,7 +63,8 @@ final class session extends core ?string $chat_type = null, ?string $auth_date = null, ?string $hash = null, - ?string $query_id = null + ?string $query_id = null, + ?string $signature = null ): null { if (str_contains($this->request->headers['accept'], content::json->value)) { // Request for JSON response @@ -70,6 +72,12 @@ final class session extends core // Declaring variables in the correct scope $identifier = $domain = $language = null; + // Initializing data of the account + $data = json_decode($user); + + // Initializing avatar of the account + $avatar = $data->photo_url; + if ($connected = isset($this->account)) { // Found the account @@ -84,10 +92,17 @@ final class session extends core } else { // Not found the account - if (isset($user, $chat_instance, $chat_type, $auth_date, $hash)) { + if (isset($user, $auth_date, $hash)) { // Received required parameters - $buffer = ['user' => $user, 'chat_instance' => $chat_instance, 'chat_type' => $chat_type, 'auth_date' => $auth_date]; + $buffer = ['user' => $user]; + + if (isset($query_id)) $buffer += ['query_id' => $query_id]; + if (isset($signature)) $buffer += ['signature' => $signature]; + if (isset($chat_instance)) $buffer += ['chat_instance' => $chat_instance]; + if (isset($chat_type)) $buffer += ['chat_type' => $chat_type]; + + $buffer += ['auth_date' => $auth_date]; ksort($buffer); @@ -109,9 +124,6 @@ final class session extends core if (time() - $auth_date < 86400) { // Authorization date less than 1 day ago - // Initializing data of the account - $data = json_decode($user); - // Initializing of the account $account = account::initialize( $data->id, @@ -146,6 +158,9 @@ final class session extends core // Initializing domain of the account $domain = $account->domain; + + // Initializing avatar of the account + $avatar = $data->photo_url; } } } @@ -161,6 +176,7 @@ final class session extends core 'connected' => (bool) $connected, 'identifier' => $identifier ?? null, 'domain' => $domain ?? null, + 'avatar' => $avatar ?? null, 'language' => $language?->name ?? null, 'errors' => $this->errors ]) diff --git a/mirzaev/huesos/system/models/account.php b/mirzaev/huesos/system/models/account.php index a3c8925..8c641b9 100755 --- a/mirzaev/huesos/system/models/account.php +++ b/mirzaev/huesos/system/models/account.php @@ -86,7 +86,7 @@ final class account extends core implements document_interface, collection_inter if (method_exists($account, '__document')) { // Object can implement a document from ArangoDB - // Abstractioning of parameters + // Implementinf parameters if (isset($result->language)) $result->language = language::{$result->language}; if (isset($result->currency)) $result->currency = currency::{$result->currency}; @@ -121,7 +121,7 @@ final class account extends core implements document_interface, collection_inter 'messages' => $registration->getCanReadAllGroupMessages() ], 'premium' => $registration->isPremium(), - 'language' => language::{$registration->getLanguageCode()}->name ?? 'en', + 'language' => language::{$registration->getLanguageCode() ?? 'en'}?->name ?? 'en', 'queries' => [ 'inline' => $registration->getSupportsInlineQueries() ] @@ -147,7 +147,6 @@ final class account extends core implements document_interface, collection_inter } else throw new exception('Failed to find account'); } else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION); } catch (exception $e) { -var_dump($errors); // Writing to the registry of errors $errors[] = [ 'text' => $e->getMessage(), diff --git a/mirzaev/huesos/system/models/acquirings/robokassa.php b/mirzaev/huesos/system/models/acquirings/robokassa.php new file mode 100755 index 0000000..3f937dc --- /dev/null +++ b/mirzaev/huesos/system/models/acquirings/robokassa.php @@ -0,0 +1,260 @@ + + */ +final class robokassa extends core +{ + /** + * Link + * + * Generate the link to pay for the order + * + * @param order $order The order + * @param array &$errors Registry of errors + * + * @return string|null The link to pay for the order, if generated + */ + public static function link(order $order, array &$errors = []): ?string + { + try { + // Initializing the settings + $settings = settings::active(); + + if ($settings instanceof settings) { + // Initialized the settings + + if ($settings->acquirings['robokassa']['enabled']) { + // Enabled the robokassa acquiring + + // Declaring the robokassa settings + $robokassa = null; + + // Initializing the test mode register + $test = 0; + + if ($settings->acquirings['robokassa']['mode'] === 'work') { + // Work mode + + // Initializing the robokassa settings + $robokassa = require(SETTINGS . DIRECTORY_SEPARATOR . 'acquirings' . DIRECTORY_SEPARATOR . 'robokassa' . DIRECTORY_SEPARATOR . 'work.php'); + } else if ($settings->acquirings['robokassa']['mode'] === 'test') { + // Test mode + + // Reinitializing the test mode register + $test = 1; + + // Initializing the robokassa settings + $robokassa = require(SETTINGS . DIRECTORY_SEPARATOR . 'acquirings' . DIRECTORY_SEPARATOR . 'robokassa' . DIRECTORY_SEPARATOR . 'test.php'); + } else { + // Failed to initialized the mode + + // Exit (fail) + throw new exception_domain('Failed to initialize the robokassa mode'); + } + + // Initializing the cart + $cart = $order->cart(); + + if ($cart instanceof cart) { + // Initialized the cart + + // Initializing robokassa parameters + $login = $robokassa['login']; + $password = $robokassa['passwords'][0]; + + // Initializing the order parameters + $identifier = $order->getKey(); + + // Initializing the invoice parameters + $description = "Оплата заказа"; + $cost = $cart->cost() + ($cart->buffer['delivery']['cost'] ?? 0); + + // Generatings the MD5 hash + $md5 = md5("$login:$cost:$identifier:$password"); +/* + // Writing the MD5 hash into the order implementator + $order->acquirings = ['robokassa' => ['hash' => $md5] + ($order->acquirings['robokassa'] ?? [])] + ($order->acquirings ?? []); + + if (document::update($order->__document(), errors: $errors)) { + // Writed to ArangoDB */ + + // Exit (success) + return "https://auth.robokassa.ru/Merchant/Index.aspx?MerchantLogin=$login&OutSum=$cost&InvId=$identifier&Description=$description&SignatureValue=$md5&IsTest=$test"; + /* } else throw new exception('Failed to write the robokassa hash into the order'); */ + } else { + // Not initialized the cart + + // Exit (fail) + throw new exception_runtime('Failed to initialize the cart'); + } + } + } + } catch (exception $e) { + // Writing to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Exit (fail) + return null; + } + + /** + * Verify (result) + * + * Generate hash by arguments and verify for result with the hash + * + * @param int $identifier Identifier of the order + * @param string $cost Cost of the order (can be with two zeros, like 1000.00) + * @param string $hash Hash of the order + * @param array &$errors Registry of errors + * + * @return string|null The link to pay for the order, if generated + */ + public static function result(int $identifier, string $cost, string $hash, bool $test = false, array &$errors = []): ?bool + { + try { + // Initializing the settings + $settings = settings::active(); + + if ($settings instanceof settings) { + // Initialized the settings + + if ($settings->acquirings['robokassa']['enabled']) { + // Enabled the robokassa acquiring + + // Declaring the robokassa settings + $robokassa = null; + + if ($test) { + // Test mode + + // Initializing the robokassa settings + $robokassa = require(SETTINGS . DIRECTORY_SEPARATOR . 'acquirings' . DIRECTORY_SEPARATOR . 'robokassa' . DIRECTORY_SEPARATOR . 'test.php'); + } else { + // Work mode + + // Initializing the robokassa settings + $robokassa = require(SETTINGS . DIRECTORY_SEPARATOR . 'acquirings' . DIRECTORY_SEPARATOR . 'robokassa' . DIRECTORY_SEPARATOR . 'work.php'); + } + + // Initializing robokassa parameters + $password = $robokassa['passwords'][1]; + + // Generatings the MD5 hash + $md5 = strtoupper(md5("$cost:$identifier:$password")); + + // Exit (success) + return $md5 === $hash; + } + } + } catch (exception $e) { + // Writing to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Exit (fail) + return null; + } + + /** + * Verify (success) + * + * Generate hash by arguments and verify for success with the hash + * + * @param int $identifier Identifier of the order + * @param string $cost Cost of the order (can be with two zeros, like 1000.00) + * @param string $hash Hash of the order + * @param array &$errors Registry of errors + * + * @return string|null The link to pay for the order, if generated + */ + public static function success(int $identifier, string $cost, string $hash, bool $test = false, array &$errors = []): ?bool + { + try { + // Initializing the settings + $settings = settings::active(); + + if ($settings instanceof settings) { + // Initialized the settings + + if ($settings->acquirings['robokassa']['enabled']) { + // Enabled the robokassa acquiring + + // Declaring the robokassa settings + $robokassa = null; + + if ($test) { + // Test mode + + // Initializing the robokassa settings + $robokassa = require(SETTINGS . DIRECTORY_SEPARATOR . 'acquirings' . DIRECTORY_SEPARATOR . 'robokassa' . DIRECTORY_SEPARATOR . 'test.php'); + } else { + // Work mode + + // Initializing the robokassa settings + $robokassa = require(SETTINGS . DIRECTORY_SEPARATOR . 'acquirings' . DIRECTORY_SEPARATOR . 'robokassa' . DIRECTORY_SEPARATOR . 'work.php'); + } + + // Initializing robokassa parameters + $password = $robokassa['passwords'][0]; + + // Generatings the MD5 hash + $md5 = md5("$cost:$identifier:$password"); + + // Exit (success) + return $md5 === $hash; + } + } + } catch (exception $e) { + // Writing to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Exit (fail) + return null; + } +} diff --git a/mirzaev/huesos/system/models/cart.php b/mirzaev/huesos/system/models/cart.php index 6eb7513..f6d0441 100755 --- a/mirzaev/huesos/system/models/cart.php +++ b/mirzaev/huesos/system/models/cart.php @@ -22,7 +22,8 @@ use mirzaev\arangodb\collection, use ArangoDBClient\Document as _document; // Built-in libraries -use exception; +use DateTime as datetime, + Exception as exception; /** * Model of cart @@ -150,11 +151,11 @@ final class cart extends core implements document_interface, collection_interfac // Search for all products in the cart $result = @collection::execute( << 'catalog', 'cart' => $this->getId(), @@ -184,7 +185,6 @@ final class cart extends core implements document_interface, collection_interfac return null; } - /** * Count * @@ -242,7 +242,7 @@ final class cart extends core implements document_interface, collection_interfac /* * Write * - * Write the product in the cart + * Write the product into the cart * * @param product $product The product * @param int $amount Amount of writings @@ -416,25 +416,262 @@ final class cart extends core implements document_interface, collection_interfac return false; } - /* - * Order + /** + * Account * - * + * Search for the connected account * * @param array &$errors Registry of errors * - * @return void + * @return account|null The connected account, if found */ - public function order(array &$errors = []): void + public function account(array &$errors = []): ?account + { + try { + if ($result = collection::execute( + <<<'AQL' + FOR v IN 1..1 OUTBOUND @cart GRAPH users + FILTER PARSE_IDENTIFIER(v._id).collection == @account + LIMIT 1 + return v + AQL, + [ + 'cart' => $this->document->getId(), + 'account' => account::COLLECTION + ], + errors: $errors + )) { + // Found the instance of the account connected to the account + + // Initializing the object + $account = new account; + + if (method_exists($account, '__document')) { + // Object can implement a document from ArangoDB + + // Implementinf parameters + if (isset($result->language)) $result->language = language::{$result->language}; + if (isset($result->currency)) $result->currency = currency::{$result->currency}; + + // Writing the instance of the account document from ArangoDB to the implement object + $account->__document($result); + + // Exit (success) + return $account; + } + } + } catch (exception $e) { + // Writing to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + // Exit (fail) + return null; + } + + /** + * Cost + * + * Generate the cart products cost + * + * @param string &$list List of the calculated products + * @param array &$errors Registry of errors + * + * @return float|int|null The cart products cost, if generated + */ + public function cost(string &$list = '', array &$errors = []): float|int|null + { + try { + // Initializing the account + $account = $this->account($errors); + + if ($account instanceof account) { + // Initialized the account + + // Initializing products in the cart + $products = $this->products(language: $account->language ?? language::ru, currency: $account->currency ?? currency::rub); + + if (!empty($products)) { + // Initialized products in the cart + + // Declaring total cost of products + $cost = 0; + + // Initializing iterator of rows + $row = 0; + + foreach ($products as $product) { + // Iterating over products + + // Generating formatted list of products for message + $list .= ++$row . '. ' . $product['document']['name'] . ' (' . $product['amount'] . 'шт)' . "\n"; + + // Generating total cost of products + $cost += $product['document']['cost'] * $product['amount']; + } + + // Exit (success) + return $cost; + } + } + } catch (exception $e) { + // Writing to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + // Exit (fail) + return null; + } + + /* + * Order + * + * Create the order and connect to the cart and to the account + * Make the cart ordered (the account will create a new cart) + * + * @param array &$errors Registry of errors + * + * @return order|null The order, if created + * + * @todo Handling errors + */ + public function order(array &$errors = []): ?order { try { if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) { - if (collection::initialize(reservation::COLLECTION, reservation::TYPE, errors: $errors)) { - if (collection::initialize(order::COLLECTION, order::TYPE, errors: $errors)) { - // Initialized collections + if (collection::initialize(order::COLLECTION, order::TYPE, errors: $errors)) { + if (collection::initialize(reservation::COLLECTION, reservation::TYPE, errors: $errors)) { + if (collection::initialize(account::COLLECTION, account::TYPE, errors: $errors)) { + // Initialized collections - } else throw new exception('Failed to initialize ' . product::TYPE->name . ' collection: ' . product::COLLECTION); - } else throw new exception('Failed to initialize ' . reservation::TYPE->name . ' collection: ' . reservation::COLLECTION); + // Searching for the order + $existed = collection::execute( + <<<'AQL' + FOR v IN 1..1 OUTBOUND @cart GRAPH users + FILTER PARSE_IDENTIFIER(v._id).collection == @order + LIMIT 1 + return v + AQL, + [ + 'cart' => $this->document->getId(), + 'order' => order::COLLECTION + ], + errors: $errors + ); + + if ($existed) { + // The order has already been created + + // Initializing the object + $order = new order; + + if (method_exists($order, '__document')) { + // Object can implement a document from ArangoDB + + // Writing the instance of the order document from ArangoDB to the implement object + $order->__document($existed); + + // Exit (success) + return $order; + } + } else { + // The order has not been created + + // Initializing a new order + $_id = document::write( + order::COLLECTION, + [ + 'active' => true, + /* 'term' => (int) new datetime('+15 minutes')->ormat('U') */ + ] + ); + + if ($result = collection::execute( + <<<'AQL' + FOR d IN @@collection + FILTER d._id == @_id && d.active == true + RETURN d + AQL, + [ + '@collection' => order::COLLECTION, + '_id' => $_id + ], + errors: $errors + )) { + // Found the instance of just created the new order + + // Writing the ordered status for the cart + $this->document->ordered = true; + + if (document::update($this->__document(), errors: $errors)) { + // Writed into ArangoDB + + // Initializing the object + $order = new order; + + if (method_exists($order, '__document')) { + // Object can implement a document from ArangoDB + + // Writing the instance of the order document from ArangoDB to the implement object + $order->__document($result); + + // Connecting the cart to the order + $connected = $order->connect($this, $errors); + + if ($connected) { + // Connected the cart with the order + + if ($result = collection::execute( + <<<'AQL' + FOR v IN 1..1 OUTBOUND @cart GRAPH users + FILTER PARSE_IDENTIFIER(v._id).collection == @account + LIMIT 1 + return v + AQL, + [ + 'cart' => $this->document->getId(), + 'account' => account::COLLECTION + ], + errors: $errors + )) { + // Found the instance of the account connected to the cart + + // Initializing the object + $account = new account; + + if (method_exists($account, '__document')) { + // Object can implement a document from ArangoDB + + // Writing the instance of the account document from ArangoDB to the implement object + $account->__document($result); + + // Connecting the account with the order + $connected = $account->connect($order, $errors); + + if ($connected) { + // Connected the account with the order + + // Exit (success) + return $order; + } + } + } + } + } else throw new exception('Class ' . order::class . ' does not implement a document from ArangoDB'); + } else throw new exception('Failed to write the ordered status for the cart'); + } else throw new exception('Failed to create or find just created ' . static::class); + } + } else throw new exception('Failed to initialize ' . account::TYPE->name . ' collection: ' . account::COLLECTION); + } else throw new exception('Failed to initialize ' . reservation::TYPE->name . ' collection: ' . reservation::COLLECTION); + } else throw new exception('Failed to initialize ' . order::TYPE->name . ' collection: ' . order::COLLECTION); } else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION); } catch (exception $e) { // Writing to the registry of errors @@ -445,5 +682,8 @@ final class cart extends core implements document_interface, collection_interfac 'stack' => $e->getTrace() ]; } + + // Exit (fail) + return null; } } diff --git a/mirzaev/huesos/system/models/catalog.php b/mirzaev/huesos/system/models/catalog.php index 9fd7722..77edf52 100755 --- a/mirzaev/huesos/system/models/catalog.php +++ b/mirzaev/huesos/system/models/catalog.php @@ -41,7 +41,8 @@ use GdImage as image; final class catalog extends core { use yandex, files { - yandex::download as yandex; + yandex::download as file; + yandex::list as folder; } /** @@ -120,7 +121,7 @@ final class catalog extends core // Iterate over categories try { - if (!empty($row['identifier']) && !empty($row['name'])) { + if (!empty($row['identifier']) && is_int($row['identifier']) && $row['identifier'] > 0 && !empty($row['name'])) { // Required cells are filled in // Incrementing the counter of loaded categories @@ -195,7 +196,10 @@ final class catalog extends core // Received images // Initializing new images of the category - $images = explode(' ', mb_trim($row['images'])); + $images = static::folder( + uri: explode(' ', mb_trim($row['images']))[0], + errors: $errors + ); // Reinitialize images? (true, if no images found or their amount does not match) /* $reinitialize = !$category->images || count($category->images) !== count($images); */ @@ -210,14 +214,14 @@ final class catalog extends core // Initializing the buffer of images $buffer = []; - foreach ($images as $index => $file) { + foreach (is_array($images) ? $images : [] as $image) { // Iterating over new images - // Skipping empty URI`s - if (empty($file = mb_trim($file))) continue; + // Initializing identifier of the image + $identifier = preg_replace('/\.\w+$/', '', $image->name); // Initializing path to directory of images in storage - $directory = DIRECTORY_SEPARATOR . 'categories' . DIRECTORY_SEPARATOR . $row['identifier'] . DIRECTORY_SEPARATOR . $index; + $directory = DIRECTORY_SEPARATOR . 'categories' . DIRECTORY_SEPARATOR . $row['identifier'] . DIRECTORY_SEPARATOR . $identifier; // Initializing URL of the image in storage $url = STORAGE . $directory; @@ -225,8 +229,8 @@ final class catalog extends core // Initializing the directory in storage if (!file_exists($url)) mkdir($url, 0775, true); - if ($downloaded = static::yandex( - uri: $file, + if ($downloaded = static::file( + uri: $image->public_url ?? $image->public_key, destination: $url, name: 'source', errors: $errors @@ -249,6 +253,11 @@ final class catalog extends core // Initializing implementator of the image $boba = imagecreatefromjpeg($uri); + } else if ($downloaded['content'] === content::webp) { + // WEBP + + // Initializing implementator of the image + $boba = imagecreatefromwebp($uri); } // Enabling better antialiasing @@ -280,10 +289,10 @@ final class catalog extends core imagecopyresampled($biba, $boba, 0, 0, 0, 0, $width, $height, $size[0], $size[1]); // Initializing URI of the resized image - $uri = $directory . DIRECTORY_SEPARATOR . "$resize." . $downloaded['content']->extension(); + $uri = $directory . DIRECTORY_SEPARATOR . "$resize.webp"; // Saving the image - imagePng($biba, STORAGE . $uri); + imagewebp($biba, STORAGE . $uri); // Writing the resized image to the buffer of resized images $resized[$resize] = $uri; @@ -291,7 +300,7 @@ final class catalog extends core // Writing the image to the buffer if images $buffer[] = [ - 'source' => $file, + 'source' => $image->public_url ?? null, 'storage' => [ 'source' => $directory . DIRECTORY_SEPARATOR . $downloaded['name'] . '.' . $downloaded['content']->extension(), ] + $resized @@ -349,7 +358,7 @@ final class catalog extends core // Iterate over products try { - if (!empty($row['identifier']) && !empty($row['name'])) { + if (!empty($row['identifier']) && is_int($row['identifier']) && $row['identifier'] > 0 && !empty($row['name'])) { // Required cells are filled in // Incrementing the counter of loaded products @@ -385,7 +394,7 @@ final class catalog extends core // Initializing position of the product if (empty($product->position) || $product->position !== $row['position']) - $product->position = $row['position']; + $product->position = isset($row['position']) ? (int) $row['position'] : 0; } else { // Not initialized the product @@ -399,7 +408,7 @@ final class catalog extends core dimensions: ['x' => $row['x'], 'y' => $row['y'], 'z' => $row['z']], brand: [$language->name => $row['brand']], compatibility: [$language->name => $row['compatibility']], - position: (int) $row['position'] ?? null, + position: isset($row['position']) ? (int) $row['position'] : 0, errors: $errors ); @@ -436,8 +445,11 @@ final class catalog extends core if (!empty($row['images'])) { // Received images - // Initializing new images of the category - $images = explode(' ', mb_trim($row['images'])); + // Initializing new images of the product + $images = static::folder( + uri: explode(' ', mb_trim($row['images']))[0], + errors: $errors + ); // Reinitialize images? (true, if no images found or their amount does not match) /* $reinitialize = !$product->images || count($product->images) !== count($images); */ @@ -452,14 +464,14 @@ final class catalog extends core // Initializing the buffer of images $buffer = []; - foreach ($images as $index => $file) { + foreach (is_array($images) ? $images : [] as $image) { // Iterating over new images - // Skipping empty URI`s - if (empty($file = mb_trim($file))) continue; + // Initializing identifier of the image + $identifier = preg_replace('/\.\w+$/', '', $image->name); // Initializing path to directory of images in storage - $directory = DIRECTORY_SEPARATOR . 'products' . DIRECTORY_SEPARATOR . $row['identifier'] . DIRECTORY_SEPARATOR . $index; + $directory = DIRECTORY_SEPARATOR . 'products' . DIRECTORY_SEPARATOR . $row['identifier'] . DIRECTORY_SEPARATOR . $identifier; // Initializing URL of the image in storage $url = STORAGE . $directory; @@ -467,8 +479,8 @@ final class catalog extends core // Initializing the directory in storage if (!file_exists($url)) mkdir($url, 0775, true); - if ($downloaded = static::yandex( - uri: $file, + if ($downloaded = static::file( + uri: $image->public_url ?? $image->public_key, destination: $url, name: 'source', errors: $errors @@ -491,6 +503,11 @@ final class catalog extends core // Initializing implementator of the image $boba = imagecreatefromjpeg($uri); + } else if ($downloaded['content'] === content::webp) { + // WEBP + + // Initializing implementator of the image + $boba = imagecreatefromwebp($uri); } // Enabling better antialiasing @@ -522,10 +539,10 @@ final class catalog extends core imagecopyresampled($biba, $boba, 0, 0, 0, 0, $width, $height, $size[0], $size[1]); // Initializing URI of the resized image - $uri = $directory . DIRECTORY_SEPARATOR . "$resize." . $downloaded['content']->extension(); + $uri = $directory . DIRECTORY_SEPARATOR . "$resize.webp"; // Saving the image - imagePng($biba, STORAGE . $uri); + imagewebp($biba, STORAGE . $uri); // Writing the resized image to the buffer of resized images $resized[$resize] = $uri; @@ -533,7 +550,7 @@ final class catalog extends core // Writing the image to the buffer if images $buffer[] = [ - 'source' => $file, + 'source' => $image->public_url ?? null, 'storage' => [ 'source' => $directory . DIRECTORY_SEPARATOR . $downloaded['name'] . '.' . $downloaded['content']->extension(), ] + $resized diff --git a/mirzaev/huesos/system/models/entry.php b/mirzaev/huesos/system/models/entry.php index dda54cd..3b04561 100755 --- a/mirzaev/huesos/system/models/entry.php +++ b/mirzaev/huesos/system/models/entry.php @@ -111,16 +111,21 @@ final class entry extends core implements document_interface, collection_interfa try { if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) { // Initialized the collection - - // Search for ascendants + + // Search for ascendants if ($result = collection::execute( sprintf( <<<'AQL' - FOR d IN @@collection - FOR ascendant IN OUTBOUND d @@edge - RETURN %s + let from = ( + FOR e IN @@edge + RETURN DISTINCT e._from + ) + + FOR d in @@collection + FILTER !POSITION(from, d._id) + RETURN %s AQL, - empty($return) ? 'DISTINCT ascendant' : $return + empty($return) ? 'DISTINCT d' : $return ), [ '@collection' => $descendant::COLLECTION, diff --git a/mirzaev/huesos/system/models/enumerations/destination.php b/mirzaev/huesos/system/models/enumerations/destination.php new file mode 100755 index 0000000..f1060bd --- /dev/null +++ b/mirzaev/huesos/system/models/enumerations/destination.php @@ -0,0 +1,46 @@ + + */ +enum destination +{ + case office; + case door; + + /** + * Label + * + * Initialize label of the destination + * + * @param language|null $language Language into which to translate + * + * @return string Translated label of the destination + */ + public function label(?language $language = language::en): string + { + // Exit (success) + return match ($this) { + destination::office => match ($language) { + language::en => 'Office', + language::ru => 'Пункт выдачи' + }, + destination::door => match ($language) { + language::en => 'Door', + language::ru => 'До двери' + } + }; + } +} diff --git a/mirzaev/huesos/system/models/order.php b/mirzaev/huesos/system/models/order.php index c8a25a8..270d7b9 100755 --- a/mirzaev/huesos/system/models/order.php +++ b/mirzaev/huesos/system/models/order.php @@ -6,6 +6,8 @@ namespace mirzaev\huesos\models; // Files of the project use mirzaev\huesos\models\core, + mirzaev\huesos\models\cart, + mirzaev\huesos\models\account, mirzaev\huesos\models\reservation, mirzaev\huesos\models\traits\document as document_trait, mirzaev\huesos\models\interfaces\document as document_interface, @@ -40,4 +42,115 @@ final class order extends core implements document_interface, collection_interfa * Name of the collection in ArangoDB */ final public const string COLLECTION = 'order'; + + /** + * Cart + * + * Search for the connected cart + * + * @param array &$errors Registry of errors + * + * @return cart|null The connected cart, if found + */ + public function cart(array &$errors = []): ?cart + { + try { + if ($result = collection::execute( + <<<'AQL' + FOR v IN 1..1 INBOUND @order GRAPH users + FILTER PARSE_IDENTIFIER(v._id).collection == @cart + LIMIT 1 + return v + AQL, + [ + 'order' => $this->document->getId(), + 'cart' => cart::COLLECTION + ], + errors: $errors + )) { + // Found the instance of the cart connected to the order + + // Initializing the object + $cart = new cart; + + if (method_exists($cart, '__document')) { + // Object can implement a document from ArangoDB + + // Writing the instance of the cart document from ArangoDB to the implement object + $cart->__document($result); + + // Exit (success) + return $cart; + } + } + } catch (exception $e) { + // Writing to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + // Exit (fail) + return null; + } + + /** + * Account + * + * Search for the connected account + * + * @param array &$errors Registry of errors + * + * @return account|null The connected account, if found + */ + public function account(array &$errors = []): ?account + { + try { + if ($result = collection::execute( + <<<'AQL' + FOR v IN 1..1 OUTBOUND @order GRAPH users + FILTER PARSE_IDENTIFIER(v._id).collection == @account + LIMIT 1 + return v + AQL, + [ + 'order' => $this->document->getId(), + 'account' => account::COLLECTION + ], + errors: $errors + )) { + // Found the instance of the account connected to the account + + // Initializing the object + $account = new account; + + if (method_exists($account, '__document')) { + // Object can implement a document from ArangoDB + + // Implementinf parameters + if (isset($result->language)) $result->language = language::{$result->language}; + if (isset($result->currency)) $result->currency = currency::{$result->currency}; + + // Writing the instance of the account document from ArangoDB to the implement object + $account->__document($result); + + // Exit (success) + return $account; + } + } + } catch (exception $e) { + // Writing to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + // Exit (fail) + return null; + } + } diff --git a/mirzaev/huesos/system/models/session.php b/mirzaev/huesos/system/models/session.php index f6df887..33a44d3 100755 --- a/mirzaev/huesos/system/models/session.php +++ b/mirzaev/huesos/system/models/session.php @@ -114,7 +114,7 @@ final class session extends core implements document_interface, collection_inter $session->hash = sodium_bin2hex(sodium_crypto_generichash($_id)); if (document::update($session, errors: $errors)) { - // Writed to ArangoDB + // Writed into ArangoDB // Writing instance of the session document from ArangoDB to the property of the implementing object $this->__document($session); diff --git a/mirzaev/huesos/system/models/telegram.php b/mirzaev/huesos/system/models/telegram.php index 5f7ab25..ab4ac0f 100755 --- a/mirzaev/huesos/system/models/telegram.php +++ b/mirzaev/huesos/system/models/telegram.php @@ -10,20 +10,28 @@ use mirzaev\huesos\models\core, mirzaev\huesos\models\catalog, mirzaev\huesos\models\suspension, mirzaev\huesos\models\account, + mirzaev\huesos\models\acquirings\robokassa, mirzaev\huesos\models\enumerations\language, - mirzaev\huesos\models\enumerations\currency; + mirzaev\huesos\models\enumerations\currency, + mirzaev\huesos\models\enumerations\destination; // Framework for Telegram use Zanzara\Zanzara, Zanzara\Context as context, - Zanzara\Telegram\Type\Input\InputFile, + Zanzara\Telegram\Type\Input\InputFile as input, Zanzara\Telegram\Type\File\Document as telegram_document, Zanzara\Middleware\MiddlewareNode as Node, Zanzara\Telegram\Type\User as user; +// Framework for asynchronous PHP +use function React\Async\await; + // Framework for ArangoDB use mirzaev\arangodb\document; +// Built-in libraries +use DateTime as datetime; + /** * Model of chat (telegram) * @@ -96,22 +104,22 @@ final class telegram extends core * * Команда: /start * - * @param context $ctx + * @param context $context * * @return void */ - public static function menu(context $ctx): void + public static function menu(context $context): void { // Declaring keyboard buttond $keyboard = []; - /* if ($ctx->get('account')) { + /* if ($context->get('account')) { // Authenticated */ // Writing the catalog button $keyboard[] = [ [ - 'text' => '🛒 Каталог', + 'text' => '🛒 Открыть магазин', 'web_app' => ['url' => 'https://telegram.arming.ru/'] ] ]; @@ -120,25 +128,45 @@ final class telegram extends core $keyboard = array_merge( $keyboard, [[ - ['text' => '🏛️ О компании'], - ['text' => '💬 Контакты'] + ['text' => '🏛️ О компании', 'callback_data' => 'company'], + ['text' => '💬 Контакты', 'callback_data' => 'contacts'] ]], [[ - ['text' => '🎯 Сообщество'] + ['text' => '🎯 Сообщество', 'callback_data' => 'community'] ]] ); - if ($ctx->get('account')?->access['settings']) $keyboard[] = [['text' => '⚙️ Настройки']]; + if ($context->get('account')?->access['settings']) { + // Authorized for settings - // Отправка сообщения - $ctx->sendMessage( + // Writing the settings button + $keyboard[] = [['text' => '⚙️ Настройки', 'callback_data' => 'settings']]; + } + + if (defined('GREETING_VIDEO') && file_exists(GREETING_VIDEO)) { + // Video message + + // Sending the video + await($context->sendVideo(new input(GREETING_VIDEO), ['disable_notification' => true])); + } + + // Sending the message + $context->sendMessage( static::unmarkdown(<< [ - 'keyboard' => $keyboard, + 'inline_keyboard' => $keyboard, 'resize_keyboard' => true ], 'disable_notification' => true @@ -151,14 +179,14 @@ final class telegram extends core * * Команда: /start * - * @param context $ctx + * @param context $context * * @return void */ - public static function start(context $ctx): void + public static function start(context $context): void { // Главное меню - static::menu($ctx); + static::menu($context); } /** @@ -166,14 +194,14 @@ final class telegram extends core * * Команда: /contacts * - * @param context $ctx + * @param context $context * * @return void */ - public static function contacts(context $ctx): void + public static function contacts(context $context): void { // Отправка сообщения - $ctx->sendMessage(static::unmarkdown(<<sendMessage(static::unmarkdown(<< [ @@ -201,14 +229,14 @@ final class telegram extends core /** * Почта * - * @param context $ctx + * @param context $context * * @return void */ - public static function _mail(context $ctx): void + public static function _mail(context $context): void { // Отправка сообщения - $ctx->sendMessage(static::unmarkdown(<<sendMessage(static::unmarkdown(<< [ @@ -223,14 +251,14 @@ final class telegram extends core * * Команда: /company * - * @param context $ctx + * @param context $context * * @return void */ - public static function company(context $ctx): void + public static function company(context $context): void { // Отправка сообщения - $ctx->sendMessage( + $context->sendMessage( static::unmarkdown(<<sendMessage(static::unmarkdown(<<sendMessage(static::unmarkdown(<< [ @@ -283,17 +311,17 @@ final class telegram extends core * * Команда: /settings * - * @param context $ctx + * @param context $context * * @return void */ - public static function settings(context $ctx): void + public static function settings(context $context): void { - if ($ctx->get('account')?->access['settings']) { + if ($context->get('account')?->access['settings']) { // Авторизован доступ к настройкам // Отправка сообщения - $ctx->sendMessage( + $context->sendMessage( static::unmarkdown(<<sendMessage('⛔ *Нет доступа*'); + $context->sendMessage('⛔ *Нет доступа*'); } } /** * Запросить файл для импорта товаров (доступ только авторизованным) * - * @param context $ctx + * @param context $context * * @return void */ - public static function import_request(context $ctx): void + public static function import_request(context $context): void { - if ($ctx->get('account')?->access['settings']) { + if ($context->get('account')?->access['settings']) { // Авторизован доступ к настройкам // Отправка сообщения - $ctx->sendMessage(static::unmarkdown('Отправьте документ в формате xlsx со списком товаров')) - ->then(function ($message) use ($ctx) { + $context->sendMessage(static::unmarkdown('Отправьте документ в формате xlsx со списком товаров')) + ->then(function ($message) use ($context) { // Отправка файла - $ctx->sendDocument(new InputFile(CATALOG_EXAMPLE), ['disable_notification' => true]); + $context->sendDocument(new input(CATALOG_EXAMPLE), ['disable_notification' => true]); // Импорт файла - $ctx->nextStep([static::class, 'import'], true); + $context->nextStep([static::class, 'import'], true); }); } else { // Не авторизован доступ к настройкам // Отправка сообщения - $ctx->sendMessage('⛔ *Нет доступа*'); + $context->sendMessage('⛔ *Нет доступа*'); } } /** * Импорт товаров (доступ только авторизованным) * - * @param context $ctx + * @param context $context * * @return void */ - public static function import(context $ctx): void + public static function import(context $context): void { - if (($account = $ctx->get('account'))?->access['settings']) { + if (($account = $context->get('account'))?->access['settings']) { // Авторизован доступ к настройкам // Инициализация документа - $document = $ctx->getMessage()?->getDocument(); + $document = $context->getMessage()?->getDocument(); if ($document instanceof telegram_document) { // Инициализирован документ // Инициализация файла - $ctx->getFile($document->getFileId())->then(function ($file) use ($ctx, $document, $account) { + $context->getFile($document->getFileId())->then(function ($file) use ($context, $document, $account) { if ($file->getFileSize() <= 50000000) { // Не превышает 50 мегабайт (50 000 000 байт) размер файла @@ -386,14 +414,14 @@ final class telegram extends core ); // Отправка сообщения - $ctx->sendMessage(sprintf( + $context->sendMessage(sprintf( <<<'TXT' 🔬 *Выполняется анализ:* %s \(%s байт\) TXT, static::unmarkdown($document->getFileName()), static::unmarkdown((string) $file->getFileSize()) )) - ->then(function ($message) use ($ctx, $import) { + ->then(function ($message) use ($context, $import) { // Инициализация счётчика загруженных товаров $categories_loaded = $products_loaded @@ -429,7 +457,7 @@ final class telegram extends core ); // Отправка сообщения - $ctx->sendMessage(<<sendMessage(<<then(function ($message) use ($ctx, $products_loaded, $products_created, $products_updated, $products_deleted, $products_old, $products_new) { - $ctx->sendMessage(<<then(function ($message) use ($context, $products_loaded, $products_created, $products_updated, $products_deleted, $products_old, $products_new) { + $context->sendMessage(<<then(function ($message) use ($ctx) { + ->then(function ($message) use ($context) { // Завершение диалога - $ctx->endConversation(); + $context->endConversation(); }); }); }); @@ -464,44 +492,44 @@ final class telegram extends core // Не имеет расширение xlsx файл // Отправка сообщения - $ctx->sendMessage(static::unmarkdown('Файл должен иметь расширение xlsx')); + $context->sendMessage(static::unmarkdown('Файл должен иметь расширение xlsx')); } } else { // Превышает 50 мегабайт (50000000 байт) размер файла // Отправка сообщения - $ctx->sendMessage(static::unmarkdown('Размер файла не должен превышать 50 мегабайт')); + $context->sendMessage(static::unmarkdown('Размер файла не должен превышать 50 мегабайт')); } }); } else { // Не инициализирован документ // Отправка сообщения - $ctx->sendMessage(static::unmarkdown('Отправьте документ в формате xlsx со списком товаров')); + $context->sendMessage(static::unmarkdown('Отправьте документ в формате xlsx со списком товаров')); } } else { // Не авторизован доступ к настройкам // Отправка сообщения - $ctx->sendMessage('⛔ *Нет доступа*'); + $context->sendMessage('⛔ *Нет доступа*'); } } /** * Инициализация аккаунта (middleware) * - * @param context $ctx + * @param context $context * @param Node $next * * @return void */ - public static function account(context $ctx, Node $next): void + public static function account(context $context, Node $next): void { // Выполнение заблокировано? - if ($ctx->get('stop')) return; + if ($context->get('stop')) return; // Инициализация аккаунта Telegram - $telegram = $ctx->getEffectiveUser(); + $telegram = $context->getEffectiveUser(); // Инициализация аккаунта $account = account::initialize($telegram->getId(), $telegram); @@ -513,22 +541,22 @@ final class telegram extends core // Заблокирован аккаунт // Отправка сообщения - $ctx->sendMessage('⛔ *Ты заблокирован*') - ->then(function ($message) use ($ctx) { + $context->sendMessage('⛔ *Ты заблокирован*') + ->then(function ($message) use ($context) { // Завершение диалога - $ctx->endConversation(); + $context->endConversation(); }); // Блокировка дальнейшего выполнения - $ctx->set('stop', true); + $context->set('stop', true); } else { // Не заблокирован аккаунт // Запись в буфер - $ctx->set('account', $account); + $context->set('account', $account); // Продолжение выполнения - $next($ctx); + $next($context); } } else { // Не инициализирован аккаунт @@ -538,15 +566,15 @@ final class telegram extends core /** * Инициализация статуса технических работ (middleware) * - * @param context $ctx + * @param context $context * @param Node $next * * @return void */ - public static function suspension(context $ctx, Node $next): void + public static function suspension(context $context, Node $next): void { // Выполнение заблокировано? - if ($ctx->get('stop')) return; + if ($context->get('stop')) return; // Поиск технических работ $suspension = suspension::search(); @@ -555,7 +583,7 @@ final class telegram extends core // Найдена активная приостановка // Инициализация аккаунта - $account = $ctx->get('account'); + $account = $context->get('account'); if ($account) { // Инициализирован аккаунт @@ -567,7 +595,7 @@ final class telegram extends core // Авторизован аккаунт // Продолжение выполнения - $next($ctx); + $next($context); // Выход (успех) return; @@ -583,34 +611,34 @@ final class telegram extends core $message .= "\n\n" . $suspension->description[$account->language ?? settings::active()?->language ?? 'en'] ?? array_values($suspension->description)[0]; // Отправка сообщения - $ctx->sendMessage($message) - ->then(function ($message) use ($ctx) { + $context->sendMessage($message) + ->then(function ($message) use ($context) { // Завершение диалога - $ctx->endConversation(); + $context->endConversation(); }); // Блокировка дальнейшего выполнения - $ctx->set('stop', true); + $context->set('stop', true); } else { // Не найдена активная приостановка // Продолжение выполнения - $next($ctx); + $next($context); } } /** * Cart attach * - * @param context $ctx + * @param context $context * @param string $share Sharing hash * * @return void */ - public static function cart_attach(context $ctx, string $share): void + public static function cart_attach(context $context, string $share): void { // Initializing account - $account = $ctx->get('account'); + $account = $context->get('account'); if ($account) { // Initialized the account @@ -627,12 +655,12 @@ final class telegram extends core // Deinitializing unnecessary variables unset($share); - // Unsharing the cart - $cart->unshare(); - if ($cart instanceof cart) { // Initialized the cart + // Unsharing the cart + $cart->unshare(); + // Connecting the cart to the account $edge = $account->connect($cart); @@ -645,24 +673,14 @@ final class telegram extends core if (!empty($products)) { // Initialized products in the cart - // Declaring total cost of products - $cost = 0; - - // Declaring formatted list of products for message + // Declaring the formatted list of products for message $list = ''; - // Initializing iterator of rows - $row = 0; + // Declaring total cost of products + $cost = $cart->cost($list); - foreach ($products as $product) { - // Iterating over products - - // Generating formatted list of products for message - $list .= static::unmarkdown(++$row . '. ' . $product['document']['name'] . ' (' . $product['amount'] . 'шт)') . "\n"; - - // Generating total cost of products - $cost += $product['document']['cost'] * $product['amount']; - } + // Escaping the formatted list of products for the message + $list = static::unmarkdown($list); // Deinitializing unnecessary variables unset($products, $product, $row); @@ -673,223 +691,45 @@ final class telegram extends core // Initializing currency symbol $symbol = ($account->currency ?? currency::rub)->symbol(); - // Initializing delivery cost for message - $delivery_cost = static::unmarkdown((string) $cart->buffer['delivery']['cost']); + // Declaring delivery texts + $delivery_cost = $delivery_days = $delivery_address = ''; - // Initializing delivery days for message - $delivery_days = static::unmarkdown((string) $cart->buffer['delivery']['days']); + if (!empty($cart->buffer['delivery'])) { + // Initialized delibery data - // Initializing delivery address for message - $delivery_address = static::unmarkdown($cart->buffer['delivery']['location']['name'] . ', ' . $cart->buffer['delivery']['street']); + // Initializing delivery cost for message + $delivery_cost = static::unmarkdown((string) $cart->buffer['delivery']['cost']); - $ctx->sendMessage( - <<buffer['delivery']['days']); - $list - *Стоимость:* $cost$symbol \+ $delivery_cost$symbol \($delivery_days дней\) - *Адрес доставки:* $delivery_address - TXT - )->then(function ($message) use ($ctx, $account, $cart) { - // Sended the message - - // Writing to the runtime buffer - $ctx->setUserDataItem('cart', $cart); - - if (empty($account->receiver['sim']) || empty($account->receiver['name'])) { - // Not registered account - - $ctx->sendMessage( - <<then(function ($message) use ($ctx) { - // Sended message - - // Sending account parameters menu - static::account_parameters($ctx); - }); - } else { - // Registered account - - $ctx->sendMessage( - <<then(function ($message) use ($ctx) { - // Sended message - - // Sending order request - static::order_request($ctx); - }); - } - }); - } - - // Deinitializing unnecessary variables - unset($cart, $list); - } - } - - // Deinitializing unnecessary variables - unset($cart); - } - - // Deinitializing unnecessary variables - unset($account); - } - - /** - * Order request - * - * @param context $ctx - * - * @return void - */ - public static function order_request(context $ctx): void - { - // Initializing the account - $account = $ctx->get('account'); - - if ($account) { - // Initialized the account - - $ctx->getUserDataItem('cart')->then(function ($cart) use ($ctx) { - // Readed the cart from the session buffer - - if (!empty($cart)) { - // Initialized the cart - - // Initializing identifier of the cart - $identifier = $cart->getKey(); - - $ctx->sendMessage( - << [ - 'inline_keyboard' => [ - [ - ['text' => '📦 Оформить заказ', 'callback_data' => 'order'], - ], - [ - ['text' => '⚡ Помощь с заказом', 'url' => 'https://t.me/iarming'], - ] - ], - 'disable_notification' => true - ] - ] - ); - } - }); - } - - // Deinitializing unnecessary variables - unset($account); - } - - /** - * Order request - * - * @param context $ctx - * - * @return void - */ - public static function order(context $ctx): void - { - // Initializing account - $account = $ctx->get('account'); - - if ($account) { - // Initialized the account - - var_dump($ctx->getCbData()); - die; - - // Initializing cart - $cart = cart::_read( - filter: 'd.share == @share', - sort: 'd.updated DESC, d.created DESC, d._key DESC', - amount: 1, - page: 1, - parameters: ['share' => $share] - ); - - // Deinitializing unnecessary variables - unset($share); - - // Unsharing the cart - $cart->unshare(); - - if ($cart instanceof cart) { - // Initialized the cart - - // Connecting the cart to the account - $edge = $account->connect($cart); - - if (!empty($edge)) { - // Connected the cart to the account - - // Initializing products in the cart - $products = $cart->products(language: $account->language ?? language::ru, currency: $account->currency ?? currency::rub); - - if (!empty($products)) { - // Initialized products in the cart - - // Declaring total cost of products - $cost = 0; - - // Declaring formatted list of products for message - $list = ''; - - // Initializing iterator of rows - $row = 0; - - foreach ($products as $product) { - // Iterating over products - - // Generating formatted list of products for message - $list .= static::unmarkdown(++$row . '. ' . $product['document']['name'] . ' (' . $product['amount'] . 'шт)') . "\n"; - - // Generating total cost of products - $cost += $product['document']['cost'] * $product['amount']; + // Initializing delivery address for message + $delivery_address = static::unmarkdown($cart->buffer['delivery']['location']['name'] . ', ' . $cart->buffer['delivery']['street']); } - // Deinitializing unnecessary variables - unset($products, $product, $row); + // Initializing the message cost part + $part_cost = "*Стоимость:* $cost$symbol"; + if (!empty($delivery_cost)) $part_cost .= " \+ $delivery_cost$symbol"; + if (!empty($delivery_days)) $part_cost .= " \($delivery_days дней\)"; - // Initializing currency symbol - $symbol = ($account->currency ?? currency::rub)->symbol(); + // Initializing the message delivery part + $part_delivery = ''; + if (!empty($delivery_address)) $part_cost .= "*Адрес доставки:* $delivery_address"; + if (!empty($part_delivery)) $part_delivery = "\n$part_delivery"; - // Initializing delivery cost for message - $delivery_cost = $cart->buffer['delivery']['cost']; - - // Initializing delivery days for message - $delivery_days = $cart->buffer['delivery']['days']; - - // Initializing delivery address for message - $delivery_address = $cart->buffer['delivery']['location']['name'] . ', ' . $cart->buffer['delivery']['street']; - - // Deinitializing unnecessary variables - unset($cart); - - $ctx->sendMessage( + $context->sendMessage( << [ 'inline_keyboard' => [ [ - /* ['text' => '🧾 Оплатить', 'web_app' => ['url' => 'https://telegram.arming.ru/']] */ - /* ['text' => '📦 Оформить заказ', 'url' => 'https://auth.robokassa.ru/Merchant/Index.aspx?MerchantLogin=demo&OutSum=11&Description=Покупка в демо магазине&SignatureValue=2c113e992e2c985e43e348ff3c12f32b'], */ - ['text' => '📦 Оформить заказ', 'callback_data' => 'order'], - ] + ['text' => '🚚 Оформить доставку', 'callback_data' => 'cart_delivery'], + ], ], 'disable_notification' => true ] @@ -911,50 +751,656 @@ final class telegram extends core } /** - * Account parameters + * Cart delivery * - * Menu for request parameters for the account - * - * @param context $ctx + * @param context $context * * @return void */ - public static function account_parameters(context $ctx): void + public static function cart_delivery(context $context): void { - // Initializing the account - $account = $ctx->get('account'); + // Initializing account + $account = $context->get('account'); if ($account) { // Initialized the account - $ctx->getUserDataItem('cart') - ->then( - function ($cart) use ($ctx, $account) { - // Readed the cart from the session buffer + // Initializing text of the message + $text = $context->getCallbackQuery()?->getMessage()?->getText() ?? ''; - if (!empty($cart) && !empty($account->receiver['sim']) && !empty($account->receiver['name'])) { - // Found process for the cart offering and initialized all required account parameters + // Searchin for the cart identifier + preg_match('/^.*\#(\d+)$/mu', $text, $matches); - // Sending the menu of requesting order - static::order_request($ctx); - } else { - // Not found process for the cart offering or not initialized all required account parameters + // Initializing the cart identifier + $identifier = $matches[1]; - $ctx->sendMessage( + if ($identifier) { + // Initialized the cart identifier + + // Initializing cart + $cart = cart::_read( + filter: 'd._key == @_key', + sort: 'd.updated DESC, d.created DESC, d._key DESC', + amount: 1, + page: 1, + parameters: ['_key' => $identifier] + ); + + if ($cart instanceof cart) { + // Initialized the cart + + // Initializin the account connected to the cart + $connected = $cart->account(); + + if ($account->getId() === $connected->getId()) { + // The account is authorized to the cart + + // Writing to the runtime buffer + $context->setUserDataItem('cart', $cart) + ->then(function () use ($context) { + static::delivery_registration($context); + }); + } + } + + // Deinitializing unnecessary variables + unset($cart); + } + } + + // Deinitializing unnecessary variables + unset($account); + } + + /** + * Delivery registration + * + * @param context $context + * + * @return void + */ + public static function delivery_registration(context $context): void + { + // Initializing account + $account = $context->get('account'); + + if ($account) { + // Initialized the account + + // Initializing the settings + $settings = settings::active(); + + // Initializing requirements + $requirements = [ + 'sim' => array_search('sim', $settings->input['deliveries']['chat'], true) !== false, + 'name' => array_search('name', $settings->input['deliveries']['chat'], true) !== false, + 'destination' => array_search('destination', $settings->input['deliveries']['chat'], true) !== false, + 'address' => array_search('address', $settings->input['deliveries']['chat'], true) !== false, + 'commentary' => array_search('commentary', $settings->input['deliveries']['chat'], true) !== false, + ]; + + // Ending the conversation + $context->endConversation() + ->then(function () use ($context, $requirements, $account) { + // Ended the conversation + + switch (true) { + case !empty($requirements['sim']) && empty($account->receiver['sim']): + // SIM-number + + /* // Sending the message + $context->sendMessage( << [ + 'disable_notification' => true, + 'remove_keyboard' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended message + + $context->nextStep([static::class, 'delivery_registration_sim_input'], false); + }); */ + + // Sending the message + $context->sendMessage( + << [ + 'disable_notification' => true, + 'remove_keyboard' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended message + + $context->nextStep([static::class, 'delivery_registration_sim_input'], false); + }); + + break; + case !empty($requirements['name']) && empty($account->receiver['name']): + // Name + + /* // Sending the message + $context->sendMessage( + << [ + 'disable_notification' => true, + 'remove_keyboard' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended message + + $context->nextStep([static::class, 'delivery_registration_name_input'], false); + }); */ + + // Sending the message + $context->sendMessage( + << [ + 'disable_notification' => true, + 'remove_keyboard' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended message + + $context->nextStep([static::class, 'delivery_registration_name_input'], false); + }); + + break; + case !empty($requirements['destination']) && empty($account->receiver['destination']): + // Destination + + // Sending the message + $context->sendMessage( + << [ 'inline_keyboard' => [ [ - ['text' => (empty($account->receiver['sim']) ? '🔴' : '🟢') . ' SIM-номер получателя', 'callback_data' => 'receiver_sim_choose'] + ['text' => '🏤 Пункт выдачи', 'callback_data' => 'delivery_registration_destination_office'], + /* ['text' => '🏠 До двери', 'callback_data' => 'delivery_registration_destination_door'], */ + ['text' => '🏠 Курьером до двери', 'callback_data' => 'delivery_registration_destination_door'], ], - [ - ['text' => (empty($account->receiver['name']) ? '🔴' : '🟢') . ' Имя получателя', 'callback_data' => 'receiver_name_choose'], - ] ], 'disable_notification' => true, + 'remove_keyboard' => true + ] + ] + ); + + break; + case !empty($requirements['address']) && empty($account->receiver['address']): + // Address + + // Initializing title for the message + $title = $account->receiver['destination'] === 'office' ? 'пункта выдачи' : 'получателя'; + + // Sending the message + $context->sendMessage( + << [ + 'disable_notification' => true, + 'remove_keyboard' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended message + + $context->nextStep([static::class, 'delivery_registration_address_input'], false); + }); + + break; + default: + // Initializing receiver domain for the message + $domain = static::unmarkdown($account->domain); + + // Initializing receiver SIM for the message + $sim = static::unmarkdown((string) $account->receiver['sim'] ?? ''); + + // Initializing receiver name for the message + $name = static::unmarkdown($account->receiver['name'] ?? ''); + + // Initializing receiver destination for the message + $destination = static::unmarkdown(destination::{$account->receiver['destination'] ?? 'office'}?->label($account->language) ?? ''); + + // Initializing receiver address for the message + $address = static::unmarkdown($account->receiver['address'] ?? ''); + + // Initializing the message delivery method part + $part_method = '*Метод доставки:* *CDEK*'; + if (!empty($destination)) $part_method .= " $destination"; + + // Initializing the message delivery part + $part_delivery = ''; + if (!empty($delivery_address)) $part_delivery .= "*Адрес доставки:* $delivery_address"; + if (!empty($part_delivery)) $part_delivery = "\n$part_delivery"; + + // Initializing the message receiver part + $part_receiver = "*Получатель:* @$domain"; + if (!empty($sim)) $part_receiver .= " $sim"; + if (!empty($name)) $part_receiver .= "\n*$name*"; + if (!empty($address)) $part_receiver .= "\n\n*Адрес:* $address"; + + // Sending the message + $context->sendMessage( + <<then(function ($message) use ($context) { + // Sended message + + // Sending order request + static::order_request($context); + }); + } + }); + } + + // Deinitializing unnecessary variables + unset($account); + } + + /** + * Order request + * + * @param context $context + * + * @return void + */ + public static function order_request(context $context): void + { + // Initializing the account + $account = $context->get('account'); + + if ($account) { + // Initialized the account + + $context->getUserDataItem('cart')->then(function ($cart) use ($context) { + // Readed the cart from the session buffer + + if (!empty($cart)) { + // Initialized the cart + + // Initializing identifier of the cart + $identifier = $cart->getKey(); + + // Deleting the order from the user telegram buffer + $context->deleteUserDataItem('order') + ->then( + function ($order) use ($context, $identifier) { + // Deleted the order from the user telegram buffer + + // Sending the message + $context->sendMessage( + << [ + 'inline_keyboard' => [ + [ + ['text' => '📦 Оформить заказ', 'callback_data' => 'order'], + ], + [ + ['text' => '✏️ Данные получателя', 'callback_data' => 'account_parameters_force'], + ], + [ + ['text' => '⚡ Помощь с заказом', 'url' => 'https://t.me/iarming'], + ] + ], + 'disable_notification' => true + ] + ] + ); + } + ); + } + }); + } + + // Deinitializing unnecessary variables + unset($account); + } + + /** + * Order request + * + * @param context $context + * + * @return void + */ + public static function order(context $context): void + { + // Initializing account + $account = $context->get('account'); + + if ($account) { + // Initialized the account + + // Ending the conversation + $context->endConversation() + ->then(function () use ($context, $account) { + // Ended the conversation + + // Reading the order from the user telegram buffer + $context->getUserDataItem('order') + ->then( + function ($order) use ($context, $account) { + // Readed the order from the user telegram buffer + + if ($order instanceof order) { + // Initialized the order + /* + // Writing timer for pay into the order + $order->term = (int) new datetime('+15 minutes')->format('U'); + + if (document::update($order->__document())) { + // Writed the order instance into the ArangoDB document */ + + // Searching for the cart + $cart = $order->cart(); + + if ($cart instanceof cart) { + // Initialized the cart + + // Skipping the order creation + goto order; + } + /* } */ + } + + // Initializing the message text + $text = $context->getCallbackQuery()?->getMessage()?->getText(); + + if (!empty($text)) { + // Initialized the message text + + // Searching for the cart identifier + preg_match('/^.*#(\d+)$/mu', $text, $matches); + + // Initializing the cart identifier + $identifier_cart = $matches[1] ?? null; + + // Searching for the cart + $cart = cart::_read( + filter: 'd._key == @_key', + sort: 'd.updated DESC, d.created DESC, d._key DESC', + amount: 1, + page: 1, + parameters: ['_key' => $identifier_cart] + ); + + if ($cart instanceof cart) { + // Initialized the cart + + if ($cart->ordered) { + // The cart was already ordered + + // Sending the message + $context->sendMessage("✅ *Корзина \#$identifier_cart уже оформлена в заказ*"); + } + + // Initializing the order + $order = $cart->order(); + + if ($order) { + // Initialized the order + + order: + + // Writing into the telegram user buffer + $context->setUserDataItem('order', $order) + ->then(function () use ($context, $order, $cart) { + // Writed into the telegram user buffer + + // Initializing identifier of the order + $identifier_order = $order->getKey(); + + if ($order->paid) { + // The order was already paid + + // Sending the message + $context->sendMessage("✅ *Заказ \#$identifier_order уже оплачен*"); + } else { + // The order was nor already paid + + // Declaring the formatted list of products for message + $list = ''; + + // Declaring total cost of products + $cost = $cart->cost($list); + + // Escaping the formatted list of products for the message + $list = static::unmarkdown($list); + + // Initializing currency symbol + $symbol = ($account->currency ?? currency::rub)->symbol(); + + // Declaring delivery texts + $delivery_cost = $delivery_days = $delivery_address = ''; + + if (!empty($cart->buffer['delivery'])) { + // Initialized delibery data + + // Initializing delivery cost for message + $delivery_cost = static::unmarkdown((string) $cart->buffer['delivery']['cost']); + + // Initializing delivery days for message + $delivery_days = static::unmarkdown((string) $cart->buffer['delivery']['days']); + + // Initializing delivery address for message + $delivery_address = static::unmarkdown($cart->buffer['delivery']['location']['name'] . ', ' . $cart->buffer['delivery']['street']); + } + + // Deinitializing unnecessary variables + unset($cart); + + // Initializing the customer account + $customer = $order->account(); + + // Initializing receiver domain for the message + $domain = static::unmarkdown($customer->domain); + + // Initializing receiver SIM for the message + $sim = static::unmarkdown((string) $customer->receiver['sim']); + + // Initializing receiver name for the message + $name = static::unmarkdown($customer->receiver['name']); + + // Initializing receiver address for the message + $address = static::unmarkdown($customer->receiver['address']); + + // Initializing the message cost part + $part_cost = "*Стоимость:* $cost$symbol"; + if (!empty($delivery_cost)) $part_cost .= " \+ $delivery_cost$symbol"; + if (!empty($delivery_days)) $part_cost .= " \($delivery_days дней\)"; + + // Initializing the message delivery part + $part_delivery = ''; + if (!empty($delivery_address)) $part_delivery .= "*Адрес доставки:* $delivery_address"; + if (!empty($part_delivery)) $part_delivery = "\n$part_delivery"; + + // Initializing the message receiver part + $part_receiver = "*Получатель:* @$domain"; + if (!empty($sim)) $part_receiver .= " $sim"; + if (!empty($name)) $part_receiver .= "\n*$name*"; + if (!empty($address)) $part_receiver .= "\n\n*Адрес:* $address"; + + // Initializing the message commentary part + $part_commentary = ''; + if (!empty($order->commentary)) $part_commentary .= "\n\n*Комментарий:* " . $order->commentary; + + // Sending the message + $context->sendMessage( + << [ + 'inline_keyboard' => [ + [ + ['text' => '💬 Комментарий к заказу', 'callback_data' => 'order_commentary_request'] + ], + [ + ['text' => '🧾 Оплатить', 'web_app' => ['url' => robokassa::link($order)]] + ] + ], + 'disable_notification' => true + ] + ] + ); + + // Deinitializing unnecessary variables + unset($cart, $list); + } + }); + } + } + } + + // Deinitializing unnecessary variables + unset($cart); + } + ); + }); + } + + // Deinitializing unnecessary variables + unset($account); + } + + /** + * Account parameters + * + * Menu for request parameters for the account + * + * @param context $context + * + * @return void + */ + public static function account_parameters(context $context, bool $force = false): void + { + // Initializing the account + $account = $context->get('account'); + + if ($account) { + // Initialized the account + + $context->getUserDataItem('cart') + ->then( + function ($cart) use ($context, $account, $force) { + // Readed the cart from the session buffer + + // Initializing the settings + $settings = settings::active(); + + // Initializing requirements + $requirements = [ + 'sim' => array_search('sim', $settings->input['deliveries']['chat'], true) !== false, + 'name' => array_search('name', $settings->input['deliveries']['chat'], true) !== false, + 'destination' => array_search('destination', $settings->input['deliveries']['chat'], true) !== false, + 'address' => array_search('address', $settings->input['deliveries']['chat'], true) !== false, + ]; + + if ( + !$force && + !empty($cart) && + (!$requirements['sim'] or $requirements['sim'] && !empty($account->receiver['sim'])) && + (!$requirements['name'] or $requirements['name'] && !empty($account->receiver['name'])) && + (!$requirements['destination'] or $requirements['destination'] && !empty($account->receiver['destination'])) && + (!$requirements['address'] or $requirements['address'] && !empty($account->receiver['address'])) + ) { + // Found process for the cart offering and initialized all required account parameters + + // Sending the menu of requesting order + static::order_request($context); + } else { + // Not found process for the cart offering or not initialized all required account parameters + + // Declaring the keyboard + $keyboard = []; + + if ($requirements['sim']) { + // Delivery receiver SIN + + // Writing into the keyboard + $keyboard[] = [ + /* ['text' => (empty($account->receiver['sim']) ? '🔴' : '🟢') . ' SIM-номер получателя', 'callback_data' => 'receiver_sim_choose'] */ + ['text' => (empty($account->receiver['sim']) ? '🔴' : '🟢') . ' Номер телефона получателя', 'callback_data' => 'receiver_sim_choose'] + ]; + } + + if ($requirements['name']) { + // Delivery receiver name + + // Writing into the keyboard + $keyboard[] = [ + ['text' => (empty($account->receiver['name']) ? '🔴' : '🟢') . ' Имя получателя', 'callback_data' => 'receiver_name_choose'], + ]; + } + + if ($requirements['destination']) { + // Delivery receiver name + + // Writing into the keyboard + $keyboard[] = [ + ['text' => (empty($account->receiver['destination']) ? '🔴' : '🟢') . ' Тип доставки', 'callback_data' => 'receiver_destination_choose'], + ]; + } + + if ($requirements['address']) { + // Delivery receiver address + + // Writing into the keyboard + $keyboard[] = [ + ['text' => (empty($account->receiver['address']) ? '🔴' : '🟢') . ' Адрес', 'callback_data' => 'receiver_address_choose'] + ]; + } + + // Sending the message + $context->sendMessage( + '📑 *Настройка параметров получателя*', + [ + 'reply_markup' => [ + 'inline_keyboard' => $keyboard, + 'disable_notification' => true, ] ] ); @@ -972,20 +1418,20 @@ final class telegram extends core * * Request the receiver SIM-number and write into account * - * @param context $ctx + * @param context $context * * @return void */ - public static function receiver_sim_choose(context $ctx): void + public static function receiver_sim_choose(context $context): void { // Initializing account - $account = $ctx->get('account'); + $account = $context->get('account'); if ($account) { // Initialized the account - // Sending the message - $ctx->sendMessage( + /* // Sending the message + $context->sendMessage( << true ] ] - )->then(function ($message) use ($ctx) { + )->then(function ($message) use ($context) { // Sended the message // Sending the message - $ctx->sendMessage( + $context->sendMessage( <<sendMessage( + << [ + 'keyboard' => [ + [ + ['text' => '📂 Использовать номер аккаунта', 'request_contact' => true] + ], + ], + 'disable_notification' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended the message + + // Sending the message + $context->sendMessage( + << [ + 'inline_keyboard' => [ + [ + ['text' => '✏️ Ввести вручную', 'callback_data' => 'receiver_sim_request'] + ], + ], + 'disable_notification' => true, + ] + ] + ); }); } @@ -1032,19 +1516,20 @@ final class telegram extends core * * Request SIM-number * - * @param context $ctx + * @param context $context * * @return void */ - public static function receiver_sim_request(context $ctx): void + public static function receiver_sim_request(context $context): void { // Initializing account - $account = $ctx->get('account'); + $account = $context->get('account'); if ($account) { - // Initialized the account + // Initialized the accountnn - $ctx->sendMessage( + /* // Sending the message + $context->sendMessage( << true ] ] - )->then(function ($message) use ($ctx) { + )->then(function ($message) use ($context) { // Sended message - $ctx->nextStep([static::class, 'receiver_sim_input'], true); + $context->nextStep([static::class, 'receiver_sim_input'], true); + }); */ + + // Sending the message + $context->sendMessage( + << [ + 'disable_notification' => true, + 'remove_keyboard' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended message + + $context->nextStep([static::class, 'receiver_sim_input'], true); }); } @@ -1072,20 +1576,20 @@ final class telegram extends core * * Receive SIM-number from message * - * @param context $ctx + * @param context $context * * @return void */ - public static function receiver_sim_input(context $ctx): void + public static function receiver_sim_input(context $context): void { // Initializing account - $account = $ctx->get('account'); + $account = $context->get('account'); if ($account) { // Initialized the account // Initializing received text (SIM-number) - $text = $ctx->getMessage()?->getText(); + $text = $context->getMessage()?->getText(); if (!empty($text)) { // Initialized received text (SIM-number) @@ -1102,39 +1606,178 @@ final class telegram extends core if (strlen($sanitized) < 20) { // Length of received SIM-number is less than 20 symbols - // Writing to the buffer - $ctx->setUserDataItem('receiver_sim', $sanitized); + // Writing into the telegram user buffer + $context->setUserDataItem('receiver_sim', $sanitized) + ->then(function () use ($context, $sanitized) { + // Writed into the telegram user buffer - $ctx->sendMessage( - << [ - 'inline_keyboard' => [ - [ - ['text' => '✅ Сохранить', 'callback_data' => 'receiver_sim_write'], - ['text' => '❎ Отменить', 'callback_data' => 'receiver_sim_choose'] + /* // Sending the message + $context->sendMessage( + << [ + 'inline_keyboard' => [ + [ + ['text' => '✅ Сохранить', 'callback_data' => 'receiver_sim_write'], + ['text' => '❎ Отменить', 'callback_data' => 'receiver_sim_choose'] + ] + ], + 'disable_notification' => true ] - ], - 'disable_notification' => true - ] - ] - ); + ] + ); */ - // Resetting the buffer - $ctx->endConversation(); + // Sending the message + $context->sendMessage( + << [ + 'inline_keyboard' => [ + [ + ['text' => '✅ Сохранить', 'callback_data' => 'receiver_sim_write'], + ['text' => '❎ Отменить', 'callback_data' => 'receiver_sim_choose'] + ] + ], + 'disable_notification' => true + ] + ] + ); + + // Resetting the buffer + $context->endConversation(); + }); } else { // Length of received SIM-number is NOT less than 20 symbols // Sending the message - $ctx->sendMessage('⚠️ *SIM\-номер должен быть короче 20\-ти символов*'); + /* $context->sendMessage('⚠️ *SIM\-номер должен быть короче 20\-ти символов*'); */ + $context->sendMessage('⚠️ *Номер телефона должен быть короче 20\-ти символов*'); } } else { // Length of received SIM-number is NOT more than 6 symbols // Sending the message - $ctx->sendMessage('⚠️ *SIM\-номер должен быть длиннее 3\-х символов*'); + /* $context->sendMessage('⚠️ *SIM\-номер должен быть длиннее 3\-х символов*'); */ + $context->sendMessage('⚠️ *Номер телефона должен быть длиннее 3\-х символов*'); + } + } + } + } + + // Deinitializing unnecessary variables + unset($account); + } + + /** + * Delivery registration SIM-number from input + * + * Receive SIM-number from message + * + * @param context $context + * + * @return void + * + * @todo i am tired of this project + */ + public static function delivery_registration_sim_input(context $context): void + { + // Initializing account + $account = $context->get('account'); + + if ($account) { + // Initialized the account + + // Initializing received text (SIM-number) + $text = $context->getMessage()?->getText(); + + if (!empty($text)) { + // Initialized received text (SIM-number) + + // Sanitizing received text (only numbers) + $sanitized = preg_replace('/[^\d]/', '', $text); + + if (!empty($sanitized)) { + // Initialized sanitized received text (only numbers) + + if (strlen($sanitized) > 6) { + // Length of received SIM-number is more than 6 symbols + + if (strlen($sanitized) < 20) { + // Length of received SIM-number is less than 20 symbols + + // Writing receiver SIM-number into the account + $account->receiver = ['sim' => (int) $sanitized] + ($account->receiver ?? []); + + // Deabstracting parameters + if ($account->language instanceof language) $account->language = $account->language?->name ?? settings::active()?->language->name; + if (isset($account->currency) && $account->currency instanceof currency) $account->currency = $account->currency?->name ?? settings::active()?->currency->name; + + if (document::update($account->__document())) { + // Writed the account instance into the ArangoDB document + + // Abstratcting paramters + $account->language = language::{$account->language}; + if (isset($account->currency)) $account->currency = currency::{$account->currency}; + + /* // Sending the message + $context->sendMessage( + << [ + 'disable_notification' => true, + 'remove_keyboard' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended message + + // Continuing the delivery registration process + static::delivery_registration($context); + }); */ + + // Sending the message + $context->sendMessage( + << [ + 'disable_notification' => true, + 'remove_keyboard' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended message + + // Continuing the delivery registration process + static::delivery_registration($context); + }); + } else { + // Not writed the account instance into the ArangoDB document + + // Sending the message + /* $context->sendMessage('⚠️ *Не удалось записать SIM\-номер*'); */ + $context->sendMessage('⚠️ *Не удалось записать номер телефона*'); + } + } else { + // Length of received SIM-number is NOT less than 20 symbols + + // Sending the message + /* $context->sendMessage('⚠️ *SIM\-номер должен быть короче 20\-ти символов*'); */ + $context->sendMessage('⚠️ *Номер телефона должен быть короче 20\-ти символов*'); + } + } else { + // Length of received SIM-number is NOT more than 6 symbols + + // Sending the message + /* $context->sendMessage('⚠️ *SIM\-номер должен быть длиннее 3\-х символов*'); */ + $context->sendMessage('⚠️ *Номер телефона должен быть длиннее 3\-х символов*'); } } } @@ -1149,20 +1792,21 @@ final class telegram extends core * * Write received and accepted receiver SIM-number into account * - * @param context $ctx + * @param context $context * * @return void */ - public static function receiver_sim_write(context $ctx): void + public static function receiver_sim_write(context $context): void { // initializing account - $account = $ctx->get('account'); + $account = $context->get('account'); if ($account) { // initialized the account - $ctx->getUserDataItem('receiver_sim')->then(function ($sim) use ($ctx, $account) { - // Initialized receiver SIM-number + // Reading from the telegram user buffer + $context->getUserDataItem('receiver_sim')->then(function ($sim) use ($context, $account) { + // Readed from the telegram user buffer if (!empty($sim)) { // Initialized receiver SIM-number @@ -1170,15 +1814,21 @@ final class telegram extends core // Writing receiver SIM-number into the account $account->receiver = ['sim' => (int) $sim] + ($account->receiver ?? []); - // Deabstracting the language parameter - $account->language = $account->language->name; + // Deabstracting parameters + if ($account->language instanceof language) $account->language = $account->language?->name ?? settings::active()?->language->name; + if (isset($account->currency) && $account->currency instanceof currency) $account->currency = $account->currency?->name ?? settings::active()?->currency->name; if (document::update($account->__document())) { // Writed the account instance into the ArangoDB document - $ctx->sendMessage( + // Abstratcting paramters + $account->language = language::{$account->language}; + if (isset($account->currency)) $account->currency = currency::{$account->currency}; + + /* // Sending the message + $context->sendMessage( << [ @@ -1186,26 +1836,49 @@ final class telegram extends core 'remove_keyboard' => true ] ] - )->then(function ($message) use ($ctx) { + )->then(function ($message) use ($context) { // Sended message // Deinitializing receiver SIM-number - $ctx->setUserDataItem('receiver_sim', null); + $context->setUserDataItem('receiver_sim', null); // Sending the account parameters menu - static::account_parameters($ctx); + static::account_parameters($context); + }); */ + + // Sending the message + $context->sendMessage( + << [ + 'disable_notification' => true, + 'remove_keyboard' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended message + + // Deinitializing receiver SIM-number + $context->setUserDataItem('receiver_sim', null); + + // Sending the account parameters menu + static::account_parameters($context); }); } else { // Not writed the account instance into the ArangoDB document // Sending the message - $ctx->sendMessage('⚠️ *Не удалось записать SIM\-номер*'); + /* $context->sendMessage('⚠️ *Не удалось записать SIM\-номер*'); */ + $context->sendMessage('⚠️ *Не удалось записать номер телефона*'); } } else { // Not initialized receiver SIM-number // Sending the message - $ctx->sendMessage('⚠️ *Ошибка при регистрации SIM\-номера*'); + /* $context->sendMessage('⚠️ *Ошибка при записи SIM\-номера*'); */ + $context->sendMessage('⚠️ *Ошибка при записи номер телефона*'); } }); } @@ -1219,22 +1892,22 @@ final class telegram extends core * * Request the receiver name and write into account * - * @param context $ctx + * @param context $context * * @return void */ - public static function receiver_name_choose(context $ctx): void + public static function receiver_name_choose(context $context): void { // Initializing account - $account = $ctx->get('account'); + $account = $context->get('account'); if ($account) { // Initialized the account // Sending the message - $ctx->sendMessage( + $context->sendMessage( <<get('account'); + $account = $context->get('account'); if ($account) { // Initialized the account - $ctx->sendMessage( + /* // Sending the message + $context->sendMessage( << true ] ] - )->then(function ($message) use ($ctx) { + )->then(function ($message) use ($context) { // Sended message - $ctx->nextStep([static::class, 'receiver_name_input'], true); + $context->nextStep([static::class, 'receiver_name_input'], true); + }); */ + + // Sending the message + $context->sendMessage( + << [ + 'disable_notification' => true, + 'remove_keyboard' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended message + + $context->nextStep([static::class, 'receiver_name_input'], true); }); } @@ -1300,20 +1993,20 @@ final class telegram extends core * * Receive name from message * - * @param context $ctx + * @param context $context * * @return void */ - public static function receiver_name_input(context $ctx): void + public static function receiver_name_input(context $context): void { // Initializing account - $account = $ctx->get('account'); + $account = $context->get('account'); if ($account) { // Initialized the account // Initializing received text (name) - $text = $ctx->getMessage()?->getText(); + $text = $context->getMessage()?->getText(); if (!empty($text)) { // Initialized received text (name) @@ -1330,39 +2023,134 @@ final class telegram extends core if (mb_strlen($sanitized) < 256) { // Length of received name is less than 256 symbols - // Writing to the buffer - $ctx->setUserDataItem('receiver_name', $sanitized); + // Writing to the telegram user buffer + $context->setUserDataItem('receiver_name', $sanitized) + ->then(function () use ($context, $sanitized) { - $ctx->sendMessage( - << [ - 'inline_keyboard' => [ - [ - ['text' => '✅ Сохранить', 'callback_data' => 'receiver_name_write'], - ['text' => '❎ Отменить', 'callback_data' => 'receiver_name_choose'] + // Sending the message + $context->sendMessage( + << [ + 'inline_keyboard' => [ + [ + ['text' => '✅ Сохранить', 'callback_data' => 'receiver_name_write'], + ['text' => '❎ Отменить', 'callback_data' => 'receiver_name_choose'] + ] + ], + 'disable_notification' => true ] - ], - 'disable_notification' => true - ] - ] - ); + ] + ); - // Resetting the buffer - $ctx->endConversation(); + // Resetting the buffer + $context->endConversation(); + }); } else { - // Length of received name is NOT less than 20 symbols + // Length of received name is NOT less than 256 symbols // Sending the message - $ctx->sendMessage('⚠️ *ФИО должны быть короче 256\-ти символов*'); + $context->sendMessage('⚠️ *ФИО должны быть короче 256\-ти символов*'); } } else { - // Length of received name is NOT more than 6 symbols + // Length of received name is NOT more than 3 symbols // Sending the message - $ctx->sendMessage('⚠️ *ФИО должны быть длиннее 3\-х символов*'); + $context->sendMessage('⚠️ *ФИО должны быть длиннее 3\-х символов*'); + } + } + } + } + + // Deinitializing unnecessary variables + unset($account); + } + + /** + * Delivery registration name from input + * + * Receive name from message + * + * @param context $context + * + * @return void + */ + public static function delivery_registration_name_input(context $context): void + { + // Initializing account + $account = $context->get('account'); + + if ($account) { + // Initialized the account + + // Initializing received text (name) + $text = $context->getMessage()?->getText(); + + if (!empty($text)) { + // Initialized received text (name) + + // Sanitizing received text (only numbers) + $sanitized = static::unmarkdown(preg_replace('/[^\s\w\-]/u', '', $text)); + + if (!empty($sanitized)) { + // Initialized sanitized received text (only numbers) + + if (mb_strlen($sanitized) > 3) { + // Length of received name is more than 3 symbols + + if (mb_strlen($sanitized) < 256) { + // Length of received name is less than 256 symbols + + // Writing receiver name into the account + $account->receiver = ['name' => $sanitized] + ($account->receiver ?? []); + + // Deabstracting parameters + if ($account->language instanceof language) $account->language = $account->language?->name ?? settings::active()?->language->name; + if (isset($account->currency) && $account->currency instanceof currency) $account->currency = $account->currency?->name ?? settings::active()?->currency->name; + + if (document::update($account->__document())) { + // Writed the account instance into the ArangoDB document + + // Abstratcting paramters + $account->language = language::{$account->language}; + if (isset($account->currency)) $account->currency = currency::{$account->currency}; + + $context->sendMessage( + << [ + 'disable_notification' => true, + 'remove_keyboard' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended message + + // Continuing the delivery registration process + static::delivery_registration($context); + }); + } else { + // Not writed the account instance into the ArangoDB document + + // Sending the message + $context->sendMessage('⚠️ *Не удалось записать ФИО*'); + } + } else { + // Length of received name is NOT less than 256 symbols + + // Sending the message + $context->sendMessage('⚠️ *ФИО должны быть короче 256\-ти символов*'); + } + } else { + // Length of received name is NOT more than 3 symbols + + // Sending the message + $context->sendMessage('⚠️ *ФИО должны быть длиннее 3\-х символов*'); } } } @@ -1377,37 +2165,720 @@ final class telegram extends core * * Write received and accepted receiver name into account * - * @param context $ctx + * @param context $context * * @return void */ - public static function receiver_name_write(context $ctx): void + public static function receiver_name_write(context $context): void { // initializing account - $account = $ctx->get('account'); + $account = $context->get('account'); if ($account) { // initialized the account - $ctx->getUserDataItem('receiver_name')->then(function ($name) use ($ctx, $account) { - // Initialized receiver name + // Reading from the telegram user buffer + $context->getUserDataItem('receiver_name') + ->then(function ($name) use ($context, $account) { + // Readed from the telegram user buffer - if (!empty($name)) { - // Initialized receiver name + if (!empty($name)) { + // Initialized receiver name - // Writing receiver name into the account - $account->receiver = ['name' => $name] + ($account->receiver ?? []); + // Writing receiver name into the account + $account->receiver = ['name' => $name] + ($account->receiver ?? []); - // Deabstracting the language parameter - $account->language = $account->language->name; + // Deabstracting parameters + if ($account->language instanceof language) $account->language = $account->language?->name ?? settings::active()?->language->name; + if (isset($account->currency) && $account->currency instanceof currency) $account->currency = $account->currency?->name ?? settings::active()?->currency->name; + + if (document::update($account->__document())) { + // Writed the account instance into the ArangoDB document + + // Abstratcting paramters + $account->language = language::{$account->language}; + if (isset($account->currency)) $account->currency = currency::{$account->currency}; + + // Sending the message + $context->sendMessage( + << [ + 'disable_notification' => true, + 'remove_keyboard' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended message + + // Deinitializing receiver name + $context->setUserDataItem('receiver_name', null); + + // Sending the account parameters menu + static::account_parameters($context); + }); + } else { + // Not writed the account instance into the ArangoDB document + + // Sending the message + $context->sendMessage('⚠️ *Не удалось записать ФИО*'); + } + } else { + // Not initialized receiver name + + // Sending the message + $context->sendMessage('⚠️ *Ошибка при регистрации ФИО*'); + } + }); + } + + // Deinitializing unnecessary variables + unset($account); + } + + + /** + * Receiver destination + * + * Request the receiver destination and write into account + * + * @param context $context + * + * @return void + */ + public static function receiver_destination_choose(context $context): void + { + // Initializing account + $account = $context->get('account'); + + if ($account) { + // Initialized the account + + // Sending the message + $context->sendMessage( + << [ + 'inline_keyboard' => [ + [ + ['text' => '🏤 Пункт выдачи', 'callback_data' => 'receiver_destination_office'], + ['text' => '🏠 До двери', 'callback_data' => 'receiver_destination_door'], + ], + ], + 'disable_notification' => true, + ] + ] + ); + } + + // Deinitializing unnecessary variables + unset($account); + } + + /** + * Receiver destination office + * + * @param context $context + * + * @return void + */ + public static function receiver_destination_office(context $context): void + { + // Initializing account + $account = $context->get('account'); + + if ($account) { + // Initialized the account + + // Initializing the destination + $destination = destination::office; + + if (!empty($destination)) { + // Initialized receiver destination + + // Writing receiver destination into the account + $account->receiver = ['destination' => $destination->name] + ($account->receiver ?? []); + + // Initializing destination for the message + $type = $destination->label($account->language); + + // Deabstracting parameters + if ($account->language instanceof language) $account->language = $account->language?->name ?? settings::active()?->language->name; + if (isset($account->currency) && $account->currency instanceof currency) $account->currency = $account->currency?->name ?? settings::active()?->currency->name; + + if (document::update($account->__document())) { + // Writed the account instance into the ArangoDB document + + // Abstratcting paramters + $account->language = language::{$account->language}; + if (isset($account->currency)) $account->currency = currency::{$account->currency}; + + // Sending the message + $context->sendMessage( + << [ + 'disable_notification' => true, + 'remove_keyboard' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended message + + // Sending the account parameters menu + static::account_parameters($context); + }); + } else { + // Not writed the account instance into the ArangoDB document + + // Sending the message + $context->sendMessage('⚠️ *Не удалось записать тип доставки*'); + } + } else { + // Not initialized receiver name + + // Sending the message + $context->sendMessage('⚠️ *Ошибка при регистрации типа доставки*'); + } + } + + // Deinitializing unnecessary variables + unset($account); + } + + /** + * Delivery registration destination office + * + * @param context $context + * + * @return void + */ + public static function delivery_registration_destination_office(context $context): void + { + // Initializing account + $account = $context->get('account'); + + if ($account) { + // Initialized the account + + // Initializing the destination + $destination = destination::office; + + if (!empty($destination)) { + // Initialized receiver destination + + // Writing receiver destination into the account + $account->receiver = ['destination' => $destination->name] + ($account->receiver ?? []); + + // Initializing destination for the message + $type = $destination->label($account->language); + + // Deabstracting parameters + if ($account->language instanceof language) $account->language = $account->language?->name ?? settings::active()?->language->name; + if (isset($account->currency) && $account->currency instanceof currency) $account->currency = $account->currency?->name ?? settings::active()?->currency->name; + + if (document::update($account->__document())) { + // Writed the account instance into the ArangoDB document + + // Abstratcting paramters + $account->language = language::{$account->language}; + if (isset($account->currency)) $account->currency = currency::{$account->currency}; + + // Sending the message + $context->sendMessage( + << [ + 'disable_notification' => true, + 'remove_keyboard' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended message + + // Continuing the delivery registration process + static::delivery_registration($context); + }); + } else { + // Not writed the account instance into the ArangoDB document + + // Sending the message + $context->sendMessage('⚠️ *Не удалось записать тип доставки*'); + } + } else { + // Not initialized receiver name + + // Sending the message + $context->sendMessage('⚠️ *Ошибка при регистрации типа доставки*'); + } + } + + // Deinitializing unnecessary variables + unset($account); + } + + /** + * Receiver destination door + * + * @param context $context + * + * @return void + */ + public static function receiver_destination_door(context $context): void + { + // Initializing account + $account = $context->get('account'); + + if ($account) { + // Initialized the account + + // Initializing the destination + $destination = destination::door; + + if (!empty($destination)) { + // Initialized receiver destination + + // Writing receiver destination into the account + $account->receiver = ['destination' => $destination->name] + ($account->receiver ?? []); + + // Initializing destination for the message + $type = $destination->label($account->language); + + // Deabstracting parameters + if ($account->language instanceof language) $account->language = $account->language?->name ?? settings::active()?->language->name; + if (isset($account->currency) && $account->currency instanceof currency) $account->currency = $account->currency?->name ?? settings::active()?->currency->name; + + if (document::update($account->__document())) { + // Writed the account instance into the ArangoDB document + + // Abstratcting paramters + $account->language = language::{$account->language}; + if (isset($account->currency)) $account->currency = currency::{$account->currency}; + + // Sending the message + $context->sendMessage( + << [ + 'disable_notification' => true, + 'remove_keyboard' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended message + + // Sending the account parameters menu + static::account_parameters($context); + }); + } else { + // Not writed the account instance into the ArangoDB document + + // Sending the message + $context->sendMessage('⚠️ *Не удалось записать тип доставки*'); + } + } else { + // Not initialized receiver name + + // Sending the message + $context->sendMessage('⚠️ *Ошибка при регистрации типа доставки*'); + } + } + + // Deinitializing unnecessary variables + unset($account); + } + + /** + * Delivery registration destination door + * + * @param context $context + * + * @return void + */ + public static function delivery_registration_destination_door(context $context): void + { + // Initializing account + $account = $context->get('account'); + + if ($account) { + // Initialized the account + + // Initializing the destination + $destination = destination::door; + + if (!empty($destination)) { + // Initialized receiver destination + + // Writing receiver destination into the account + $account->receiver = ['destination' => $destination->name] + ($account->receiver ?? []); + + // Initializing destination for the message + $type = $destination->label($account->language); + + // Deabstracting parameters + if ($account->language instanceof language) $account->language = $account->language?->name ?? settings::active()?->language->name; + if (isset($account->currency) && $account->currency instanceof currency) $account->currency = $account->currency?->name ?? settings::active()?->currency->name; + + if (document::update($account->__document())) { + // Writed the account instance into the ArangoDB document + + // Abstratcting paramters + $account->language = language::{$account->language}; + if (isset($account->currency)) $account->currency = currency::{$account->currency}; + + // Sending the message + $context->sendMessage( + << [ + 'disable_notification' => true, + 'remove_keyboard' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended message + + // Continuing the delivery registration process + static::delivery_registration($context); + }); + } else { + // Not writed the account instance into the ArangoDB document + + // Sending the message + $context->sendMessage('⚠️ *Не удалось записать тип доставки*'); + } + } else { + // Not initialized receiver name + + // Sending the message + $context->sendMessage('⚠️ *Ошибка при регистрации типа доставки*'); + } + } + + // Deinitializing unnecessary variables + unset($account); + } + + /** + * Receiver address + * + * Request the receiver address and write into account + * + * @param context $context + * @param bool $office Is the destination are office? + * + * @return void + */ + public static function receiver_address_choose(context $context, bool $office = false): void + { + // Initializing account + $account = $context->get('account'); + + if ($account) { + // Initialized the account + + // Initializing title for the message + $title = $office ? 'пункта выдачи' : 'получателя'; + + // Sending the message + $context->sendMessage( + << [ + 'inline_keyboard' => [ + [ + ['text' => '✏️ Ввести вручную', 'callback_data' => 'receiver_address_request_' . ($office ? 'office' : 'door')] + ], + ], + 'disable_notification' => true, + ] + ] + ); + } + + // Deinitializing unnecessary variables + unset($account); + } + + /** + * Receiver address request + * + * Request address + * + * @param context $context + * @param bool $office Is the destination are office? + * + * @return void + */ + public static function receiver_address_request(context $context, bool $office = false): void + { + // Initializing account + $account = $context->get('account'); + + if ($account) { + // Initialized the account + + // Initializing title for the message + $title = $office ? 'пункта выдачи' : 'получателя'; + + // Sending the message + $context->sendMessage( + << [ + 'disable_notification' => true, + 'remove_keyboard' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended message + + $context->nextStep([static::class, 'receiver_address_input'], true); + }); + } + + // Deinitializing unnecessary variables + unset($account); + } + + /** + * Receiver address from input + * + * Receive address from message + * + * @param context $context + * + * @return void + */ + public static function receiver_address_input(context $context): void + { + // Initializing account + $account = $context->get('account'); + + if ($account) { + // Initialized the account + + // Initializing received text (address) + $text = $context->getMessage()?->getText(); + + if (!empty($text)) { + // Initialized received text (address) + + // Sanitizing received text + $sanitized = static::unmarkdown($text); + + if (!empty($sanitized)) { + // Initialized sanitized received text (only numbers) + + if (mb_strlen($sanitized) > 6) { + // Length of received address is more than 6 symbols + + if (mb_strlen($sanitized) < 256) { + // Length of received address is less than 256 symbols + + // Writing to the telegram user buffer + $context->setUserDataItem('receiver_address', $sanitized) + ->then(function () use ($context, $sanitized) { + // Writed to the telegram user buffer + + $context->sendMessage( + << [ + 'inline_keyboard' => [ + [ + ['text' => '✅ Сохранить', 'callback_data' => 'receiver_address_write'], + ['text' => '❎ Отменить', 'callback_data' => 'receiver_address_choose'] + ] + ], + 'disable_notification' => true + ] + ] + ); + + // Resetting the buffer + $context->endConversation(); + }); + } else { + // Length of received address is NOT less than 256 symbols + + // Sending the message + $context->sendMessage('⚠️ *Адрес должен быть короче 256\-ти символов*'); + } + } else { + // Length of received address is NOT more than 6 symbols + + // Sending the message + $context->sendMessage('⚠️ *Адрес должен быть длиннее 6\-ти символов*'); + } + } + } + } + + // Deinitializing unnecessary variables + unset($account); + } + + /** + * Delivery registration address from input + * + * Receive address from message + * + * @param context $context + * + * @return void + */ + public static function delivery_registration_address_input(context $context): void + { + // Initializing account + $account = $context->get('account'); + + if ($account) { + // Initialized the account + + // Initializing received text (address) + $text = $context->getMessage()?->getText(); + + if (!empty($text)) { + // Initialized received text (address) + + // Sanitizing received text + $sanitized = static::unmarkdown($text); + + if (!empty($sanitized)) { + // Initialized sanitized received text (only numbers) + + if (mb_strlen($sanitized) > 6) { + // Length of received address is more than 6 symbols + + if (mb_strlen($sanitized) < 256) { + // Length of received address is less than 256 symbols + + // Writing receiver address into the account + $account->receiver = ['address' => $sanitized] + ($account->receiver ?? []); + + // Deabstracting parameters + if ($account->language instanceof language) $account->language = $account->language?->name ?? settings::active()?->language->name; + if (isset($account->currency) && $account->currency instanceof currency) $account->currency = $account->currency?->name ?? settings::active()?->currency->name; + + if (document::update($account->__document())) { + // Writed the account instance into the ArangoDB document + + // Abstratcting paramters + $account->language = language::{$account->language}; + if (isset($account->currency)) $account->currency = currency::{$account->currency}; + + // Sending the message + $context->sendMessage( + << [ + 'disable_notification' => true, + 'remove_keyboard' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended the message + + // Continuing the delivery registration process + static::delivery_registration($context); + }); + } else { + // Not writed the account instance into the ArangoDB document + + // Sending the message + $context->sendMessage('⚠️ *Не удалось записать адрес*'); + } + } else { + // Length of received address is NOT less than 256 symbols + + // Sending the message + $context->sendMessage('⚠️ *Адрес должен быть короче 256\-ти символов*'); + } + } else { + // Length of received address is NOT more than 6 symbols + + // Sending the message + $context->sendMessage('⚠️ *Адрес должен быть длиннее 6\-ти символов*'); + } + } + } + } + + // Deinitializing unnecessary variables + unset($account); + } + + /** + * Receiver address write + * + * Write received and accepted receiver address into account + * + * @param context $context + * + * @return void + */ + public static function receiver_address_write(context $context): void + { + // initializing account + $account = $context->get('account'); + + if ($account) { + // initialized the account + + $context->getUserDataItem('receiver_address')->then(function ($address) use ($context, $account) { + // Initialized receiver address + + if (!empty($address)) { + // Initialized receiver address + + // Writing receiver address into the account + $account->receiver = ['address' => $address] + ($account->receiver ?? []); + + // Deabstracting parameters + if ($account->language instanceof language) $account->language = $account->language?->name ?? settings::active()?->language->name; + if (isset($account->currency) && $account->currency instanceof currency) $account->currency = $account->currency?->name ?? settings::active()?->currency->name; if (document::update($account->__document())) { // Writed the account instance into the ArangoDB document - $ctx->sendMessage( + // Abstratcting paramters + $account->language = language::{$account->language}; + if (isset($account->currency)) $account->currency = currency::{$account->currency}; + + // Sending the message + $context->sendMessage( << [ @@ -1415,26 +2886,26 @@ final class telegram extends core 'remove_keyboard' => true ] ] - )->then(function ($message) use ($ctx) { - // Sended message + )->then(function ($message) use ($context) { + // Sended the message - // Deinitializing receiver name - $ctx->setUserDataItem('receiver_name', null); + // Deinitializing receiver address + $context->setUserDataItem('receiver_address', null); // Sending the account parameters menu - static::account_parameters($ctx); + static::account_parameters($context); }); } else { // Not writed the account instance into the ArangoDB document // Sending the message - $ctx->sendMessage('⚠️ *Не удалось записать ФИО*'); + $context->sendMessage('⚠️ *Не удалось записать адрес*'); } } else { - // Not initialized receiver name + // Not initialized receiver address // Sending the message - $ctx->sendMessage('⚠️ *Ошибка при регистрации ФИО*'); + $context->sendMessage('⚠️ *Ошибка при записи адреса*'); } }); } @@ -1442,4 +2913,155 @@ final class telegram extends core // Deinitializing unnecessary variables unset($account); } + + /** + * Order commentary request + * + * Request commentary + * + * @param context $context + * + * @return void + */ + public static function order_commentary_request(context $context): void + { + // Initializing account + $account = $context->get('account'); + + if ($account) { + // Initialized the account + + // Reading from the telegram user buffer + $context->getUserDataItem('order') + ->then(function ($order) use ($context) { + // Readed from the telegram user buffer + + if ($order instanceof order) { + // Initialized the order + + // Initializing the order identifier for the message + $identifier = $order->getKey(); + + // Sending the message + $context->sendMessage( + << [ + 'inline_keyboard' => [ + [ + ['text' => '❎ Отменить', 'callback_data' => 'order'] + ], + ], + 'disable_notification' => true, + 'remove_keyboard' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended message + + $context->nextStep([static::class, 'order_commenary_input'], true); + }); + } + }); + } + + // Deinitializing unnecessary variables + unset($account); + } + + /** + * Order commentary from input + * + * Receive order commentary from message + * + * @param context $context + * + * @return void + */ + public static function order_commenary_input(context $context): void + { + // Initializing account + $account = $context->get('account'); + + if ($account) { + // Initialized the account + + // Initializing received text (address) + $text = $context->getMessage()?->getText(); + + if (!empty($text)) { + // Initialized received text (address) + + // Sanitizing received text + $sanitized = static::unmarkdown($text); + + if (!empty($sanitized)) { + // Initialized sanitized received text (only numbers) + + if (mb_strlen($sanitized) > 3) { + // Length of received address is more than 3 symbols + + if (mb_strlen($sanitized) < 256) { + // Length of received address is less than 256 symbols + + // Readed the order from the user telegram buffer + $context->getUserDataItem('order') + ->then( + function ($order) use ($context, $account, $sanitized) { + // Readed the order from the user telegram buffer + + if ($order instanceof order) { + // Initialized the order + + // Writing the commentary into the order + $order->commentary = $sanitized; + + if (document::update($order->__document())) { + // Writed the order instance into the ArangoDB document + + // Sending the message + $context->sendMessage( + << [ + 'disable_notification' => true, + 'remove_keyboard' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended the message + + // Continuing the delivery registration process + static::order($context); + }); + } + } + } + ); + } else { + // Length of received address is NOT less than 256 symbols + + // Sending the message + $context->sendMessage('⚠️ *Адрес должен быть короче 256\-ти символов*'); + } + } else { + // Length of received address is NOT more than 3 symbols + + // Sending the message + $context->sendMessage('⚠️ *Адрес должен быть длиннее 3\-ти символов*'); + } + } + } + } + + // Deinitializing unnecessary variables + unset($account); + } } diff --git a/mirzaev/huesos/system/models/traits/document.php b/mirzaev/huesos/system/models/traits/document.php index 60b20b2..2f264ca 100755 --- a/mirzaev/huesos/system/models/traits/document.php +++ b/mirzaev/huesos/system/models/traits/document.php @@ -79,10 +79,12 @@ trait document /** * Connect * + * Searches for a connection document, otherwise creates one + * * @param collecton_interface $document Document * @param array &$errors Registry of errors * - * @return string|null The identifier of the created edge of the "connect" collection, if created + * @return string|null The identifier of the "connect" edge collection, if created or found */ public function connect(collection_interface $document, array &$errors = []): ?string { @@ -95,15 +97,46 @@ trait document if ($this->document instanceof _document) { // Initialized instance of the document from ArangoDB - // Writing document and exit (success) - return framework_document::write( - connect::COLLECTION, + // Searching for a connection + $found = collection::execute( + <<<'AQL' + FOR d IN @@collection + FILTER d._from == @_from && d._to == @_to && d.active == true + RETURN d + AQL, [ + '@collection' => connect::COLLECTION, '_from' => $document->getId(), '_to' => $this->document->getId() ], errors: $errors ); + + if ($found) { + // Found the connection document + + // Exit (success) + return $found->getId(); + } else { + // Not found the connection document + + // Creting the connection document + $created = framework_document::write( + connect::COLLECTION, + [ + '_from' => $document->getId(), + '_to' => $this->document->getId() + ], + errors: $errors + ); + + if ($created) { + // Created the connection document + + // Exit (success) + return $created; + } + } } else throw new exception('The instance of the document from ArangoDB is not initialized'); } else throw new exception('Failed to initialize ' . $document::TYPE->name . ' collection: ' . $document::COLLECTION); } else throw new exception('Failed to initialize ' . connect::TYPE->name . ' collection: ' . connect::COLLECTION); diff --git a/mirzaev/huesos/system/models/traits/yandex/disk.php b/mirzaev/huesos/system/models/traits/yandex/disk.php index 1fec65e..1105d5d 100755 --- a/mirzaev/huesos/system/models/traits/yandex/disk.php +++ b/mirzaev/huesos/system/models/traits/yandex/disk.php @@ -21,14 +21,14 @@ use exception; trait disk { /** - * Download file from "Yandex Disk" + * Download the file from "Yandex Disk" * * @param string $uri URI of the file from "Yandex Disk" * @param string $destination Destination to write the file * @param string|int $name Name for the file * @param array &$errors Registry of errors * - * @return array|false The [destination, name, content] of the downloaded file, if the file was downloaded + * @return array|false The [destination, name, content] array of the downloaded file, if the file was downloaded */ private static function download( string $uri, @@ -101,4 +101,52 @@ trait disk // Exit (fail) return false; } + + /** + * Initialize list of files inside the folder from "Yandex Disk" + * + * @param string $uri URI of the folder from "Yandex Disk" + * @param array &$errors Registry of errors + * + * @return array|false JSON objects list of files in the folder + */ + private static function list(string $uri, array &$errors = []): array|false + { + try { + if (!empty($uri)) { + // Not empty URI + + // Initializing URL of the file + $url = "https://cloud-api.yandex.net/v1/disk/public/resources?public_key=$uri"; + + // Checking if the folder is available + $session = curl_init($url); + curl_setopt($session, CURLOPT_RETURNTRANSFER, true); + curl_exec($session); + $code = curl_getinfo($session, CURLINFO_RESPONSE_CODE); + curl_close($session); + + if ($code === 200) { + // The folder is available + + // Downloading the list of files in the folder + $files = json_decode(file_get_contents($url)); + + // Exit (success) + return isset($files?->_embedded?->items) ? $files->_embedded->items : [$files]; + } else throw new exception("Failed to download list of files inside the folder by link: $uri"); + } else throw new exception("Empty URI"); + } catch (exception $e) { + // Writing to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Exit (fail) + return false; + } } diff --git a/mirzaev/huesos/system/public/index.php b/mirzaev/huesos/system/public/index.php index 13ad59d..4a21c76 100755 --- a/mirzaev/huesos/system/public/index.php +++ b/mirzaev/huesos/system/public/index.php @@ -25,6 +25,8 @@ define('THEME', 'default'); define('CDEK', require(SETTINGS . DIRECTORY_SEPARATOR . 'deliveries' . DIRECTORY_SEPARATOR . 'cdek.php')); +define('TELEGRAM_KEY', require(SETTINGS . DIRECTORY_SEPARATOR . 'telegram.php')); + // Initialize dependencies require ROOT . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php'; @@ -38,9 +40,12 @@ $core->router ->write('/cart', new route('cart', 'index', 'cart'), 'GET') ->write('/cart/product', new route('cart', 'product', 'cart'), 'PATCH') ->write('/cart/summary', new route('cart', 'summary', 'cart'), 'GET') - /* ->write('/cart/share', new route('cart', 'share', 'cart'), 'POST') */ ->write('/cart/share', new route('cart', 'share', 'cart'), 'POST') + ->write('/cart/attach', new route('cart', 'attach', 'cart'), 'POST') ->write('/order/robokassa', new route('cart', 'robokassa', 'cart'), 'GET') + ->write('/api/robokassa/result', new route('api\acquirings\robokassa', 'result'), 'POST') + ->write('/robokassa/success', new route('api\acquirings\robokassa', 'success'), 'GET') + ->write('/robokassa/fail', new route('api\acquirings\robokassa', 'fail'), 'GET') ->write('/account/write', new route('account', 'write', 'account'), 'PATCH') ->write('/session/write', new route('session', 'write', 'session'), 'PATCH') ->write('/session/connect/telegram', new route('session', 'telegram', 'session'), 'PUT') diff --git a/mirzaev/huesos/system/public/js/closing.js b/mirzaev/huesos/system/public/js/closing.js new file mode 100644 index 0000000..78cb801 --- /dev/null +++ b/mirzaev/huesos/system/public/js/closing.js @@ -0,0 +1,28 @@ +// Initializing the closing element +const closing = document.getElementById("closing"); +console.log(closing); +// Initializing the closing iterator +let iterator = + parseInt(closing.style.getPropertyValue("--iterator").replaceAll("'", "")) || + 0; +console.log(iterator); +// Initializing the closing inteval +const interval = setInterval(function () { + if (iterator-- <= 0) { + // Deinitializing the closing inteval + clearInterval(interval); + + core.modules.connect("telegram").then(() => { + // Imported the telegram module + + // Closing the window + core.telegram.api.close(); + }); + + // Exit (success) + return; + } + + // Writing the iterator into the closing element + closing.style.setProperty("--iterator", "'" + iterator + "'"); +}, 1000); diff --git a/mirzaev/huesos/system/public/js/core.js b/mirzaev/huesos/system/public/js/core.js index 2b872ee..b98cdd7 100755 --- a/mirzaev/huesos/system/public/js/core.js +++ b/mirzaev/huesos/system/public/js/core.js @@ -17,11 +17,11 @@ class core { // Window static window; - // The "loading" element - static status_loading = document.getElementById("loading"); + // Account + static account; - // The "account" element - static status_account = document.getElementById("account"); + // The "loading" element + static loading = document.getElementById("loading"); // The
element static header = document.body.getElementsByTagName("header")[0]; diff --git a/mirzaev/huesos/system/public/js/modules/account.mjs b/mirzaev/huesos/system/public/js/modules/account.mjs index 948efc8..502472e 100755 --- a/mirzaev/huesos/system/public/js/modules/account.mjs +++ b/mirzaev/huesos/system/public/js/modules/account.mjs @@ -30,10 +30,10 @@ export default class account { * @return {void} */ static authentication() { - core.status_loading.removeAttribute("disabled"); + core.loading.removeAttribute("disabled"); const timer_for_response = setTimeout(() => { - core.status_loading.setAttribute("disabled", true); + core.loading.setAttribute("disabled", true); }, 200); core.modules.connect("telegram").then(() => { @@ -44,7 +44,7 @@ export default class account { .request( "/session/connect/telegram", core.telegram.api.initData, - 'PUT' + "PUT", ) .then((json) => { if (json) { @@ -63,20 +63,66 @@ export default class account { // Success (not received errors) if (json.connected === true) { - core.status_loading.setAttribute("disabled", true); + // Deactivating the loading screen + core.loading.setAttribute("disabled", true); clearTimeout(timer_for_response); - const a = core.status_account.getElementsByTagName("a")[0]; - a.setAttribute("onclick", "core.account.profile()"); - a.innerText = json.domain.length > 0 - ? "@" + json.domain - : "ERROR"; + core.account = { + identifier: json.identifier + }; + + // Initializing the account element + const account = document.getElementById("account"); + + if (account instanceof HTMLElement) { + // Initialized the account element + + // Initializing the account link + const a = account.getElementsByTagName("a")[0]; + + if (a instanceof HTMLElement) { + // Initialized the account link + + a.setAttribute("onclick", "core.account.profile()"); + a.innerText = json.domain.length > 0 + ? "@" + json.domain + : "ERROR"; + } else { + // Not initialized the account link + + if (json.avatar) { + // Received the avatar image + + // Initialize the menu button icon + const icon = account.getElementsByTagName("i")[0]; + + if (icon instanceof HTMLElement) { + // Initialized the menu button icon + + setTimeout(function () { + // Hiding the menu button icon + icon.classList.add("hidden"); + }, 3000); + } + + // Initializing the avatar image element + const image = document.createElement("img"); + image.setAttribute("src", json.avatar); + image.style.setProperty("opacity", "0"); + image.style.setProperty("--animation-delay", "2s"); + image.classList.add("opacity", "animated"); + + // Writing the avatar image element + account.appendChild(image); + } + } + } } if ( json.language !== null && typeof json.language === "string" && - json.langiage.length === 2 + json.language.length === 2 ) { core.language = json.language; } diff --git a/mirzaev/huesos/system/public/js/modules/cart.mjs b/mirzaev/huesos/system/public/js/modules/cart.mjs index 0adae3e..d33c0fe 100755 --- a/mirzaev/huesos/system/public/js/modules/cart.mjs +++ b/mirzaev/huesos/system/public/js/modules/cart.mjs @@ -69,7 +69,7 @@ export default class cart { * @name Write (interface) * * @description - * Write the product in the cart + * Write the product into the cart * * @param {HTMLButtonElement|HTMLInputElement|null} element Handler elememnt of the product * @param {HTMLElement} product The product element @@ -388,7 +388,7 @@ export default class cart { static async share(button) { return await core.modules.connect("telegram").then( () => { - // Imported the damper module + // Imported the telegram module // Disabling button button?.setAttribute("disabled", true); @@ -771,6 +771,24 @@ Object.assign( } else { // Success (not received errors) + if (json.amount > 0) { + // The cart has products + + // Writing the CSS variable of the document element + document.documentElement.style.setProperty( + "--cart-amount", + '"' + json.amount + '"', + ); + } else { + // The cart has no products + + // Writing the CSS variable of the document element + document.documentElement.style.setProperty( + "--cart-amount", + "unset", + ); + } + // Initializing the summary amount element const amount = document.getElementById("amount"); @@ -844,7 +862,7 @@ Object.assign( try { // Request return await core.request("/cart/share", undefined, "POST") - .then((json) => { + .then(async (json) => { if (json) { // Received a JSON-response @@ -863,13 +881,43 @@ Object.assign( if (json.share) { // Received sharing hash - // Request to the chat-robot - core.telegram.api.sendData( + // Sending the request to the chat-robot + const sended = core.telegram.api.sendData( JSON.stringify({ type: "cart_share", hash: json.share, }), ); + + if (sended === undefined) { + // Failed to send the request + + if (core.account.identifier > 0) { + // Initialized the account identifier + + // Request + return await core.request( + "/cart/attach", + 'share=' + json.share, + "POST", + ).then((json) => { + if (json) { + // Received a JSON-response + + if (json.success) { + // Received the success status + + core.modules.connect("telegram").then(() => { + // Imported the telegram module + + // Closing the Telegram Mini App + core.telegram.api.close(); + }); + } + } + }); + } + } } /* if (json.robokassa) { diff --git a/mirzaev/huesos/system/public/js/modules/catalog.mjs b/mirzaev/huesos/system/public/js/modules/catalog.mjs index aa9bb74..26d23e6 100755 --- a/mirzaev/huesos/system/public/js/modules/catalog.mjs +++ b/mirzaev/huesos/system/public/js/modules/catalog.mjs @@ -415,13 +415,16 @@ Object.assign( // Initializing the search element const search = document.getElementById("search"); - if (search instanceof HTMLElement) { - // Found the search element + if ( + search instanceof HTMLElement && + search.parentElement?.getAttribute("id") !== "top" + ) { + // Found the search element in the
element and it is not fixed to the top - // Writing into the search element + // Writing into the search element in the
element search.outerHTML = json.search; } else { - // Not found the search element + // Not found the search element in the
element // Initialize the search element const search = document.createElement("search"); @@ -503,8 +506,11 @@ Object.assign( // Initializing the search element const search = document.getElementById("search"); - if (search instanceof HTMLElement) { - // Initialized the search element in the
element + if ( + search instanceof HTMLElement && + search.parentElement?.getAttribute("id") !== "top" + ) { + // Initialized the search element in the
element and it is not fixed to the top // Writing the categories
element after the search element in the
element core.main.insertBefore( @@ -604,9 +610,10 @@ Object.assign( const search = document.getElementById("search"); if ( - search instanceof HTMLElement + search instanceof HTMLElement && + search.parentElement?.getAttribute("id") !== "top" ) { - // Initialized the search element in the
element + // Initialized the search element in the
element and it is not fixed to the top // Writing the filters
element after the search element in the
element core.main.insertBefore( @@ -721,9 +728,10 @@ Object.assign( const search = document.getElementById("search"); if ( - search instanceof HTMLElement + search instanceof HTMLElement && + search.parentElement?.getAttribute("id") !== "top" ) { - // Initialized the search element in the
element + // Initialized the search element in the
element and it is not fixed to the top // Writing the sorting
element after the search element in the
element core.main.insertBefore( @@ -855,9 +863,11 @@ Object.assign( const search = document.getElementById("search"); if ( - search instanceof HTMLElement + search instanceof HTMLElement && + search.parentElement?.getAttribute("id") !== + "top" ) { - // Initialized the search element in the
element + // Initialized the search element in the
element and it is not fixed to the top // Writing the products
element after the search element in the
element core.main.insertBefore( @@ -1035,13 +1045,16 @@ Object.assign( // Initializing the search element const search = document.getElementById("search"); - if (search instanceof HTMLElement) { - // Found the search element + if ( + search instanceof HTMLElement && + search.parentElement?.getAttribute("id") !== "top" + ) { + // Found the search element int the
element and it is not fixed to the top - // Writing into the search element + // Writing into the search element in the
element search.outerHTML = json.search; } else { - // Not found the search element + // Not found the search element in the
element // Initialize the search element const search = document.createElement("search"); @@ -1123,8 +1136,11 @@ Object.assign( // Initializing the search element const search = document.getElementById("search"); - if (search instanceof HTMLElement) { - // Initialized the search element in the
element + if ( + search instanceof HTMLElement && + search.parentElement?.getAttribute("id") !== "top" + ) { + // Initialized the search element in the
element and it is not fixed to the top // Writing the categories
element after the search element in the
element core.main.insertBefore( @@ -1224,9 +1240,10 @@ Object.assign( const search = document.getElementById("search"); if ( - search instanceof HTMLElement + search instanceof HTMLElement && + search.parentElement?.getAttribute("id") !== "top" ) { - // Initialized the search element in the
element + // Initialized the search element in the
element and it is not fixed to the top // Writing the filters
element after the search element in the
element core.main.insertBefore( @@ -1341,9 +1358,10 @@ Object.assign( const search = document.getElementById("search"); if ( - search instanceof HTMLElement + search instanceof HTMLElement && + search.parentElement?.getAttribute("id") !== "top" ) { - // Initialized the search element in the
element + // Initialized the search element in the
element and it is not fixed to the top // Writing the sorting
element after the search element in the
element core.main.insertBefore( @@ -1475,9 +1493,10 @@ Object.assign( const search = document.getElementById("search"); if ( - search instanceof HTMLElement + search instanceof HTMLElement && + search.parentElement?.getAttribute("id") !== "top" ) { - // Initialized the search element in the
element + // Initialized the search element in the
element and it is not fixed to the top // Writing the products
element after the search element in the
element core.main.insertBefore( @@ -1730,6 +1749,7 @@ Object.assign( if (button) { core.telegram.api.MainButton.hide(); + // core.telegram.api.SecondaryButton.hide(); } setTimeout(() => { @@ -1798,6 +1818,7 @@ Object.assign( if (button) { core.telegram.api.MainButton.show(); + // core.telegram.api.SecondaryButton.show(); } images.removeEventListener("mouseup", _close); @@ -1895,6 +1916,11 @@ Object.assign( // Reinitialize parameter core.window = document.getElementById("window"); + // Go to the cart + const to_the_cart = () => { + window.location = "/cart"; + }; + // Write const add = () => { core.cart.write( @@ -1907,7 +1933,7 @@ Object.assign( core.telegram.api.MainButton .setText(json.product.cart.text.added) .setParams({ - color: "#90be36", + color: getComputedStyle(document.body).getPropertyValue('--product-button-cart-added-background') || core.telegram.api.themeParams.button_color, has_shine_effect: true, }) .offClick(add) @@ -1927,7 +1953,7 @@ Object.assign( core.telegram.api.MainButton .setText(json.product.cart.text.add) .setParams({ - color: core.telegram.api.themeParams.button_color, + color: getComputedStyle(document.body).getPropertyValue('--product-button-cart-background') || core.telegram.api.themeParams.button_color, // has_shine_effect: json.product.discount > 0, has_shine_effect: false, }) @@ -1940,7 +1966,7 @@ Object.assign( core.telegram.api.MainButton .setText(json.product.cart.text.added) .setParams({ - color: "#90be36", + color: getComputedStyle(document.body).getPropertyValue('--product-button-cart-added-background') || core.telegram.api.themeParams.button_color, has_shine_effect: true, }) .onClick(added) @@ -1952,7 +1978,7 @@ Object.assign( core.telegram.api.MainButton .setText(json.product.cart.text.add) .setParams({ - color: core.telegram.api.themeParams.button_color, + color: getComputedStyle(document.body).getPropertyValue('--product-button-cart-background') || core.telegram.api.themeParams.button_color, // has_shine_effect: json.product.discount > 0, has_shine_effect: false, }) @@ -1962,6 +1988,19 @@ Object.assign( .show(); } + /* core.telegram.api.SecondaryButton + .setText(json.product.cart.text.cart) + .setParams({ + position: "bottom", + text_color: core.telegram.api.themeParams.text_color, + color: + core.telegram.api.themeParams.secondary_bg_color, + }) + .onClick(to_the_cart) + .hideProgress() + .enable() + .show(); */ + // блокировка закрытия карточки let from; const _from = (event) => (from = event.target); @@ -2026,6 +2065,12 @@ Object.assign( .offClick(added) .disable() .hide(); + + // Deinitializin the "Secondary Button" of the "Web App" window + /* core.telegram.api.SecondaryButton + .offClick(to_the_cart) + .disable() + .hide(); */ }; const close = (event) => { diff --git a/mirzaev/huesos/system/public/js/telegram.js b/mirzaev/huesos/system/public/js/telegram.js index dac5e3f..2082c44 100755 --- a/mirzaev/huesos/system/public/js/telegram.js +++ b/mirzaev/huesos/system/public/js/telegram.js @@ -5,7 +5,7 @@ core.modules.connect(["telegram"]) // Imported the telegram module // Expanding the "Web App" window - // core.telegram.api.expand(); + core.telegram.api.expand(); // Writing settings for the "Web App" window core.telegram.api.enableVerticalSwipes(); diff --git a/mirzaev/huesos/system/public/robot.php b/mirzaev/huesos/system/public/robot.php index 553eb63..3f169e7 100755 --- a/mirzaev/huesos/system/public/robot.php +++ b/mirzaev/huesos/system/public/robot.php @@ -11,9 +11,9 @@ use mirzaev\huesos\controllers\core as controller, mirzaev\huesos\models\telegram; // Framework for Telegram -use Zanzara\Zanzara, - Zanzara\Context, - Zanzara\Config; +use Zanzara\Zanzara as zanzara, + Zanzara\Context as context, + Zanzara\Config as config; // Framework for ArangoDB use mirzaev\arangodb\document; @@ -34,6 +34,9 @@ define('STORAGE', __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . ' // Файл в формате xlsx с примером excel-документа для импорта каталога define('CATALOG_EXAMPLE', STORAGE . DIRECTORY_SEPARATOR . 'example.xlsx'); +// Файл +define('GREETING_VIDEO', STORAGE . DIRECTORY_SEPARATOR . 'greeting.mp4'); + // Файл в формате xlsx для импорта каталога define('CATALOG_IMPORT', STORAGE . DIRECTORY_SEPARATOR . 'import.xlsx'); @@ -59,15 +62,15 @@ require __DIR__ . DIRECTORY_SEPARATOR // Инициализация ядра моделей MINIMAL new model(true); -$config = new Config(); -$config->setParseMode(Config::PARSE_MODE_MARKDOWN); +$config = new config(); +$config->setParseMode(config::PARSE_MODE_MARKDOWN); $config->useReactFileSystem(true); -$bot = new Zanzara(TELEGRAM_KEY, $config); +$robot = new zanzara(TELEGRAM_KEY, $config); -$bot->onUpdate(function (Context $ctx): void { +$robot->onUpdate(function (context $context): void { // Initializing the message - $message = $ctx->getMessage(); + $message = $context->getMessage(); // Initializing the "web app" data $app = $message?->getWebAppData(); @@ -82,13 +85,13 @@ $bot->onUpdate(function (Context $ctx): void { // Cart attaching // Attaching cart to the Telegram account - telegram::cart_attach($ctx, $request->hash); + telegram::cart_attach($context, $request->hash); } } else { // Not initialized the "web app" data // Initializing account - $account = $ctx->get('account'); + $account = $context->get('account'); if ($account) { // Initialized the account @@ -117,7 +120,9 @@ $bot->onUpdate(function (Context $ctx): void { if (document::update($account->__document())) { // Writed the account instance into the ArangoDB document - $ctx->sendMessage( + /* + // Sending the message + $context->sendMessage( <<onUpdate(function (Context $ctx): void { 'remove_keyboard' => true ] ] - )->then(function ($message) use ($ctx) { + )->then(function ($message) use ($context) { // Sended message // Sending the account parameters menu - telegram::account_parameters($ctx); + telegram::account_parameters($context); + }); */ + + // Sending the message + $context->sendMessage( + << [ + 'remove_keyboard' => true + ] + ] + )->then(function ($message) use ($context) { + // Sended message + + // Sending the account parameters menu + telegram::account_parameters($context); }); } else { // Not writed the account instance into the ArangoDB document // Sending the message - $ctx->sendMessage('⚠️ *Не удалось записать SIM\-номер*'); + $context->sendMessage('⚠️ *Не удалось записать SIM\-номер*'); } } } @@ -147,42 +169,71 @@ $bot->onUpdate(function (Context $ctx): void { unset($app); }); -$bot->onCommand('start', fn($ctx) => telegram::start($ctx)); -$bot->onCommand('contacts', fn($ctx) => telegram::contacts($ctx)); -$bot->onCommand('company', fn($ctx) => telegram::company($ctx)); -$bot->onCommand('community', fn($ctx) => telegram::community($ctx)); -$bot->onCommand('settings', fn($ctx) => telegram::settings($ctx)); +$robot->onCommand('start', fn(context $context) => telegram::start($context)); +$robot->onCommand('contacts', fn(context $context) => telegram::contacts($context)); +$robot->onCommand('company', fn(context $context) => telegram::company($context)); +$robot->onCommand('community', fn(context $context) => telegram::community($context)); +$robot->onCommand('settings', fn(context $context) => telegram::settings($context)); -$bot->onText('💬 Контакты', fn($ctx) => telegram::contacts($ctx)); -$bot->onText('🏛️ О компании', fn($ctx) => telegram::company($ctx)); -$bot->onText('🎯 Сообщество', fn($ctx) => telegram::community($ctx)); -$bot->onText('⚙️ Настройки', fn($ctx) => telegram::settings($ctx)); +$robot->onText('💬 Контакты', fn(context $context) => telegram::contacts($context)); +$robot->onText('🏛️ О компании', fn(context $context) => telegram::company($context)); +$robot->onText('🎯 Сообщество', fn(context $context) => telegram::community($context)); +$robot->onText('⚙️ Настройки', fn(context $context) => telegram::settings($context)); -$bot->onCbQueryData(['mail'], fn($ctx) => telegram::_mail($ctx)); -$bot->onCbQueryData(['import_request'], fn($ctx) => telegram::import_request($ctx)); -$bot->onCbQueryData(['order'], fn($ctx) => telegram::order($ctx)); -$bot->onCbQueryData(['tuning'], fn($ctx) => telegram::tuning($ctx)); -$bot->onCbQueryData(['brands'], fn($ctx) => telegram::brands($ctx)); +$robot->onCbQueryData(['contacts'], fn(context $context) => telegram::contacts($context)); +$robot->onCbQueryData(['company'], fn(context $context) => telegram::company($context)); +$robot->onCbQueryData(['community'], fn(context $context) => telegram::community($context)); +$robot->onCbQueryData(['settings'], fn(context $context) => telegram::settings($context)); -$bot->onCbQueryData(['receiver_sim_choose'], fn($ctx) => telegram::receiver_sim_choose($ctx)); -$bot->onCbQueryData(['receiver_sim_request'], fn($ctx) => telegram::receiver_sim_request($ctx)); -$bot->onCbQueryData(['receiver_sim_input'], fn($ctx) => telegram::receiver_sim_input($ctx)); -$bot->onCbQueryData(['receiver_sim_write'], fn($ctx) => telegram::receiver_sim_write($ctx)); +$robot->onCbQueryData(['mail'], fn(context $context) => telegram::_mail($context)); +$robot->onCbQueryData(['import_request'], fn(context $context) => telegram::import_request($context)); -$bot->onCbQueryData(['receiver_name_choose'], fn($ctx) => telegram::receiver_name_choose($ctx)); -$bot->onCbQueryData(['receiver_name_request'], fn($ctx) => telegram::receiver_name_request($ctx)); -$bot->onCbQueryData(['receiver_name_input'], fn($ctx) => telegram::receiver_name_input($ctx)); -$bot->onCbQueryData(['receiver_name_write'], fn($ctx) => telegram::receiver_name_write($ctx)); +$robot->onCbQueryData(['order_commentary_request'], fn(context $context) => telegram::order_commentary_request($context)); +$robot->onCbQueryData(['order'], fn(context $context) => telegram::order($context)); -$bot->onException(function (Context $ctx, $exception) { +$robot->onCbQueryData(['tuning'], fn(context $context) => telegram::tuning($context)); +$robot->onCbQueryData(['brands'], fn(context $context) => telegram::brands($context)); + +$robot->onCbQueryData(['cart_delivery'], fn(context $context) => telegram::cart_delivery($context)); + +$robot->onCbQueryData(['delivery_registration_destination_office'], fn(context $context) => telegram::delivery_registration_destination_office($context)); +$robot->onCbQueryData(['delivery_registration_destination_door'], fn(context $context) => telegram::delivery_registration_destination_door($context)); +$robot->onCbQueryData(['delivery_registration_sim_input'], fn(context $context) => telegram::delivery_registration_sim_input($context)); +$robot->onCbQueryData(['delivery_registration_name_input'], fn(context $context) => telegram::delivery_registration_name_input($context)); +$robot->onCbQueryData(['delivery_registration_address_input'], fn(context $context) => telegram::delivery_registration_address_input($context)); +$robot->onCbQueryData(['delivery_registration'], fn(context $context) => telegram::delivery_registration($context)); + +$robot->onCbQueryData(['account_parameters_force'], fn(context $context) => telegram::account_parameters($context, force: true)); + +$robot->onCbQueryData(['receiver_sim_choose'], fn(context $context) => telegram::receiver_sim_choose($context)); +$robot->onCbQueryData(['receiver_sim_request'], fn(context $context) => telegram::receiver_sim_request($context)); +/* $robot->onCbQueryData(['receiver_sim_input'], fn(context $context) => telegram::receiver_sim_input($context)); */ +$robot->onCbQueryData(['receiver_sim_write'], fn(context $context) => telegram::receiver_sim_write($context)); + +$robot->onCbQueryData(['receiver_name_choose'], fn(context $context) => telegram::receiver_name_choose($context)); +$robot->onCbQueryData(['receiver_name_request'], fn(context $context) => telegram::receiver_name_request($context)); +/* $robot->onCbQueryData(['receiver_name_input'], fn(context $context) => telegram::receiver_name_input($context)); */ +$robot->onCbQueryData(['receiver_name_write'], fn(context $context) => telegram::receiver_name_write($context)); + +$robot->onCbQueryData(['receiver_destination_choose'], fn(context $context) => telegram::receiver_destination_choose($context)); +$robot->onCbQueryData(['receiver_destination_office'], fn(context $context) => telegram::receiver_destination_office($context)); +$robot->onCbQueryData(['receiver_destination_door'], fn(context $context) => telegram::receiver_destination_door($context)); + +$robot->onCbQueryData(['receiver_address_choose'], fn(context $context) => telegram::receiver_address_choose($context)); +$robot->onCbQueryData(['receiver_address_request_office'], fn(context $context) => telegram::receiver_address_request($context, office: true)); +$robot->onCbQueryData(['receiver_address_request_door'], fn(context $context) => telegram::receiver_address_request($context, office: false)); +/* $robot->onCbQueryData(['receiver_address_input'], fn(context $context) => telegram::receiver_address_input($context)); */ +$robot->onCbQueryData(['receiver_address_write'], fn(context $context) => telegram::receiver_address_write($context)); + +$robot->onException(function (Context $context, $exception) { var_dump($exception); }); // Инициализация middleware с обработкой аккаунта -$bot->middleware([telegram::class, "account"]); +$robot->middleware([telegram::class, "account"]); // Инициализация middleware с обработкой технических работ разных уровней -$bot->middleware([telegram::class, "suspension"]); +$robot->middleware([telegram::class, "suspension"]); // Запуск чат-робота -$bot->run(); +$robot->run(); diff --git a/mirzaev/huesos/system/public/themes/default/css/account.css b/mirzaev/huesos/system/public/themes/default/css/account.css index 25571a9..26f0b44 100755 --- a/mirzaev/huesos/system/public/themes/default/css/account.css +++ b/mirzaev/huesos/system/public/themes/default/css/account.css @@ -9,3 +9,11 @@ section#account { display: flex; } +nav#menu>a#account>img { + position: absolute; + width: auto; + height: inherit; + object-fit: contain; + border-radius: 100%; + border: 2px solid var(--tg-theme-bottom-bar-bg-color); +} diff --git a/mirzaev/huesos/system/public/themes/default/css/acquirings/robokassa/fail.css b/mirzaev/huesos/system/public/themes/default/css/acquirings/robokassa/fail.css new file mode 100644 index 0000000..ed8f553 --- /dev/null +++ b/mirzaev/huesos/system/public/themes/default/css/acquirings/robokassa/fail.css @@ -0,0 +1,40 @@ +@charset "UTF-8"; + +main { + --offset-bottom: 2rem; + justify-content: center; + gap: unset; +} + +main>:is(:first-child, :last-child) { + margin-top: auto; +} + +main>h2 { + margin: unset; + margin-bottom: 0.5rem; + font-size: 1.2rem; + color: var(--tg-theme-accent-text-color); +} + +main>h2+small { + margin-bottom: calc(0 - var(--offset-bottom)); + color: var(--tg-theme-subtitle-text-color); +} + +main>#closing { + display: flex; + align-items: center; + font-size: 0.8rem; + margin-bottom: var(--offset-bottom); +} + +main>#closing>i.icon:first-child { + margin-right: 1rem; +} + +main>#closing:after { + content: ': ' var(--iterator); + font-weight: bold; + color: var(--tg-theme-accent-text-color); +} diff --git a/mirzaev/huesos/system/public/themes/default/css/acquirings/robokassa/success.css b/mirzaev/huesos/system/public/themes/default/css/acquirings/robokassa/success.css new file mode 100644 index 0000000..ed8f553 --- /dev/null +++ b/mirzaev/huesos/system/public/themes/default/css/acquirings/robokassa/success.css @@ -0,0 +1,40 @@ +@charset "UTF-8"; + +main { + --offset-bottom: 2rem; + justify-content: center; + gap: unset; +} + +main>:is(:first-child, :last-child) { + margin-top: auto; +} + +main>h2 { + margin: unset; + margin-bottom: 0.5rem; + font-size: 1.2rem; + color: var(--tg-theme-accent-text-color); +} + +main>h2+small { + margin-bottom: calc(0 - var(--offset-bottom)); + color: var(--tg-theme-subtitle-text-color); +} + +main>#closing { + display: flex; + align-items: center; + font-size: 0.8rem; + margin-bottom: var(--offset-bottom); +} + +main>#closing>i.icon:first-child { + margin-right: 1rem; +} + +main>#closing:after { + content: ': ' var(--iterator); + font-weight: bold; + color: var(--tg-theme-accent-text-color); +} diff --git a/mirzaev/huesos/system/public/themes/default/css/animations.css b/mirzaev/huesos/system/public/themes/default/css/animations.css index 7942108..d7a0028 100644 --- a/mirzaev/huesos/system/public/themes/default/css/animations.css +++ b/mirzaev/huesos/system/public/themes/default/css/animations.css @@ -1,5 +1,24 @@ @charset "UTF-8"; +@keyframes slide-down { + 0% { + transform: translate(0, -100%); + clip-path: polygon(0% 100%, 100% 100%, 100% 200%, 0% 200%); + } + + 100% { + transform: translate(0, 0%); + clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%); + } +} + +.slide.down.animated { + animation-duration: var(--animation-duration, 0.25s); + animation-name: slide-down; + animation-fill-mode: forwards; + animation-timing-function: var(--animatiom-timing, ease-out); +} + @keyframes slide-down-revert { 0% { transform: translate(0, 0%); @@ -13,8 +32,26 @@ } .slide.down.revert.animated { - animation-duration: var(--animation-duration, 0.2s); + animation-duration: var(--animation-duration, 0.25s); animation-name: slide-down-revert; animation-fill-mode: forwards; - animation-timing-function: cubic-bezier(1, 0, 1, 1); + animation-timing-function: var(--animatiom-timing, ease-in); +} + +@keyframes opacity { + 0% { + opacity: 0%; + } + + 100% { + opacity: 100%; + } +} + +.opacity.animated { + animation-duration: var(--animation-duration, 0.25s); + animation-name: opacity; + animation-fill-mode: forwards; + animation-timing-function: var(--animatiom-timing, ease-in); + animation-delay: var(--animation-delay, 0s); } diff --git a/mirzaev/huesos/system/public/themes/default/css/cart.css b/mirzaev/huesos/system/public/themes/default/css/cart.css index 9547d11..94eb646 100755 --- a/mirzaev/huesos/system/public/themes/default/css/cart.css +++ b/mirzaev/huesos/system/public/themes/default/css/cart.css @@ -7,6 +7,10 @@ main>section:is(#summary, #products, #delivery, #delivery_request) { overflow: hidden; } +main:not(:has(h2#title + section#delivery))>h2#title { + margin-bottom: 1rem; +} + main>section:is(#summary, #delivery) { background-color: var(--tg-theme-section-bg-color); } @@ -245,12 +249,13 @@ main>section#products>article.product>a { } main>section#products>article.product>a>img:first-of-type { - /* width: 5rem; */ - min-width: 5rem; + width: 7rem; + /* min-width: 5rem; */ min-height: 100%; object-fit: cover; image-rendering: auto; border-radius: 0.75rem; + border: 0.2rem solid var(--tg-theme-hint-color); box-shadow: -5px 0px 50px 10px rgba(0, 0, 0, 0.4); -webkit-box-shadow: -5px 0px 50px 10px rgba(0, 0, 0, 0.4); -moz-box-shadow: -5px 0px 50px 10px rgba(0, 0, 0, 0.4); @@ -276,12 +281,17 @@ main>section#products>article.product>div>div.head { gap: 1rem; } +main>section#products>article.product>div>div.head>button { + align-self: start; +} + main>section#products>article.product>div>div>button:first-of-type { margin-left: auto; } main>section#products>article.product>div>div>button { padding: 0.4rem; + color: var(--tg-theme-text-color); background: unset; } diff --git a/mirzaev/huesos/system/public/themes/default/css/catalog.css b/mirzaev/huesos/system/public/themes/default/css/catalog.css index 6f4c106..ffc42b9 100755 --- a/mirzaev/huesos/system/public/themes/default/css/catalog.css +++ b/mirzaev/huesos/system/public/themes/default/css/catalog.css @@ -19,9 +19,20 @@ main>section#categories>a.category[type="button"] { overflow: hidden; border-radius: 0.75rem; color: var(--tg-theme-button-text-color); - background-color: var(--tg-theme-button-color); + background: unset; } +main>section#categories>a.category[type="button"]:after { + z-index: -100; + position: absoulute; + left: 0; + top: 0; + content: ''; + width: 100%; + height: 100%; + filter: brightness(0.8); + background-color: var(--tg-theme-button-color); +} main>section#categories:last-child { /* margin-bottom: unset; */ @@ -47,7 +58,7 @@ main>section#categories>a.category[type="button"]>img { height: 110%; object-fit: cover; /* filter: blur(1px); */ - filter: brightness(60%); + filter: contrast(1.2) brightness(60%); } main>section#categories>a.category[type="button"]:is(:hover, :focus)>img { @@ -63,10 +74,22 @@ main>section#categories>a.category[type="button"]>p { margin: unset; width: min-content; border-radius: 0.75rem; - background: var(--tg-theme-section-bg-color); - box-shadow: 0px 0px 8px 4px rgba(0, 0, 0, 0.3); - -webkit-box-shadow: 0px 0px 8px 4px rgba(0, 0, 0, 0.3); - -moz-box-shadow: 0px 0px 8px 4px rgba(0, 0, 0, 0.3); + /* background: var(--tg-theme-hint-color); */ +} + +main>section#categories>a.category[type="button"]>p:after { + z-index: -100; + position: absolute; + left: 0; + top: 0; + content: ''; + width: 100%; + height: 100%; + border-radius: 0.75rem; + background-color: var(--tg-theme-button-color); + box-shadow: 0px 0px 8px 4px rgba(0, 0, 0, 0.1); + -webkit-box-shadow: 0px 0px 8px 4px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0px 0px 8px 4px rgba(0, 0, 0, 0.1); } main>section#categories>a.category[type="button"]>p { @@ -75,8 +98,9 @@ main>section#categories>a.category[type="button"]>p { } main>section#filters { + --filters-height: 2rem; width: var(--width); - max-height: 2.5rem; + max-height: var(--filters-height); display: flex; align-items: start; } @@ -124,9 +148,11 @@ main>section#products>div.column>article.product:not(:is(:hover, :focus))>* { } main>section#products>div.column>article.product>a>img:first-of-type { - width: 100%; + --border: 0.2rem; + width: calc(100% - var(--border) * 2); image-rendering: auto; border-radius: 0.75rem; + border: 0.2rem solid var(--tg-theme-hint-color); box-shadow: 0px 5px 70px 20px rgba(0, 0, 0, 0.3); -webkit-box-shadow: 0px 5px 70px 20px rgba(0, 0, 0, 0.3); -moz-box-shadow: 0px 5px 70px 20px rgba(0, 0, 0, 0.3); @@ -144,9 +170,14 @@ main>section#products>div.column>article.product>a>p.title { font-weight: bold; overflow-wrap: anywhere; hyphens: auto; + color: var(--tg-theme-text-color); } main>section#products>div.column>article.product>a>p.title>span { + margin-top: 0.2rem; + display: block; + font-weight: 400; + font-size: small; color: var(--tg-theme-hint-color); } @@ -160,7 +191,8 @@ main>section#products>div.column>article.product>div[data-product="buttons"]:las border-radius: 0.75rem; } -main>section#products>div.column>article.product[data-product-amount]:not(:is([data-product-amount="0"], [data-product-amount="1"]))>div[data-product="buttons"]:last-of-type { +/* main>section#products>div.column>article.product[data-product-amount]:not(:is([data-product-amount="0"], [data-product-amount="1"]))>div[data-product="buttons"]:last-of-type { */ +main>section#products>div.column>article.product[data-product-amount]:not(:is([data-product-amount="0"]))>div[data-product="buttons"]:last-of-type { container-type: inline-size; container-name: product-buttons; } @@ -168,9 +200,11 @@ main>section#products>div.column>article.product[data-product-amount]:not(:is([d main>section#products>div.column>article.product>div[data-product="buttons"]>button[data-product-button="toggle"] { padding: 0; flex-grow: 1; + background-color: var(--catalog-button-cart-background, var(--tg-theme-button-color)); } -main>section#products>div.column>article.product:is([data-product-amount="0"], [data-product-amount="1"])>div[data-product="buttons"]>button[data-product-button="toggle"]>span[data-product-parameter="amount"], +/* main>section#products>div.column>article.product:is([data-product-amount="0"], [data-product-amount="1"])>div[data-product="buttons"]>button[data-product-button="toggle"]>span[data-product-parameter="amount"], */ +main>section#products>div.column>article.product:is([data-product-amount="0"])>div[data-product="buttons"]>button[data-product-button="toggle"]>span[data-product-parameter="amount"], main>section#products>div.column>article.product[data-product-amount="0"]>div[data-product="buttons"]>button:is([data-product-button="write"], [data-product-button="delete"]) { display: none; } @@ -180,8 +214,17 @@ main>section#products>div.column>article.product>div[data-product="buttons"]>but margin: 0 0.2rem; } +main>section#products>div.column>article.product[data-product-amount]:not([data-product-amount="0"])>div[data-product="buttons"]>button[data-product-button="toggle"] { + background-color: var(--catalog-button-cart-added-background, var(--tg-theme-button-color)); +} + main>section#products>div.column>article.product[data-product-amount]:not([data-product-amount="0"])>div[data-product="buttons"] { - filter: hue-rotate(calc(120deg + var(--hue-rotate-offset, 0deg))); + /* hehe */ + filter: var(--catalog-button-cart-added-background, hue-rotate(calc(120deg + var(--hue-rotate-offset, 0deg)))); +} + +main>section#products>div.column>article.product>div[data-product="buttons"]>button { + background-color: var(--catalog-button-cart-added-background, var(--tg-theme-button-color)); } @container product-buttons (max-width: 200px) { diff --git a/mirzaev/huesos/system/public/themes/default/css/icons/house.css b/mirzaev/huesos/system/public/themes/default/css/icons/house.css index efd5a0f..72cfbde 100644 --- a/mirzaev/huesos/system/public/themes/default/css/icons/house.css +++ b/mirzaev/huesos/system/public/themes/default/css/icons/house.css @@ -2,7 +2,7 @@ i.icon.house { position: relative; - margin-bottom: -2px; + margin-bottom: -7px; width: 18px; height: 14px; display: block; diff --git a/mirzaev/huesos/system/public/themes/default/css/icons/user.css b/mirzaev/huesos/system/public/themes/default/css/icons/user.css new file mode 100755 index 0000000..884de30 --- /dev/null +++ b/mirzaev/huesos/system/public/themes/default/css/icons/user.css @@ -0,0 +1,35 @@ +@charset "UTF-8"; + +i.icon.user { + width: 12px; + height: 18px; + display: block; + box-sizing: border-box; + transform: scale(1); +} + +i.icon.user::after, +i.icon.user::before { + content: ""; + position: absolute; + display: block; + box-sizing: border-box; + border: 2px solid; +} + +i.icon.user::before { + left: 2px; + top: 0; + width: 8px; + height: 8px; + border-radius: 30px; +} + +i.icon.user::after { + top: 9px; + width: 12px; + height: 9px; + border-bottom: 0; + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} diff --git a/mirzaev/huesos/system/public/themes/default/css/interface/select.css b/mirzaev/huesos/system/public/themes/default/css/interface/select.css index 5021c56..ff0e2b1 100755 --- a/mirzaev/huesos/system/public/themes/default/css/interface/select.css +++ b/mirzaev/huesos/system/public/themes/default/css/interface/select.css @@ -1,15 +1,16 @@ @charset "UTF-8"; -section[data-type="select"] { - --width: max(14rem, 20vw); - --height-element: 2rem; - --height-close: var(--height-element); - --height-open: max-content; +div[data-type="select"] { + --filter-width: max(14rem, 30vw); + --filter-button-width: 2.5rem; + --filter-height-element: var(--filters-height, 2rem); + --filter-height-close: var(--filter-height-element); + --filter-height-open: max-content; position: relative; - width: var(--width); + width: var(--filter-width); + min-width: var(--width); height: var(--height-close); display: flex; - flex-direction: column; cursor: pointer; border-radius: 0.75rem; overflow-x: hidden; @@ -17,18 +18,31 @@ section[data-type="select"] { transition: 0s; } -section[data-type="select"]>button:has(>i.icon.close) { - align-self: end; - height: 100%; +div[data-type="select"]>section { + position: relative; + height: var(--filter-height-close); + display: flex; + flex-direction: column; + flex-grow: 1; + cursor: pointer; + background-color: var(--tg-theme-button-color); + transition: 0s; +} + +div[data-type="select"]>button:has(>i.icon.close) { + z-index: 100; + align-self: start; + width: var(--filter-button-width); + height: var(--filter-height-close); padding: 0 0.4rem; } -section[data-type="select"]:has(input[id$="title"]:checked)>button:has(>i.icon.close), -section[data-type="select"]:focus>button:has(>i.icon.close) { +div[data-type="select"]:has(>section>input[id$="title"]:checked)>button:has(>i.icon.close), +div[data-type="select"]:focus>button:has(>i.icon.close) { display: none; } -section[data-type="select"]:not(:focus, :has(>button>i.icon.close)):after { +div[data-type="select"]:not(>section:focus, >section:has(>button>i.icon.close)):after { z-index: 30; content: ''; top: calc(50% - 2.5px); @@ -42,19 +56,19 @@ section[data-type="select"]:not(:focus, :has(>button>i.icon.close)):after { border-right: 5px solid transparent; } -section[data-type="select"]>input { +div[data-type="select"]>section>input { left: -99999px; position: absolute; opacity: 0; } -section[data-type="select"]>label { +div[data-type="select"]>section>label { z-index: 10; order: 2; top: 0; position: absolute; - width: 100%; - height: var(--height-element); + width: calc(100% + var(--filter-button-width)); + height: var(--filter-height-element); padding: 0 1rem; display: none; overflow: hidden; @@ -66,61 +80,62 @@ section[data-type="select"]>label { transition: 0s; } -section[data-type="select"]:is([data-select="open"], :focus)>input:not(:checked)+label[for$='title'] { +div[data-type="select"]>section:is([data-select="open"], :focus)>input:not(:checked)+label[for$='title'] { display: none; } -section[data-type="select"]:is([data-select="open"], :focus)>input:not(:checked)+label[for$='all']:not(:hover, :active, :focus) { +div[data-type="select"]>section:is([data-select="open"], :focus)>input:not(:checked)+label[for$='all']:not(:hover, :active, :focus) { filter: brightness(90%); } -section[data-type="select"]>input:not(:checked)+label { +div[data-type="select"]>section>input:not(:checked)+label { cursor: pointer; filter: brightness(80%); } -section[data-type="select"]:is([data-select="open"], :focus)>input+label:hover { +div[data-type="select"]>section:is([data-select="open"], :focus)>input+label:hover { filter: brightness(110%); } -section[data-type="select"]:is([data-select="open"], :focus)>input:checked+label:hover { +div[data-type="select"]>section:is([data-select="open"], :focus)>input:checked+label:hover { filter: brightness(120%); } -section[data-type="select"]:is([data-select="open"], :focus)>input+label:is(:active, :focus) { +div[data-type="select"]>section:is([data-select="open"], :focus)>input+label:is(:active, :focus) { filter: brightness(60%); } -section[data-type="select"]:is([data-select="open"], :focus)>input:checked+label:is(:active, :focus) { +div[data-type="select"]>section:is([data-select="open"], :focus)>input:checked+label:is(:active, :focus) { filter: brightness(70%); } -section[data-type="select"]>input:checked+label { +div[data-type="select"]>section>input:checked+label { order: 1; - max-width: calc(var(--width) - 2rem - 10px); + max-width: calc(var(--filter-width) - 2rem - 10px); display: inline; - line-height: var(--height-element); + line-height: var(--filter-height-element); padding-right: 0; } -section[data-type="select"]:is([data-select="open"], :focus)>input:checked+label { +div[data-type="select"]>section:is([data-select="open"], :focus)>input:checked+label { max-width: initial; padding-right: initial; } -section[data-type="select"]:is([data-select="open"], :focus) { - height: var(--height-open, max-content); +div[data-type="select"]>section:is([data-select="open"], :focus) { + height: var(--filter-height-open, max-content); } -section[data-type="select"]:is([data-select="open"], :focus)>label { +div[data-type="select"]>section:is([data-select="open"], :focus)>label { position: relative; display: inline; - line-height: var(--height-element); + line-height: var(--filter-height-element); pointer-events: all; } @media only screen and (max-width: 500px) { - section[data-type="select"]:only-child { + div[data-type="select"]>section:only-child { --width: 100% } } + diff --git a/mirzaev/huesos/system/public/themes/default/css/main.css b/mirzaev/huesos/system/public/themes/default/css/main.css index 35ce9cd..0628021 100755 --- a/mirzaev/huesos/system/public/themes/default/css/main.css +++ b/mirzaev/huesos/system/public/themes/default/css/main.css @@ -28,7 +28,8 @@ a { body { --gap: 16px; - --width: calc(100% - var(--gap) * 2); + /* --width: calc(100% - var(--gap) * 2); */ + --width: calc(100vw - var(--gap) * 2 - 1rem); --offset-x: 2%; width: 100%; height: 100%; @@ -49,9 +50,10 @@ body:has(section#window) { aside {} header { + z-index: 1000; container-type: inline-size; container-name: header; - margin-top: 2rem; + position: relative; padding: 0 var(--offset-x); display: flex; flex-direction: column; @@ -59,7 +61,12 @@ header { gap: 26px; } +body:has(>div#top>search)>header { + margin-top: var(--header-margin-top, 2rem); +} + main { + --gap-main: calc(var(--gap) + 10px); container-type: inline-size; container-name: main; flex-grow: 1; @@ -67,7 +74,7 @@ main { display: flex; flex-direction: column; align-items: center; - gap: calc(var(--gap) + 10px); + gap: var(--gap-main); transition: 0s; } @@ -101,7 +108,7 @@ main>article>h3 { margin-top: 2rem; } -main>search { +main>search.relative { --gap: 16px; --border-width: 1px; width: var(--width); @@ -113,7 +120,71 @@ main>search { overflow: clip; } -footer {} +div#top { + z-index: 1000; + position: fixed !important; + top: 0; + padding: 0.6rem 1rem; + display: flex; + flex-direction: column; + align-items: center; + overflow: hidden; + background-color: var(--tg-theme-bg-color); + transform: translate3d(0, 0, 0); +} + +div#top>search.fixed { + --gap: 16px; + --border-width: 1px; + width: var(--width); + display: flex; + flex-flow: row; + border-radius: 1.375rem; + backdrop-filter: contrast(0.8); + overflow: hidden; + border: 2px solid transparent; +} + +a#cart { + --size: 2.2rem; + position: fixed !important; + bottom: 1rem; + right: 1rem; + width: var(--size); + height: var(--size); + padding: 0.25rem 0.3rem 0.35rem 0.3rem; + border-radius: 0.75rem; + overflow: hidden; + background-color: var(--tg-theme-section-header-text-color); + box-shadow: 0px 0px 12px 3px rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0px 0px 12px 3px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0px 0px 12px 3px rgba(0, 0, 0, 0.2); + transform: translate3d(0, 0, 0); +} + +a#cart:before { + content: var(--cart-amount); + position: absolute; + right: -0.5rem; + top: -0.6rem; + padding: 0.2rem 0.3rem; + min-width: 0.7rem; + display: flex; + justify-content: center; + align-items: center; + font-size: small; + border-radius: 1.125rem; + border: 0.2rem solid var(--tg-theme-button-color); + color: var(--tg-theme-button-color); + background-color: var(--tg-theme-button-text-color); + box-shadow: 0px 0px 12px 3px rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0px 0px 12px 3px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0px 0px 12px 3px rgba(0, 0, 0, 0.2); +} + +footer { + margin-bottom: var(--footer-margin-bottom); +} footer>section#govno { align-items: center; @@ -256,6 +327,7 @@ input { .cost.currency:after { content: var(--currency); margin-left: var(--currency-offset, 0.1rem); + font-weight: normal; } .cost.plus:before { diff --git a/mirzaev/huesos/system/public/themes/default/css/menu.css b/mirzaev/huesos/system/public/themes/default/css/menu.css index 6b1fe6b..bb8e583 100755 --- a/mirzaev/huesos/system/public/themes/default/css/menu.css +++ b/mirzaev/huesos/system/public/themes/default/css/menu.css @@ -1,9 +1,8 @@ @charset "UTF-8"; -header>nav#menu { +nav#menu.relative { container-type: inline-size; container-name: menu; - margin-bottom: 1rem; width: var(--width); min-height: 3rem; display: flex; @@ -13,7 +12,7 @@ header>nav#menu { overflow: hidden; } -header>nav#menu>a[type="button"] { +nav#menu.relative>a[type="button"] { height: 3rem; padding: unset; border-radius: 1.375rem; @@ -21,34 +20,76 @@ header>nav#menu>a[type="button"] { background-color: var(--tg-theme-button-color); } -header>nav#menu>a[type=button]>:first-child { +nav#menu.relative>a[type=button]>:first-child { margin-left: 1rem; } -header>nav#menu>a[type="button"]>* { +nav#menu.relative>a[type="button"]>* { margin-right: 1rem; } @container header (max-width: 450px) { - header>nav#menu>a[type="button"]:nth-child(1)>i.icon+span { + nav#menu.relative>a[type="button"]:nth-child(1)>i.icon+span { display: none; } } @container header (max-width: 350px) { - header>nav#menu>a[type="button"]:nth-child(2)>i.icon+span { + nav#menu.relative>a[type="button"]:nth-child(2)>i.icon+span { display: none; } } @container header (max-width: 250px) { - header>nav#menu>a[type="button"]:nth-child(3)>i.icon+span { + nav#menu.relative>a[type="button"]:nth-child(3)>i.icon+span { display: none; } } @container header (max-width: 150px) { - header>nav#menu>a[type="button"]>i.icon+span { + nav#menu.relative>a[type="button"]>i.icon+span { display: none; } } + +nav#menu.fixed { + z-index: 1000; + position: fixed !important; + left: 0; + bottom: 0; + width: 100%; + height: var(--menu-height, 3rem); + display: flex; + flex-flow: row; + justify-content: space-around; + align-items: center; + overflow: hidden; + background-color: var(--tg-theme-secondary-bg-color); + transform: translate3d(0, 0, 0); +} + +nav#menu.fixed>a[type="button"] { + position: relative; + flex-grow: 1; + padding: 0.6rem; + color: var(--tg-theme-text-color); + background-color: unset; +} + +nav#menu.fixed>a[type="button"]>i.icon { + position: absolute; +} + +nav#menu.fixed>a[type="button"].cart:before { + content: var(--cart-amount); + position: absolute; + margin-right: -1.3rem; + margin-top: -1.5rem; + padding: 0.2rem 0.3rem; + min-width: 0.7rem; + display: flex; + justify-content: center; + align-items: center; + font-size: small; + color: var(--tg-color-scheme); +} diff --git a/mirzaev/huesos/system/settings/.gitignore b/mirzaev/huesos/system/settings/.gitignore index d1e495d..6a0825d 100755 --- a/mirzaev/huesos/system/settings/.gitignore +++ b/mirzaev/huesos/system/settings/.gitignore @@ -1,4 +1,6 @@ * +!acquirings/ +!acquirings/robokassa !deliveries/ !.gitignore !*.sample diff --git a/mirzaev/huesos/system/settings/acquirings/robokassa/test.php.sample b/mirzaev/huesos/system/settings/acquirings/robokassa/test.php.sample new file mode 100644 index 0000000..311705c --- /dev/null +++ b/mirzaev/huesos/system/settings/acquirings/robokassa/test.php.sample @@ -0,0 +1,7 @@ + '', + 'passwords' => ['', ''] +]; diff --git a/mirzaev/huesos/system/settings/acquirings/robokassa/work.php.sample b/mirzaev/huesos/system/settings/acquirings/robokassa/work.php.sample new file mode 100644 index 0000000..311705c --- /dev/null +++ b/mirzaev/huesos/system/settings/acquirings/robokassa/work.php.sample @@ -0,0 +1,7 @@ + '', + 'passwords' => ['', ''] +]; diff --git a/mirzaev/huesos/system/settings/project.php.sample b/mirzaev/huesos/system/settings/project.php.sample index 2409c84..752313b 100644 --- a/mirzaev/huesos/system/settings/project.php.sample +++ b/mirzaev/huesos/system/settings/project.php.sample @@ -13,5 +13,59 @@ return [ 'offer' => false, 'sim' => null, 'mail' => null + ], + 'search' => [ + 'enabled' => true, + 'position' => 'fixed' + ], + 'cart' => [ + 'enabled' => false + ], + 'css' => [ + 'catalog-button-cart-background' => '#40a7e3', + 'product-button-cart-background' => '#40a7e3', + 'catalog-button-cart-added-background' => '#90be36', + 'product-button-cart-added-background' => '#90be36' + ], + 'account' => [ + 'enabled' => false + ], + 'menu' => [ + 'enabled' => true, + 'position' => 'fixed' + ], + 'header' => [ + 'enabled' => true, + 'position' => 'fixed' + ], + 'acquirings' => [ + 'robokassa' => [ + 'enabled' => true, + 'mode' => 'test' + ] + ], + 'input' => [ + 'deliveries' => [ + 'site' => [], + 'chat' => [ + 'sim', + 'name', + 'destination', + 'address', + 'commentary' + ] + ] + ], + 'deliveries' => [ + 'cdek' => [ + 'enabled' => true, + 'label' => 'CDEK' + ] + ], + 'chats' => [ + [ + 'id' => -1002599391893, + 'orders' => true + ] ] ]; diff --git a/mirzaev/huesos/system/storage/.gitignore b/mirzaev/huesos/system/storage/.gitignore new file mode 100644 index 0000000..3ceaed3 --- /dev/null +++ b/mirzaev/huesos/system/storage/.gitignore @@ -0,0 +1 @@ +!*.mp4 diff --git a/mirzaev/huesos/system/storage/example.xlsx b/mirzaev/huesos/system/storage/example.xlsx old mode 100755 new mode 100644 index 5fdfe7c..0b67777 Binary files a/mirzaev/huesos/system/storage/example.xlsx and b/mirzaev/huesos/system/storage/example.xlsx differ diff --git a/mirzaev/huesos/system/storage/greeting.mp4 b/mirzaev/huesos/system/storage/greeting.mp4 new file mode 100644 index 0000000..579c55e Binary files /dev/null and b/mirzaev/huesos/system/storage/greeting.mp4 differ diff --git a/mirzaev/huesos/system/views/templater.php b/mirzaev/huesos/system/views/templater.php index 6b9dff1..da769ab 100755 --- a/mirzaev/huesos/system/views/templater.php +++ b/mirzaev/huesos/system/views/templater.php @@ -8,6 +8,7 @@ namespace mirzaev\huesos\views; use mirzaev\huesos\models\session, mirzaev\huesos\models\account, mirzaev\huesos\models\settings, + mirzaev\huesos\models\cart, mirzaev\huesos\models\enumerations\language, mirzaev\huesos\models\enumerations\currency; @@ -139,7 +140,7 @@ final class templater extends controller implements array_access 'sim_format', function (string|int|float|null $sim = null) { // Universalizing SIM-number - preg_match_all('/\d/', $sim, $numbers); + preg_match_all('/\d/', (string) $sim, $numbers); $universalized = implode($numbers[0]); // Deinitializing unnecessary variables( diff --git a/mirzaev/huesos/system/views/themes/default/account.html b/mirzaev/huesos/system/views/themes/default/account.html index 6697d4c..637e7be 100755 --- a/mirzaev/huesos/system/views/themes/default/account.html +++ b/mirzaev/huesos/system/views/themes/default/account.html @@ -3,6 +3,7 @@ {% endblock %} {% block body %} +{% if settings.account.enabled and not (settings.menu.enabled and settings.menu.position == 'fixed') %} {% if account is empty %}
+ {{ language.name == "ru" ? "товаров на " : "products worth" }} {{ cart.summary.cost ?? 0 }} {% if session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company].cost %} {{ session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company].cost }} diff --git a/mirzaev/huesos/system/views/themes/default/catalog/elements/cart.html b/mirzaev/huesos/system/views/themes/default/catalog/elements/cart.html new file mode 100644 index 0000000..675701c --- /dev/null +++ b/mirzaev/huesos/system/views/themes/default/catalog/elements/cart.html @@ -0,0 +1,3 @@ + + + diff --git a/mirzaev/huesos/system/views/themes/default/catalog/elements/filters.html b/mirzaev/huesos/system/views/themes/default/catalog/elements/filters.html index dd8d208..0c8da1f 100755 --- a/mirzaev/huesos/system/views/themes/default/catalog/elements/filters.html +++ b/mirzaev/huesos/system/views/themes/default/catalog/elements/filters.html @@ -1,23 +1,26 @@ {% if filters is not empty %}
-
- {% set buffer_brand = session.buffer.catalog.filters.brand ?? account.buffer.catalog.filters.brand %} - - - - {% for brand in filters.brands %} - - - {% endfor %} - -
+ {% for brand in filters.brands %} + + + {% endfor %} +
+ +
{% endif %} diff --git a/mirzaev/huesos/system/views/themes/default/catalog/elements/menu.html b/mirzaev/huesos/system/views/themes/default/catalog/elements/menu.html new file mode 100755 index 0000000..dd8d208 --- /dev/null +++ b/mirzaev/huesos/system/views/themes/default/catalog/elements/menu.html @@ -0,0 +1,23 @@ +{% if filters is not empty %} +
+
+ {% set buffer_brand = session.buffer.catalog.filters.brand ?? account.buffer.catalog.filters.brand %} + + + + {% for brand in filters.brands %} + + + {% endfor %} + +
+
+{% endif %} diff --git a/mirzaev/huesos/system/views/themes/default/catalog/elements/search.html b/mirzaev/huesos/system/views/themes/default/catalog/elements/search.html index ef25fc4..3c7f512 100755 --- a/mirzaev/huesos/system/views/themes/default/catalog/elements/search.html +++ b/mirzaev/huesos/system/views/themes/default/catalog/elements/search.html @@ -1,7 +1,21 @@ - +{% if settings.search.position == 'fixed' %} +
+ + + {% set buffer_search = session.buffer.catalog.search.text ?? account.buffer.catalog.search.text %} + + +
+{% elseif settings.search.position == 'relative' %} + {% set buffer_search = session.buffer.catalog.search.text ?? account.buffer.catalog.search.text %} - +{% endif %} diff --git a/mirzaev/huesos/system/views/themes/default/catalog/page.html b/mirzaev/huesos/system/views/themes/default/catalog/page.html index ddf9890..5919c93 100755 --- a/mirzaev/huesos/system/views/themes/default/catalog/page.html +++ b/mirzaev/huesos/system/views/themes/default/catalog/page.html @@ -11,12 +11,23 @@ {% endblock %} +{% block search %} +{% if settings.search.enabled and settings.search.position == 'fixed' %} +{% include "/themes/default/catalog/elements/search.html" %} +{% endif %} +{% endblock %} + {% block main %}

{{ h2 }}

+{% if settings.search.enabled and settings.search.position == 'relative' %} {% include "/themes/default/catalog/elements/search.html" %} +{% endif %} {% include "/themes/default/catalog/elements/categories.html" %} {% include "/themes/default/catalog/elements/filters.html" %} {% include "/themes/default/catalog/elements/products.html" %} +{% if settings.cart.enabled %} +{% include "/themes/default/catalog/elements/cart.html" %} +{% endif %} {% endblock %} {% block js %} diff --git a/mirzaev/huesos/system/views/themes/default/catalog/search.html.dev b/mirzaev/huesos/system/views/themes/default/catalog/search.html.dev new file mode 100644 index 0000000..46cb5f9 --- /dev/null +++ b/mirzaev/huesos/system/views/themes/default/catalog/search.html.dev @@ -0,0 +1,83 @@ + + diff --git a/mirzaev/huesos/system/views/themes/default/head.html b/mirzaev/huesos/system/views/themes/default/head.html index 8920a9b..4ff9911 100755 --- a/mirzaev/huesos/system/views/themes/default/head.html +++ b/mirzaev/huesos/system/views/themes/default/head.html @@ -4,7 +4,8 @@ {% block meta %} - + + {% for meta in head.metas %} {% endfor %} @@ -22,6 +23,27 @@ --currency: "{{ currency.symbol ?? '$' }}"; --days: "{{ language.name == 'ru' ? 'дней' : 'days' }}"; --days-short: "{{ language.name == 'ru' ? 'дн' : 'd' }}"; + {% if settings.search.enabled and settings.search.position == 'fixed' %} + {% if settings.menu.enabled %} + {% if settings.menu.position == 'fixed' %} + --header-margin-top: 3rem; + {% elseif settings.menu.position == 'relative' %} + --header-margin-top: 5rem; + {% endif %} + {% else %} + --header-margin-top: 3rem; + {% endif %} + {% endif %} + {% if settings.menu.enabled and settings.menu.position == 'fixed' %} + --menu-height: {{ settings.menu.height ?? '3rem' }}; + --footer-margin-bottom: var(--menu-height); + {% endif %} + {% for parameter, value in settings.css %} + --{{ parameter }}: {{ value }}; + {% endfor %} + {% if cart.summary.amount > 0 %} + --cart-amount: "{{ cart.summary.amount }}"; + {% endif %} } diff --git a/mirzaev/huesos/system/views/themes/default/header.html b/mirzaev/huesos/system/views/themes/default/header.html index 551dff2..30bf9fe 100755 --- a/mirzaev/huesos/system/views/themes/default/header.html +++ b/mirzaev/huesos/system/views/themes/default/header.html @@ -1,15 +1,24 @@ {% use "/themes/default/menu.html" with css as menu_css, body as menu_body, js as menu_js %} {% block css %} +{% if settings.menu.enabled %} {{ block('menu_css') }} +{% endif %} {% endblock %} {% block body %} -
+
+ {% if settings.menu.enabled and settings.menu.position == 'relative' %} {{ block('menu_body') }} + {% endif %}
+{% if settings.menu.enabled and settings.menu.position == 'fixed' %} +{{ block('menu_body') }} +{% endif %} {% endblock %} {% block js %} +{% if settings.menu.enabled %} {{ block('menu_js') }} +{% endif %} {% endblock %} diff --git a/mirzaev/huesos/system/views/themes/default/index.html b/mirzaev/huesos/system/views/themes/default/index.html index 3132e44..f1086c3 100755 --- a/mirzaev/huesos/system/views/themes/default/index.html +++ b/mirzaev/huesos/system/views/themes/default/index.html @@ -16,12 +16,20 @@ {% block body %} {{ block('account_body') }} + +{% if settings.header.enabled %} {{ block('header') }} +{% endif %} + +{% block search %} +{% endblock %} +
{% block main %} {{ main|raw }} {% endblock %}
+ {{ block('footer') }} {% endblock %} diff --git a/mirzaev/huesos/system/views/themes/default/menu.html b/mirzaev/huesos/system/views/themes/default/menu.html index 38497e6..f1bb240 100755 --- a/mirzaev/huesos/system/views/themes/default/menu.html +++ b/mirzaev/huesos/system/views/themes/default/menu.html @@ -8,11 +8,29 @@ {% endblock %} {% block body %} -