Compare commits
23 Commits
|
@ -1 +1,2 @@
|
||||||
|
node_modules
|
||||||
vendor
|
vendor
|
||||||
|
|
324
README.md
324
README.md
|
@ -1,51 +1,158 @@
|
||||||
# huesos
|
# huesos
|
||||||
Basis for developing chat-robots with "Web App" technology for Telegram
|
Base for creating shop chat-robots using Web App technology for [Telegram](https://telegram.org)
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
1. Tree-structured catalog
|
||||||
|
2. Product cards with images carousel ([mirzaev/hotline.mjs](https://git.svoboda.works/mirzaev/hotline.mjs))
|
||||||
|
3. Cart (CRUD with limits and session binding)
|
||||||
|
4. Saving user data (and session) for all devices
|
||||||
|
5. Deliveries settings (with interactive maps and automatic geolocation detection on smartphones)
|
||||||
|
6. Real time price generation
|
||||||
|
7. Interface according to all Telegram standards
|
||||||
|
8. Public offer, dynamic settings and suspensions
|
||||||
|
9. Multi-language and easy to add new languages
|
||||||
|
10. Multi-currency and easy to add new currencies
|
||||||
|
11. Loading products and categories from an excel-file with automatic updating of existing ones
|
||||||
|
12. Flag authorization system, separate access for testers
|
||||||
|
13. Sending the generated order directly to the chat-robot
|
||||||
|
14. Intelligent search by titles, descriptions and other parameters (Levenshtein algorithm + separate settings for different languages)
|
||||||
|
15. Asynchronous chat-robot and Web App based on dynamic queries (AJAX)
|
||||||
|
16. Modern non-relational database ready for scaling and integration with third-party CRM
|
||||||
|
17. Fully documented code in English
|
||||||
|
18. Customizable menu buttons
|
||||||
|
19. Responsive design with built-in Telegram buttons and haptic functions
|
||||||
|
20. Automatic download and compression of images in 4 sizes (currently only from Yandex.Disk, but the system is ready to add new sources)
|
||||||
|
21. Commercially approved fonts and pure CSS icons
|
||||||
|
22. Product filter panel using pure CSS
|
||||||
|
23. Damper technology on all user interaction functions ([mirzaev/damper.mjs](https://git.svoboda.works/mirzaev/damper.mjs))
|
||||||
|
24. Two-step registration system (entering other data after creating an order)
|
||||||
|
25. Delivery company selection system (ready for scaling)
|
||||||
|
26. Acquiring company selection system (ready for scaling)
|
||||||
|
27. Sending paid orders to the operators chat with the customer contacts
|
||||||
|
|
||||||
|
## Integrations
|
||||||
|
|
||||||
|
### Import
|
||||||
|
*Methods for importing products into the shop*<br>
|
||||||
|
1. Excel-file (products and categories)
|
||||||
|
|
||||||
|
### Images download
|
||||||
|
*Methods of transferring images when importing products into the shop*<br>
|
||||||
|
1. [Yandex.Disk](https://360.yandex.ru/disk/) (russian) ([API](https://yandex.com/dev/disk/))
|
||||||
|
|
||||||
|
### Delivery companies
|
||||||
|
*Companies that deliver products from the shop*<br>
|
||||||
|
1. [CDEK](https://www.cdek.ru/) (russian) ([API](https://api-docs.cdek.ru/29923741.html)) ([PHP library](https://github.com/TTATPuOT/cdek-sdk2.0))
|
||||||
|
|
||||||
|
### Acquiring companies
|
||||||
|
*Companies that provide acquiring for the shop*<br>
|
||||||
|
1. [Robokassa](https://robokassa.com) (russian) (no swift) ([API](https://docs.robokassa.ru/pay-interface/))
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
1. [PHP 8.4](https://www.php.net/releases/8.4/en.php)
|
||||||
|
2. [Composer](https://getcomposer.org/) (php package manager)
|
||||||
|
3. [MINIMAL](https://git.svoboda.works/mirzaev/minimal) (PHP framework)
|
||||||
|
4. [Twig](https://twig.symfony.com/) (HTML templater)
|
||||||
|
5. [Zanzara](https://github.com/badfarm/zanzara) (Telegram framework + ReactPHP)
|
||||||
|
6. [ArangoDB](https://docs.arangodb.com/3.11/about-arangodb/) (non-relational database)
|
||||||
|
7. [NGINX](https://nginx.org/en/) (web server) *(can be replaced)*
|
||||||
|
8. [SystemD](https://systemd.io/) (service manager) *(can be replaced)*
|
||||||
|
|
||||||
|
<small>You can find other dependencies in the file `/composer.json`</small>
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### AnangoDB
|
### AnangoDB
|
||||||
|
|
||||||
1. Create a Graph with the specified values
|
1. **Configure unix-socket**<br>
|
||||||
**Name:** catalog<br>
|
|
||||||
|
Edit the file `/etc/arangodb3/arangod.conf`<br>
|
||||||
|
`endpoint = tcp://127.0.0.1:8529` -> `endpoint = unix:///var/run/arangodb3/arango.sock` (this will disable the web panel)<br>
|
||||||
<br>
|
<br>
|
||||||
* Relatin 1
|
To make the web panel work, you can add this to the NGINX server settings:
|
||||||
|
```lua
|
||||||
|
server {
|
||||||
|
...
|
||||||
|
|
||||||
|
server_name arangodb.domain.zone;
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
allow YOUR_IP_ADDRESS;
|
||||||
|
allow 192.168.1.1/24;
|
||||||
|
allow 127.0.0.1;
|
||||||
|
deny all;
|
||||||
|
|
||||||
|
# ArangoDB
|
||||||
|
location / {
|
||||||
|
proxy_pass http://arangodb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream arangodb {
|
||||||
|
server unix:/var/run/arangodb3/arango.sock;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
[here is my solution for "permission denied" problem on Ubuntu (accepted by ArangoDB maintainer)](https://github.com/arangodb/arangodb/issues/17302)<br>
|
||||||
|
|
||||||
|
1. **Configure TCP (instead of unix-socket)**<br>
|
||||||
|
|
||||||
|
Edit the file `/etc/arangodb3/arangod.conf`<br>
|
||||||
|
`endpoint = tcp://127.0.0.1:8529` -> `endpoint = tcp://0.0.0.0:8529`<br>
|
||||||
|
|
||||||
|
Edit the file `mirzaev/huesos/system/settings/arangodb.php`<br>
|
||||||
|
`unix:///var/run/arangodb3/arango.sock` -> `tcp://YOUR_IP_ADDRESS:8529` (it is slow and not secure)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
2. **Create a Graph with the specified values**<br>
|
||||||
|
**Name:** catalog<br>
|
||||||
|
|
||||||
|
* Relation 1<br>
|
||||||
**edgeDefinition:** entry<br>
|
**edgeDefinition:** entry<br>
|
||||||
**fromCollections:** categoy, product<br>
|
**fromCollections:** category, product<br>
|
||||||
**toCollections:** category
|
**toCollections:** category
|
||||||
|
|
||||||
* Relation 2
|
* Relation 2<br>
|
||||||
**edgeDefinition:** reservation<br>
|
**edgeDefinition:** reservation<br>
|
||||||
**fromCollections:** product<br>
|
**fromCollections:** product<br>
|
||||||
**toCollections:** cart
|
**toCollections:** cart
|
||||||
|
|
||||||
2. Create a Graph with the specified values
|
---
|
||||||
|
|
||||||
|
3. **Create a Graph with the specified values**<br>
|
||||||
**Name:** users<br>
|
**Name:** users<br>
|
||||||
<br>
|
|
||||||
* Relation 1
|
* Relation 1<br>
|
||||||
**edgeDefinition:** connect<br>
|
**edgeDefinition:** connect<br>
|
||||||
**fromCollections:** cart, session<br>
|
**fromCollections:** cart, session<br>
|
||||||
**toCollections:** account, session
|
**toCollections:** account, session<br>
|
||||||
|
|
||||||
**Orphan Collections:** product
|
* Orphan Collections<br>
|
||||||
|
product
|
||||||
|
|
||||||
3. Create indexes for the "product" collection
|
---
|
||||||
|
|
||||||
|
4. **Create indexes for the "product" collection**<br>
|
||||||
**Type:** "Inverted Index"<br>
|
**Type:** "Inverted Index"<br>
|
||||||
**Fields:** name.ru<br>
|
**Fields:** name.ru<br>
|
||||||
**Analyzer:** "text_ru"<br>
|
**Analyzer:** "text_ru"<br>
|
||||||
**Search field:** true<br>
|
**Search field:** true<br>
|
||||||
**Name:** name_ru<br>
|
**Name:** name_ru<br><br>
|
||||||
<br>
|
|
||||||
*Add indexes for all search parameters and for all languages (search language is selected based on the user's language, <br>
|
*Add indexes for all search parameters and for all languages (search language is selected based on the user's language, <br>
|
||||||
otherwise from the default language specified in the active settings from **settings** collection document)*<br>
|
otherwise from the default language specified in the active settings from **settings** collection document)*<br>
|
||||||
<br>
|
<br>
|
||||||
*See fields in the `mirzaev/arming_bot/models/product`<br>
|
*See fields in the `mirzaev/arming_bot/models/product`<br>
|
||||||
**name.ru**, **description.ru** and **compatibility.ru***
|
**name.ru**, **description.ru** and **compatibility.ru***<br>
|
||||||
|
|
||||||
4. Create a View with the specified values
|
---
|
||||||
|
|
||||||
|
5. **Create a View with the specified values**<br>
|
||||||
**type:** search-alias (you can also use "arangosearch")<br>
|
**type:** search-alias (you can also use "arangosearch")<br>
|
||||||
**name:** **product**s_search<br>
|
**name:** **product**s_search<br>
|
||||||
**indexes:**<br>
|
**indexes:**<br><br>
|
||||||
<br>
|
|
||||||
You can copy an example of view file from here: `/examples/arangodb/views/products_search.json`
|
You can copy an example of view file from here: `/examples/arangodb/views/products_search.json`
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
@ -59,50 +166,177 @@ You can copy an example of view file from here: `/examples/arangodb/views/produc
|
||||||
|
|
||||||
### NGINX
|
### NGINX
|
||||||
|
|
||||||
1. Create a NGINX server
|
1. **Create a NGINX server**<br>
|
||||||
You can copy an example of server file from here: `/examples/nginx/server.conf`
|
You can copy an example of server file from here: `/examples/nginx/server.conf`
|
||||||
|
|
||||||
2. Add support for javascript modules
|
2. **Add support for javascript modules**<br>
|
||||||
Edit the file `/etc/nginx/mime.types`<br>
|
Edit the file `/etc/nginx/mime.types`<br>
|
||||||
`application/javascript js;` -> `application/javascript js mjs;`
|
`application/javascript js;` -> `application/javascript js mjs;`
|
||||||
|
|
||||||
|
3. **Generate a TLS/SSL sertificate** (via [certbot](http://certbot.eff.org/) for [ubuntu](https://ubuntu.com/))<br>
|
||||||
|
3.1. `sudo apt install certbot python3-certbot-nginx`<br>
|
||||||
|
3.2. `sudo certbot certonly --nginx` (The **domain** must already be **bound** to the **IP-address** of the server by `A-record` or `AAAA-record`)
|
||||||
|
|
||||||
|
5. **Firewall rules for HTTP and HTTPS** (for [ubuntu](https://ubuntu.com/))<br>
|
||||||
|
4.1 `sudo ufw allow "NGINX Full"`<br>
|
||||||
|
4.1.1 `sudo ufw allow 22` (make sure that the port for SSH connection is open)<br>
|
||||||
|
4.2 `sudo ufw enable`
|
||||||
|
|
||||||
### SystemD (or any alternative you like)
|
### SystemD (or any alternative you like)
|
||||||
You can copy an example of systemd file from here: `/examples/systemd/huesos.service`<br>
|
You can copy an example of systemd file from here: `/examples/systemd/huesos.service`<br>
|
||||||
<br>
|
1. `sudo cp huesos.service /etc/systemd/system/huesos.service && sudo chmod +x /etc/systemd/system/huesos.service`
|
||||||
**Execute:** `sudo cp huesos.service /etc/systemd/system/huesos.service && sudo chmod +x /etc/systemd/system/huesos.service`<br>
|
2. `sudo systemctl daemon-reload`
|
||||||
<br>
|
3. `sudo systemctl enable huesos`<br>
|
||||||
|
|
||||||
*before you execute the command think about **what it does** and whether the **paths** are specified correctly*<br>
|
*before you execute the command think about **what it does** and whether the **paths** are specified correctly*<br>
|
||||||
*the configuration file is very simple and you can remake it for any alternative to SystemD that you like*
|
*the configuration file is very simple and you can remake it for any alternative to SystemD that you like*
|
||||||
|
|
||||||
|
## Menu
|
||||||
|
*Menu inside the Web App*<br><br>
|
||||||
|
Make sure you have a **menu** collection (can be created automatically)<br>
|
||||||
|
You can copy a clean menu documents without comments from here: `/examples/arangodb/collections/menu`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"urn": "/", // Link
|
||||||
|
"name": {
|
||||||
|
"en": "Main page",
|
||||||
|
"ru": "Главная страница"
|
||||||
|
},
|
||||||
|
"style": { // The `style` attribute
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
"class": "",
|
||||||
|
"icon": { // Icon from `/themes/default/css/icons`
|
||||||
|
"style": { // The `style` attribute
|
||||||
|
"rotate": "-135deg"
|
||||||
|
},
|
||||||
|
"class": "arrow circle" // Classes of the icon
|
||||||
|
},
|
||||||
|
"image": { // Image at the background @deprecated?
|
||||||
|
"storage": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
Settings of chat-robot and Web App<br>
|
*Settings of chat-robot and Web App*<br><br>
|
||||||
<br>
|
|
||||||
Make sure you have a **settings** collection (can be created automatically) and at least one document with the "status" parameter set to "active"<br>
|
Make sure you have a **settings** collection (can be created automatically) and at least one document with the "status" parameter set to "active"<br>
|
||||||
You can copy a clean settings document without comments from here: `/examples/arangodb/collections/settings.json`
|
You can copy a clean settings document without comments from here: `/examples/arangodb/collections/settings.json`
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"status": "active",
|
"status": "active", // Values: "active", "inactive" (string) Status of the settings document?
|
||||||
"project": {
|
"project": {
|
||||||
"name": "PROJECT"
|
"name": "PROJECT" // Name of the projext (string)
|
||||||
},
|
},
|
||||||
"language": "en", // Will be converted to an instance of enumeration `mirzaev\arming_bot\models\enumerations\language`
|
"language": "en", // Will be converted to an instance of enumeration `mirzaev\arming_bot\models\enumerations\language`
|
||||||
"currency": "usd", // Will be converted to an instance of enumeration `mirzaev\arming_bot\models\enumerations\currency`
|
"currency": "usd", // Will be converted to an instance of enumeration `mirzaev\arming_bot\models\enumerations\currency`
|
||||||
"company": {
|
"company": {
|
||||||
"identifier": null, // Example: "000000000000000" (string|null) (if `null` it will not be displayed)
|
"identifier": null, // Example: "000000000000000" (string|null) (if `null` it will not be displayed)
|
||||||
"tax": null, // Example: "000000000000" (string|null) (if `null` it will not be displayed)
|
"tax": null, // Example: "000000000000" (string|null) (if `null` it will not be displayed)
|
||||||
"name": null, // Example: "COMPANY" (string|null) (if `null` it will not be displayed)
|
"name": null, // Example: "COMPANY" (string|null) (if `null` it will not be displayed)
|
||||||
"offer": false, // Display the data of a public offer in the footer? (bool) (does not affect the `/offer` page generation)
|
"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)
|
"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)
|
"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"
|
||||||
|
},
|
||||||
|
"catalog": {
|
||||||
|
"categories": {
|
||||||
|
"display": "column", // Values: "row" (flex wrap), "column" (rows) Type of the catalog display
|
||||||
|
"structure": "lists", // Values: "pages" (pages with categories and products), "lists" (all categories as tree lists on the main page)
|
||||||
|
"buttons": {
|
||||||
|
"height": "120px", // Examples: "80px", "120px", "180px" (string|null) Height of buttons
|
||||||
|
"background": "#fafafa", // Examples: "#fafafa", "yellow" (string|null) Color of buttons background
|
||||||
|
"separator": {
|
||||||
|
"enabled": true, // Enable separators?
|
||||||
|
"width": "60%" // Exaples: "100%", "80%", "60%" (string|null) Width of separators over images (relative to image width from the left)
|
||||||
|
},
|
||||||
|
"lists": {
|
||||||
|
"height": "800px", // Examples: "500px", "100%" (string|null) Maximum height of lists (`max-height` for animations working)
|
||||||
|
"background": null, // Examples: "#fafafa", "yellow" (string|null) Color of lists
|
||||||
|
"separator": null, // Examples: "#fafafa", "yellow" (string|null) Color of separators between rows
|
||||||
|
"separated": true, // Separate lists from its buttons?
|
||||||
|
"blocks": true, // Blocks instead of plain text?
|
||||||
|
"arrow": true // Add arrow at the right?
|
||||||
|
},
|
||||||
|
"texts": {
|
||||||
|
"position": {
|
||||||
|
"vertical": "center" // Values: "top", "center", "bottom" (string|null) Position of texts of ascendants categories
|
||||||
|
},
|
||||||
|
"width": "max(8rem, 20%)", // Examples: "60%", "5rem", "max(8rem, 20%)" (string|null) Width of the text section (left side of buttons)
|
||||||
|
"background": false, // Enable wrapping element for texts?
|
||||||
|
"title": {
|
||||||
|
"color": "#020202" // Examples: "#fafafa", "yellow" (string|null) Color of titles
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"color": "#121212" // Examples: "#fafafa", "yellow" (string|null) Color of descriptions
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"images": {
|
||||||
|
"filter": "contrast(1.2)" // Example: "contrast(1.2)" (string|null) Filter for images
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"cart": {
|
||||||
|
"enabled": true // Enable the cart button?
|
||||||
|
},
|
||||||
|
"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 // Enable the account section? (works only when opened from telegram `inline-button`)
|
||||||
|
},
|
||||||
|
"menu": {
|
||||||
|
"enabled": true, // Enable the main menu?
|
||||||
|
"position": "fixed" // Values: "fixed" (fixed to the bottom as a solid line), "relative" (at the top as separated buttons) (stirng) Position of the main menu
|
||||||
|
},
|
||||||
|
"header": {
|
||||||
|
"enabled": true, // Enable the header?
|
||||||
|
"position": "fixed" // Values: "fixed" (fixed to the bottom), "relative" (at the top) (stirng) Position of the header
|
||||||
|
},
|
||||||
|
"acquirings": {
|
||||||
|
"robokassa": {
|
||||||
|
"enabled": true, // Enable the Robokassa acquiring?
|
||||||
|
"mode": "test" // Values: "work", "test" (string) Mode of the Robokassa acquiring
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"input": {
|
||||||
|
"deliveries": {
|
||||||
|
"site": [], // Values: "sim", "name", "destination", "address", "commentary"
|
||||||
|
"chat": [
|
||||||
|
"sim",
|
||||||
|
"name",
|
||||||
|
"destination",
|
||||||
|
"address",
|
||||||
|
"commentary"
|
||||||
|
] // Values: "sim", "name", "destination", "address", "commentary"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"deliveries": {
|
||||||
|
"cdek": {
|
||||||
|
"enabled": true, // Enable CDEK delivery?
|
||||||
|
"label": "CDEK" // Name of the CDEK delivery
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"chats": [
|
||||||
|
{
|
||||||
|
"id": null, // Example: -1002599391893 (int) (negative number) The telegram chat identifier
|
||||||
|
"orders": true // Send orders? (for moderators)
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Suspensions
|
## Suspensions
|
||||||
System of suspensions of chat-robot and Web App<br>
|
*System of suspensions of chat-robot and Web App*<br><br>
|
||||||
<br>
|
|
||||||
Make sure you have a **suspension** collection (can be created automatically)<br>
|
Make sure you have a **suspension** collection (can be created automatically)<br>
|
||||||
You can copy a clean suspension document without comments from here: `/examples/arangodb/collections/suspension.json`
|
You can copy a clean suspension document without comments from here: `/examples/arangodb/collections/suspension.json`
|
||||||
```json
|
```json
|
||||||
|
@ -122,3 +356,13 @@ You can copy a clean suspension document without comments from here: `/examples/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Used by
|
||||||
|
*List of projects created on the basis of [huesos](https://git.svoboda.works/mirzaev/huesos)*
|
||||||
|
|
||||||
|
- ARMING [@arming_bot](https://t.me/arming_bot)<br>
|
||||||
|
*Russian weapons tuning shop* ([repository](https://git.svoboda.works/mirzaev/arming))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "mirzaev/arming_bot",
|
"name": "mirzaev/huesos",
|
||||||
"description": "Chat-robot for tuning weapons",
|
"description": "Chat-robot for tuning weapons",
|
||||||
"homepage": "https://t.me/arming_bot",
|
"homepage": "https://t.me/huesos",
|
||||||
"type": "chat-robot",
|
"type": "chat-robot",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"telegram",
|
"telegram",
|
||||||
|
@ -20,9 +20,10 @@
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.4",
|
"php": "^8.4",
|
||||||
"ext-gd": "^8.4",
|
"ext-gd": "^8.4",
|
||||||
|
"ext-intl": "^8.4",
|
||||||
"triagens/arangodb": "^3.8",
|
"triagens/arangodb": "^3.8",
|
||||||
"mirzaev/minimal": "^2.2",
|
"mirzaev/minimal": "^3.4.0",
|
||||||
"mirzaev/arangodb": "^1.3",
|
"mirzaev/arangodb": "^2",
|
||||||
"badfarm/zanzara": "^0.9.1",
|
"badfarm/zanzara": "^0.9.1",
|
||||||
"nyholm/psr7": "^1.8",
|
"nyholm/psr7": "^1.8",
|
||||||
"react/filesystem": "^0.1.2",
|
"react/filesystem": "^0.1.2",
|
||||||
|
@ -32,11 +33,12 @@
|
||||||
"avadim/fast-excel-reader": "^2.19",
|
"avadim/fast-excel-reader": "^2.19",
|
||||||
"ttatpuot/cdek-sdk2.0": "^1.2",
|
"ttatpuot/cdek-sdk2.0": "^1.2",
|
||||||
"guzzlehttp/guzzle": "^7.9",
|
"guzzlehttp/guzzle": "^7.9",
|
||||||
"php-http/guzzle7-adapter": "^1.0"
|
"php-http/guzzle7-adapter": "^1.0",
|
||||||
|
"react/async": "^4.3"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"mirzaev\\arming_bot\\": "mirzaev/arming_bot/system/"
|
"mirzaev\\huesos\\": "mirzaev/huesos/system/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimum-stability": "stable",
|
"minimum-stability": "stable",
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"urn": "/cart",
|
||||||
|
"name": {
|
||||||
|
"en": "Cart",
|
||||||
|
"ru": "Корзина"
|
||||||
|
},
|
||||||
|
"style": {
|
||||||
|
"order": 999
|
||||||
|
},
|
||||||
|
"class": "cart",
|
||||||
|
"icon": {
|
||||||
|
"style": {},
|
||||||
|
"class": "shopping cart"
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"storage": null
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"urn": "/",
|
||||||
|
"name": {
|
||||||
|
"en": "Main page",
|
||||||
|
"ru": "Главная страница"
|
||||||
|
},
|
||||||
|
"style": {
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
"class": "",
|
||||||
|
"icon": {
|
||||||
|
"style": {},
|
||||||
|
"class": "house"
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"storage": null
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,16 +1,27 @@
|
||||||
{
|
{
|
||||||
"status": "active",
|
"status": "active",
|
||||||
"project": {
|
"project": {
|
||||||
"name": "PROJECT"
|
"name": "PROJECT"
|
||||||
},
|
},
|
||||||
"language": "en",
|
"language": "en",
|
||||||
"currency": "usd",
|
"currency": "usd",
|
||||||
"company": {
|
"company": {
|
||||||
"identifier": null,
|
"identifier": null,
|
||||||
"tax": null,
|
"tax": null,
|
||||||
"name": null,
|
"name": null,
|
||||||
"offer": false,
|
"offer": false,
|
||||||
"sim": null,
|
"sim": null,
|
||||||
"mail": null
|
"mail": null
|
||||||
}
|
},
|
||||||
|
"search": {
|
||||||
|
"enabled": true,
|
||||||
|
"position": "fixed"
|
||||||
|
},
|
||||||
|
"cart": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"css": {
|
||||||
|
"catalog-button-cart-background": "#40a7e3",
|
||||||
|
"product-button-cart-background": "#40a7e3"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +1,41 @@
|
||||||
server {
|
#
|
||||||
listen 443 ssl;
|
# This section is commented out to make it possible to run NGINX without errors
|
||||||
listen [::]:443 ssl ipv6only=on;
|
# to generate TLS/SSL certificate via CertBot (see README.md)
|
||||||
|
#
|
||||||
|
# server {
|
||||||
|
# listen 443 default_server ssl;
|
||||||
|
# listen [::]:443 ssl default_server;
|
||||||
|
|
||||||
server_name domain.zone;
|
# server_name domain.zone;
|
||||||
|
|
||||||
root /var/www/project/mirzaev/huesos/system/public;
|
# root /var/www/huesos/mirzaev/huesos/system/public;
|
||||||
|
|
||||||
index index.php;
|
# index index.php;
|
||||||
|
|
||||||
ssl_certificate /etc/letsencrypt/live/domain.zone/fullchain.pem;
|
# ssl_certificate /etc/letsencrypt/live/domain.zone/fullchain.pem;
|
||||||
ssl_certificate_key /etc/letsencrypt/live/domain.zone/privkey.pem;
|
# ssl_certificate_key /etc/letsencrypt/live/domain.zone/privkey.pem;
|
||||||
include /etc/letsencrypt/options-ssl-nginx.conf;
|
# include /etc/letsencrypt/options-ssl-nginx.conf;
|
||||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
# ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
||||||
|
|
||||||
location / {
|
# location / {
|
||||||
try_files $uri $uri/ /index.php;
|
# try_files $uri $uri/ /index.php?$query_string;
|
||||||
}
|
# }
|
||||||
|
|
||||||
location /api/cdek {
|
# location /api/cdek {
|
||||||
rewrite ^/api/cdek(.*)$ /$1 break;
|
# rewrite ^/api/cdek(.*)$ /$1 break;
|
||||||
index cdek.php;
|
# index cdek.php;
|
||||||
}
|
# }
|
||||||
|
|
||||||
location ~ /(?<type>categories|products) {
|
# location ~ /(?<type>categories|products) {
|
||||||
root /var/www/arming_bot/mirzaev/arming_bot/system/storage;
|
# root /var/www/huesos/mirzaev/huesos/system/storage;
|
||||||
try_files $uri =404;
|
# try_files $uri =404;
|
||||||
}
|
# }
|
||||||
|
|
||||||
location ~ \.php$ {
|
# location ~ \.php$ {
|
||||||
include snippets/fastcgi-php.conf;
|
# include snippets/fastcgi-php.conf;
|
||||||
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
|
# fastcgi_pass unix:/run/php/php8.4-fpm.sock;
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
|
|
||||||
server {
|
server {
|
||||||
listen 80 default_server;
|
listen 80 default_server;
|
||||||
|
|
|
@ -5,7 +5,7 @@ Wants=network.target
|
||||||
After=syslog.target network-online.target
|
After=syslog.target network-online.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=sudo -u www-data /usr/bin/php /var/www/project/mirzaev/huesos/system/public/robot.php
|
ExecStart=sudo -u www-data /usr/bin/php /var/www/huesos/mirzaev/huesos/system/public/robot.php
|
||||||
PIDFile=/var/run/php/huesos.pid
|
PIDFile=/var/run/php/huesos.pid
|
||||||
RemainAfterExit=no
|
RemainAfterExit=no
|
||||||
RuntimeMaxSec=3600s
|
RuntimeMaxSec=3600s
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,43 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models;
|
|
||||||
|
|
||||||
// Files of the project
|
|
||||||
use mirzaev\arming_bot\models\core,
|
|
||||||
mirzaev\arming_bot\models\reservation,
|
|
||||||
mirzaev\arming_bot\models\traits\document as document_trait,
|
|
||||||
mirzaev\arming_bot\models\interfaces\document as document_interface,
|
|
||||||
mirzaev\arming_bot\models\interfaces\collection as collection_interface,
|
|
||||||
mirzaev\arming_bot\models\enumerations\language,
|
|
||||||
mirzaev\arming_bot\models\enumerations\currency;
|
|
||||||
|
|
||||||
// Framework for ArangoDB
|
|
||||||
use mirzaev\arangodb\collection,
|
|
||||||
mirzaev\arangodb\document;
|
|
||||||
|
|
||||||
// Library for ArangoDB
|
|
||||||
use ArangoDBClient\Document as _document;
|
|
||||||
|
|
||||||
// Built-in libraries
|
|
||||||
use exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Model of order
|
|
||||||
*
|
|
||||||
* @uses !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
||||||
* @package mirzaev\arming_bot\models
|
|
||||||
*
|
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
||||||
*/
|
|
||||||
final class order extends core implements document_interface, collection_interface
|
|
||||||
{
|
|
||||||
use document_trait;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of the collection in ArangoDB
|
|
||||||
*/
|
|
||||||
final public const string COLLECTION = 'order';
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,188 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace mirzaev\arming_bot;
|
|
||||||
|
|
||||||
// Files of the project
|
|
||||||
use mirzaev\arming_bot\controllers\core as controller,
|
|
||||||
mirzaev\arming_bot\models\core as model,
|
|
||||||
mirzaev\arming_bot\models\cart,
|
|
||||||
mirzaev\arming_bot\models\telegram;
|
|
||||||
|
|
||||||
// Framework for Telegram
|
|
||||||
use Zanzara\Zanzara,
|
|
||||||
Zanzara\Context,
|
|
||||||
Zanzara\Config;
|
|
||||||
|
|
||||||
// Framework for ArangoDB
|
|
||||||
use mirzaev\arangodb\document;
|
|
||||||
|
|
||||||
ini_set('error_reporting', E_ALL ^ E_DEPRECATED);
|
|
||||||
ini_set('display_errors', 1);
|
|
||||||
ini_set('display_startup_errors', 1);
|
|
||||||
|
|
||||||
// Версия робота
|
|
||||||
define('ROBOT_VERSION', '1.0.0');
|
|
||||||
|
|
||||||
// Путь до настроек
|
|
||||||
define('SETTINGS', __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'settings');
|
|
||||||
|
|
||||||
// Путь до хранилища
|
|
||||||
define('STORAGE', __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'storage');
|
|
||||||
|
|
||||||
// Файл в формате xlsx с примером excel-документа для импорта каталога
|
|
||||||
define('CATALOG_EXAMPLE', STORAGE . DIRECTORY_SEPARATOR . 'example.xlsx');
|
|
||||||
|
|
||||||
// Файл в формате xlsx для импорта каталога
|
|
||||||
define('CATALOG_IMPORT', STORAGE . DIRECTORY_SEPARATOR . 'import.xlsx');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ключ чат-робота Telegram
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
define('KEY', require(SETTINGS . DIRECTORY_SEPARATOR . 'telegram.php'));
|
|
||||||
define('TELEGRAM_KEY', require(SETTINGS . DIRECTORY_SEPARATOR . 'telegram.php'));
|
|
||||||
|
|
||||||
// Initialize dependencies
|
|
||||||
require __DIR__ . DIRECTORY_SEPARATOR
|
|
||||||
. '..' . DIRECTORY_SEPARATOR
|
|
||||||
. '..' . DIRECTORY_SEPARATOR
|
|
||||||
. '..' . DIRECTORY_SEPARATOR
|
|
||||||
. '..' . DIRECTORY_SEPARATOR
|
|
||||||
. 'vendor' . DIRECTORY_SEPARATOR
|
|
||||||
. 'autoload.php';
|
|
||||||
|
|
||||||
// Инициализация ядра контроллеров MINIMAL
|
|
||||||
/* new controller(new core, false); */
|
|
||||||
|
|
||||||
// Инициализация ядра моделей MINIMAL
|
|
||||||
new model(true);
|
|
||||||
|
|
||||||
$config = new Config();
|
|
||||||
$config->setParseMode(Config::PARSE_MODE_MARKDOWN);
|
|
||||||
$config->useReactFileSystem(true);
|
|
||||||
|
|
||||||
$bot = new Zanzara(TELEGRAM_KEY, $config);
|
|
||||||
|
|
||||||
$bot->onUpdate(function (Context $ctx): void {
|
|
||||||
// Initializing the message
|
|
||||||
$message = $ctx->getMessage();
|
|
||||||
|
|
||||||
// Initializing the "web app" data
|
|
||||||
$app = $message?->getWebAppData();
|
|
||||||
|
|
||||||
if (!empty($app)) {
|
|
||||||
// Initialized the "web app" data
|
|
||||||
|
|
||||||
// Initializing request from "web app" data
|
|
||||||
$request = json_decode($app->getData(), false, 10);
|
|
||||||
|
|
||||||
if ($request->type === 'cart_share') {
|
|
||||||
// Cart attaching
|
|
||||||
|
|
||||||
// Attaching cart to the Telegram account
|
|
||||||
telegram::cart_attach($ctx, $request->hash);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Not initialized the "web app" data
|
|
||||||
|
|
||||||
// Initializing account
|
|
||||||
$account = $ctx->get('account');
|
|
||||||
|
|
||||||
if ($account) {
|
|
||||||
// Initialized the account
|
|
||||||
|
|
||||||
if (!empty($message)) {
|
|
||||||
// Initialized the message
|
|
||||||
|
|
||||||
// Initializing the contact data
|
|
||||||
$contact = $message?->getContact();
|
|
||||||
|
|
||||||
if (!empty($contact)) {
|
|
||||||
// Initialized the contact data
|
|
||||||
|
|
||||||
// Sanitizing received SIM-number (only numbers)
|
|
||||||
$sanitized = preg_replace('/[^\d]/', '', $contact->getPhoneNumber());
|
|
||||||
|
|
||||||
if (!empty($sanitized)) {
|
|
||||||
// Sanitized receiver SIM-number
|
|
||||||
|
|
||||||
// Writing receiver SIM-number into the account
|
|
||||||
$account->receiver = ['sim' => (int) $sanitized] + ($account->receiver ?? []);
|
|
||||||
|
|
||||||
// Deabstracting the language parameter
|
|
||||||
$account->language = $account->language->name;
|
|
||||||
|
|
||||||
if (document::update($account->__document())) {
|
|
||||||
// Writed the account instance into the ArangoDB document
|
|
||||||
|
|
||||||
$ctx->sendMessage(
|
|
||||||
<<<TXT
|
|
||||||
✅ *SIM\-номер зарегистрирован:* $sanitized
|
|
||||||
TXT,
|
|
||||||
[
|
|
||||||
'reply_markup' => [
|
|
||||||
'remove_keyboard' => true
|
|
||||||
]
|
|
||||||
]
|
|
||||||
)->then(function ($message) use ($ctx) {
|
|
||||||
// Sended message
|
|
||||||
|
|
||||||
// Sending the account parameters menu
|
|
||||||
telegram::account_parameters($ctx);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Not writed the account instance into the ArangoDB document
|
|
||||||
|
|
||||||
// Sending the message
|
|
||||||
$ctx->sendMessage('⚠️ *Не удалось записать SIM\-номер*');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
$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));
|
|
||||||
|
|
||||||
$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));
|
|
||||||
|
|
||||||
$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));
|
|
||||||
|
|
||||||
$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));
|
|
||||||
|
|
||||||
$bot->onException(function (Context $ctx, $exception) {
|
|
||||||
var_dump($exception);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Инициализация middleware с обработкой аккаунта
|
|
||||||
$bot->middleware([telegram::class, "account"]);
|
|
||||||
|
|
||||||
// Инициализация middleware с обработкой технических работ разных уровней
|
|
||||||
$bot->middleware([telegram::class, "suspension"]);
|
|
||||||
|
|
||||||
// Запуск чат-робота
|
|
||||||
$bot->run();
|
|
|
@ -1,11 +0,0 @@
|
||||||
@charset "UTF-8";
|
|
||||||
|
|
||||||
section#account {
|
|
||||||
z-index: 999;
|
|
||||||
position: fixed;
|
|
||||||
bottom: 20px;
|
|
||||||
left: 20px;
|
|
||||||
height: 16px;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
@charset "UTF-8";
|
|
||||||
|
|
||||||
@keyframes slide-down-revert {
|
|
||||||
0% {
|
|
||||||
transform: translate(0, 0%);
|
|
||||||
clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
transform: translate(0, -100%);
|
|
||||||
clip-path: polygon(0% 100%, 100% 100%, 100% 200%, 0% 200%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.slide.down.revert.animated {
|
|
||||||
animation-duration: var(--animation-duration, 0.2s);
|
|
||||||
animation-name: slide-down-revert;
|
|
||||||
animation-fill-mode: forwards;
|
|
||||||
animation-timing-function: cubic-bezier(1, 0, 1, 1);
|
|
||||||
}
|
|
|
@ -1,188 +0,0 @@
|
||||||
@charset "UTF-8";
|
|
||||||
|
|
||||||
main>section#categories {
|
|
||||||
width: var(--width);
|
|
||||||
display: flex;
|
|
||||||
flex-flow: row wrap;
|
|
||||||
gap: var(--gap, 5px);
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#categories>a.category[type="button"] {
|
|
||||||
--padding: 0.7rem;
|
|
||||||
position: relative;
|
|
||||||
height: 23px;
|
|
||||||
padding: var(--padding);
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
flex-grow: 1;
|
|
||||||
overflow: hidden;
|
|
||||||
border-radius: 0.75rem;
|
|
||||||
color: var(--tg-theme-button-text-color);
|
|
||||||
background-color: var(--tg-theme-button-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
main>section#categories:last-child {
|
|
||||||
/* margin-bottom: unset; */
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#categories>a.category[type="button"]:has(>img) {
|
|
||||||
min-width: calc(50% - var(--padding) * 2);
|
|
||||||
height: 180px;
|
|
||||||
padding: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#categories>a.category[type="button"]>img {
|
|
||||||
position: absolute;
|
|
||||||
left: -5%;
|
|
||||||
top: -5%;
|
|
||||||
width: 110%;
|
|
||||||
height: 110%;
|
|
||||||
object-fit: cover;
|
|
||||||
/* filter: blur(1px); */
|
|
||||||
filter: brightness(60%);
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#categories>a.category[type="button"]:is(:hover, :focus)>img {
|
|
||||||
filter: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#categories>a.category[type="button"]:has(>img)>p {
|
|
||||||
position: absolute;
|
|
||||||
left: var(--padding);
|
|
||||||
bottom: var(--padding);
|
|
||||||
right: var(--padding);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#categories>a.category[type="button"]>p {
|
|
||||||
z-index: 100;
|
|
||||||
padding: 8px 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#filters {
|
|
||||||
width: var(--width);
|
|
||||||
max-height: 2.5rem;
|
|
||||||
display: flex;
|
|
||||||
align-items: start;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products {
|
|
||||||
--column: calc((100% - var(--gap)) / 2);
|
|
||||||
width: var(--width);
|
|
||||||
display: grid;
|
|
||||||
grid-gap: var(--gap);
|
|
||||||
grid-template-columns: repeat(2, var(--column));
|
|
||||||
grid-auto-flow: row dense;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>div.column {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: var(--gap);
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>div.column>article.product {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-grow: 0;
|
|
||||||
flex-direction: column;
|
|
||||||
border-radius: 0.75rem;
|
|
||||||
overflow: clip;
|
|
||||||
cursor: pointer;
|
|
||||||
backdrop-filter: brightness(0.7);
|
|
||||||
background-color: var(--tg-theme-section-bg-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>div.column>article.product:is(:hover, :focus) {
|
|
||||||
/* flex-grow: 0.1; */
|
|
||||||
/* background-color: var(--tg-theme-section-bg-color); */
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>div.column>article.product:is(:hover, :focus)>* {
|
|
||||||
transition: 0s;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>div.column>article.product:not(:is(:hover, :focus))>* {
|
|
||||||
transition: 0.2s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>div.column>article.product>a>img:first-of-type {
|
|
||||||
width: 100%;
|
|
||||||
image-rendering: auto;
|
|
||||||
border-radius: 0.75rem;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>div.column>article.product>a>img:first-of-type+* {
|
|
||||||
margin-top: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>div.column>article.product>a>p.title {
|
|
||||||
z-index: 50;
|
|
||||||
margin: unset;
|
|
||||||
padding: 4px 8px 8px;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
font-weight: bold;
|
|
||||||
overflow-wrap: anywhere;
|
|
||||||
hyphens: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>div.column>article.product>a>p.title>span {
|
|
||||||
color: var(--tg-theme-hint-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>div.column>article.product>div[data-product="buttons"]:last-of-type {
|
|
||||||
z-index: 100;
|
|
||||||
height: 33px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
overflow: hidden;
|
|
||||||
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 {
|
|
||||||
container-type: inline-size;
|
|
||||||
container-name: product-buttons;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>div.column>article.product>div[data-product="buttons"]>button[data-product-button="toggle"] {
|
|
||||||
padding: 0;
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
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[data-product-amount="0"]>div[data-product="buttons"]>button:is([data-product-button="write"], [data-product-button="delete"]) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>div.column>article.product>div[data-product="buttons"]>button[data-product-button="toggle"]>span[data-product-parameter="amount"]:after {
|
|
||||||
content: '*';
|
|
||||||
margin: 0 0.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@container product-buttons (max-width: 200px) {
|
|
||||||
main>section#products>div.column>article.product>div[data-product="buttons"]>button[data-product-button="toggle"]>span:is([data-product-parameter="cost"], [data-product-parameter="currency"]) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>div.column>article.product>div[data-product="buttons"]>button[data-product-button="toggle"]>span[data-product-parameter="amount"]:after {
|
|
||||||
content: unset;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,126 +0,0 @@
|
||||||
@charset "UTF-8";
|
|
||||||
|
|
||||||
section[data-type="select"] {
|
|
||||||
--width: max(14rem, 20vw);
|
|
||||||
--height-element: 2rem;
|
|
||||||
--height-close: var(--height-element);
|
|
||||||
--height-open: max-content;
|
|
||||||
position: relative;
|
|
||||||
width: var(--width);
|
|
||||||
height: var(--height-close);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
cursor: pointer;
|
|
||||||
border-radius: 0.75rem;
|
|
||||||
overflow-x: hidden;
|
|
||||||
background-color: var(--tg-theme-button-color);
|
|
||||||
transition: 0s;
|
|
||||||
}
|
|
||||||
|
|
||||||
section[data-type="select"]>button:has(>i.icon.close) {
|
|
||||||
align-self: end;
|
|
||||||
height: 100%;
|
|
||||||
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) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
section[data-type="select"]:not(:focus, :has(>button>i.icon.close)):after {
|
|
||||||
z-index: 30;
|
|
||||||
content: '';
|
|
||||||
top: calc(50% - 2.5px);
|
|
||||||
right: 1rem;
|
|
||||||
position: absolute;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
border-left: 5px solid transparent;
|
|
||||||
border-top: 5px solid var(--tg-theme-button-text-color, black);
|
|
||||||
border-right: 5px solid transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
section[data-type="select"]>input {
|
|
||||||
left: -99999px;
|
|
||||||
position: absolute;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
section[data-type="select"]>label {
|
|
||||||
z-index: 10;
|
|
||||||
order: 2;
|
|
||||||
top: 0;
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
height: var(--height-element);
|
|
||||||
padding: 0 1rem;
|
|
||||||
display: none;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
box-sizing: border-box;
|
|
||||||
pointer-events: none;
|
|
||||||
color: var(--tg-theme-button-text-color);
|
|
||||||
transition: 0s;
|
|
||||||
}
|
|
||||||
|
|
||||||
section[data-type="select"]: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) {
|
|
||||||
filter: brightness(90%);
|
|
||||||
}
|
|
||||||
|
|
||||||
section[data-type="select"]>input:not(:checked)+label {
|
|
||||||
cursor: pointer;
|
|
||||||
filter: brightness(80%);
|
|
||||||
}
|
|
||||||
|
|
||||||
section[data-type="select"]:is([data-select="open"], :focus)>input+label:hover {
|
|
||||||
filter: brightness(110%);
|
|
||||||
}
|
|
||||||
|
|
||||||
section[data-type="select"]: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) {
|
|
||||||
filter: brightness(60%);
|
|
||||||
}
|
|
||||||
|
|
||||||
section[data-type="select"]:is([data-select="open"], :focus)>input:checked+label:is(:active, :focus) {
|
|
||||||
filter: brightness(70%);
|
|
||||||
}
|
|
||||||
|
|
||||||
section[data-type="select"]>input:checked+label {
|
|
||||||
order: 1;
|
|
||||||
max-width: calc(var(--width) - 2rem - 10px);
|
|
||||||
display: inline;
|
|
||||||
line-height: var(--height-element);
|
|
||||||
padding-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
section[data-type="select"]: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);
|
|
||||||
}
|
|
||||||
|
|
||||||
section[data-type="select"]:is([data-select="open"], :focus)>label {
|
|
||||||
position: relative;
|
|
||||||
display: inline;
|
|
||||||
line-height: var(--height-element);
|
|
||||||
pointer-events: all;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 500px) {
|
|
||||||
section[data-type="select"]:only-child {
|
|
||||||
--width: 100%
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
@charset "UTF-8";
|
|
||||||
|
|
||||||
header>nav#menu {
|
|
||||||
container-type: inline-size;
|
|
||||||
container-name: menu;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
width: var(--width);
|
|
||||||
min-height: 3rem;
|
|
||||||
display: flex;
|
|
||||||
flex-flow: row wrap;
|
|
||||||
gap: 1rem;
|
|
||||||
border-radius: 1.375rem;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
header>nav#menu>a[type="button"] {
|
|
||||||
height: 3rem;
|
|
||||||
padding: unset;
|
|
||||||
border-radius: 1.375rem;
|
|
||||||
color: var(--tg-theme-button-text-color);
|
|
||||||
background-color: var(--tg-theme-button-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
header>nav#menu>a[type=button]>:first-child {
|
|
||||||
margin-left: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
header>nav#menu>a[type="button"]>* {
|
|
||||||
margin-right: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@container header (max-width: 450px) {
|
|
||||||
header>nav#menu>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 {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@container header (max-width: 250px) {
|
|
||||||
header>nav#menu>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 {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
return [
|
|
||||||
'account' => '',
|
|
||||||
'secret' => ''
|
|
||||||
];
|
|
|
@ -1,6 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
return [
|
|
||||||
'account' => '',
|
|
||||||
'secret' => ''
|
|
||||||
];
|
|
Binary file not shown.
|
@ -1,16 +0,0 @@
|
||||||
{% if categories is not empty %}
|
|
||||||
<section id="categories" class="unselectable">
|
|
||||||
{% for category in categories %}
|
|
||||||
<a id="category_{{ category.identifier }}" data-category-identifier="{{ category.identifier }}" class="category"
|
|
||||||
type="button" href="?category={{ category.identifier }}"
|
|
||||||
onclick="core.catalog.parameters.set('category', {{ category.identifier }}); return !core.catalog.search(event);"
|
|
||||||
onkeydown="event.keyCode === 13 && (core.catalog.parameters.set('category', {{ category.identifier }}), core.catalog.search(event))"
|
|
||||||
tabindex="3">
|
|
||||||
{% if category.images %}
|
|
||||||
<img src="{{ category.images.0.storage.400 }}" alt="{{ category.name }}" ondragstart="return false;">
|
|
||||||
{% endif %}
|
|
||||||
<p>{{ category.name }}</p>
|
|
||||||
</a>
|
|
||||||
{% endfor %}
|
|
||||||
</section>
|
|
||||||
{% endif %}
|
|
|
@ -1,7 +0,0 @@
|
||||||
<search id="search">
|
|
||||||
<label class="unselectable"><i class="icon search"></i></label>
|
|
||||||
{% set buffer_search = session.buffer.catalog.search.text ?? account.buffer.catalog.search.text %}
|
|
||||||
<input placeholder="{{ language.name == 'ru' ? 'Поиск по каталогу' : 'Search in the catalog' }}" type="search" tabindex="1"
|
|
||||||
onkeyup="event.keyCode === 9 || core.catalog.parameters.set('text', this.value); return core.catalog.search(event, this)"
|
|
||||||
{% if buffer_search is not empty %} value="{{ buffer_search }}" {% endif %} />
|
|
||||||
</search>
|
|
|
@ -1,28 +0,0 @@
|
||||||
{% block title %}
|
|
||||||
<title>{% if head.title is not empty %}{{ head.title }}{% else %}{{ settings.project.name }}{% endif %}</title>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block meta %}
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
||||||
{% for meta in head.metas %}
|
|
||||||
<meta {% for name, value in meta.attributes %}{{ name }}="{{ value }}" {% endfor %}>
|
|
||||||
{% endfor %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block css %}
|
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/main.css" />
|
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/icons/loading_spinner.css" rel="preload" />
|
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/loading.css" rel="preload" />
|
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/window.css" />
|
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/fonts/dejavu.css" />
|
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/fonts/kabrio.css" rel="preload" />
|
|
||||||
<style>
|
|
||||||
:root {
|
|
||||||
--currency: "{{ currency.symbol ?? '$' }}";
|
|
||||||
--days: "{{ language.name == 'ru' ? 'дней' : 'days' }}";
|
|
||||||
--days-short: "{{ language.name == 'ru' ? 'дн' : 'd' }}";
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/animations.css" />
|
|
||||||
{% endblock %}
|
|
|
@ -1,15 +0,0 @@
|
||||||
{% use "/themes/default/menu.html" with css as menu_css, body as menu_body, js as menu_js %}
|
|
||||||
|
|
||||||
{% block css %}
|
|
||||||
{{ block('menu_css') }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block body %}
|
|
||||||
<header>
|
|
||||||
{{ block('menu_body') }}
|
|
||||||
</header>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block js %}
|
|
||||||
{{ block('menu_js') }}
|
|
||||||
{% endblock %}
|
|
|
@ -1,32 +0,0 @@
|
||||||
{% block css %}
|
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/default/css/menu.css">
|
|
||||||
{% for button in menu %}
|
|
||||||
{% if button.icon %}
|
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/default/css/icons/{{ button.icon.class|replace({' ': '_'}) }}.css">
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block body %}
|
|
||||||
<nav id="menu">
|
|
||||||
{% for button in menu %}
|
|
||||||
<a href='{{ button.urn }}' onclick="return core.loader.load('{{ button.urn }}');" type="button" class="unselectable"
|
|
||||||
title="{{ button.name }}" {% if button.style %}
|
|
||||||
style="{% for parameter, value in button.style %}{{ parameter ~ ': ' ~ value ~ '; ' }}{% endfor %}" {% endif %}>
|
|
||||||
{% if button.icon %}
|
|
||||||
<i class="icon {{ button.icon.class }}" {% if button.icon.style %}
|
|
||||||
style="{% for parameter, value in button.icon.style %}{{ parameter ~ ': ' ~ value ~ '; ' }}{% endfor %}" {% endif
|
|
||||||
%}></i>
|
|
||||||
{% endif %}
|
|
||||||
<span>{{ button.name }}</span>
|
|
||||||
{% if button.image.storage %}
|
|
||||||
<img src="{{ button.image.storage }}" alt="{{ button.name }}" ondragstart="return false;">
|
|
||||||
{% endif %}
|
|
||||||
</a>
|
|
||||||
{% endfor %}
|
|
||||||
</nav>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block js %}
|
|
||||||
<script src="/js/menu.js"></script>
|
|
||||||
{% endblock %}
|
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\controllers;
|
namespace mirzaev\huesos\controllers;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\controllers\core;
|
use mirzaev\huesos\controllers\core;
|
||||||
|
|
||||||
// Framework for PHP
|
// Framework for PHP
|
||||||
use mirzaev\minimal\http\enumerations\status;
|
use mirzaev\minimal\http\enumerations\status;
|
||||||
|
@ -13,7 +13,7 @@ use mirzaev\minimal\http\enumerations\status;
|
||||||
/**
|
/**
|
||||||
* Controller of account
|
* Controller of account
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\controllers
|
* @package mirzaev\huesos\controllers
|
||||||
*
|
*
|
||||||
* @param array $errors Registry of errors
|
* @param array $errors Registry of errors
|
||||||
*
|
*
|
|
@ -0,0 +1,375 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace mirzaev\huesos\controllers\api\acquirings;
|
||||||
|
|
||||||
|
// Files of the project
|
||||||
|
use mirzaev\huesos\controllers\core,
|
||||||
|
mirzaev\huesos\models\order,
|
||||||
|
mirzaev\huesos\models\cart,
|
||||||
|
mirzaev\huesos\models\product,
|
||||||
|
mirzaev\huesos\models\telegram,
|
||||||
|
mirzaev\huesos\models\acquirings\robokassa as model,
|
||||||
|
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 ArangoDB
|
||||||
|
use mirzaev\arangodb\collection,
|
||||||
|
mirzaev\arangodb\document;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// Built-in libraries
|
||||||
|
use DateTime as datetime,
|
||||||
|
Exception as exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller of robokassa
|
||||||
|
*
|
||||||
|
* @package mirzaev\huesos\controllers\api\acquirings
|
||||||
|
*
|
||||||
|
* @param array $errors Registry of errors
|
||||||
|
*
|
||||||
|
* @method null result()
|
||||||
|
* @method null success()
|
||||||
|
* @method null fail()
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
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,
|
||||||
|
<<<TXT
|
||||||
|
📦 *Заказ* \#$identifier
|
||||||
|
|
||||||
|
$list
|
||||||
|
$part_cost$part_delivery
|
||||||
|
|
||||||
|
$part_receiver$part_commentary
|
||||||
|
TXT,
|
||||||
|
[
|
||||||
|
'reply_markup' => [
|
||||||
|
'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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,23 +2,34 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\controllers;
|
namespace mirzaev\huesos\controllers;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\controllers\core,
|
use mirzaev\huesos\controllers\core,
|
||||||
mirzaev\arming_bot\models\cart as model,
|
mirzaev\huesos\models\cart as model,
|
||||||
mirzaev\arming_bot\models\product,
|
mirzaev\huesos\models\product,
|
||||||
mirzaev\arming_bot\models\menu,
|
mirzaev\huesos\models\menu,
|
||||||
mirzaev\arming_bot\models\enumerations\language;
|
mirzaev\huesos\models\telegram,
|
||||||
|
mirzaev\huesos\models\enumerations\currency,
|
||||||
|
mirzaev\huesos\models\enumerations\language;
|
||||||
|
|
||||||
// Framework for PHP
|
// Framework for PHP
|
||||||
use mirzaev\minimal\http\enumerations\content,
|
use mirzaev\minimal\http\enumerations\content,
|
||||||
mirzaev\minimal\http\enumerations\status;
|
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
|
* Controller of cart
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\controllers
|
* @package mirzaev\huesos\controllers
|
||||||
*
|
*
|
||||||
* @param model|null $cart Instance of the cart
|
* @param model|null $cart Instance of the cart
|
||||||
* @param array $errors Registry of errors
|
* @param array $errors Registry of errors
|
||||||
|
@ -74,6 +85,9 @@ final class cart extends core
|
||||||
parameters: ['language' => $this->language->name],
|
parameters: ['language' => $this->language->name],
|
||||||
errors: $this->errors['menu']
|
errors: $this->errors['menu']
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Universalizing
|
||||||
|
if ($this->view->menu instanceof _document) $this->view->menu = [$this->view->menu];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializing the cart
|
// Initializing the cart
|
||||||
|
@ -110,12 +124,26 @@ final class cart extends core
|
||||||
$this->view->formatted = $formatted;
|
$this->view->formatted = $formatted;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializing types of avaiabld deliveries
|
if (array_search('address', $this->settings->input['deliveries']['site'], true) !== false) {
|
||||||
$this->view->deliveries = [
|
// The deliveries input is enabled for the site
|
||||||
'cdek' => [
|
|
||||||
'label' => 'CDEK'
|
// 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)) {
|
if (str_contains($this->request->headers['accept'], content::json->value)) {
|
||||||
// Request for JSON response
|
// Request for JSON response
|
||||||
|
@ -441,85 +469,147 @@ final class cart extends core
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pay
|
* Attach
|
||||||
*
|
*
|
||||||
* Pay for the cart
|
* Attach the cart
|
||||||
*
|
*
|
||||||
* @return null
|
* @return null
|
||||||
|
*
|
||||||
|
* @todo кажется я сделал хуйню
|
||||||
*/
|
*/
|
||||||
public function pay(): null
|
public function attach(?string $share = null): 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
|
// Request for JSON response
|
||||||
|
|
||||||
// Initializing the cart
|
if ($this->account) {
|
||||||
$this->cart ??= $this->account?->cart() ?? $this->session?->cart();
|
// Initialized the account
|
||||||
|
|
||||||
if ($this->cart instanceof model) {
|
$config = new config();
|
||||||
// Initialized the cart
|
$config->setParseMode(config::PARSE_MODE_MARKDOWN);
|
||||||
|
$config->useReactFileSystem(true);
|
||||||
|
/* $config->setLoop(loop::get()); */
|
||||||
|
|
||||||
if ($share = $this->cart->share ?? $this->cart->share()) {
|
$robot = new zanzara(TELEGRAM_KEY, $config);
|
||||||
// The cart is available for sharing
|
|
||||||
|
|
||||||
// Sending response
|
// Initializing cart
|
||||||
$this->response
|
$cart = model::_read(
|
||||||
->start()
|
filter: 'd.share == @share',
|
||||||
->clean()
|
sort: 'd.updated DESC, d.created DESC, d._key DESC',
|
||||||
->sse()
|
amount: 1,
|
||||||
->json([
|
page: 1,
|
||||||
'share' => $share,
|
parameters: ['share' => $share]
|
||||||
'errors' => $this->errors
|
);
|
||||||
])
|
|
||||||
->validate($this->request)
|
|
||||||
?->body()
|
|
||||||
->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deinitializing unnecessary variables
|
// 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(
|
||||||
|
<<<TXT
|
||||||
|
🛒 *Добавлена корзина* \#$identifier
|
||||||
|
|
||||||
|
$list
|
||||||
|
$part_cost$part_delivery
|
||||||
|
TXT,
|
||||||
|
[
|
||||||
|
'chat_id' => $this->account->identifier,
|
||||||
|
'reply_markup' => [
|
||||||
|
'inline_keyboard' => [
|
||||||
|
[
|
||||||
|
['text' => '🚚 Оформить доставку', 'callback_data' => 'cart_delivery'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'disable_notification' => true
|
||||||
|
]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deinitializing unnecessary variables
|
||||||
|
unset($cart, $list);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Exit (success/fail)
|
// Deinitializing unnecessary variables
|
||||||
return null;
|
unset($cart);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
$robot->getLoop()->run();
|
||||||
* 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');
|
|
||||||
|
|
||||||
// Sending response
|
// Sending response
|
||||||
$this->response
|
$this->response
|
||||||
->start()
|
->start()
|
||||||
->clean()
|
->clean()
|
||||||
->sse()
|
->sse()
|
||||||
->write($page)
|
->json([
|
||||||
|
'success' => true,
|
||||||
|
'errors' => $this->errors
|
||||||
|
])
|
||||||
->validate($this->request)
|
->validate($this->request)
|
||||||
?->body()
|
?->body()
|
||||||
->end();
|
->end();
|
||||||
|
|
||||||
// Deinitializing rendered page
|
|
||||||
unset($page);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exit (success/fail)
|
// Exit (success/fail)
|
|
@ -2,16 +2,17 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\controllers;
|
namespace mirzaev\huesos\controllers;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\controllers\core,
|
use mirzaev\huesos\controllers\core,
|
||||||
mirzaev\arming_bot\models\enumerations\language,
|
mirzaev\huesos\models\enumerations\language,
|
||||||
mirzaev\arming_bot\models\entry,
|
mirzaev\huesos\models\catalog as model,
|
||||||
mirzaev\arming_bot\models\category,
|
mirzaev\huesos\models\entry,
|
||||||
mirzaev\arming_bot\models\product,
|
mirzaev\huesos\models\category,
|
||||||
mirzaev\arming_bot\models\cart,
|
mirzaev\huesos\models\product,
|
||||||
mirzaev\arming_bot\models\menu;
|
mirzaev\huesos\models\cart,
|
||||||
|
mirzaev\huesos\models\menu;
|
||||||
|
|
||||||
// Framework for PHP
|
// Framework for PHP
|
||||||
use mirzaev\minimal\http\enumerations\content,
|
use mirzaev\minimal\http\enumerations\content,
|
||||||
|
@ -24,7 +25,7 @@ use ArangoDBClient\Document as _document;
|
||||||
/**
|
/**
|
||||||
* Controller of catalog
|
* Controller of catalog
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\controllers
|
* @package mirzaev\huesos\controllers
|
||||||
*
|
*
|
||||||
* @param cart|null $cart Instance of the cart
|
* @param cart|null $cart Instance of the cart
|
||||||
* @param array $errors Registry of errors
|
* @param array $errors Registry of errors
|
||||||
|
@ -52,7 +53,8 @@ final class catalog extends core
|
||||||
'session' => [],
|
'session' => [],
|
||||||
'account' => [],
|
'account' => [],
|
||||||
'menu' => [],
|
'menu' => [],
|
||||||
'catalog' => []
|
'catalog' => [],
|
||||||
|
'cart' => []
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -80,9 +82,13 @@ final class catalog extends core
|
||||||
// Initializing the cart
|
// Initializing the cart
|
||||||
$this->cart ??= $this->account?->cart() ?? $this->session?->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
|
// Initializing the cart data
|
||||||
$this->view->cart = [
|
$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
|
// Validating received product identifier
|
||||||
|
@ -113,6 +119,7 @@ final class catalog extends core
|
||||||
'cart' => [
|
'cart' => [
|
||||||
'amount' => $this->view->cart['products'][$this->view->product->getId()]['amount'] ?? 0,
|
'amount' => $this->view->cart['products'][$this->view->product->getId()]['amount'] ?? 0,
|
||||||
'text' => [
|
'text' => [
|
||||||
|
'cart' => $this->language === language::ru ? 'Корзина' : 'Cart',
|
||||||
'add' => $this->language === language::ru ? 'Добавить в корзину' : 'Add to the cart',
|
'add' => $this->language === language::ru ? 'Добавить в корзину' : 'Add to the cart',
|
||||||
'added' => $this->language === language::ru ? 'Добавлено в корзину' : 'Added to the cart'
|
'added' => $this->language === language::ru ? 'Добавлено в корзину' : 'Added to the cart'
|
||||||
]
|
]
|
||||||
|
@ -189,31 +196,26 @@ final class catalog extends core
|
||||||
// Write to the response buffer
|
// Write to the response buffer
|
||||||
$response['category'] = ['name' => $category->name ?? null];
|
$response['category'] = ['name' => $category->name ?? null];
|
||||||
|
|
||||||
// Search for categories that are descendants of $category
|
// Searching for entries that are descendants of $category
|
||||||
$entries = entry::search(
|
$search = model::search(
|
||||||
document: $category,
|
document: $category,
|
||||||
amount: 50,
|
amount: 200,
|
||||||
|
depth: 100,
|
||||||
categories_merge: 'name: v.name.@language',
|
categories_merge: 'name: v.name.@language',
|
||||||
/* products_merge: 'DISTINCT MERGE(d, {name: d.name.@language, description: d.description.@language, compatibility: d.compatibility.@language, brand: d.brand.@language, cost: d.cost.@currency})', */
|
/* products_merge: 'DISTINCT MERGE(d, {name: d.name.@language, description: d.description.@language, compatibility: d.compatibility.@language, brand: d.brand.@language, cost: d.cost.@currency})', */
|
||||||
parameters: ['language' => $this->language->name],
|
parameters: ['language' => $this->language->name],
|
||||||
errors: $this->errors['catalog']
|
errors: $this->errors['catalog']
|
||||||
);
|
);
|
||||||
|
|
||||||
// Initialize buffers of entries (in singular, by parameter from ArangoDB)
|
if (isset($this->settings->catalog['categories']['structure']) && $this->settings->catalog['categories']['structure'] === 'pages') {
|
||||||
$category = $product = [];
|
// Pages
|
||||||
|
|
||||||
foreach ($entries as $entry) {
|
// Write to the buffer of global variables of view templater
|
||||||
// Iterate over entries (descendands)
|
$this->view->categories = $search['categories'];
|
||||||
|
|
||||||
// Write entry to the buffer of entries (sort by $category and $product)
|
|
||||||
${$entry->_type}[] = $entry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write to the buffer of global variables of view templater
|
// Write to the buffer of global variables of view templater
|
||||||
$this->view->categories = $category;
|
$this->view->products = $search['products'];
|
||||||
|
|
||||||
// Write to the buffer of global variables of view templater
|
|
||||||
$this->view->products = $product;
|
|
||||||
|
|
||||||
if (isset($this->view->products) && count($this->view->products) > 0) {
|
if (isset($this->view->products) && count($this->view->products) > 0) {
|
||||||
// Amount of rendered products is more than 0
|
// Amount of rendered products is more than 0
|
||||||
|
@ -228,13 +230,51 @@ final class catalog extends core
|
||||||
} else if (!isset($category)) {
|
} else if (!isset($category)) {
|
||||||
// Not received identifier of the category
|
// Not received identifier of the category
|
||||||
|
|
||||||
// search for root ascendants categories
|
if (isset($this->settings->catalog['categories']['structure']) && $this->settings->catalog['categories']['structure'] === 'pages') {
|
||||||
$this->view->categories = entry::ascendants(
|
// Pages
|
||||||
descendant: new category,
|
|
||||||
return: 'DISTINCT MERGE(ascendant, { name: ascendant.name.@language})',
|
// Searching for root ascendants categories
|
||||||
parameters: ['language' => $this->language->name],
|
$this->view->categories = entry::ascendants(
|
||||||
errors: $this->errors['catalog']
|
descendant: new category,
|
||||||
) ?? null;
|
return: 'DISTINCT MERGE(d, { name: d.name.@language})',
|
||||||
|
parameters: ['language' => $this->language->name],
|
||||||
|
errors: $this->errors['catalog']
|
||||||
|
) ?? null;
|
||||||
|
} else if (isset($this->settings->catalog['categories']['structure']) && $this->settings->catalog['categories']['structure'] === 'lists') {
|
||||||
|
// Lists
|
||||||
|
|
||||||
|
// Initializing the list of all categories
|
||||||
|
$categories = [];
|
||||||
|
|
||||||
|
// Initializing the structure of the list of all categories
|
||||||
|
$structure = [];
|
||||||
|
|
||||||
|
foreach (
|
||||||
|
entry::ascendants(
|
||||||
|
descendant: new category,
|
||||||
|
return: 'DISTINCT MERGE(d, { name: d.name.@language})',
|
||||||
|
parameters: ['language' => $this->language->name],
|
||||||
|
errors: $this->errors['catalog']
|
||||||
|
) ?? null as $document
|
||||||
|
) {
|
||||||
|
// Iterating over found root ascendants categories
|
||||||
|
|
||||||
|
// Generating the list (entering into recursion)
|
||||||
|
static::list(
|
||||||
|
document: $document,
|
||||||
|
language: $this->language,
|
||||||
|
categories: $categories,
|
||||||
|
structure: $structure,
|
||||||
|
errors: $this->errors['catalog']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writing the list of all categories into the templater variable
|
||||||
|
$this->view->categories = $categories;
|
||||||
|
|
||||||
|
// Writing the structure of the list of all categories into the templater variable
|
||||||
|
$this->view->structure = $structure;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validating @todo add throwing errors
|
// Validating @todo add throwing errors
|
||||||
|
@ -293,9 +333,12 @@ final class catalog extends core
|
||||||
parameters: ['language' => $this->language->name],
|
parameters: ['language' => $this->language->name],
|
||||||
errors: $this->errors['menu']
|
errors: $this->errors['menu']
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Universalizing
|
||||||
|
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
|
// Request for JSON response
|
||||||
|
|
||||||
// Initializing the response body buffer
|
// Initializing the response body buffer
|
||||||
|
@ -384,4 +427,56 @@ final class catalog extends core
|
||||||
// Exit (success/fail)
|
// Exit (success/fail)
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function list(_document $document, language $language, array &$categories = [], array &$structure = [], array &$errors = []): void
|
||||||
|
{
|
||||||
|
// Initializing the object
|
||||||
|
$category = new category;
|
||||||
|
|
||||||
|
if (method_exists($category, '__document')) {
|
||||||
|
// Object can implement a document from ArangoDB
|
||||||
|
|
||||||
|
// Writing the instance of product document from ArangoDB to the implement object
|
||||||
|
$category->__document($document);
|
||||||
|
|
||||||
|
// Writing the category into the list of categories
|
||||||
|
$categories[$category->getId()] = $category;
|
||||||
|
|
||||||
|
// Writing the category into the structure of the list categories
|
||||||
|
$structure[$category->getId()] = [];
|
||||||
|
|
||||||
|
// Searching for entries that are descendants of $category
|
||||||
|
$search = model::search(
|
||||||
|
document: $category,
|
||||||
|
amount: 200,
|
||||||
|
categories_merge: 'name: v.name.@language',
|
||||||
|
parameters: ['language' => $language->name],
|
||||||
|
errors: $errors
|
||||||
|
);
|
||||||
|
|
||||||
|
if (count($search['categories']) > 0) {
|
||||||
|
// Found descendants categories
|
||||||
|
|
||||||
|
foreach ($search['categories'] as $document) {
|
||||||
|
// Iterating over descendants categories
|
||||||
|
|
||||||
|
// Entering into descendant level of the recursion for the list generation
|
||||||
|
static::list(
|
||||||
|
document: $document,
|
||||||
|
language: $language,
|
||||||
|
categories: $categories,
|
||||||
|
structure: $structure[$category->getId()],
|
||||||
|
errors: $errors
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -2,18 +2,18 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\controllers;
|
namespace mirzaev\huesos\controllers;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\views\templater,
|
use mirzaev\huesos\views\templater,
|
||||||
mirzaev\arming_bot\models\core as models,
|
mirzaev\huesos\models\core as models,
|
||||||
mirzaev\arming_bot\models\account,
|
mirzaev\huesos\models\account,
|
||||||
mirzaev\arming_bot\models\session,
|
mirzaev\huesos\models\session,
|
||||||
mirzaev\arming_bot\models\settings,
|
mirzaev\huesos\models\settings,
|
||||||
mirzaev\arming_bot\models\cart,
|
mirzaev\huesos\models\cart,
|
||||||
mirzaev\arming_bot\models\suspension,
|
mirzaev\huesos\models\suspension,
|
||||||
mirzaev\arming_bot\models\enumerations\language,
|
mirzaev\huesos\models\enumerations\language,
|
||||||
mirzaev\arming_bot\models\enumerations\currency;
|
mirzaev\huesos\models\enumerations\currency;
|
||||||
|
|
||||||
// Framework for PHP
|
// Framework for PHP
|
||||||
use mirzaev\minimal\core as minimal,
|
use mirzaev\minimal\core as minimal,
|
||||||
|
@ -24,7 +24,7 @@ use mirzaev\minimal\core as minimal,
|
||||||
/**
|
/**
|
||||||
* Core of controllers
|
* Core of controllers
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\controllers
|
* @package mirzaev\huesos\controllers
|
||||||
*
|
*
|
||||||
* @param settings $settings Instance of the settings
|
* @param settings $settings Instance of the settings
|
||||||
* @param session $session Instance of the session
|
* @param session $session Instance of the session
|
||||||
|
@ -167,7 +167,7 @@ class core extends controller
|
||||||
$this->account = $this->session->account($this->errors['account']);
|
$this->account = $this->session->account($this->errors['account']);
|
||||||
|
|
||||||
// Initializing of the settings
|
// Initializing of the settings
|
||||||
$this->settings = settings::active();
|
$this->settings = settings::active(create: SETTINGS_PROJECT);
|
||||||
|
|
||||||
// Initializing of the language
|
// Initializing of the language
|
||||||
$this->language = $this->account?->language ?? $this->session?->buffer['language'] ?? $this->settings?->language ?? language::en;
|
$this->language = $this->account?->language ?? $this->session?->buffer['language'] ?? $this->settings?->language ?? language::en;
|
File diff suppressed because it is too large
Load Diff
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\controllers;
|
namespace mirzaev\huesos\controllers;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\controllers\core,
|
use mirzaev\huesos\controllers\core,
|
||||||
mirzaev\arming_bot\models\menu;
|
mirzaev\huesos\models\menu;
|
||||||
|
|
||||||
// Framework for PHP
|
// Framework for PHP
|
||||||
use mirzaev\minimal\http\enumerations\content;
|
use mirzaev\minimal\http\enumerations\content;
|
||||||
|
@ -14,7 +14,7 @@ use mirzaev\minimal\http\enumerations\content;
|
||||||
/**
|
/**
|
||||||
* Controller of pages
|
* Controller of pages
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\controllers
|
* @package mirzaev\huesos\controllers
|
||||||
* @param array $errors Registry of errors
|
* @param array $errors Registry of errors
|
||||||
*
|
*
|
||||||
* @method null offer() Public offer
|
* @method null offer() Public offer
|
||||||
|
@ -56,6 +56,9 @@ final class index extends core
|
||||||
parameters: ['language' => $this->language->name],
|
parameters: ['language' => $this->language->name],
|
||||||
errors: $this->errors['menu']
|
errors: $this->errors['menu']
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Universalizing
|
||||||
|
if ($this->view->menu instanceof _document) $this->view->menu = [$this->view->menu];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (str_contains($this->request->headers['accept'], content::any->value)) {
|
if (str_contains($this->request->headers['accept'], content::any->value)) {
|
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\controllers;
|
namespace mirzaev\huesos\controllers;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\controllers\core,
|
use mirzaev\huesos\controllers\core,
|
||||||
mirzaev\arming_bot\models\cart as model,
|
mirzaev\huesos\models\cart as model,
|
||||||
mirzaev\arming_bot\models\product,
|
mirzaev\huesos\models\product,
|
||||||
mirzaev\arming_bot\models\menu,
|
mirzaev\huesos\models\menu,
|
||||||
mirzaev\arming_bot\models\enumerations\language;
|
mirzaev\huesos\models\enumerations\language;
|
||||||
|
|
||||||
// Framework for PHP
|
// Framework for PHP
|
||||||
use mirzaev\minimal\http\enumerations\content,
|
use mirzaev\minimal\http\enumerations\content,
|
||||||
|
@ -18,7 +18,7 @@ use mirzaev\minimal\http\enumerations\content,
|
||||||
/**
|
/**
|
||||||
* Controller of cart
|
* Controller of cart
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\controllers
|
* @package mirzaev\huesos\controllers
|
||||||
*
|
*
|
||||||
* @param model|null $cart Instance of the cart
|
* @param model|null $cart Instance of the cart
|
||||||
* @param array $errors Registry of errors
|
* @param array $errors Registry of errors
|
||||||
|
@ -74,6 +74,9 @@ final class cart extends core
|
||||||
parameters: ['language' => $this->language->name],
|
parameters: ['language' => $this->language->name],
|
||||||
errors: $this->errors['menu']
|
errors: $this->errors['menu']
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Universalizing
|
||||||
|
if ($this->view->menu instanceof _document) $this->view->menu = [$this->view->menu];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializing the cart
|
// Initializing the cart
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\controllers;
|
namespace mirzaev\huesos\controllers;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\controllers\core,
|
use mirzaev\huesos\controllers\core,
|
||||||
mirzaev\arming_bot\models\account;
|
mirzaev\huesos\models\account;
|
||||||
|
|
||||||
// Framework for PHP
|
// Framework for PHP
|
||||||
use mirzaev\minimal\http\enumerations\content,
|
use mirzaev\minimal\http\enumerations\content,
|
||||||
|
@ -18,7 +18,7 @@ use mirzaev\arangodb\document;
|
||||||
/**
|
/**
|
||||||
* Controller of session
|
* Controller of session
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\controllers
|
* @package mirzaev\huesos\controllers
|
||||||
*
|
*
|
||||||
* @param array $errors Registry of errors
|
* @param array $errors Registry of errors
|
||||||
*
|
*
|
||||||
|
@ -53,6 +53,7 @@ final class session extends core
|
||||||
* @param ?string $auth_date
|
* @param ?string $auth_date
|
||||||
* @param ?string $hash
|
* @param ?string $hash
|
||||||
* @param ?string $query_id
|
* @param ?string $query_id
|
||||||
|
* @param ?string $signature
|
||||||
*
|
*
|
||||||
* @return null
|
* @return null
|
||||||
*/
|
*/
|
||||||
|
@ -62,7 +63,8 @@ final class session extends core
|
||||||
?string $chat_type = null,
|
?string $chat_type = null,
|
||||||
?string $auth_date = null,
|
?string $auth_date = null,
|
||||||
?string $hash = null,
|
?string $hash = null,
|
||||||
?string $query_id = null
|
?string $query_id = null,
|
||||||
|
?string $signature = null
|
||||||
): null {
|
): 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
|
// Request for JSON response
|
||||||
|
@ -70,6 +72,12 @@ final class session extends core
|
||||||
// Declaring variables in the correct scope
|
// Declaring variables in the correct scope
|
||||||
$identifier = $domain = $language = null;
|
$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)) {
|
if ($connected = isset($this->account)) {
|
||||||
// Found the account
|
// Found the account
|
||||||
|
|
||||||
|
@ -84,10 +92,17 @@ final class session extends core
|
||||||
} else {
|
} else {
|
||||||
// Not found the account
|
// Not found the account
|
||||||
|
|
||||||
if (isset($user, $chat_instance, $chat_type, $auth_date, $hash)) {
|
if (isset($user, $auth_date, $hash)) {
|
||||||
// Received required parameters
|
// 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);
|
ksort($buffer);
|
||||||
|
|
||||||
|
@ -109,9 +124,6 @@ final class session extends core
|
||||||
if (time() - $auth_date < 86400) {
|
if (time() - $auth_date < 86400) {
|
||||||
// Authorization date less than 1 day ago
|
// Authorization date less than 1 day ago
|
||||||
|
|
||||||
// Initializing data of the account
|
|
||||||
$data = json_decode($user);
|
|
||||||
|
|
||||||
// Initializing of the account
|
// Initializing of the account
|
||||||
$account = account::initialize(
|
$account = account::initialize(
|
||||||
$data->id,
|
$data->id,
|
||||||
|
@ -146,6 +158,9 @@ final class session extends core
|
||||||
|
|
||||||
// Initializing domain of the account
|
// Initializing domain of the account
|
||||||
$domain = $account->domain;
|
$domain = $account->domain;
|
||||||
|
|
||||||
|
// Initializing avatar of the account
|
||||||
|
$avatar = $data->photo_url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,6 +176,7 @@ final class session extends core
|
||||||
'connected' => (bool) $connected,
|
'connected' => (bool) $connected,
|
||||||
'identifier' => $identifier ?? null,
|
'identifier' => $identifier ?? null,
|
||||||
'domain' => $domain ?? null,
|
'domain' => $domain ?? null,
|
||||||
|
'avatar' => $avatar ?? null,
|
||||||
'language' => $language?->name ?? null,
|
'language' => $language?->name ?? null,
|
||||||
'errors' => $this->errors
|
'errors' => $this->errors
|
||||||
])
|
])
|
|
@ -2,18 +2,18 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models;
|
namespace mirzaev\huesos\models;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\core,
|
use mirzaev\huesos\models\core,
|
||||||
mirzaev\arming_bot\models\traits\status,
|
mirzaev\huesos\models\traits\status,
|
||||||
mirzaev\arming_bot\models\traits\buffer,
|
mirzaev\huesos\models\traits\buffer,
|
||||||
mirzaev\arming_bot\models\traits\cart,
|
mirzaev\huesos\models\traits\cart,
|
||||||
mirzaev\arming_bot\models\traits\document as document_trait,
|
mirzaev\huesos\models\traits\document as document_trait,
|
||||||
mirzaev\arming_bot\models\interfaces\document as document_interface,
|
mirzaev\huesos\models\interfaces\document as document_interface,
|
||||||
mirzaev\arming_bot\models\interfaces\collection as collection_interface,
|
mirzaev\huesos\models\interfaces\collection as collection_interface,
|
||||||
mirzaev\arming_bot\models\enumerations\language,
|
mirzaev\huesos\models\enumerations\language,
|
||||||
mirzaev\arming_bot\models\enumerations\currency;
|
mirzaev\huesos\models\enumerations\currency;
|
||||||
|
|
||||||
// Framework for ArangoDB
|
// Framework for ArangoDB
|
||||||
use mirzaev\arangodb\collection,
|
use mirzaev\arangodb\collection,
|
||||||
|
@ -31,7 +31,7 @@ use exception;
|
||||||
/**
|
/**
|
||||||
* Model of account
|
* Model of account
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\huesos\models
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
@ -86,7 +86,7 @@ final class account extends core implements document_interface, collection_inter
|
||||||
if (method_exists($account, '__document')) {
|
if (method_exists($account, '__document')) {
|
||||||
// Object can implement a document from ArangoDB
|
// Object can implement a document from ArangoDB
|
||||||
|
|
||||||
// Abstractioning of parameters
|
// Implementinf parameters
|
||||||
if (isset($result->language)) $result->language = language::{$result->language};
|
if (isset($result->language)) $result->language = language::{$result->language};
|
||||||
if (isset($result->currency)) $result->currency = currency::{$result->currency};
|
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()
|
'messages' => $registration->getCanReadAllGroupMessages()
|
||||||
],
|
],
|
||||||
'premium' => $registration->isPremium(),
|
'premium' => $registration->isPremium(),
|
||||||
'language' => language::{$registration->getLanguageCode()}->name ?? 'en',
|
'language' => language::{$registration->getLanguageCode() ?? 'en'}?->name ?? 'en',
|
||||||
'queries' => [
|
'queries' => [
|
||||||
'inline' => $registration->getSupportsInlineQueries()
|
'inline' => $registration->getSupportsInlineQueries()
|
||||||
]
|
]
|
||||||
|
@ -145,7 +145,7 @@ final class account extends core implements document_interface, collection_inter
|
||||||
return static::initialize($identifier, errors: $errors);
|
return static::initialize($identifier, errors: $errors);
|
||||||
} else throw new exception('Failed to register account');
|
} else throw new exception('Failed to register account');
|
||||||
} else throw new exception('Failed to find account');
|
} else throw new exception('Failed to find account');
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
|
@ -0,0 +1,260 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace mirzaev\huesos\models\acquirings;
|
||||||
|
|
||||||
|
// Files of the project
|
||||||
|
use mirzaev\huesos\models\core,
|
||||||
|
mirzaev\huesos\models\settings,
|
||||||
|
mirzaev\huesos\models\cart,
|
||||||
|
mirzaev\huesos\models\order,
|
||||||
|
mirzaev\huesos\models\enumerations\currency;
|
||||||
|
|
||||||
|
// Framework for ArangoDB
|
||||||
|
use mirzaev\arangodb\collection,
|
||||||
|
mirzaev\arangodb\document;
|
||||||
|
|
||||||
|
// Library for ArangoDB
|
||||||
|
use ArangoDBClient\Document as _document;
|
||||||
|
|
||||||
|
// Built-in libraries
|
||||||
|
use exception,
|
||||||
|
DomainException as exception_domain,
|
||||||
|
RuntimeException as exception_runtime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model of robokassa
|
||||||
|
*
|
||||||
|
* @package mirzaev\huesos\models\acquirings
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,17 +2,17 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models;
|
namespace mirzaev\huesos\models;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\core,
|
use mirzaev\huesos\models\core,
|
||||||
mirzaev\arming_bot\models\reservation,
|
mirzaev\huesos\models\reservation,
|
||||||
mirzaev\arming_bot\models\traits\buffer,
|
mirzaev\huesos\models\traits\buffer,
|
||||||
mirzaev\arming_bot\models\traits\document as document_trait,
|
mirzaev\huesos\models\traits\document as document_trait,
|
||||||
mirzaev\arming_bot\models\interfaces\document as document_interface,
|
mirzaev\huesos\models\interfaces\document as document_interface,
|
||||||
mirzaev\arming_bot\models\interfaces\collection as collection_interface,
|
mirzaev\huesos\models\interfaces\collection as collection_interface,
|
||||||
mirzaev\arming_bot\models\enumerations\language,
|
mirzaev\huesos\models\enumerations\language,
|
||||||
mirzaev\arming_bot\models\enumerations\currency;
|
mirzaev\huesos\models\enumerations\currency;
|
||||||
|
|
||||||
// Framework for ArangoDB
|
// Framework for ArangoDB
|
||||||
use mirzaev\arangodb\collection,
|
use mirzaev\arangodb\collection,
|
||||||
|
@ -22,13 +22,14 @@ use mirzaev\arangodb\collection,
|
||||||
use ArangoDBClient\Document as _document;
|
use ArangoDBClient\Document as _document;
|
||||||
|
|
||||||
// Built-in libraries
|
// Built-in libraries
|
||||||
use exception;
|
use DateTime as datetime,
|
||||||
|
Exception as exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model of cart
|
* Model of cart
|
||||||
*
|
*
|
||||||
* @uses reservation
|
* @uses reservation
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\huesos\models
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
@ -110,9 +111,9 @@ final class cart extends core implements document_interface, collection_interfac
|
||||||
|
|
||||||
// Exit (success)
|
// Exit (success)
|
||||||
return isset($products['amount']) ? [$products['document']['_id'] => $products] : $products;
|
return isset($products['amount']) ? [$products['document']['_id'] => $products] : $products;
|
||||||
} else throw new exception('Failed to initialize ' . product::TYPE . ' collection: ' . product::COLLECTION);
|
} else throw new exception('Failed to initialize ' . product::TYPE->name . ' collection: ' . product::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . reservation::TYPE . ' collection: ' . reservation::COLLECTION);
|
} else throw new exception('Failed to initialize ' . reservation::TYPE->name . ' collection: ' . reservation::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
|
@ -150,11 +151,11 @@ final class cart extends core implements document_interface, collection_interfac
|
||||||
// Search for all products in the cart
|
// Search for all products in the cart
|
||||||
$result = @collection::execute(
|
$result = @collection::execute(
|
||||||
<<<AQL
|
<<<AQL
|
||||||
FOR v IN 1..1 INBOUND @cart GRAPH @graph
|
FOR v IN 1..1 INBOUND @cart GRAPH @graph
|
||||||
FILTER IS_SAME_COLLECTION(@collection, v._id)
|
FILTER IS_SAME_COLLECTION(@collection, v._id)
|
||||||
COLLECT AGGREGATE amount = COUNT(v), cost = SUM(v.cost.@currency)
|
COLLECT AGGREGATE amount = COUNT(v), cost = SUM(v.cost.@currency)
|
||||||
RETURN { amount, cost }
|
RETURN { amount, cost }
|
||||||
AQL,
|
AQL,
|
||||||
[
|
[
|
||||||
'graph' => 'catalog',
|
'graph' => 'catalog',
|
||||||
'cart' => $this->getId(),
|
'cart' => $this->getId(),
|
||||||
|
@ -167,9 +168,9 @@ final class cart extends core implements document_interface, collection_interfac
|
||||||
|
|
||||||
// Exit (success)
|
// Exit (success)
|
||||||
return $result;
|
return $result;
|
||||||
} else throw new exception('Failed to initialize ' . product::TYPE . ' collection: ' . product::COLLECTION);
|
} else throw new exception('Failed to initialize ' . product::TYPE->name . ' collection: ' . product::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . reservation::TYPE . ' collection: ' . reservation::COLLECTION);
|
} else throw new exception('Failed to initialize ' . reservation::TYPE->name . ' collection: ' . reservation::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
|
@ -184,7 +185,6 @@ final class cart extends core implements document_interface, collection_interfac
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Count
|
* Count
|
||||||
*
|
*
|
||||||
|
@ -222,9 +222,9 @@ final class cart extends core implements document_interface, collection_interfac
|
||||||
],
|
],
|
||||||
errors: $errors
|
errors: $errors
|
||||||
);
|
);
|
||||||
} else throw new exception('Failed to initialize ' . product::TYPE . ' collection: ' . product::COLLECTION);
|
} else throw new exception('Failed to initialize ' . product::TYPE->name . ' collection: ' . product::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . reservation::TYPE . ' collection: ' . reservation::COLLECTION);
|
} else throw new exception('Failed to initialize ' . reservation::TYPE->name . ' collection: ' . reservation::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
|
@ -242,7 +242,7 @@ final class cart extends core implements document_interface, collection_interfac
|
||||||
/*
|
/*
|
||||||
* Write
|
* Write
|
||||||
*
|
*
|
||||||
* Write the product in the cart
|
* Write the product into the cart
|
||||||
*
|
*
|
||||||
* @param product $product The product
|
* @param product $product The product
|
||||||
* @param int $amount Amount of writings
|
* @param int $amount Amount of writings
|
||||||
|
@ -273,9 +273,9 @@ final class cart extends core implements document_interface, collection_interfac
|
||||||
],
|
],
|
||||||
errors: $errors
|
errors: $errors
|
||||||
);
|
);
|
||||||
} else throw new exception('Failed to initialize ' . product::TYPE . ' collection: ' . product::COLLECTION);
|
} else throw new exception('Failed to initialize ' . product::TYPE->name . ' collection: ' . product::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . reservation::TYPE . ' collection: ' . reservation::COLLECTION);
|
} else throw new exception('Failed to initialize ' . reservation::TYPE->name . ' collection: ' . reservation::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
|
@ -324,9 +324,9 @@ final class cart extends core implements document_interface, collection_interfac
|
||||||
],
|
],
|
||||||
errors: $errors
|
errors: $errors
|
||||||
);
|
);
|
||||||
} else throw new exception('Failed to initialize ' . product::TYPE . ' collection: ' . product::COLLECTION);
|
} else throw new exception('Failed to initialize ' . product::TYPE->name . ' collection: ' . product::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . reservation::TYPE . ' collection: ' . reservation::COLLECTION);
|
} else throw new exception('Failed to initialize ' . reservation::TYPE->name . ' collection: ' . reservation::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
|
@ -362,7 +362,7 @@ final class cart extends core implements document_interface, collection_interfac
|
||||||
// Exit (success)
|
// Exit (success)
|
||||||
return $this->share;
|
return $this->share;
|
||||||
} else throw new exception('Failed to write confirmed cart to ArangoDB');
|
} else throw new exception('Failed to write confirmed cart to ArangoDB');
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
|
@ -401,7 +401,7 @@ final class cart extends core implements document_interface, collection_interfac
|
||||||
// Exit (success)
|
// Exit (success)
|
||||||
return true;
|
return true;
|
||||||
} else throw new exception('Failed to write confirmed cart to ArangoDB');
|
} else throw new exception('Failed to write confirmed cart to ArangoDB');
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
|
@ -416,26 +416,50 @@ final class cart extends core implements document_interface, collection_interfac
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Order
|
* Account
|
||||||
*
|
|
||||||
*
|
*
|
||||||
|
* Search for the connected account
|
||||||
*
|
*
|
||||||
* @param array &$errors Registry of errors
|
* @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 {
|
try {
|
||||||
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
if ($result = collection::execute(
|
||||||
if (collection::initialize(reservation::COLLECTION, reservation::TYPE, errors: $errors)) {
|
<<<'AQL'
|
||||||
if (collection::initialize(order::COLLECTION, order::TYPE, errors: $errors)) {
|
FOR v IN 1..1 OUTBOUND @cart GRAPH users
|
||||||
// Initialized collections
|
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
|
||||||
|
|
||||||
} else throw new exception('Failed to initialize ' . product::TYPE . ' collection: ' . product::COLLECTION);
|
// Initializing the object
|
||||||
} else throw new exception('Failed to initialize ' . reservation::TYPE . ' collection: ' . reservation::COLLECTION);
|
$account = new account;
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
|
||||||
|
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) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
|
@ -445,5 +469,221 @@ final class cart extends core implements document_interface, collection_interfac
|
||||||
'stack' => $e->getTrace()
|
'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(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
|
||||||
|
|
||||||
|
// 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
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,17 +2,17 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models;
|
namespace mirzaev\huesos\models;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\core,
|
use mirzaev\huesos\models\core,
|
||||||
mirzaev\arming_bot\models\product,
|
mirzaev\huesos\models\product,
|
||||||
mirzaev\arming_bot\models\category,
|
mirzaev\huesos\models\category,
|
||||||
mirzaev\arming_bot\models\entry,
|
mirzaev\huesos\models\entry,
|
||||||
mirzaev\arming_bot\models\traits\files,
|
mirzaev\huesos\models\traits\files,
|
||||||
mirzaev\arming_bot\models\enumerations\language,
|
mirzaev\huesos\models\enumerations\language,
|
||||||
mirzaev\arming_bot\models\enumerations\currency,
|
mirzaev\huesos\models\enumerations\currency,
|
||||||
mirzaev\arming_bot\models\traits\yandex\disk as yandex;
|
mirzaev\huesos\models\traits\yandex\disk as yandex;
|
||||||
|
|
||||||
// Framework for PHP
|
// Framework for PHP
|
||||||
use mirzaev\minimal\http\enumerations\content;
|
use mirzaev\minimal\http\enumerations\content;
|
||||||
|
@ -33,7 +33,7 @@ use GdImage as image;
|
||||||
/**
|
/**
|
||||||
* Model of the catalog
|
* Model of the catalog
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\huesos\models
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
@ -41,7 +41,64 @@ use GdImage as image;
|
||||||
final class catalog extends core
|
final class catalog extends core
|
||||||
{
|
{
|
||||||
use yandex, files {
|
use yandex, files {
|
||||||
yandex::download as yandex;
|
yandex::download as file;
|
||||||
|
yandex::list as folder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search
|
||||||
|
*
|
||||||
|
* @param category|product $document Ascendant document
|
||||||
|
* @param string|null $filter Expression for filtering (AQL)
|
||||||
|
* @param string|null $sort Expression for sorting (AQL)
|
||||||
|
* @param int $depth Amount of nodes for traversal search (subcategories/products inside subcategories...)
|
||||||
|
* @param int $page Page
|
||||||
|
* @param int $amount Amount of documents per page
|
||||||
|
* @param string|null $categories_merge Expression with paremeters to return for categories (AQL)
|
||||||
|
* @param string|null $products_merge Expression with paremeters to return for products (AQL)
|
||||||
|
* @param array $parameters Binded parameters for placeholders ['placeholder' => parameter]
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return array [categories => [document::class...], $products => [document::class...]]
|
||||||
|
*/
|
||||||
|
public static function search(
|
||||||
|
category|product $document,
|
||||||
|
?string $filter = 'v.deleted != true && v.hidden != true',
|
||||||
|
?string $sort = 'v.position ASC, v.created DESC',
|
||||||
|
int $depth = 1,
|
||||||
|
int $page = 1,
|
||||||
|
int $amount = 100,
|
||||||
|
?string $categories_merge = null,
|
||||||
|
?string $products_merge = null,
|
||||||
|
array $parameters = [],
|
||||||
|
array &$errors = []
|
||||||
|
): array {
|
||||||
|
// Search for entries that are descendants of $category
|
||||||
|
$entries = entry::search(
|
||||||
|
document: $document,
|
||||||
|
filter: $filter,
|
||||||
|
sort: $sort,
|
||||||
|
depth: $depth,
|
||||||
|
page: $page,
|
||||||
|
amount: $amount,
|
||||||
|
categories_merge: $categories_merge,
|
||||||
|
products_merge: $products_merge,
|
||||||
|
parameters: $parameters,
|
||||||
|
errors: $errors
|
||||||
|
);
|
||||||
|
|
||||||
|
// Initialize buffers of entries (in singular, by parameter from ArangoDB)
|
||||||
|
$category = $product = [];
|
||||||
|
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
// Iterate over entries (descendands)
|
||||||
|
|
||||||
|
// Write entry to the buffer of entries (sort by $category and $product)
|
||||||
|
${$entry->_type}[] = $entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return ['categories' => $category, 'products' => $product];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -120,7 +177,7 @@ final class catalog extends core
|
||||||
// Iterate over categories
|
// Iterate over categories
|
||||||
|
|
||||||
try {
|
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
|
// Required cells are filled in
|
||||||
|
|
||||||
// Incrementing the counter of loaded categories
|
// Incrementing the counter of loaded categories
|
||||||
|
@ -195,7 +252,10 @@ final class catalog extends core
|
||||||
// Received images
|
// Received images
|
||||||
|
|
||||||
// Initializing new images of the category
|
// 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 images? (true, if no images found or their amount does not match)
|
||||||
/* $reinitialize = !$category->images || count($category->images) !== count($images); */
|
/* $reinitialize = !$category->images || count($category->images) !== count($images); */
|
||||||
|
@ -210,14 +270,14 @@ final class catalog extends core
|
||||||
// Initializing the buffer of images
|
// Initializing the buffer of images
|
||||||
$buffer = [];
|
$buffer = [];
|
||||||
|
|
||||||
foreach ($images as $index => $file) {
|
foreach (is_array($images) ? $images : [] as $image) {
|
||||||
// Iterating over new images
|
// Iterating over new images
|
||||||
|
|
||||||
// Skipping empty URI`s
|
// Initializing identifier of the image
|
||||||
if (empty($file = mb_trim($file))) continue;
|
$identifier = preg_replace('/\.\w+$/', '', $image->name);
|
||||||
|
|
||||||
// Initializing path to directory of images in storage
|
// 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
|
// Initializing URL of the image in storage
|
||||||
$url = STORAGE . $directory;
|
$url = STORAGE . $directory;
|
||||||
|
@ -225,8 +285,8 @@ final class catalog extends core
|
||||||
// Initializing the directory in storage
|
// Initializing the directory in storage
|
||||||
if (!file_exists($url)) mkdir($url, 0775, true);
|
if (!file_exists($url)) mkdir($url, 0775, true);
|
||||||
|
|
||||||
if ($downloaded = static::yandex(
|
if ($downloaded = static::file(
|
||||||
uri: $file,
|
uri: $image->public_url ?? $image->public_key,
|
||||||
destination: $url,
|
destination: $url,
|
||||||
name: 'source',
|
name: 'source',
|
||||||
errors: $errors
|
errors: $errors
|
||||||
|
@ -249,6 +309,11 @@ final class catalog extends core
|
||||||
|
|
||||||
// Initializing implementator of the image
|
// Initializing implementator of the image
|
||||||
$boba = imagecreatefromjpeg($uri);
|
$boba = imagecreatefromjpeg($uri);
|
||||||
|
} else if ($downloaded['content'] === content::webp) {
|
||||||
|
// WEBP
|
||||||
|
|
||||||
|
// Initializing implementator of the image
|
||||||
|
$boba = imagecreatefromwebp($uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enabling better antialiasing
|
// Enabling better antialiasing
|
||||||
|
@ -280,10 +345,10 @@ final class catalog extends core
|
||||||
imagecopyresampled($biba, $boba, 0, 0, 0, 0, $width, $height, $size[0], $size[1]);
|
imagecopyresampled($biba, $boba, 0, 0, 0, 0, $width, $height, $size[0], $size[1]);
|
||||||
|
|
||||||
// Initializing URI of the resized image
|
// Initializing URI of the resized image
|
||||||
$uri = $directory . DIRECTORY_SEPARATOR . "$resize." . $downloaded['content']->extension();
|
$uri = $directory . DIRECTORY_SEPARATOR . "$resize.webp";
|
||||||
|
|
||||||
// Saving the image
|
// Saving the image
|
||||||
imagePng($biba, STORAGE . $uri);
|
imagewebp($biba, STORAGE . $uri);
|
||||||
|
|
||||||
// Writing the resized image to the buffer of resized images
|
// Writing the resized image to the buffer of resized images
|
||||||
$resized[$resize] = $uri;
|
$resized[$resize] = $uri;
|
||||||
|
@ -291,7 +356,7 @@ final class catalog extends core
|
||||||
|
|
||||||
// Writing the image to the buffer if images
|
// Writing the image to the buffer if images
|
||||||
$buffer[] = [
|
$buffer[] = [
|
||||||
'source' => $file,
|
'source' => $image->public_url ?? null,
|
||||||
'storage' => [
|
'storage' => [
|
||||||
'source' => $directory . DIRECTORY_SEPARATOR . $downloaded['name'] . '.' . $downloaded['content']->extension(),
|
'source' => $directory . DIRECTORY_SEPARATOR . $downloaded['name'] . '.' . $downloaded['content']->extension(),
|
||||||
] + $resized
|
] + $resized
|
||||||
|
@ -349,7 +414,7 @@ final class catalog extends core
|
||||||
// Iterate over products
|
// Iterate over products
|
||||||
|
|
||||||
try {
|
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
|
// Required cells are filled in
|
||||||
|
|
||||||
// Incrementing the counter of loaded products
|
// Incrementing the counter of loaded products
|
||||||
|
@ -385,7 +450,7 @@ final class catalog extends core
|
||||||
|
|
||||||
// Initializing position of the product
|
// Initializing position of the product
|
||||||
if (empty($product->position) || $product->position !== $row['position'])
|
if (empty($product->position) || $product->position !== $row['position'])
|
||||||
$product->position = $row['position'];
|
$product->position = isset($row['position']) ? (int) $row['position'] : 0;
|
||||||
} else {
|
} else {
|
||||||
// Not initialized the product
|
// Not initialized the product
|
||||||
|
|
||||||
|
@ -399,7 +464,7 @@ final class catalog extends core
|
||||||
dimensions: ['x' => $row['x'], 'y' => $row['y'], 'z' => $row['z']],
|
dimensions: ['x' => $row['x'], 'y' => $row['y'], 'z' => $row['z']],
|
||||||
brand: [$language->name => $row['brand']],
|
brand: [$language->name => $row['brand']],
|
||||||
compatibility: [$language->name => $row['compatibility']],
|
compatibility: [$language->name => $row['compatibility']],
|
||||||
position: (int) $row['position'] ?? null,
|
position: isset($row['position']) ? (int) $row['position'] : 0,
|
||||||
errors: $errors
|
errors: $errors
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -436,8 +501,11 @@ final class catalog extends core
|
||||||
if (!empty($row['images'])) {
|
if (!empty($row['images'])) {
|
||||||
// Received images
|
// Received images
|
||||||
|
|
||||||
// Initializing new images of the category
|
// Initializing new images of the product
|
||||||
$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 images? (true, if no images found or their amount does not match)
|
||||||
/* $reinitialize = !$product->images || count($product->images) !== count($images); */
|
/* $reinitialize = !$product->images || count($product->images) !== count($images); */
|
||||||
|
@ -452,14 +520,14 @@ final class catalog extends core
|
||||||
// Initializing the buffer of images
|
// Initializing the buffer of images
|
||||||
$buffer = [];
|
$buffer = [];
|
||||||
|
|
||||||
foreach ($images as $index => $file) {
|
foreach (is_array($images) ? $images : [] as $image) {
|
||||||
// Iterating over new images
|
// Iterating over new images
|
||||||
|
|
||||||
// Skipping empty URI`s
|
// Initializing identifier of the image
|
||||||
if (empty($file = mb_trim($file))) continue;
|
$identifier = preg_replace('/\.\w+$/', '', $image->name);
|
||||||
|
|
||||||
// Initializing path to directory of images in storage
|
// 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
|
// Initializing URL of the image in storage
|
||||||
$url = STORAGE . $directory;
|
$url = STORAGE . $directory;
|
||||||
|
@ -467,8 +535,8 @@ final class catalog extends core
|
||||||
// Initializing the directory in storage
|
// Initializing the directory in storage
|
||||||
if (!file_exists($url)) mkdir($url, 0775, true);
|
if (!file_exists($url)) mkdir($url, 0775, true);
|
||||||
|
|
||||||
if ($downloaded = static::yandex(
|
if ($downloaded = static::file(
|
||||||
uri: $file,
|
uri: $image->public_url ?? $image->public_key,
|
||||||
destination: $url,
|
destination: $url,
|
||||||
name: 'source',
|
name: 'source',
|
||||||
errors: $errors
|
errors: $errors
|
||||||
|
@ -491,6 +559,11 @@ final class catalog extends core
|
||||||
|
|
||||||
// Initializing implementator of the image
|
// Initializing implementator of the image
|
||||||
$boba = imagecreatefromjpeg($uri);
|
$boba = imagecreatefromjpeg($uri);
|
||||||
|
} else if ($downloaded['content'] === content::webp) {
|
||||||
|
// WEBP
|
||||||
|
|
||||||
|
// Initializing implementator of the image
|
||||||
|
$boba = imagecreatefromwebp($uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enabling better antialiasing
|
// Enabling better antialiasing
|
||||||
|
@ -522,10 +595,10 @@ final class catalog extends core
|
||||||
imagecopyresampled($biba, $boba, 0, 0, 0, 0, $width, $height, $size[0], $size[1]);
|
imagecopyresampled($biba, $boba, 0, 0, 0, 0, $width, $height, $size[0], $size[1]);
|
||||||
|
|
||||||
// Initializing URI of the resized image
|
// Initializing URI of the resized image
|
||||||
$uri = $directory . DIRECTORY_SEPARATOR . "$resize." . $downloaded['content']->extension();
|
$uri = $directory . DIRECTORY_SEPARATOR . "$resize.webp";
|
||||||
|
|
||||||
// Saving the image
|
// Saving the image
|
||||||
imagePng($biba, STORAGE . $uri);
|
imagewebp($biba, STORAGE . $uri);
|
||||||
|
|
||||||
// Writing the resized image to the buffer of resized images
|
// Writing the resized image to the buffer of resized images
|
||||||
$resized[$resize] = $uri;
|
$resized[$resize] = $uri;
|
||||||
|
@ -533,7 +606,7 @@ final class catalog extends core
|
||||||
|
|
||||||
// Writing the image to the buffer if images
|
// Writing the image to the buffer if images
|
||||||
$buffer[] = [
|
$buffer[] = [
|
||||||
'source' => $file,
|
'source' => $image->public_url ?? null,
|
||||||
'storage' => [
|
'storage' => [
|
||||||
'source' => $directory . DIRECTORY_SEPARATOR . $downloaded['name'] . '.' . $downloaded['content']->extension(),
|
'source' => $directory . DIRECTORY_SEPARATOR . $downloaded['name'] . '.' . $downloaded['content']->extension(),
|
||||||
] + $resized
|
] + $resized
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models;
|
namespace mirzaev\huesos\models;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\core,
|
use mirzaev\huesos\models\core,
|
||||||
mirzaev\arming_bot\models\traits\document as document_trait,
|
mirzaev\huesos\models\traits\document as document_trait,
|
||||||
mirzaev\arming_bot\models\interfaces\document as document_interface,
|
mirzaev\huesos\models\interfaces\document as document_interface,
|
||||||
mirzaev\arming_bot\models\interfaces\collection as collection_interface;
|
mirzaev\huesos\models\interfaces\collection as collection_interface;
|
||||||
|
|
||||||
// Framework for ArangoDB
|
// Framework for ArangoDB
|
||||||
use mirzaev\arangodb\collection,
|
use mirzaev\arangodb\collection,
|
||||||
|
@ -21,7 +21,7 @@ use exception;
|
||||||
/**
|
/**
|
||||||
* Model of category
|
* Model of category
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\huesos\models
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
@ -69,7 +69,7 @@ final class category extends core implements document_interface, collection_inte
|
||||||
],
|
],
|
||||||
errors: $errors
|
errors: $errors
|
||||||
);
|
);
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models;
|
namespace mirzaev\huesos\models;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\core,
|
use mirzaev\huesos\models\core,
|
||||||
mirzaev\arming_bot\models\traits\document as document_trait,
|
mirzaev\huesos\models\traits\document as document_trait,
|
||||||
mirzaev\arming_bot\models\interfaces\document as document_interface,
|
mirzaev\huesos\models\interfaces\document as document_interface,
|
||||||
mirzaev\arming_bot\models\interfaces\collection as collection_interface;
|
mirzaev\huesos\models\interfaces\collection as collection_interface;
|
||||||
|
|
||||||
// Framework for ArangoDB
|
// Framework for ArangoDB
|
||||||
use mirzaev\arangodb\enumerations\collection\type;
|
use mirzaev\arangodb\enumerations\collection\type;
|
||||||
|
@ -16,7 +16,7 @@ use mirzaev\arangodb\enumerations\collection\type;
|
||||||
/**
|
/**
|
||||||
* Model of connect
|
* Model of connect
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\huesos\models
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models;
|
namespace mirzaev\huesos\models;
|
||||||
|
|
||||||
// Framework for PHP
|
// Framework for PHP
|
||||||
use mirzaev\minimal\model;
|
use mirzaev\minimal\model;
|
||||||
|
@ -20,7 +20,7 @@ use exception;
|
||||||
/**
|
/**
|
||||||
* Core of models
|
* Core of models
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\huesos\models
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
@ -127,7 +127,7 @@ class core extends model
|
||||||
|
|
||||||
// Exit (success)
|
// Exit (success)
|
||||||
return $result;
|
return $result;
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to registry of errors
|
// Writing to registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models\deliveries;
|
namespace mirzaev\huesos\models\deliveries;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\core,
|
use mirzaev\huesos\models\core,
|
||||||
mirzaev\arming_bot\models\traits\document as document_trait,
|
mirzaev\huesos\models\traits\document as document_trait,
|
||||||
mirzaev\arming_bot\models\interfaces\document as document_interface,
|
mirzaev\huesos\models\interfaces\document as document_interface,
|
||||||
mirzaev\arming_bot\models\interfaces\collection as collection_interface;
|
mirzaev\huesos\models\interfaces\collection as collection_interface;
|
||||||
|
|
||||||
// The HTTP PSR-18 adapter for Guzzle HTTP client
|
// The HTTP PSR-18 adapter for Guzzle HTTP client
|
||||||
use Http\Adapter\Guzzle7\Client as guzzle;
|
use Http\Adapter\Guzzle7\Client as guzzle;
|
||||||
|
@ -30,7 +30,7 @@ use exception,
|
||||||
/**
|
/**
|
||||||
* Model of CDEK
|
* Model of CDEK
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models\deliveries
|
* @package mirzaev\huesos\models\deliveries
|
||||||
*
|
*
|
||||||
* @method cities|null location(string $name, array &$errors) Search for CDEK location by name
|
* @method cities|null location(string $name, array &$errors) Search for CDEK location by name
|
||||||
*
|
*
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models;
|
namespace mirzaev\huesos\models;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\core,
|
use mirzaev\huesos\models\core,
|
||||||
mirzaev\arming_bot\models\enumerations\delivery as company;
|
mirzaev\huesos\models\enumerations\delivery as company;
|
||||||
|
|
||||||
// Built-in libraries
|
// Built-in libraries
|
||||||
use exception;
|
use exception;
|
||||||
|
@ -14,7 +14,7 @@ use exception;
|
||||||
/**
|
/**
|
||||||
* Model of settings
|
* Model of settings
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\huesos\models
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models;
|
namespace mirzaev\huesos\models;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\core,
|
use mirzaev\huesos\models\core,
|
||||||
mirzaev\arming_bot\models\traits\document as document_trait,
|
mirzaev\huesos\models\traits\document as document_trait,
|
||||||
mirzaev\arming_bot\models\interfaces\document as document_interface,
|
mirzaev\huesos\models\interfaces\document as document_interface,
|
||||||
mirzaev\arming_bot\models\interfaces\collection as collection_interface;
|
mirzaev\huesos\models\interfaces\collection as collection_interface;
|
||||||
|
|
||||||
// Library for ArangoDB
|
// Library for ArangoDB
|
||||||
use ArangoDBClient\Document as _document;
|
use ArangoDBClient\Document as _document;
|
||||||
|
@ -24,7 +24,7 @@ use exception;
|
||||||
/**
|
/**
|
||||||
* Model of entry
|
* Model of entry
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\huesos\models
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
@ -73,9 +73,9 @@ final class entry extends core implements document_interface, collection_interfa
|
||||||
],
|
],
|
||||||
errors: $errors
|
errors: $errors
|
||||||
);
|
);
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . $to::TYPE . ' collection: ' . $to::COLLECTION);
|
} else throw new exception('Failed to initialize ' . $to::TYPE->name . ' collection: ' . $to::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . $from::TYPE . ' collection: ' . $from::COLLECTION);
|
} else throw new exception('Failed to initialize ' . $from::TYPE->name . ' collection: ' . $from::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
|
@ -112,15 +112,20 @@ final class entry extends core implements document_interface, collection_interfa
|
||||||
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
||||||
// Initialized the collection
|
// Initialized the collection
|
||||||
|
|
||||||
// Search for ascendants
|
// Search for ascendants
|
||||||
if ($result = collection::execute(
|
if ($result = collection::execute(
|
||||||
sprintf(
|
sprintf(
|
||||||
<<<'AQL'
|
<<<'AQL'
|
||||||
FOR d IN @@collection
|
let from = (
|
||||||
FOR ascendant IN OUTBOUND d @@edge
|
FOR e IN @@edge
|
||||||
RETURN %s
|
RETURN DISTINCT e._from
|
||||||
|
)
|
||||||
|
|
||||||
|
FOR d in @@collection
|
||||||
|
FILTER !POSITION(from, d._id)
|
||||||
|
RETURN %s
|
||||||
AQL,
|
AQL,
|
||||||
empty($return) ? 'DISTINCT ascendant' : $return
|
empty($return) ? 'DISTINCT d' : $return
|
||||||
),
|
),
|
||||||
[
|
[
|
||||||
'@collection' => $descendant::COLLECTION,
|
'@collection' => $descendant::COLLECTION,
|
||||||
|
@ -133,7 +138,7 @@ final class entry extends core implements document_interface, collection_interfa
|
||||||
// Exit (success)
|
// Exit (success)
|
||||||
return is_array($result) ? $result : [$result];
|
return is_array($result) ? $result : [$result];
|
||||||
} else return [];
|
} else return [];
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
|
@ -189,9 +194,9 @@ final class entry extends core implements document_interface, collection_interfa
|
||||||
// Exit (success)
|
// Exit (success)
|
||||||
return is_array($entry) ? $entry[0] : $entry;
|
return is_array($entry) ? $entry[0] : $entry;
|
||||||
} else return null;
|
} else return null;
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . $to::TYPE . ' collection: ' . $to::COLLECTION);
|
} else throw new exception('Failed to initialize ' . $to::TYPE->name . ' collection: ' . $to::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . $from::TYPE . ' collection: ' . $from::COLLECTION);
|
} else throw new exception('Failed to initialize ' . $from::TYPE->name . ' collection: ' . $from::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
|
@ -218,8 +223,9 @@ final class entry extends core implements document_interface, collection_interfa
|
||||||
* @param category|product $document Ascendant document
|
* @param category|product $document Ascendant document
|
||||||
* @param string|null $filter Expression for filtering (AQL)
|
* @param string|null $filter Expression for filtering (AQL)
|
||||||
* @param string|null $sort Expression for sorting (AQL)
|
* @param string|null $sort Expression for sorting (AQL)
|
||||||
* @param int $page Страница
|
* @param int $depth Amount of nodes for traversal search (subcategories/products inside subcategories...)
|
||||||
* @param int $amount Количество товаров на странице
|
* @param int $page Page
|
||||||
|
* @param int $amount Amount of documents per page
|
||||||
* @param string|null $categories_merge Expression with paremeters to return for categories (AQL)
|
* @param string|null $categories_merge Expression with paremeters to return for categories (AQL)
|
||||||
* @param string|null $products_merge Expression with paremeters to return for products (AQL)
|
* @param string|null $products_merge Expression with paremeters to return for products (AQL)
|
||||||
* @param array $parameters Binded parameters for placeholders ['placeholder' => parameter]
|
* @param array $parameters Binded parameters for placeholders ['placeholder' => parameter]
|
||||||
|
@ -231,6 +237,7 @@ final class entry extends core implements document_interface, collection_interfa
|
||||||
category|product $document,
|
category|product $document,
|
||||||
?string $filter = 'v.deleted != true && v.hidden != true',
|
?string $filter = 'v.deleted != true && v.hidden != true',
|
||||||
?string $sort = 'v.position ASC, v.created DESC',
|
?string $sort = 'v.position ASC, v.created DESC',
|
||||||
|
int $depth = 1,
|
||||||
int $page = 1,
|
int $page = 1,
|
||||||
int $amount = 100,
|
int $amount = 100,
|
||||||
?string $categories_merge = null,
|
?string $categories_merge = null,
|
||||||
|
@ -247,12 +254,13 @@ final class entry extends core implements document_interface, collection_interfa
|
||||||
return is_array($result = collection::execute(
|
return is_array($result = collection::execute(
|
||||||
sprintf(
|
sprintf(
|
||||||
<<<'AQL'
|
<<<'AQL'
|
||||||
FOR v IN 1..1 INBOUND @document GRAPH @graph
|
FOR v IN 1..%u INBOUND @document GRAPH @graph
|
||||||
%s
|
%s
|
||||||
%s
|
%s
|
||||||
LIMIT @offset, @amount
|
LIMIT @offset, @amount
|
||||||
RETURN DISTINCT IS_SAME_COLLECTION(@category, v._id) ? MERGE(v, {_type: @category%s}) : MERGE(v, {_type: @product%s})
|
RETURN DISTINCT IS_SAME_COLLECTION(@category, v._id) ? MERGE(v, {_type: @category%s}) : MERGE(v, {_type: @product%s})
|
||||||
AQL,
|
AQL,
|
||||||
|
$depth,
|
||||||
empty($filter) ? '' : "FILTER $filter",
|
empty($filter) ? '' : "FILTER $filter",
|
||||||
empty($sort) ? '' : "SORT $sort",
|
empty($sort) ? '' : "SORT $sort",
|
||||||
empty($categories_merge) ? '' : ", $categories_merge",
|
empty($categories_merge) ? '' : ", $categories_merge",
|
||||||
|
@ -268,8 +276,8 @@ final class entry extends core implements document_interface, collection_interfa
|
||||||
] + $parameters,
|
] + $parameters,
|
||||||
errors: $errors
|
errors: $errors
|
||||||
)) ? $result : [$result];
|
)) ? $result : [$result];
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . $document::TYPE . ' collection: ' . $document::COLLECTION);
|
} else throw new exception('Failed to initialize ' . $document::TYPE->name . ' collection: ' . $document::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
|
@ -315,8 +323,8 @@ final class entry extends core implements document_interface, collection_interfa
|
||||||
],
|
],
|
||||||
errors: $errors
|
errors: $errors
|
||||||
);
|
);
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . $document::TYPE . ' collection: ' . $document::COLLECTION);
|
} else throw new exception('Failed to initialize ' . $document::TYPE->name . ' collection: ' . $document::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
|
@ -2,15 +2,15 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models\enumerations;
|
namespace mirzaev\huesos\models\enumerations;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\enumerations\language;
|
use mirzaev\huesos\models\enumerations\language;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Types of currencies by ISO 4217 standart
|
* Types of currencies by ISO 4217 standart
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models\enumerations
|
* @package mirzaev\huesos\models\enumerations
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models\enumerations;
|
namespace mirzaev\huesos\models\enumerations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Types of deliveries
|
* Types of deliveries
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models\enumerations
|
* @package mirzaev\huesos\models\enumerations
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace mirzaev\huesos\models\enumerations;
|
||||||
|
|
||||||
|
// Files of the project
|
||||||
|
use mirzaev\huesos\models\enumerations\language;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Types of destination
|
||||||
|
*
|
||||||
|
* @package mirzaev\huesos\models\enumerations
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
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 => 'До двери'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models\enumerations;
|
namespace mirzaev\huesos\models\enumerations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Types of languages by ISO 639-1 standart
|
* Types of languages by ISO 639-1 standart
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models\enumerations
|
* @package mirzaev\huesos\models\enumerations
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models\enumerations;
|
namespace mirzaev\huesos\models\enumerations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Types of session verification
|
* Types of session verification
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models\enumerations
|
* @package mirzaev\huesos\models\enumerations
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models\interfaces;
|
namespace mirzaev\huesos\models\interfaces;
|
||||||
|
|
||||||
// Framework for ArangoDB
|
// Framework for ArangoDB
|
||||||
use mirzaev\arangodb\enumerations\collection\type;
|
use mirzaev\arangodb\enumerations\collection\type;
|
||||||
|
@ -10,7 +10,7 @@ use mirzaev\arangodb\enumerations\collection\type;
|
||||||
/**
|
/**
|
||||||
* Interface for implementing a collection from ArangoDB
|
* Interface for implementing a collection from ArangoDB
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models\traits
|
* @package mirzaev\huesos\models\traits
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models\interfaces;
|
namespace mirzaev\huesos\models\interfaces;
|
||||||
|
|
||||||
// Library для ArangoDB
|
// Library для ArangoDB
|
||||||
use ArangoDBClient\Document as _document;
|
use ArangoDBClient\Document as _document;
|
||||||
|
@ -12,7 +12,7 @@ use ArangoDBClient\Document as _document;
|
||||||
*
|
*
|
||||||
* @param _document $document An instance of the ArangoDB document from ArangoDB (protected readonly)
|
* @param _document $document An instance of the ArangoDB document from ArangoDB (protected readonly)
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models\traits
|
* @package mirzaev\huesos\models\traits
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
@ -2,18 +2,18 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models;
|
namespace mirzaev\huesos\models;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\core,
|
use mirzaev\huesos\models\core,
|
||||||
mirzaev\arming_bot\models\traits\document as document_trait,
|
mirzaev\huesos\models\traits\document as document_trait,
|
||||||
mirzaev\arming_bot\models\interfaces\document as document_interface,
|
mirzaev\huesos\models\interfaces\document as document_interface,
|
||||||
mirzaev\arming_bot\models\interfaces\collection as collection_interface;
|
mirzaev\huesos\models\interfaces\collection as collection_interface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model of menu
|
* Model of menu
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\huesos\models
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
@ -0,0 +1,156 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
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,
|
||||||
|
mirzaev\huesos\models\interfaces\collection as collection_interface,
|
||||||
|
mirzaev\huesos\models\enumerations\language,
|
||||||
|
mirzaev\huesos\models\enumerations\currency;
|
||||||
|
|
||||||
|
// Framework for ArangoDB
|
||||||
|
use mirzaev\arangodb\collection,
|
||||||
|
mirzaev\arangodb\document;
|
||||||
|
|
||||||
|
// Library for ArangoDB
|
||||||
|
use ArangoDBClient\Document as _document;
|
||||||
|
|
||||||
|
// Built-in libraries
|
||||||
|
use exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model of order
|
||||||
|
*
|
||||||
|
* @uses !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
* @package mirzaev\huesos\models
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
final class order extends core implements document_interface, collection_interface
|
||||||
|
{
|
||||||
|
use document_trait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,15 +2,15 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models;
|
namespace mirzaev\huesos\models;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\core,
|
use mirzaev\huesos\models\core,
|
||||||
mirzaev\arming_bot\models\traits\document as document_trait,
|
mirzaev\huesos\models\traits\document as document_trait,
|
||||||
mirzaev\arming_bot\models\interfaces\document as document_interface,
|
mirzaev\huesos\models\interfaces\document as document_interface,
|
||||||
mirzaev\arming_bot\models\interfaces\collection as collection_interface,
|
mirzaev\huesos\models\interfaces\collection as collection_interface,
|
||||||
mirzaev\arming_bot\models\enumerations\language,
|
mirzaev\huesos\models\enumerations\language,
|
||||||
mirzaev\arming_bot\models\enumerations\currency;
|
mirzaev\huesos\models\enumerations\currency;
|
||||||
|
|
||||||
// Framework for ArangoDB
|
// Framework for ArangoDB
|
||||||
use mirzaev\arangodb\collection,
|
use mirzaev\arangodb\collection,
|
||||||
|
@ -25,7 +25,7 @@ use exception;
|
||||||
/**
|
/**
|
||||||
* Model of a product
|
* Model of a product
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\huesos\models
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
@ -100,7 +100,7 @@ final class product extends core implements document_interface, collection_inter
|
||||||
] + $data,
|
] + $data,
|
||||||
errors: $errors
|
errors: $errors
|
||||||
);
|
);
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
|
@ -225,7 +225,7 @@ final class product extends core implements document_interface, collection_inter
|
||||||
// Exit (success)
|
// Exit (success)
|
||||||
return is_array($result) ? $result : [$result];
|
return is_array($result) ? $result : [$result];
|
||||||
}
|
}
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
|
@ -281,7 +281,7 @@ final class product extends core implements document_interface, collection_inter
|
||||||
// Exit (success)
|
// Exit (success)
|
||||||
return is_array($result) ? $result : [$result];
|
return is_array($result) ? $result : [$result];
|
||||||
} else return [];
|
} else return [];
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models;
|
namespace mirzaev\huesos\models;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\core,
|
use mirzaev\huesos\models\core,
|
||||||
mirzaev\arming_bot\models\cart,
|
mirzaev\huesos\models\cart,
|
||||||
mirzaev\arming_bot\models\traits\document as document_trait,
|
mirzaev\huesos\models\traits\document as document_trait,
|
||||||
mirzaev\arming_bot\models\interfaces\document as document_interface,
|
mirzaev\huesos\models\interfaces\document as document_interface,
|
||||||
mirzaev\arming_bot\models\interfaces\collection as collection_interface;
|
mirzaev\huesos\models\interfaces\collection as collection_interface;
|
||||||
|
|
||||||
// Framework for ArangoDB
|
// Framework for ArangoDB
|
||||||
use mirzaev\arangodb\enumerations\collection\type;
|
use mirzaev\arangodb\enumerations\collection\type;
|
||||||
|
@ -18,7 +18,7 @@ use mirzaev\arangodb\enumerations\collection\type;
|
||||||
* Model of reservtion
|
* Model of reservtion
|
||||||
*
|
*
|
||||||
* @used-by cart
|
* @used-by cart
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\huesos\models
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
@ -2,20 +2,20 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models;
|
namespace mirzaev\huesos\models;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\account,
|
use mirzaev\huesos\models\account,
|
||||||
mirzaev\arming_bot\models\connect,
|
mirzaev\huesos\models\connect,
|
||||||
mirzaev\arming_bot\models\enumerations\session as verification,
|
mirzaev\huesos\models\enumerations\session as verification,
|
||||||
mirzaev\arming_bot\models\traits\status,
|
mirzaev\huesos\models\traits\status,
|
||||||
mirzaev\arming_bot\models\traits\buffer,
|
mirzaev\huesos\models\traits\buffer,
|
||||||
mirzaev\arming_bot\models\traits\cart,
|
mirzaev\huesos\models\traits\cart,
|
||||||
mirzaev\arming_bot\models\traits\document as document_trait,
|
mirzaev\huesos\models\traits\document as document_trait,
|
||||||
mirzaev\arming_bot\models\interfaces\document as document_interface,
|
mirzaev\huesos\models\interfaces\document as document_interface,
|
||||||
mirzaev\arming_bot\models\interfaces\collection as collection_interface,
|
mirzaev\huesos\models\interfaces\collection as collection_interface,
|
||||||
mirzaev\arming_bot\models\enumerations\language,
|
mirzaev\huesos\models\enumerations\language,
|
||||||
mirzaev\arming_bot\models\enumerations\currency;
|
mirzaev\huesos\models\enumerations\currency;
|
||||||
|
|
||||||
// Framework for ArangoDB
|
// Framework for ArangoDB
|
||||||
use mirzaev\arangodb\collection,
|
use mirzaev\arangodb\collection,
|
||||||
|
@ -30,7 +30,7 @@ use exception;
|
||||||
/**
|
/**
|
||||||
* Model of a session
|
* Model of a session
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\huesos\models
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
@ -114,14 +114,14 @@ final class session extends core implements document_interface, collection_inter
|
||||||
$session->hash = sodium_bin2hex(sodium_crypto_generichash($_id));
|
$session->hash = sodium_bin2hex(sodium_crypto_generichash($_id));
|
||||||
|
|
||||||
if (document::update($session, errors: $errors)) {
|
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
|
// Writing instance of the session document from ArangoDB to the property of the implementing object
|
||||||
$this->__document($session);
|
$this->__document($session);
|
||||||
} else throw new exception('Failed to write the session data');
|
} else throw new exception('Failed to write the session data');
|
||||||
} else throw new exception('Failed to create or find just created session');
|
} else throw new exception('Failed to create or find just created session');
|
||||||
}
|
}
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
|
@ -185,9 +185,9 @@ final class session extends core implements document_interface, collection_inter
|
||||||
return $account;
|
return $account;
|
||||||
} else throw new exception('Class ' . account::class . ' does not implement a document from ArangoDB');
|
} else throw new exception('Class ' . account::class . ' does not implement a document from ArangoDB');
|
||||||
} else return null;
|
} else return null;
|
||||||
} else throw new exception('Failed to initialize ' . account::TYPE . ' collection: ' . account::COLLECTION);
|
} else throw new exception('Failed to initialize ' . account::TYPE->name . ' collection: ' . account::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . connect::TYPE . ' collection: ' . connect::COLLECTION);
|
} else throw new exception('Failed to initialize ' . connect::TYPE->name . ' collection: ' . connect::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
|
@ -232,7 +232,7 @@ final class session extends core implements document_interface, collection_inter
|
||||||
],
|
],
|
||||||
errors: $errors
|
errors: $errors
|
||||||
);
|
);
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
|
@ -279,7 +279,7 @@ final class session extends core implements document_interface, collection_inter
|
||||||
],
|
],
|
||||||
errors: $errors
|
errors: $errors
|
||||||
);
|
);
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
|
@ -2,15 +2,15 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models;
|
namespace mirzaev\huesos\models;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\core,
|
use mirzaev\huesos\models\core,
|
||||||
mirzaev\arming_bot\models\traits\document as document_trait,
|
mirzaev\huesos\models\traits\document as document_trait,
|
||||||
mirzaev\arming_bot\models\interfaces\document as document_interface,
|
mirzaev\huesos\models\interfaces\document as document_interface,
|
||||||
mirzaev\arming_bot\models\interfaces\collection as collection_interface,
|
mirzaev\huesos\models\interfaces\collection as collection_interface,
|
||||||
mirzaev\arming_bot\models\enumerations\language,
|
mirzaev\huesos\models\enumerations\language,
|
||||||
mirzaev\arming_bot\models\enumerations\currency;
|
mirzaev\huesos\models\enumerations\currency;
|
||||||
|
|
||||||
// Framework for ArangoDB
|
// Framework for ArangoDB
|
||||||
use mirzaev\arangodb\collection,
|
use mirzaev\arangodb\collection,
|
||||||
|
@ -25,7 +25,7 @@ use exception;
|
||||||
/**
|
/**
|
||||||
* Model of settings
|
* Model of settings
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\huesos\models
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
@ -96,7 +96,7 @@ final class settings extends core implements document_interface, collection_inte
|
||||||
// Re-search (without creating) and exit (success || fail)
|
// Re-search (without creating) and exit (success || fail)
|
||||||
return static::active(errors: $errors);
|
return static::active(errors: $errors);
|
||||||
} else throw new exception('Active settings not found');
|
} else throw new exception('Active settings not found');
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models;
|
namespace mirzaev\huesos\models;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\core,
|
use mirzaev\huesos\models\core,
|
||||||
mirzaev\arming_bot\models\traits\document as document_trait,
|
mirzaev\huesos\models\traits\document as document_trait,
|
||||||
mirzaev\arming_bot\models\interfaces\document as document_interface,
|
mirzaev\huesos\models\interfaces\document as document_interface,
|
||||||
mirzaev\arming_bot\models\interfaces\collection as collection_interface,
|
mirzaev\huesos\models\interfaces\collection as collection_interface,
|
||||||
mirzaev\arming_bot\models\enumerations\language;
|
mirzaev\huesos\models\enumerations\language;
|
||||||
|
|
||||||
// Framework for ArangoDB
|
// Framework for ArangoDB
|
||||||
use mirzaev\arangodb\collection,
|
use mirzaev\arangodb\collection,
|
||||||
|
@ -25,7 +25,7 @@ use exception,
|
||||||
/**
|
/**
|
||||||
* Model of a suspension
|
* Model of a suspension
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models
|
* @package mirzaev\huesos\models
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
@ -84,7 +84,7 @@ final class suspension extends core implements document_interface, collection_in
|
||||||
return $suspension;
|
return $suspension;
|
||||||
} else throw new exception('Class ' . static::class . ' does not implement a document from ArangoDB');
|
} else throw new exception('Class ' . static::class . ' does not implement a document from ArangoDB');
|
||||||
} else return null;
|
} else return null;
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
File diff suppressed because it is too large
Load Diff
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models\traits;
|
namespace mirzaev\huesos\models\traits;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\interfaces\collection as collection_interface,
|
use mirzaev\huesos\models\interfaces\collection as collection_interface,
|
||||||
mirzaev\arming_bot\models\enumerations\language,
|
mirzaev\huesos\models\enumerations\language,
|
||||||
mirzaev\arming_bot\models\enumerations\currency;
|
mirzaev\huesos\models\enumerations\currency;
|
||||||
|
|
||||||
// Library for ArangoDB
|
// Library for ArangoDB
|
||||||
use ArangoDBClient\Document as _document;
|
use ArangoDBClient\Document as _document;
|
||||||
|
@ -28,7 +28,7 @@ use exception;
|
||||||
* @param static TYPE Type of the collection in ArangoDB
|
* @param static TYPE Type of the collection in ArangoDB
|
||||||
*
|
*
|
||||||
* @uses collection_interface
|
* @uses collection_interface
|
||||||
* @package mirzaev\arming_bot\models\traits
|
* @package mirzaev\huesos\models\traits
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
@ -64,7 +64,7 @@ trait buffer
|
||||||
|
|
||||||
// Writing to ArangoDB and exit (success)
|
// Writing to ArangoDB and exit (success)
|
||||||
return document::update($this->__document(), errors: $errors);
|
return document::update($this->__document(), errors: $errors);
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models\traits;
|
namespace mirzaev\huesos\models\traits;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\interfaces\collection as collection_interface,
|
use mirzaev\huesos\models\interfaces\collection as collection_interface,
|
||||||
mirzaev\arming_bot\models\interfaces\document as document_interface,
|
mirzaev\huesos\models\interfaces\document as document_interface,
|
||||||
mirzaev\arming_bot\models\traits\document as document_trait,
|
mirzaev\huesos\models\traits\document as document_trait,
|
||||||
mirzaev\arming_bot\models\connect,
|
mirzaev\huesos\models\connect,
|
||||||
mirzaev\arming_bot\models\cart as model;
|
mirzaev\huesos\models\cart as model;
|
||||||
|
|
||||||
// Library для ArangoDB
|
// Library для ArangoDB
|
||||||
use ArangoDBClient\Document as _document;
|
use ArangoDBClient\Document as _document;
|
||||||
|
@ -28,7 +28,7 @@ use exception;
|
||||||
*
|
*
|
||||||
* @uses collection_interface
|
* @uses collection_interface
|
||||||
* @uses document_interface
|
* @uses document_interface
|
||||||
* @package mirzaev\arming_bot\models\traits
|
* @package mirzaev\huesos\models\traits
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
@ -132,9 +132,9 @@ trait cart
|
||||||
} else throw new exception('Class ' . model::class . ' does not implement a document from ArangoDB');
|
} else throw new exception('Class ' . model::class . ' does not implement a document from ArangoDB');
|
||||||
} else throw new exception('Failed to create or find just created ' . static::class);
|
} else throw new exception('Failed to create or find just created ' . static::class);
|
||||||
}
|
}
|
||||||
} else throw new exception('Failed to initialize ' . model::TYPE . ' collection: ' . model::COLLECTION);
|
} else throw new exception('Failed to initialize ' . model::TYPE->name . ' collection: ' . model::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . connect::TYPE . ' collection: ' . connect::COLLECTION);
|
} else throw new exception('Failed to initialize ' . connect::TYPE->name . ' collection: ' . connect::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models\traits;
|
namespace mirzaev\huesos\models\traits;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\models\interfaces\document as document_interface,
|
use mirzaev\huesos\models\interfaces\document as document_interface,
|
||||||
mirzaev\arming_bot\models\interfaces\collection as collection_interface,
|
mirzaev\huesos\models\interfaces\collection as collection_interface,
|
||||||
mirzaev\arming_bot\models\connect;
|
mirzaev\huesos\models\connect;
|
||||||
|
|
||||||
// Library для ArangoDB
|
// Library для ArangoDB
|
||||||
use ArangoDBClient\Document as _document;
|
use ArangoDBClient\Document as _document;
|
||||||
|
@ -26,7 +26,7 @@ use exception;
|
||||||
* @var protected readonly _document|null $document An instance of the ArangoDB document
|
* @var protected readonly _document|null $document An instance of the ArangoDB document
|
||||||
*
|
*
|
||||||
* @uses document_interface
|
* @uses document_interface
|
||||||
* @package mirzaev\arming_bot\models\traits
|
* @package mirzaev\huesos\models\traits
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
@ -79,10 +79,12 @@ trait document
|
||||||
/**
|
/**
|
||||||
* Connect
|
* Connect
|
||||||
*
|
*
|
||||||
|
* Searches for a connection document, otherwise creates one
|
||||||
|
*
|
||||||
* @param collecton_interface $document Document
|
* @param collecton_interface $document Document
|
||||||
* @param array &$errors Registry of errors
|
* @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
|
public function connect(collection_interface $document, array &$errors = []): ?string
|
||||||
{
|
{
|
||||||
|
@ -95,19 +97,50 @@ trait document
|
||||||
if ($this->document instanceof _document) {
|
if ($this->document instanceof _document) {
|
||||||
// Initialized instance of the document from ArangoDB
|
// Initialized instance of the document from ArangoDB
|
||||||
|
|
||||||
// Writing document and exit (success)
|
// Searching for a connection
|
||||||
return framework_document::write(
|
$found = collection::execute(
|
||||||
connect::COLLECTION,
|
<<<'AQL'
|
||||||
|
FOR d IN @@collection
|
||||||
|
FILTER d._from == @_from && d._to == @_to && d.active == true
|
||||||
|
RETURN d
|
||||||
|
AQL,
|
||||||
[
|
[
|
||||||
|
'@collection' => connect::COLLECTION,
|
||||||
'_from' => $document->getId(),
|
'_from' => $document->getId(),
|
||||||
'_to' => $this->document->getId()
|
'_to' => $this->document->getId()
|
||||||
],
|
],
|
||||||
errors: $errors
|
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('The instance of the document from ArangoDB is not initialized');
|
||||||
} else throw new exception('Failed to initialize ' . $document::TYPE . ' collection: ' . $document::COLLECTION);
|
} else throw new exception('Failed to initialize ' . $document::TYPE->name . ' collection: ' . $document::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . connect::TYPE . ' collection: ' . connect::COLLECTION);
|
} else throw new exception('Failed to initialize ' . connect::TYPE->name . ' collection: ' . connect::COLLECTION);
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE->name . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models\traits;
|
namespace mirzaev\huesos\models\traits;
|
||||||
|
|
||||||
// Built-in libraries
|
// Built-in libraries
|
||||||
use exception;
|
use exception;
|
||||||
|
@ -10,7 +10,7 @@ use exception;
|
||||||
/**
|
/**
|
||||||
* Trait for initialization of files handlers
|
* Trait for initialization of files handlers
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models\traits
|
* @package mirzaev\huesos\models\traits
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models\traits;
|
namespace mirzaev\huesos\models\traits;
|
||||||
|
|
||||||
// Built-in libraries
|
// Built-in libraries
|
||||||
use exception;
|
use exception;
|
||||||
|
@ -10,7 +10,7 @@ use exception;
|
||||||
/**
|
/**
|
||||||
* Trait for initialization of a status
|
* Trait for initialization of a status
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models\traits
|
* @package mirzaev\huesos\models\traits
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot\models\traits\yandex;
|
namespace mirzaev\huesos\models\traits\yandex;
|
||||||
|
|
||||||
// Framework for PHP
|
// Framework for PHP
|
||||||
use mirzaev\minimal\http\enumerations\content;
|
use mirzaev\minimal\http\enumerations\content;
|
||||||
|
@ -13,7 +13,7 @@ use exception;
|
||||||
/**
|
/**
|
||||||
* Trait for "Yandex Disk"
|
* Trait for "Yandex Disk"
|
||||||
*
|
*
|
||||||
* @package mirzaev\arming_bot\models\traits\yandex
|
* @package mirzaev\huesos\models\traits\yandex
|
||||||
*
|
*
|
||||||
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
@ -21,14 +21,14 @@ use exception;
|
||||||
trait disk
|
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 $uri URI of the file from "Yandex Disk"
|
||||||
* @param string $destination Destination to write the file
|
* @param string $destination Destination to write the file
|
||||||
* @param string|int $name Name for the file
|
* @param string|int $name Name for the file
|
||||||
* @param array &$errors Registry of errors
|
* @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(
|
private static function download(
|
||||||
string $uri,
|
string $uri,
|
||||||
|
@ -101,4 +101,52 @@ trait disk
|
||||||
// Exit (fail)
|
// Exit (fail)
|
||||||
return false;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -2,28 +2,31 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot;
|
namespace mirzaev\huesos;
|
||||||
|
|
||||||
// Framework for PHP
|
// Framework for PHP
|
||||||
use mirzaev\minimal\core,
|
use mirzaev\minimal\core,
|
||||||
mirzaev\minimal\route;
|
mirzaev\minimal\route;
|
||||||
|
|
||||||
// Enabling debugging
|
// Enabling debugging
|
||||||
ini_set('error_reporting', E_ALL);
|
/* ini_set('error_reporting', E_ALL);
|
||||||
ini_set('display_errors', 1);
|
ini_set('display_errors', 1);
|
||||||
ini_set('display_startup_errors', 1);
|
ini_set('display_startup_errors', 1); */
|
||||||
|
|
||||||
// Версия робота
|
// Версия робота
|
||||||
define('ROBOT_VERSION', '1.0.0');
|
define('ROBOT_VERSION', '1.0.0');
|
||||||
define('VIEWS', realpath('..' . DIRECTORY_SEPARATOR . 'views'));
|
define('VIEWS', realpath('..' . DIRECTORY_SEPARATOR . 'views'));
|
||||||
define('STORAGE', realpath('..' . DIRECTORY_SEPARATOR . 'storage'));
|
define('STORAGE', realpath('..' . DIRECTORY_SEPARATOR . 'storage'));
|
||||||
define('SETTINGS', realpath('..' . DIRECTORY_SEPARATOR . 'settings'));
|
define('SETTINGS', realpath('..' . DIRECTORY_SEPARATOR . 'settings'));
|
||||||
|
define('SETTINGS_PROJECT', require(SETTINGS . DIRECTORY_SEPARATOR . 'project.php'));
|
||||||
define('INDEX', __DIR__);
|
define('INDEX', __DIR__);
|
||||||
define('ROOT', INDEX . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR);
|
define('ROOT', INDEX . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR);
|
||||||
define('THEME', 'default');
|
define('THEME', 'default');
|
||||||
|
|
||||||
define('CDEK', require(SETTINGS . DIRECTORY_SEPARATOR . 'deliveries' . DIRECTORY_SEPARATOR . 'cdek.php'));
|
define('CDEK', require(SETTINGS . DIRECTORY_SEPARATOR . 'deliveries' . DIRECTORY_SEPARATOR . 'cdek.php'));
|
||||||
|
|
||||||
|
define('TELEGRAM_KEY', require(SETTINGS . DIRECTORY_SEPARATOR . 'telegram.php'));
|
||||||
|
|
||||||
// Initialize dependencies
|
// Initialize dependencies
|
||||||
require ROOT . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
|
require ROOT . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
|
||||||
|
|
||||||
|
@ -37,9 +40,12 @@ $core->router
|
||||||
->write('/cart', new route('cart', 'index', 'cart'), 'GET')
|
->write('/cart', new route('cart', 'index', 'cart'), 'GET')
|
||||||
->write('/cart/product', new route('cart', 'product', 'cart'), 'PATCH')
|
->write('/cart/product', new route('cart', 'product', 'cart'), 'PATCH')
|
||||||
->write('/cart/summary', new route('cart', 'summary', 'cart'), 'GET')
|
->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/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('/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('/account/write', new route('account', 'write', 'account'), 'PATCH')
|
||||||
->write('/session/write', new route('session', 'write', 'session'), 'PATCH')
|
->write('/session/write', new route('session', 'write', 'session'), 'PATCH')
|
||||||
->write('/session/connect/telegram', new route('session', 'telegram', 'session'), 'PUT')
|
->write('/session/connect/telegram', new route('session', 'telegram', 'session'), 'PUT')
|
|
@ -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);
|
|
@ -17,11 +17,11 @@ class core {
|
||||||
// Window
|
// Window
|
||||||
static window;
|
static window;
|
||||||
|
|
||||||
// The "loading" element
|
// Account
|
||||||
static status_loading = document.getElementById("loading");
|
static account;
|
||||||
|
|
||||||
// The "account" element
|
// The "loading" element
|
||||||
static status_account = document.getElementById("account");
|
static loading = document.getElementById("loading");
|
||||||
|
|
||||||
// The <header> element
|
// The <header> element
|
||||||
static header = document.body.getElementsByTagName("header")[0];
|
static header = document.body.getElementsByTagName("header")[0];
|
|
@ -30,10 +30,10 @@ export default class account {
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
static authentication() {
|
static authentication() {
|
||||||
core.status_loading.removeAttribute("disabled");
|
core.loading.removeAttribute("disabled");
|
||||||
|
|
||||||
const timer_for_response = setTimeout(() => {
|
const timer_for_response = setTimeout(() => {
|
||||||
core.status_loading.setAttribute("disabled", true);
|
core.loading.setAttribute("disabled", true);
|
||||||
}, 200);
|
}, 200);
|
||||||
|
|
||||||
core.modules.connect("telegram").then(() => {
|
core.modules.connect("telegram").then(() => {
|
||||||
|
@ -44,7 +44,7 @@ export default class account {
|
||||||
.request(
|
.request(
|
||||||
"/session/connect/telegram",
|
"/session/connect/telegram",
|
||||||
core.telegram.api.initData,
|
core.telegram.api.initData,
|
||||||
'PUT'
|
"PUT",
|
||||||
)
|
)
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
if (json) {
|
if (json) {
|
||||||
|
@ -63,20 +63,66 @@ export default class account {
|
||||||
// Success (not received errors)
|
// Success (not received errors)
|
||||||
|
|
||||||
if (json.connected === true) {
|
if (json.connected === true) {
|
||||||
core.status_loading.setAttribute("disabled", true);
|
// Deactivating the loading screen
|
||||||
|
core.loading.setAttribute("disabled", true);
|
||||||
clearTimeout(timer_for_response);
|
clearTimeout(timer_for_response);
|
||||||
|
|
||||||
const a = core.status_account.getElementsByTagName("a")[0];
|
core.account = {
|
||||||
a.setAttribute("onclick", "core.account.profile()");
|
identifier: json.identifier
|
||||||
a.innerText = json.domain.length > 0
|
};
|
||||||
? "@" + json.domain
|
|
||||||
: "ERROR";
|
// 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 (
|
if (
|
||||||
json.language !== null &&
|
json.language !== null &&
|
||||||
typeof json.language === "string" &&
|
typeof json.language === "string" &&
|
||||||
json.langiage.length === 2
|
json.language.length === 2
|
||||||
) {
|
) {
|
||||||
core.language = json.language;
|
core.language = json.language;
|
||||||
}
|
}
|
|
@ -69,7 +69,7 @@ export default class cart {
|
||||||
* @name Write (interface)
|
* @name Write (interface)
|
||||||
*
|
*
|
||||||
* @description
|
* @description
|
||||||
* Write the product in the cart
|
* Write the product into the cart
|
||||||
*
|
*
|
||||||
* @param {HTMLButtonElement|HTMLInputElement|null} element Handler elememnt of the product
|
* @param {HTMLButtonElement|HTMLInputElement|null} element Handler elememnt of the product
|
||||||
* @param {HTMLElement} product The product element
|
* @param {HTMLElement} product The product element
|
||||||
|
@ -388,7 +388,7 @@ export default class cart {
|
||||||
static async share(button) {
|
static async share(button) {
|
||||||
return await core.modules.connect("telegram").then(
|
return await core.modules.connect("telegram").then(
|
||||||
() => {
|
() => {
|
||||||
// Imported the damper module
|
// Imported the telegram module
|
||||||
|
|
||||||
// Disabling button
|
// Disabling button
|
||||||
button?.setAttribute("disabled", true);
|
button?.setAttribute("disabled", true);
|
||||||
|
@ -771,6 +771,24 @@ Object.assign(
|
||||||
} else {
|
} else {
|
||||||
// Success (not received errors)
|
// 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 <span> element
|
// Initializing the summary amount <span> element
|
||||||
const amount = document.getElementById("amount");
|
const amount = document.getElementById("amount");
|
||||||
|
|
||||||
|
@ -844,7 +862,7 @@ Object.assign(
|
||||||
try {
|
try {
|
||||||
// Request
|
// Request
|
||||||
return await core.request("/cart/share", undefined, "POST")
|
return await core.request("/cart/share", undefined, "POST")
|
||||||
.then((json) => {
|
.then(async (json) => {
|
||||||
if (json) {
|
if (json) {
|
||||||
// Received a JSON-response
|
// Received a JSON-response
|
||||||
|
|
||||||
|
@ -863,13 +881,43 @@ Object.assign(
|
||||||
if (json.share) {
|
if (json.share) {
|
||||||
// Received sharing hash
|
// Received sharing hash
|
||||||
|
|
||||||
// Request to the chat-robot
|
// Sending the request to the chat-robot
|
||||||
core.telegram.api.sendData(
|
const sended = core.telegram.api.sendData(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
type: "cart_share",
|
type: "cart_share",
|
||||||
hash: json.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) {
|
/* if (json.robokassa) {
|
File diff suppressed because it is too large
Load Diff
|
@ -15,6 +15,11 @@ export default class loader {
|
||||||
*/
|
*/
|
||||||
static type = "module";
|
static type = "module";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Actial URI
|
||||||
|
*/
|
||||||
|
static uri;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name Load
|
* @name Load
|
||||||
*
|
*
|
||||||
|
@ -23,7 +28,7 @@ export default class loader {
|
||||||
*
|
*
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
static async load(uri = "/", body) {
|
static async load(uri = "/", body, back = false) {
|
||||||
if (typeof uri === "string") {
|
if (typeof uri === "string") {
|
||||||
// Received and validated uri
|
// Received and validated uri
|
||||||
|
|
||||||
|
@ -54,8 +59,27 @@ export default class loader {
|
||||||
} else {
|
} else {
|
||||||
// Success (not received errors)
|
// Success (not received errors)
|
||||||
|
|
||||||
// Writing to the browser history
|
if (back) {
|
||||||
history.pushState({}, json.title ?? uri, uri);
|
// Requested to go back
|
||||||
|
|
||||||
|
// Writing actual URI
|
||||||
|
this.uri = history.state?.previous;
|
||||||
|
|
||||||
|
// Deletimg from the browser history
|
||||||
|
history.back();
|
||||||
|
} else {
|
||||||
|
// Requested to go forward
|
||||||
|
|
||||||
|
// Writing to the browser history
|
||||||
|
history.pushState(
|
||||||
|
{ previous: this.uri },
|
||||||
|
json.title ?? uri,
|
||||||
|
uri,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Writing actual URI
|
||||||
|
this.uri = uri;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The <title>
|
* The <title>
|
||||||
|
@ -222,7 +246,10 @@ export default class loader {
|
||||||
// Found the last <section> element inside the <body> element
|
// Found the last <section> element inside the <body> element
|
||||||
|
|
||||||
// Writing the <main> element after the last <section> element inside the <body> element
|
// Writing the <main> element after the last <section> element inside the <body> element
|
||||||
body.insertBefore(core.main, section.nextElementSibling);
|
body.insertBefore(
|
||||||
|
core.main,
|
||||||
|
section.nextElementSibling,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// Not found section elements <section> inside the <body> element
|
// Not found section elements <section> inside the <body> element
|
||||||
|
|
|
@ -21,6 +21,11 @@ export default class telegram {
|
||||||
* @see {@link https://core.telegram.org/bots/webapps#initializing-mini-apps}
|
* @see {@link https://core.telegram.org/bots/webapps#initializing-mini-apps}
|
||||||
*/
|
*/
|
||||||
static api = window.Telegram.WebApp;
|
static api = window.Telegram.WebApp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name List of BackButton events
|
||||||
|
*/
|
||||||
|
static back = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connecting to the core
|
// Connecting to the core
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
core.modules.connect(["telegram"])
|
core.modules.connect(["telegram"])
|
||||||
.then(() => {
|
.then(() => {
|
||||||
//
|
// Imported the telegram module
|
||||||
|
|
||||||
// Expanding the "Web App" window
|
// Expanding the "Web App" window
|
||||||
// core.telegram.api.expand();
|
core.telegram.api.expand();
|
||||||
|
|
||||||
// Writing settings for the "Web App" window
|
// Writing settings for the "Web App" window
|
||||||
core.telegram.api.enableVerticalSwipes();
|
core.telegram.api.enableVerticalSwipes();
|
||||||
|
@ -24,6 +24,20 @@ core.modules.connect(["telegram"])
|
||||||
document.documentElement.style.setProperty('--tg-theme-section-bg-color', 'var(--tg-theme-secondary-bg-color)');
|
document.documentElement.style.setProperty('--tg-theme-section-bg-color', 'var(--tg-theme-secondary-bg-color)');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (core.telegram.back.length > 0) {
|
||||||
|
// Initialized BackButton events
|
||||||
|
|
||||||
|
// Initializing the "Back Button" of the "Web App" window
|
||||||
|
core.telegram.api.BackButton.show();
|
||||||
|
|
||||||
|
for (const event of core.telegram.back) {
|
||||||
|
// Iterating over BackButton events
|
||||||
|
|
||||||
|
// Initializing the BackButton event listener
|
||||||
|
core.telegram.api.BackButton.onClick(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
core.modules.connect(["session", "account"])
|
core.modules.connect(["session", "account"])
|
||||||
.then(() => {
|
.then(() => {
|
||||||
//
|
//
|
|
@ -0,0 +1,239 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace mirzaev\huesos;
|
||||||
|
|
||||||
|
// Files of the project
|
||||||
|
use mirzaev\huesos\controllers\core as controller,
|
||||||
|
mirzaev\huesos\models\core as model,
|
||||||
|
mirzaev\huesos\models\cart,
|
||||||
|
mirzaev\huesos\models\telegram;
|
||||||
|
|
||||||
|
// Framework for Telegram
|
||||||
|
use Zanzara\Zanzara as zanzara,
|
||||||
|
Zanzara\Context as context,
|
||||||
|
Zanzara\Config as config;
|
||||||
|
|
||||||
|
// Framework for ArangoDB
|
||||||
|
use mirzaev\arangodb\document;
|
||||||
|
|
||||||
|
ini_set('error_reporting', E_ALL ^ E_DEPRECATED);
|
||||||
|
ini_set('display_errors', 1);
|
||||||
|
ini_set('display_startup_errors', 1);
|
||||||
|
|
||||||
|
// Версия робота
|
||||||
|
define('ROBOT_VERSION', '1.0.0');
|
||||||
|
|
||||||
|
// Путь до настроек
|
||||||
|
define('SETTINGS', __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'settings');
|
||||||
|
|
||||||
|
// Путь до хранилища
|
||||||
|
define('STORAGE', __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'storage');
|
||||||
|
|
||||||
|
// Файл в формате 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');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ключ чат-робота Telegram
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
define('KEY', require(SETTINGS . DIRECTORY_SEPARATOR . 'telegram.php'));
|
||||||
|
define('TELEGRAM_KEY', require(SETTINGS . DIRECTORY_SEPARATOR . 'telegram.php'));
|
||||||
|
|
||||||
|
// Initialize dependencies
|
||||||
|
require __DIR__ . DIRECTORY_SEPARATOR
|
||||||
|
. '..' . DIRECTORY_SEPARATOR
|
||||||
|
. '..' . DIRECTORY_SEPARATOR
|
||||||
|
. '..' . DIRECTORY_SEPARATOR
|
||||||
|
. '..' . DIRECTORY_SEPARATOR
|
||||||
|
. 'vendor' . DIRECTORY_SEPARATOR
|
||||||
|
. 'autoload.php';
|
||||||
|
|
||||||
|
// Инициализация ядра контроллеров MINIMAL
|
||||||
|
/* new controller(new core, false); */
|
||||||
|
|
||||||
|
// Инициализация ядра моделей MINIMAL
|
||||||
|
new model(true);
|
||||||
|
|
||||||
|
$config = new config();
|
||||||
|
$config->setParseMode(config::PARSE_MODE_MARKDOWN);
|
||||||
|
$config->useReactFileSystem(true);
|
||||||
|
|
||||||
|
$robot = new zanzara(TELEGRAM_KEY, $config);
|
||||||
|
|
||||||
|
$robot->onUpdate(function (context $context): void {
|
||||||
|
// Initializing the message
|
||||||
|
$message = $context->getMessage();
|
||||||
|
|
||||||
|
// Initializing the "web app" data
|
||||||
|
$app = $message?->getWebAppData();
|
||||||
|
|
||||||
|
if (!empty($app)) {
|
||||||
|
// Initialized the "web app" data
|
||||||
|
|
||||||
|
// Initializing request from "web app" data
|
||||||
|
$request = json_decode($app->getData(), false, 10);
|
||||||
|
|
||||||
|
if ($request->type === 'cart_share') {
|
||||||
|
// Cart attaching
|
||||||
|
|
||||||
|
// Attaching cart to the Telegram account
|
||||||
|
telegram::cart_attach($context, $request->hash);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Not initialized the "web app" data
|
||||||
|
|
||||||
|
// Initializing account
|
||||||
|
$account = $context->get('account');
|
||||||
|
|
||||||
|
if ($account) {
|
||||||
|
// Initialized the account
|
||||||
|
|
||||||
|
if (!empty($message)) {
|
||||||
|
// Initialized the message
|
||||||
|
|
||||||
|
// Initializing the contact data
|
||||||
|
$contact = $message?->getContact();
|
||||||
|
|
||||||
|
if (!empty($contact)) {
|
||||||
|
// Initialized the contact data
|
||||||
|
|
||||||
|
// Sanitizing received SIM-number (only numbers)
|
||||||
|
$sanitized = preg_replace('/[^\d]/', '', $contact->getPhoneNumber());
|
||||||
|
|
||||||
|
if (!empty($sanitized)) {
|
||||||
|
// Sanitized receiver SIM-number
|
||||||
|
|
||||||
|
// Writing receiver SIM-number into the account
|
||||||
|
$account->receiver = ['sim' => (int) $sanitized] + ($account->receiver ?? []);
|
||||||
|
|
||||||
|
// Deabstracting the language parameter
|
||||||
|
$account->language = $account->language->name;
|
||||||
|
|
||||||
|
if (document::update($account->__document())) {
|
||||||
|
// Writed the account instance into the ArangoDB document
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Sending the message
|
||||||
|
$context->sendMessage(
|
||||||
|
<<<TXT
|
||||||
|
✅ *SIM\-номер зарегистрирован:* $sanitized
|
||||||
|
TXT,
|
||||||
|
[
|
||||||
|
'reply_markup' => [
|
||||||
|
'remove_keyboard' => true
|
||||||
|
]
|
||||||
|
]
|
||||||
|
)->then(function ($message) use ($context) {
|
||||||
|
// Sended message
|
||||||
|
|
||||||
|
// Sending the account parameters menu
|
||||||
|
telegram::account_parameters($context);
|
||||||
|
}); */
|
||||||
|
|
||||||
|
// Sending the message
|
||||||
|
$context->sendMessage(
|
||||||
|
<<<TXT
|
||||||
|
✅ *Номер телефона зарегистрирован:* $sanitized
|
||||||
|
TXT,
|
||||||
|
[
|
||||||
|
'reply_markup' => [
|
||||||
|
'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
|
||||||
|
$context->sendMessage('⚠️ *Не удалось записать SIM\-номер*');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($app);
|
||||||
|
});
|
||||||
|
|
||||||
|
$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));
|
||||||
|
|
||||||
|
$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));
|
||||||
|
|
||||||
|
$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));
|
||||||
|
|
||||||
|
$robot->onCbQueryData(['mail'], fn(context $context) => telegram::_mail($context));
|
||||||
|
$robot->onCbQueryData(['import_request'], fn(context $context) => telegram::import_request($context));
|
||||||
|
|
||||||
|
$robot->onCbQueryData(['order_commentary_request'], fn(context $context) => telegram::order_commentary_request($context));
|
||||||
|
$robot->onCbQueryData(['order'], fn(context $context) => telegram::order($context));
|
||||||
|
|
||||||
|
$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 с обработкой аккаунта
|
||||||
|
$robot->middleware([telegram::class, "account"]);
|
||||||
|
|
||||||
|
// Инициализация middleware с обработкой технических работ разных уровней
|
||||||
|
$robot->middleware([telegram::class, "suspension"]);
|
||||||
|
|
||||||
|
// Запуск чат-робота
|
||||||
|
$robot->run();
|
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace mirzaev\arming_bot;
|
namespace mirzaev\huesos;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\controllers\core as controller,
|
use mirzaev\huesos\controllers\core as controller,
|
||||||
mirzaev\arming_bot\models\core as model,
|
mirzaev\huesos\models\core as model,
|
||||||
mirzaev\arming_bot\models\socket;
|
mirzaev\huesos\models\socket;
|
||||||
|
|
||||||
// Framework for PHP
|
// Framework for PHP
|
||||||
use mirzaev\minimal\core;
|
use mirzaev\minimal\core;
|
|
@ -0,0 +1,19 @@
|
||||||
|
@charset "UTF-8";
|
||||||
|
|
||||||
|
section#account {
|
||||||
|
z-index: 999;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 20px;
|
||||||
|
left: 20px;
|
||||||
|
height: 16px;
|
||||||
|
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); */
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
@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%);
|
||||||
|
clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translate(0, -100%);
|
||||||
|
clip-path: polygon(0% 100%, 100% 100%, 100% 200%, 0% 200%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide.down.revert.animated {
|
||||||
|
animation-duration: var(--animation-duration, 0.25s);
|
||||||
|
animation-name: slide-down-revert;
|
||||||
|
animation-fill-mode: forwards;
|
||||||
|
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);
|
||||||
|
}
|
|
@ -7,6 +7,10 @@ main>section:is(#summary, #products, #delivery, #delivery_request) {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main:not(:has(h2#title + section#delivery))>h2#title {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
main>section:is(#summary, #delivery) {
|
main>section:is(#summary, #delivery) {
|
||||||
background-color: var(--tg-theme-section-bg-color);
|
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 {
|
main>section#products>article.product>a>img:first-of-type {
|
||||||
/* width: 5rem; */
|
width: 7rem;
|
||||||
min-width: 5rem;
|
/* min-width: 5rem; */
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
image-rendering: auto;
|
image-rendering: auto;
|
||||||
border-radius: 0.75rem;
|
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);
|
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);
|
-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);
|
-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;
|
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 {
|
main>section#products>article.product>div>div>button:first-of-type {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
main>section#products>article.product>div>div>button {
|
main>section#products>article.product>div>div>button {
|
||||||
padding: 0.4rem;
|
padding: 0.4rem;
|
||||||
|
color: var(--tg-theme-text-color);
|
||||||
background: unset;
|
background: unset;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,346 @@
|
||||||
|
@charset "UTF-8";
|
||||||
|
|
||||||
|
main>section#categories:has(a),
|
||||||
|
main>section#categories:not(:has(a))>ul:has(li.category[type="button"]) {
|
||||||
|
width: var(--width);
|
||||||
|
display: flex;
|
||||||
|
flex-flow: var(--catalog-categories-wrap-flex-wrap, row wrap);
|
||||||
|
flex-direction: var(--catalog-categories-wrap-flex-direction, 'row');
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories:has(a) {
|
||||||
|
gap: var(--gap, 5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories:not(:has(a))>ul:has(li.category[type="button"])>ul {
|
||||||
|
margin-bottom: var(--gap, 5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories ul {
|
||||||
|
padding-left: 1.3rem;
|
||||||
|
list-style-type: none;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories>li {
|
||||||
|
line-height: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories li {
|
||||||
|
/* font-family: "Chalet"; */
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories li.openable {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories ul>li:has(+ ul) {
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories ul>ul {
|
||||||
|
--offset: 1rem;
|
||||||
|
--padding: 1rem;
|
||||||
|
margin-top: calc(var(--offset, 1rem) * -1);
|
||||||
|
padding-top: calc(var(--offset, 1rem) + var(--padding, 1rem));
|
||||||
|
padding-bottom: var(--padding, 1rem);
|
||||||
|
border-radius: 0 0 0.75rem 0.75rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.3rem;
|
||||||
|
background: var(--catalog-categories-buttons-lists-background-color, var(--tg-theme-secondary-bg-color));
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories:not(:has(a))>ul:has(li.category[type="button"]) {
|
||||||
|
margin: unset;
|
||||||
|
padding: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories>a.category[type="button"],
|
||||||
|
main>section#categories>ul>li.category[type="button"] {
|
||||||
|
--padding: 0.7rem;
|
||||||
|
z-index: unset;
|
||||||
|
position: relative;
|
||||||
|
height: 23px;
|
||||||
|
padding: var(--padding);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-grow: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
color: var(--tg-theme-button-text-color);
|
||||||
|
background: var(--catalog-categories-buttons-background);
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories>a.category[type="button"]:not(.column):after,
|
||||||
|
main>section#categories>ul>li.category[type="button"]:not(.column):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; */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* main>section#categories>a.category[type="button"]:has(>img) {
|
||||||
|
min-width: calc(50% - var(--padding) * 2);
|
||||||
|
height: 180px;
|
||||||
|
padding: unset;
|
||||||
|
} */
|
||||||
|
|
||||||
|
main>section#categories>a.category[type="button"],
|
||||||
|
main>section#categories>ul>li.category[type="button"] {
|
||||||
|
width: var(--catalog-categories-buttons-width, calc(50% - var(--padding) * 2));
|
||||||
|
height: var(--catalog-categories-buttons-height, 180px);
|
||||||
|
padding: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories ul>li[type="button"].opened+ul {
|
||||||
|
max-height: var(--catalog-categories-buttons-lists-height, 500px);
|
||||||
|
transition: max-height 0.15s ease-in 0.1s, margin 0s ease-out 0.1s, padding 0s ease-out 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories ul>li[type="button"]:not(.opened)+ul {
|
||||||
|
max-height: 0;
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
margin-top: 0;
|
||||||
|
transition: max-height 0.25s ease-out, margin 0s ease-out 0.25s, padding 0s ease-out 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories>a.category[type="button"]>img,
|
||||||
|
main>section#categories>ul>li.category[type="button"]>img {
|
||||||
|
position: absolute;
|
||||||
|
left: -5%;
|
||||||
|
top: -5%;
|
||||||
|
width: 110%;
|
||||||
|
height: 110%;
|
||||||
|
object-fit: cover;
|
||||||
|
/* filter: blur(1px); */
|
||||||
|
filter: var(--catalog-categories-buttons-images-filter, contrast(1.2) brightness(60%));
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories>a.category[type="button"]>img.right,
|
||||||
|
main>section#categories>ul>li.category[type="button"]>img.right {
|
||||||
|
/* position: absolute; */
|
||||||
|
left: unset;
|
||||||
|
top: unset;
|
||||||
|
right: 0;
|
||||||
|
width: calc(100% - var(--catalog-categories-buttons-texts-width, 10rem));
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories>a.category[type="button"]:is(:hover, :focus)>img,
|
||||||
|
main>section#categories>ul>li.category[type="button"]:is(:hover, :focus)>img {
|
||||||
|
filter: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* main>section#categories>a.category[type="button"]:has(>img)>p { */
|
||||||
|
main>section#categories>a.category[type="button"]>p,
|
||||||
|
main>section#categories>ul>li.category[type="button"]>p {
|
||||||
|
position: absolute;
|
||||||
|
left: var(--padding);
|
||||||
|
top: var(--catalog-categories-buttons-texts-top, var(--padding));
|
||||||
|
bottom: var(--catalog-categories-buttons-texts-bottom, var(--padding));
|
||||||
|
right: var(--padding);
|
||||||
|
margin: unset;
|
||||||
|
width: calc(var(--catalog-categories-buttons-texts-width, 10rem) - 0.7rem * 2);
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
color: var(--catalog-categories-buttons-texts-title-color, var(--tg-theme-text-color));
|
||||||
|
/* background: var(--tg-theme-hint-color); */
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories>a.category[type="button"]>div.separator.gradient:has(+img.right),
|
||||||
|
main>section#categories>ul>li.category[type="button"]>div.separator.gradient:has(+img.right) {
|
||||||
|
--background: var(--catalog-categories-buttons-background, var(--tg-theme-button-color));
|
||||||
|
z-index: 100;
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
width: calc(100% - var(--catalog-categories-buttons-texts-width, 10rem));
|
||||||
|
height: 100%;
|
||||||
|
background: var(--background);
|
||||||
|
background: linear-gradient(90deg, var(--background) 0%, transparent var(--catalog-categories-buttons-separator-width, 100%));
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories>a.category[type="button"]>p,
|
||||||
|
main>section#categories>ul>li.category[type="button"]>p {
|
||||||
|
z-index: 100;
|
||||||
|
padding: 0 calc(var(--padding) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories>a.category[type="button"]>p:not(.background),
|
||||||
|
main>section#categories>ul>li.category[type="button"]>p:not(.background) {
|
||||||
|
font-family: "Cygre";
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories>a.category[type="button"]>p.background,
|
||||||
|
main>section#categories>ul>li.category[type="button"]>p.background {
|
||||||
|
padding: 8px calc(var(--padding, 0.7rem) * 1.3);
|
||||||
|
width: min-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories>a.category[type="button"]>p.background:after,
|
||||||
|
main>section#categories>ul>li.category[type="button"]>p.background: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#filters {
|
||||||
|
--filters-height: 2rem;
|
||||||
|
width: var(--width);
|
||||||
|
max-height: var(--filters-height);
|
||||||
|
display: flex;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#products {
|
||||||
|
--column: calc((100% - var(--gap)) / 2);
|
||||||
|
width: var(--width);
|
||||||
|
display: grid;
|
||||||
|
grid-gap: var(--gap);
|
||||||
|
grid-template-columns: repeat(2, var(--column));
|
||||||
|
grid-auto-flow: row dense;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#products>div.column {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--gap);
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#products>div.column>article.product {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-direction: column;
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
overflow: clip;
|
||||||
|
cursor: pointer;
|
||||||
|
backdrop-filter: brightness(0.7);
|
||||||
|
background-color: var(--tg-theme-section-bg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#products>div.column>article.product:is(:hover, :focus) {
|
||||||
|
/* flex-grow: 0.1; */
|
||||||
|
/* background-color: var(--tg-theme-section-bg-color); */
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#products>div.column>article.product:is(:hover, :focus)>* {
|
||||||
|
transition: 0s;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#products>div.column>article.product:not(:is(:hover, :focus))>* {
|
||||||
|
transition: 0.2s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#products>div.column>article.product>a>img:first-of-type {
|
||||||
|
--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);
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#products>div.column>article.product>a>img:first-of-type+* {
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#products>div.column>article.product>a>p.title {
|
||||||
|
z-index: 50;
|
||||||
|
margin: unset;
|
||||||
|
padding: 4px 8px 8px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#products>div.column>article.product>div[data-product="buttons"]:last-of-type {
|
||||||
|
z-index: 100;
|
||||||
|
height: 33px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
|
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"]))>div[data-product="buttons"]:last-of-type {
|
||||||
|
container-type: inline-size;
|
||||||
|
container-name: product-buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
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"])>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;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#products>div.column>article.product>div[data-product="buttons"]>button[data-product-button="toggle"]>span[data-product-parameter="amount"]:after {
|
||||||
|
content: '*';
|
||||||
|
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"] {
|
||||||
|
/* 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) {
|
||||||
|
main>section#products>div.column>article.product>div[data-product="buttons"]>button[data-product-button="toggle"]>span:is([data-product-parameter="cost"], [data-product-parameter="currency"]) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#products>div.column>article.product>div[data-product="buttons"]>button[data-product-button="toggle"]>span[data-product-parameter="amount"]:after {
|
||||||
|
content: unset;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
@charset "UTF-8";
|
||||||
|
|
||||||
|
main>section#categories ul>ul {
|
||||||
|
--padding: 1rem;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories>ul ul>li {
|
||||||
|
--padding-row: calc(var(--gap, 5px) * 1);
|
||||||
|
position: relative;
|
||||||
|
padding: var(--padding-row);
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories>ul ul>li>:is(small, i.icon):last-child {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: 0.1rem;
|
||||||
|
rotate: 0deg;
|
||||||
|
transition: rotate 0.1s ease-out;
|
||||||
|
font-family: monospace;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories>ul ul>li.opened>:is(small, i.icon):last-child {
|
||||||
|
rotate: 90deg;
|
||||||
|
transition: rotate 0.1s ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories>ul ul>li:after,
|
||||||
|
main>section#categories>ul ul>li[type="button"].opened+ul:has(+ li)>li:last-of-type:after {
|
||||||
|
position: absolute;
|
||||||
|
content: '';
|
||||||
|
bottom: 0px;
|
||||||
|
width: calc(100% - var(--padding-row) * 2);
|
||||||
|
display: block;
|
||||||
|
align-self: center;
|
||||||
|
border-bottom: 1px solid var(--catalog-categories-buttons-lists-separatpr-color, var(--tg-theme-hint-color));
|
||||||
|
transition: bottom 0s linear 0s;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories>ul ul>li:last-of-type:not(.opened):after {
|
||||||
|
bottom: -1rem;
|
||||||
|
transition: bottom 0.1s ease-out 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories>ul ul>li:last-of-type.opened:after {
|
||||||
|
bottom: -1px;
|
||||||
|
transition: bottom 0.1s ease-in;
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
@charset "UTF-8";
|
||||||
|
|
||||||
|
main>section#categories ul>li:not(.opened):has(+ ul) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
transition: margin 0.1s ease-out 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories>ul>li.opened:has(+ ul) {
|
||||||
|
margin-bottom: var(--gap, 5px);
|
||||||
|
transition: margin 0.1s ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories ul>ul {
|
||||||
|
--offset: 0rem;
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
main>section#categories>ul ul>ul {
|
||||||
|
margin-left: var(--gap, 5px);
|
||||||
|
width: calc(100% - var(--gap, 5px));
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
@charset "UTF-8";
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Chalet';
|
||||||
|
src: url("/themes/default/fonts/chalet/chalet.otf") format('opentype');
|
||||||
|
font-weight: 600;
|
||||||
|
font-style: bold;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
@charset "UTF-8";
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Cygre';
|
||||||
|
src: url("/themes/default/fonts/cygre/Cygre-Bold.ttf");
|
||||||
|
font-weight: 600;
|
||||||
|
font-style: bold;
|
||||||
|
}
|
|
@ -26,7 +26,7 @@ i.icon.arrow:not(.circle, .square)::after {
|
||||||
bottom: 7px;
|
bottom: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
i.icon.arrow:not(.circle, .square)::before {
|
i.icon.arrow:not(.circle, .square, .short)::before {
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 2px;
|
height: 2px;
|
||||||
bottom: 10px;
|
bottom: 10px;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue