Compare commits

..

No commits in common. "stable" and "1.12.0" have entirely different histories.

190 changed files with 5209 additions and 9083 deletions

View File

@ -1,6 +1,7 @@
# Ebala # Ebala
Site-registry of tasks for outsourced employees Site-registry of tasks for outsourced employees
From this project i earned >**1 000 000** Russian rubles</br> From this project i earned **700 000** Russian rubles</br>
**DEVELOPMENT COMPLETED. PROJECT CLOSED.**</br> *As long as commits appear in the repository, this means that i continue paid development*</br>
</br> </br>
I am selling this site to **capitalist scum** for a lot of money, but you, friend, can use my code **for free** ✌️

View File

@ -30,17 +30,16 @@
} }
], ],
"require": { "require": {
"php": "~8.3", "php": "~8.2",
"ext-sodium": "~8.3", "ext-sodium": "~8.2.4",
"mirzaev/minimal": "^2.0.x-dev", "mirzaev/minimal": "^2.0.x-dev",
"mirzaev/accounts": "~1.2.x-dev", "mirzaev/accounts": "~1.2.x-dev",
"mirzaev/arangodb": "^1.0.0", "mirzaev/arangodb": "^1.0.0",
"triagens/arangodb": "~3.9.x-dev", "triagens/arangodb": "~3.9.x-dev",
"twig/twig": "^3.10", "twig/twig": "^3.4",
"twig/extra-bundle": "^3.7", "twig/extra-bundle": "^3.7",
"twig/intl-extra": "^3.10", "twig/intl-extra": "^3.7",
"phpoffice/phpspreadsheet": "^2.1", "phpoffice/phpspreadsheet": "^1.29"
"openswoole/core": "^22.1"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "~9.5" "phpunit/phpunit": "~9.5"

396
composer.lock generated
View File

@ -4,8 +4,69 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "c0be2095032e176b9fb16a24e7a4d1a1", "content-hash": "588f1020cbf90d4c8ed02b057592c14f",
"packages": [ "packages": [
{
"name": "ezyang/htmlpurifier",
"version": "v4.16.0",
"source": {
"type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git",
"reference": "523407fb06eb9e5f3d59889b3978d5bfe94299c8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/523407fb06eb9e5f3d59889b3978d5bfe94299c8",
"reference": "523407fb06eb9e5f3d59889b3978d5bfe94299c8",
"shasum": ""
},
"require": {
"php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0"
},
"require-dev": {
"cerdic/css-tidy": "^1.7 || ^2.0",
"simpletest/simpletest": "dev-master"
},
"suggest": {
"cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.",
"ext-bcmath": "Used for unit conversion and imagecrash protection",
"ext-iconv": "Converts text to and from non-UTF-8 encodings",
"ext-tidy": "Used for pretty-printing HTML"
},
"type": "library",
"autoload": {
"files": [
"library/HTMLPurifier.composer.php"
],
"psr-0": {
"HTMLPurifier": "library/"
},
"exclude-from-classmap": [
"/library/HTMLPurifier/Language/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1-or-later"
],
"authors": [
{
"name": "Edward Z. Yang",
"email": "admin@htmlpurifier.org",
"homepage": "http://ezyang.com"
}
],
"description": "Standards compliant HTML filter written in PHP",
"homepage": "http://htmlpurifier.org/",
"keywords": [
"html"
],
"support": {
"issues": "https://github.com/ezyang/htmlpurifier/issues",
"source": "https://github.com/ezyang/htmlpurifier/tree/v4.16.0"
},
"time": "2022-09-18T07:06:19+00:00"
},
{ {
"name": "guzzlehttp/guzzle", "name": "guzzlehttp/guzzle",
"version": "7.7.0", "version": "7.7.0",
@ -666,89 +727,18 @@
}, },
"time": "2023-03-20T11:46:41+00:00" "time": "2023-03-20T11:46:41+00:00"
}, },
{
"name": "openswoole/core",
"version": "22.1.5",
"source": {
"type": "git",
"url": "https://github.com/openswoole/core.git",
"reference": "06dae68fdac73341ccf565ecef388434bd893141"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/openswoole/core/zipball/06dae68fdac73341ccf565ecef388434bd893141",
"reference": "06dae68fdac73341ccf565ecef388434bd893141",
"shasum": ""
},
"require": {
"ext-openswoole": ">=22.0",
"php": ">=7.4",
"psr/http-message": "^1.0 || ^2.0",
"psr/http-server-middleware": "^1.0.0"
},
"require-dev": {
"ext-curl": "*",
"ext-sockets": "*",
"friendsofphp/php-cs-fixer": "^3.6",
"openswoole/ide-helper": "^22.0",
"php-http/psr7-integration-tests": "^1.1",
"phpunit/phpunit": "^9.5"
},
"suggest": {
"ext-mysqli": "*",
"ext-pdo": "*",
"ext-redis": "Required to use redis database, and the required version is greater than or equal to 3.1.3"
},
"type": "library",
"autoload": {
"files": [
"src/Coroutine/functions.php"
],
"psr-4": {
"OpenSwoole\\Core\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "OpenSwoole Group",
"email": "hello@openswoole.com"
}
],
"description": "Openswoole core library",
"homepage": "https://openswoole.com",
"keywords": [
"http",
"http2",
"mqtt",
"openswoole",
"php",
"tcp",
"websocket"
],
"support": {
"docs": "https://openswoole.com/docs",
"issues": "https://github.com/openswoole/openswoole/issues",
"pull-request": "https://github.com/openswoole/openswoole/pulls",
"source": "https://github.com/openswoole/openswoole"
},
"time": "2023-12-10T19:02:13+00:00"
},
{ {
"name": "phpoffice/phpspreadsheet", "name": "phpoffice/phpspreadsheet",
"version": "2.1.0", "version": "1.29.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git", "url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
"reference": "dbed77bd3a0f68f96c0dd68ad4499d5674fecc3e" "reference": "fde2ccf55eaef7e86021ff1acce26479160a0fa0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/dbed77bd3a0f68f96c0dd68ad4499d5674fecc3e", "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/fde2ccf55eaef7e86021ff1acce26479160a0fa0",
"reference": "dbed77bd3a0f68f96c0dd68ad4499d5674fecc3e", "reference": "fde2ccf55eaef7e86021ff1acce26479160a0fa0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -765,24 +755,25 @@
"ext-xmlwriter": "*", "ext-xmlwriter": "*",
"ext-zip": "*", "ext-zip": "*",
"ext-zlib": "*", "ext-zlib": "*",
"ezyang/htmlpurifier": "^4.15",
"maennchen/zipstream-php": "^2.1 || ^3.0", "maennchen/zipstream-php": "^2.1 || ^3.0",
"markbaker/complex": "^3.0", "markbaker/complex": "^3.0",
"markbaker/matrix": "^3.0", "markbaker/matrix": "^3.0",
"php": "^8.0", "php": "^7.4 || ^8.0",
"psr/http-client": "^1.0", "psr/http-client": "^1.0",
"psr/http-factory": "^1.0", "psr/http-factory": "^1.0",
"psr/simple-cache": "^1.0 || ^2.0 || ^3.0" "psr/simple-cache": "^1.0 || ^2.0 || ^3.0"
}, },
"require-dev": { "require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "dev-main", "dealerdirect/phpcodesniffer-composer-installer": "dev-main",
"dompdf/dompdf": "^2.0", "dompdf/dompdf": "^1.0 || ^2.0",
"friendsofphp/php-cs-fixer": "^3.2", "friendsofphp/php-cs-fixer": "^3.2",
"mitoteam/jpgraph": "^10.3", "mitoteam/jpgraph": "^10.3",
"mpdf/mpdf": "^8.1.1", "mpdf/mpdf": "^8.1.1",
"phpcompatibility/php-compatibility": "^9.3", "phpcompatibility/php-compatibility": "^9.3",
"phpstan/phpstan": "^1.1", "phpstan/phpstan": "^1.1",
"phpstan/phpstan-phpunit": "^1.0", "phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^9.6", "phpunit/phpunit": "^8.5 || ^9.0 || ^10.0",
"squizlabs/php_codesniffer": "^3.7", "squizlabs/php_codesniffer": "^3.7",
"tecnickcom/tcpdf": "^6.5" "tecnickcom/tcpdf": "^6.5"
}, },
@ -837,9 +828,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues",
"source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/2.1.0" "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.29.0"
}, },
"time": "2024-05-11T04:17:56+00:00" "time": "2023-06-14T22:48:31+00:00"
}, },
{ {
"name": "psr/cache", "name": "psr/cache",
@ -1153,119 +1144,6 @@
}, },
"time": "2023-04-04T09:54:51+00:00" "time": "2023-04-04T09:54:51+00:00"
}, },
{
"name": "psr/http-server-handler",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-server-handler.git",
"reference": "84c4fb66179be4caaf8e97bd239203245302e7d4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/84c4fb66179be4caaf8e97bd239203245302e7d4",
"reference": "84c4fb66179be4caaf8e97bd239203245302e7d4",
"shasum": ""
},
"require": {
"php": ">=7.0",
"psr/http-message": "^1.0 || ^2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Server\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for HTTP server-side request handler",
"keywords": [
"handler",
"http",
"http-interop",
"psr",
"psr-15",
"psr-7",
"request",
"response",
"server"
],
"support": {
"source": "https://github.com/php-fig/http-server-handler/tree/1.0.2"
},
"time": "2023-04-10T20:06:20+00:00"
},
{
"name": "psr/http-server-middleware",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-server-middleware.git",
"reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/c1481f747daaa6a0782775cd6a8c26a1bf4a3829",
"reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829",
"shasum": ""
},
"require": {
"php": ">=7.0",
"psr/http-message": "^1.0 || ^2.0",
"psr/http-server-handler": "^1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Server\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for HTTP server-side middleware",
"keywords": [
"http",
"http-interop",
"middleware",
"psr",
"psr-15",
"psr-7",
"request",
"response"
],
"support": {
"issues": "https://github.com/php-fig/http-server-middleware/issues",
"source": "https://github.com/php-fig/http-server-middleware/tree/1.0.2"
},
"time": "2023-04-11T06:14:47+00:00"
},
{ {
"name": "psr/log", "name": "psr/log",
"version": "3.0.0", "version": "3.0.0",
@ -1741,16 +1619,16 @@
}, },
{ {
"name": "symfony/deprecation-contracts", "name": "symfony/deprecation-contracts",
"version": "v3.5.0", "version": "v3.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git", "url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf",
"reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1759,7 +1637,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "3.5-dev" "dev-main": "3.4-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/contracts", "name": "symfony/contracts",
@ -1788,7 +1666,7 @@
"description": "A generic function and convention to trigger deprecation notices", "description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" "source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0"
}, },
"funding": [ "funding": [
{ {
@ -1804,7 +1682,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-04-18T09:32:20+00:00" "time": "2023-05-23T14:45:45+00:00"
}, },
{ {
"name": "symfony/error-handler", "name": "symfony/error-handler",
@ -2499,25 +2377,25 @@
}, },
{ {
"name": "symfony/intl", "name": "symfony/intl",
"version": "v7.0.7", "version": "v6.3.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/intl.git", "url": "https://github.com/symfony/intl.git",
"reference": "dd12042707110995e2e7d80103f8d9928bea8621" "reference": "1f8cb145c869ed089a8531c51a6a4b31ed0b3c69"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/intl/zipball/dd12042707110995e2e7d80103f8d9928bea8621", "url": "https://api.github.com/repos/symfony/intl/zipball/1f8cb145c869ed089a8531c51a6a4b31ed0b3c69",
"reference": "dd12042707110995e2e7d80103f8d9928bea8621", "reference": "1f8cb145c869ed089a8531c51a6a4b31ed0b3c69",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=8.2" "php": ">=8.1"
}, },
"require-dev": { "require-dev": {
"symfony/filesystem": "^6.4|^7.0", "symfony/filesystem": "^5.4|^6.0",
"symfony/finder": "^6.4|^7.0", "symfony/finder": "^5.4|^6.0",
"symfony/var-exporter": "^6.4|^7.0" "symfony/var-exporter": "^5.4|^6.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -2525,8 +2403,7 @@
"Symfony\\Component\\Intl\\": "" "Symfony\\Component\\Intl\\": ""
}, },
"exclude-from-classmap": [ "exclude-from-classmap": [
"/Tests/", "/Tests/"
"/Resources/data/"
] ]
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
@ -2562,7 +2439,7 @@
"localization" "localization"
], ],
"support": { "support": {
"source": "https://github.com/symfony/intl/tree/v7.0.7" "source": "https://github.com/symfony/intl/tree/v6.3.2"
}, },
"funding": [ "funding": [
{ {
@ -2578,20 +2455,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-04-18T09:29:19+00:00" "time": "2023-07-20T07:43:09+00:00"
}, },
{ {
"name": "symfony/polyfill-ctype", "name": "symfony/polyfill-ctype",
"version": "v1.29.0", "version": "v1.27.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git", "url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4" "reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4", "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
"reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4", "reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2605,6 +2482,9 @@
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill" "url": "https://github.com/symfony/polyfill"
@ -2641,7 +2521,7 @@
"portable" "portable"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0" "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
}, },
"funding": [ "funding": [
{ {
@ -2657,20 +2537,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-01-29T20:11:03+00:00" "time": "2022-11-03T14:55:06+00:00"
}, },
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-mbstring",
"version": "v1.29.0", "version": "v1.27.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git", "url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2684,6 +2564,9 @@
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill" "url": "https://github.com/symfony/polyfill"
@ -2721,7 +2604,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0" "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
}, },
"funding": [ "funding": [
{ {
@ -2737,20 +2620,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-01-29T20:11:03+00:00" "time": "2022-11-03T14:55:06+00:00"
}, },
{ {
"name": "symfony/polyfill-php80", "name": "symfony/polyfill-php80",
"version": "v1.29.0", "version": "v1.28.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php80.git", "url": "https://github.com/symfony/polyfill-php80.git",
"reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b" "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2758,6 +2641,9 @@
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": {
"dev-main": "1.28-dev"
},
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill" "url": "https://github.com/symfony/polyfill"
@ -2801,7 +2687,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0" "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0"
}, },
"funding": [ "funding": [
{ {
@ -2817,7 +2703,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-01-29T20:11:03+00:00" "time": "2023-01-26T09:26:14+00:00"
}, },
{ {
"name": "symfony/polyfill-php83", "name": "symfony/polyfill-php83",
@ -3630,25 +3516,25 @@
}, },
{ {
"name": "twig/intl-extra", "name": "twig/intl-extra",
"version": "v3.10.0", "version": "v3.7.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/twigphp/intl-extra.git", "url": "https://github.com/twigphp/intl-extra.git",
"reference": "693f6beb8ca91fc6323e01b3addf983812f65c93" "reference": "4f4fe572f635534649cc069e1dafe4a8ad63774d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/twigphp/intl-extra/zipball/693f6beb8ca91fc6323e01b3addf983812f65c93", "url": "https://api.github.com/repos/twigphp/intl-extra/zipball/4f4fe572f635534649cc069e1dafe4a8ad63774d",
"reference": "693f6beb8ca91fc6323e01b3addf983812f65c93", "reference": "4f4fe572f635534649cc069e1dafe4a8ad63774d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.2.5", "php": ">=7.1.3",
"symfony/intl": "^5.4|^6.4|^7.0", "symfony/intl": "^5.4|^6.0",
"twig/twig": "^3.10" "twig/twig": "^2.7|^3.0"
}, },
"require-dev": { "require-dev": {
"symfony/phpunit-bridge": "^6.4|^7.0" "symfony/phpunit-bridge": "^5.4|^6.3"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -3678,7 +3564,7 @@
"twig" "twig"
], ],
"support": { "support": {
"source": "https://github.com/twigphp/intl-extra/tree/v3.10.0" "source": "https://github.com/twigphp/intl-extra/tree/v3.7.1"
}, },
"funding": [ "funding": [
{ {
@ -3690,41 +3576,33 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-05-11T07:35:57+00:00" "time": "2023-07-29T15:34:56+00:00"
}, },
{ {
"name": "twig/twig", "name": "twig/twig",
"version": "v3.10.3", "version": "v3.6.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/twigphp/Twig.git", "url": "https://github.com/twigphp/Twig.git",
"reference": "67f29781ffafa520b0bbfbd8384674b42db04572" "reference": "7e7d5839d4bec168dfeef0ac66d5c5a2edbabffd"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/67f29781ffafa520b0bbfbd8384674b42db04572", "url": "https://api.github.com/repos/twigphp/Twig/zipball/7e7d5839d4bec168dfeef0ac66d5c5a2edbabffd",
"reference": "67f29781ffafa520b0bbfbd8384674b42db04572", "reference": "7e7d5839d4bec168dfeef0ac66d5c5a2edbabffd",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.2.5", "php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-ctype": "^1.8", "symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-mbstring": "^1.3", "symfony/polyfill-mbstring": "^1.3"
"symfony/polyfill-php80": "^1.22"
}, },
"require-dev": { "require-dev": {
"psr/container": "^1.0|^2.0", "psr/container": "^1.0|^2.0",
"symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
"files": [
"src/Resources/core.php",
"src/Resources/debug.php",
"src/Resources/escaper.php",
"src/Resources/string_loader.php"
],
"psr-4": { "psr-4": {
"Twig\\": "src/" "Twig\\": "src/"
} }
@ -3757,7 +3635,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/twigphp/Twig/issues", "issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.10.3" "source": "https://github.com/twigphp/Twig/tree/v3.6.1"
}, },
"funding": [ "funding": [
{ {
@ -3769,7 +3647,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-05-16T10:04:27+00:00" "time": "2023-06-08T12:52:13+00:00"
} }
], ],
"packages-dev": [ "packages-dev": [
@ -5515,8 +5393,8 @@
"prefer-stable": false, "prefer-stable": false,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
"php": "~8.3", "php": "~8.2",
"ext-sodium": "~8.3" "ext-sodium": "~8.2.4"
}, },
"platform-dev": [], "platform-dev": [],
"plugin-api-version": "2.2.0" "plugin-api-version": "2.2.0"

View File

@ -1,17 +0,0 @@
[Unit]
Description=Ebala-socket
Wants=network.target
After=syslog.target network-online.target
[Service]
ExecStart=sudo -u www-data /usr/bin/php /var/www/ebala/mirzaev/ebala/system/public/socket.php
PIDFile=/var/run/php/ebala-socket.pid
RemainAfterExit=no
RuntimeMaxSec=3600s
Restart=always
RestartSec=30s
[Install]
WantedBy=multi-user.target

View File

@ -8,7 +8,6 @@ namespace mirzaev\ebala\controllers;
use mirzaev\ebala\controllers\core, use mirzaev\ebala\controllers\core,
mirzaev\ebala\controllers\traits\errors, mirzaev\ebala\controllers\traits\errors,
mirzaev\ebala\models\account as model, mirzaev\ebala\models\account as model,
mirzaev\ebala\models\task,
mirzaev\ebala\models\registry, mirzaev\ebala\models\registry,
mirzaev\ebala\models\core as _core; mirzaev\ebala\models\core as _core;
@ -28,37 +27,6 @@ final class account extends core
{ {
use errors; use errors;
/**
* Страница аккаунта
*
* @param array $parameters Параметры запроса
*/
public function index(array $parameters = []): ?string
{
if ($this->account->status()) {
// Авторизован аккаунт
// Инициализация истории заявок
$this->view->history = task::list(before: 'FILTER task.worker == "' . model::worker($this->account->getId())?->id . '"');
// Инициализация баланса счёта
// В будущем сделать перебор по всем связанным с аккаунтам сотрудникам и магазинам (сейчас только 1 сотрудник может быть)
$this->view->balance = 0;
foreach (task::list(before: 'FILTER task.worker == "' . model::worker($this->account->getId())?->id . '" && task.result.processed == false') as $task) $this->view->balance += $task->task['result']['hours'] * $task->task['result']['hour'] + $task->task['result']['penalty'] + $task->task['result']['bonus'];
// Генерация представления
$main = $this->view->render(DIRECTORY_SEPARATOR . 'pages' . DIRECTORY_SEPARATOR . 'account.html');
} else $main = $this->authorization();
// Возврат (успех)
if ($_SERVER['REQUEST_METHOD'] === 'GET') return $this->view->render(DIRECTORY_SEPARATOR . 'index.html', ['main' => $main]);
else if ($_SERVER['REQUEST_METHOD'] === 'POST') return $main;
// Возврат (провал)
return null;
}
/** /**
* Прочитать данные * Прочитать данные
* *
@ -70,7 +38,7 @@ final class account extends core
// Авторизован аккаунт администратора или оператора // Авторизован аккаунт администратора или оператора
// Инициализация данных аккаунта // Инициализация данных аккаунта
$account = model::read('d._key == "' . $parameters['id'] . '"', return: '{ name: d.name, number: d.number, mail: d.mail, commentary: d.commentary, transactions: d.transactions }')->getAll(); $account = model::read('d._key == "' . $parameters['id'] . '"', return: '{ name: d.name, number: d.number, mail: d.mail, commentary: d.commentary }')->getAll();
if (!empty($account)) { if (!empty($account)) {
// Найдены данные аккаунта // Найдены данные аккаунта
@ -106,7 +74,6 @@ final class account extends core
*/ */
public function update(array $parameters = []): ?string public function update(array $parameters = []): ?string
{ {
try {
if ($this->account->status() && ($this->account->type === 'administrator' || $this->account->type === 'operator')) { if ($this->account->status() && ($this->account->type === 'administrator' || $this->account->type === 'operator')) {
// Авторизован аккаунт администратора или оператора // Авторизован аккаунт администратора или оператора
@ -127,7 +94,7 @@ final class account extends core
if (mb_strlen($parameters['number']) === 11) $account->number = $parameters['number']; if (mb_strlen($parameters['number']) === 11) $account->number = $parameters['number'];
else throw new exception('Номер должен состоять из 11 символов'); else throw new exception('Номер должен состоять из 11 символов');
if ($parameters['mail'] !== $account->mail) $account->mail = $parameters['mail']; if ($parameters['mail'] !== $account->mail) $account->mail = $parameters['mail'];
if (!empty($parameters['password']) && !@sodium_crypto_pwhash_str_verify($parameters['password'], $account->password ?? '') && $password = true) if (!empty($parameters['password']) && !sodium_crypto_pwhash_str_verify($parameters['password'], $account->password) && $password = true)
if (mb_strlen($parameters['password']) > 6) $account->password = sodium_crypto_pwhash_str( if (mb_strlen($parameters['password']) > 6) $account->password = sodium_crypto_pwhash_str(
$parameters['password'], $parameters['password'],
SODIUM_CRYPTO_PWHASH_OPSLIMIT_SENSITIVE, SODIUM_CRYPTO_PWHASH_OPSLIMIT_SENSITIVE,
@ -135,12 +102,6 @@ final class account extends core
); );
else throw new exception('Пароль должен быть длиннее 6 символов'); else throw new exception('Пароль должен быть длиннее 6 символов');
if ($parameters['commentary'] !== $account->commentary) $account->commentary = $parameters['commentary']; if ($parameters['commentary'] !== $account->commentary) $account->commentary = $parameters['commentary'];
if (!empty($parameters['transactions']) && $parameters['transactions'] !== $account->transactions)
$account->transactions = match ($parameters['transactions']) {
'true' => true,
'false' => false,
default => false
};
if (_core::update($account)) { if (_core::update($account)) {
// Записаны данные аккаунта // Записаны данные аккаунта
@ -223,40 +184,6 @@ final class account extends core
} else throw new exception('Не удалось записать изменения в базу данных'); } else throw new exception('Не удалось записать изменения в базу данных');
} else throw new exception('Не удалось найти аккаунт'); } else throw new exception('Не удалось найти аккаунт');
} }
} catch (exception $e) {
// Write to the errors registry
$this->errors['account'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
// Запись заголовков ответа
header('Content-Type: application/json');
header('Content-Encoding: none');
header('X-Accel-Buffering: no');
// Инициализация буфера вывода
ob_start();
// Инициализация буфера ответа
$return = [
'updated' => false,
'errors' => self::parse_only_text($this->errors)
];
// Генерация ответа
echo json_encode($return);
// Запись заголовков ответа
header('Content-Length: ' . ob_get_length());
// Отправка и деинициализация буфера вывода
ob_end_flush();
flush();
}
// Возврат (провал) // Возврат (провал)
return null; return null;
@ -269,7 +196,6 @@ final class account extends core
*/ */
public function delete(array $parameters = []): ?string public function delete(array $parameters = []): ?string
{ {
try {
if ($this->account->status() && ($this->account->type === 'administrator' || $this->account->type === 'operator')) { if ($this->account->status() && ($this->account->type === 'administrator' || $this->account->type === 'operator')) {
// Авторизован аккаунт администратора или оператора // Авторизован аккаунт администратора или оператора
@ -338,40 +264,6 @@ final class account extends core
} else throw new exception('Не удалось записать изменения в базу данных'); } else throw new exception('Не удалось записать изменения в базу данных');
} else throw new exception('Не удалось найти аккаунт'); } else throw new exception('Не удалось найти аккаунт');
} }
} catch (exception $e) {
// Write to the errors registry
$this->errors['account'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
// Запись заголовков ответа
header('Content-Type: application/json');
header('Content-Encoding: none');
header('X-Accel-Buffering: no');
// Инициализация буфера вывода
ob_start();
// Инициализация буфера ответа
$return = [
'deleted' => false,
'errors' => self::parse_only_text($this->errors)
];
// Генерация ответа
echo json_encode($return);
// Запись заголовков ответа
header('Content-Length: ' . ob_get_length());
// Отправка и деинициализация буфера вывода
ob_end_flush();
flush();
}
// Возврат (провал) // Возврат (провал)
return null; return null;
@ -384,7 +276,6 @@ final class account extends core
*/ */
public function ban(array $parameters = []): ?string public function ban(array $parameters = []): ?string
{ {
try {
if ($this->account->status() && ($this->account->type === 'administrator' || $this->account->type === 'operator')) { if ($this->account->status() && ($this->account->type === 'administrator' || $this->account->type === 'operator')) {
// Авторизован аккаунт администратора или оператора // Авторизован аккаунт администратора или оператора
@ -424,40 +315,6 @@ final class account extends core
} else throw new exception('Не удалось записать изменения в базу данных'); } else throw new exception('Не удалось записать изменения в базу данных');
} else throw new exception('Не удалось найти аккаунт'); } else throw new exception('Не удалось найти аккаунт');
} }
} catch (exception $e) {
// Write to the errors registry
$this->errors['account'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
// Запись заголовков ответа
header('Content-Type: application/json');
header('Content-Encoding: none');
header('X-Accel-Buffering: no');
// Инициализация буфера вывода
ob_start();
// Инициализация буфера ответа
$return = [
'banned' => false,
'errors' => self::parse_only_text($this->errors)
];
// Генерация ответа
echo json_encode($return);
// Запись заголовков ответа
header('Content-Length: ' . ob_get_length());
// Отправка и деинициализация буфера вывода
ob_end_flush();
flush();
}
// Возврат (провал) // Возврат (провал)
return null; return null;
@ -470,7 +327,6 @@ final class account extends core
*/ */
public function unban(array $parameters = []): ?string public function unban(array $parameters = []): ?string
{ {
try {
if ($this->account->status() && ($this->account->type === 'administrator' || $this->account->type === 'operator')) { if ($this->account->status() && ($this->account->type === 'administrator' || $this->account->type === 'operator')) {
// Авторизован аккаунт администратора или оператора // Авторизован аккаунт администратора или оператора
@ -510,40 +366,6 @@ final class account extends core
} else throw new exception('Не удалось записать изменения в базу данных'); } else throw new exception('Не удалось записать изменения в базу данных');
} else throw new exception('Не удалось найти аккаунт'); } else throw new exception('Не удалось найти аккаунт');
} }
} catch (exception $e) {
// Write to the errors registry
$this->errors['account'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
// Запись заголовков ответа
header('Content-Type: application/json');
header('Content-Encoding: none');
header('X-Accel-Buffering: no');
// Инициализация буфера вывода
ob_start();
// Инициализация буфера ответа
$return = [
'unbanned' => false,
'errors' => self::parse_only_text($this->errors)
];
// Генерация ответа
echo json_encode($return);
// Запись заголовков ответа
header('Content-Length: ' . ob_get_length());
// Отправка и деинициализация буфера вывода
ob_end_flush();
flush();
}
// Возврат (провал) // Возврат (провал)
return null; return null;

View File

@ -147,13 +147,8 @@ final class administrator extends core
$search_query, $search_query,
empty($filters) ? null : " && ($filters)" empty($filters) ? null : " && ($filters)"
), ),
after: <<<AQL
COLLECT x = account OPTIONS { method: "sorted" }
AQL,
page: (int) $this->session->buffer[$_SERVER['INTERFACE']]['administrators']['page'], page: (int) $this->session->buffer[$_SERVER['INTERFACE']]['administrators']['page'],
sort: 'x.created DESC, x._key DESC',
target: empty($search) ? account::COLLECTION : 'registry_accounts', target: empty($search) ? account::COLLECTION : 'registry_accounts',
return: '{account: x}',
binds: empty($search) ? [] : [ binds: empty($search) ? [] : [
'search' => $search 'search' => $search
] ]
@ -234,35 +229,12 @@ final class administrator extends core
if (empty($account)) throw new exception('Не удалось создать аккаунт'); if (empty($account)) throw new exception('Не удалось создать аккаунт');
} catch (exception $e) { } catch (exception $e) {
// Write to the errors registry // Write to the errors registry
$this->errors['administrator'][] = [ $this->errors['account'][] = [
'text' => $e->getMessage(), 'text' => $e->getMessage(),
'file' => $e->getFile(), 'file' => $e->getFile(),
'line' => $e->getLine(), 'line' => $e->getLine(),
'stack' => $e->getTrace() 'stack' => $e->getTrace()
]; ];
// Запись заголовков ответа
header('Content-Type: application/json');
header('Content-Encoding: none');
header('X-Accel-Buffering: no');
// Инициализация буфера вывода
ob_start();
// Инициализация буфера ответа
$return = [
'errors' => self::parse_only_text($this->errors)
];
// Генерация ответа
echo json_encode($return);
// Запись заголовков ответа
header('Content-Length: ' . ob_get_length());
// Отправка и деинициализация буфера вывода
ob_end_flush();
flush();
} }
// Инициализация идентификатора аккаунта (ключ документа инстанции аккаунта в базе данных) // Инициализация идентификатора аккаунта (ключ документа инстанции аккаунта в базе данных)

View File

@ -56,7 +56,7 @@ class core extends controller
public function __construct(bool $initialize = true) public function __construct(bool $initialize = true)
{ {
// Блокировка запросов от CloudFlare // Блокировка запросов от CloudFlare
if (!empty($_SERVER['HTTP_USER_AGENT']) && $_SERVER['HTTP_USER_AGENT'] === 'nginx-ssl early hints') return; if ($_SERVER['HTTP_USER_AGENT'] === 'nginx-ssl early hints') return;
parent::__construct($initialize); parent::__construct($initialize);

View File

@ -180,15 +180,12 @@ final class market extends core
FILTER account.type == 'market' && b.deleted != true FILTER account.type == 'market' && b.deleted != true
%s %s
%s %s
COLLECT x = account, y = market OPTIONS { method: "sorted" }
AQL, AQL,
empty($filters_before) ? null : "FILTER $filters_before", empty($filters_before) ? null : "FILTER $filters_before",
empty($filters_after) ? null : "FILTER $filters_after" empty($filters_after) ? null : "FILTER $filters_after"
), ),
page: (int) $this->session->buffer[$_SERVER['INTERFACE']]['markets']['page'], page: (int) $this->session->buffer[$_SERVER['INTERFACE']]['markets']['page'],
sort: 'x.created DESC, y.created DESC, x._key DESC, y._key DESC',
target: empty($search) ? account::COLLECTION : 'registry_accounts', target: empty($search) ? account::COLLECTION : 'registry_accounts',
return: '{account: x, market: y}',
binds: empty($search) ? [] : [ binds: empty($search) ? [] : [
'search' => $search 'search' => $search
] ]
@ -341,7 +338,7 @@ final class market extends core
throw new exception('Не инициализирован аккаунт'); throw new exception('Не инициализирован аккаунт');
} catch (exception $e) { } catch (exception $e) {
// Write to the errors registry // Write to the errors registry
$this->errors['market'][] = [ $this->errors['account'][] = [
'text' => $e->getMessage(), 'text' => $e->getMessage(),
'file' => $e->getFile(), 'file' => $e->getFile(),
'line' => $e->getLine(), 'line' => $e->getLine(),
@ -362,7 +359,7 @@ final class market extends core
// Авторизован аккаунт администратора или оператора // Авторизован аккаунт администратора или оператора
// Инициализация данных магазина // Инициализация данных магазина
$market = model::read('d.id == "' . urldecode($parameters['id']) . '"', return: '{ name: d.name, number: d.number, mail: d.mail, type: d.type, city: d.city, district: d.district, address: d.address}')->getAll(); $market = model::read('d.id == "' . $parameters['id'] . '"', return: '{ name: d.name, number: d.number, mail: d.mail, type: d.type, city: d.city, district: d.district, address: d.address}')->getAll();
if (!empty($market)) { if (!empty($market)) {
// Найдены данные магазина // Найдены данные магазина
@ -391,267 +388,6 @@ final class market extends core
return null; return null;
} }
/**
* Заблокировать сотрудника в магазине
*
* @param array $parameters Параметры запроса
*/
public function ban(array $parameters = []): ?string
{
try {
if ($this->account->status() && $this->account->type === 'market') {
// Авторизован аккаунт магазина
// Инициализация данных магазина
$market = account::market($this->account->getId());
if ($market instanceof _document) {
// Найден магазин
// Блокировка сотрудника
if (!in_array($parameters['worker'], $market->bans ??= [], true)) $market->bans = $market->bans + [$parameters['worker']];
if (_core::update($market)) {
// Записаны данные магазина
// Запись в глобальную переменную шаблонизатора обрабатываемой страницы (отключение)
$this->view->page = null;
// Запись заголовков ответа
header('Content-Type: application/json');
header('Content-Encoding: none');
header('X-Accel-Buffering: no');
// Инициализация буфера вывода
ob_start();
// Инициализация буфера ответа
$return = [
'banned' => true,
'errors' => self::parse_only_text($this->errors)
];
// Генерация ответа
echo json_encode($return);
// Запись заголовков ответа
header('Content-Length: ' . ob_get_length());
// Отправка и деинициализация буфера вывода
ob_end_flush();
flush();
} else throw new exception('Не удалось записать изменения в базу данных');
} else throw new exception('Не удалось найти магазин');
}
} catch (exception $e) {
// Write to the errors registry
$this->errors['market'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
// Запись заголовков ответа
header('Content-Type: application/json');
header('Content-Encoding: none');
header('X-Accel-Buffering: no');
// Инициализация буфера вывода
ob_start();
// Инициализация буфера ответа
$return = [
'banned' => false,
'errors' => self::parse_only_text($this->errors)
];
// Генерация ответа
echo json_encode($return);
// Запись заголовков ответа
header('Content-Length: ' . ob_get_length());
// Отправка и деинициализация буфера вывода
ob_end_flush();
flush();
}
// Возврат (провал)
return null;
}
/**
* Разблокировать сотрудника в магазине
*
* @param array $parameters Параметры запроса
*/
public function unban(array $parameters = []): ?string
{
try {
if ($this->account->status() && $this->account->type === 'market') {
// Авторизован аккаунт магазина
// Инициализация данных магазина
$market = account::market($this->account->getId());
if ($market instanceof _document) {
// Найден магазин
// Разблокировка сотрудника
if (in_array($parameters['worker'], $market->bans ??= [], true)) $market->bans = array_diff($market->bans ??= [], [$parameters['worker']]);
if (_core::update($market)) {
// Записаны данные магазина
// Запись в глобальную переменную шаблонизатора обрабатываемой страницы (отключение)
$this->view->page = null;
// Запись заголовков ответа
header('Content-Type: application/json');
header('Content-Encoding: none');
header('X-Accel-Buffering: no');
// Инициализация буфера вывода
ob_start();
// Инициализация буфера ответа
$return = [
'unbanned' => true,
'errors' => self::parse_only_text($this->errors)
];
// Генерация ответа
echo json_encode($return);
// Запись заголовков ответа
header('Content-Length: ' . ob_get_length());
// Отправка и деинициализация буфера вывода
ob_end_flush();
flush();
} else throw new exception('Не удалось записать изменения в базу данных');
} else throw new exception('Не удалось найти магазин');
}
} catch (exception $e) {
// Write to the errors registry
$this->errors['market'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
// Запись заголовков ответа
header('Content-Type: application/json');
header('Content-Encoding: none');
header('X-Accel-Buffering: no');
// Инициализация буфера вывода
ob_start();
// Инициализация буфера ответа
$return = [
'unbanned' => false,
'errors' => self::parse_only_text($this->errors)
];
// Генерация ответа
echo json_encode($return);
// Запись заголовков ответа
header('Content-Length: ' . ob_get_length());
// Отправка и деинициализация буфера вывода
ob_end_flush();
flush();
}
// Возврат (провал)
return null;
}
/**
* Проверить наличие сотрудника в реестре заблокированных
*
* @param array $parameters Параметры запроса
*/
public function banned(array $parameters = []): ?string
{
try {
if ($this->account->status() && $this->account->type === 'market') {
// Авторизован аккаунт магазина
// Инициализация данных магазина
$market = account::market($this->account->getId());
if ($market instanceof _document) {
// Найден магазин
// Запись в глобальную переменную шаблонизатора обрабатываемой страницы (отключение)
$this->view->page = null;
// Запись заголовков ответа
header('Content-Type: application/json');
header('Content-Encoding: none');
header('X-Accel-Buffering: no');
// Инициализация буфера вывода
ob_start();
// Инициализация буфера ответа
$return = [
'banned' => in_array($parameters['worker'], $market->bans ?? [], true),
'errors' => self::parse_only_text($this->errors)
];
// Генерация ответа
echo json_encode($return);
// Запись заголовков ответа
header('Content-Length: ' . ob_get_length());
// Отправка и деинициализация буфера вывода
ob_end_flush();
flush();
} else throw new exception('Не удалось найти магазин');
}
} catch (exception $e) {
// Write to the errors registry
$this->errors['market'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
// Запись заголовков ответа
header('Content-Type: application/json');
header('Content-Encoding: none');
header('X-Accel-Buffering: no');
// Инициализация буфера вывода
ob_start();
// Инициализация буфера ответа
$return = [
'errors' => self::parse_only_text($this->errors)
];
// Генерация ответа
echo json_encode($return);
// Запись заголовков ответа
header('Content-Length: ' . ob_get_length());
// Отправка и деинициализация буфера вывода
ob_end_flush();
flush();
}
return null;
}
/** /**
* Обновить данные * Обновить данные
* *
@ -659,12 +395,11 @@ final class market extends core
*/ */
public function update(array $parameters = []): ?string public function update(array $parameters = []): ?string
{ {
try {
if ($this->account->status() && ($this->account->type === 'administrator' || $this->account->type === 'operator')) { if ($this->account->status() && ($this->account->type === 'administrator' || $this->account->type === 'operator')) {
// Авторизован аккаунт администратора или оператора // Авторизован аккаунт администратора или оператора
// Инициализация данных магазина // Инициализация данных магазина
$market = model::read('d.id == "' . urldecode($parameters['id']) . '"'); $market = model::read('d.id == "' . $parameters['id'] . '"');
if (!empty($market)) { if (!empty($market)) {
// Найден магазин // Найден магазин
@ -681,7 +416,6 @@ final class market extends core
if ($parameters['city'] !== $market->city) $market->city = $parameters['city']; if ($parameters['city'] !== $market->city) $market->city = $parameters['city'];
if ($parameters['district'] !== $market->district) $market->district = $parameters['district']; if ($parameters['district'] !== $market->district) $market->district = $parameters['district'];
if ($parameters['address'] !== $market->address) $market->address = $parameters['address']; if ($parameters['address'] !== $market->address) $market->address = $parameters['address'];
if (!in_array($parameters['ban'], $market->bans, true)) $market->bans[] = $parameters['ban'];
if (_core::update($market)) { if (_core::update($market)) {
// Записаны данные магазина // Записаны данные магазина
@ -731,39 +465,6 @@ final class market extends core
} else throw new exception('Не удалось записать изменения в базу данных'); } else throw new exception('Не удалось записать изменения в базу данных');
} else throw new exception('Не удалось найти аккаунт'); } else throw new exception('Не удалось найти аккаунт');
} }
} catch (exception $e) {
// Write to the errors registry
$this->errors['market'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
// Запись заголовков ответа
header('Content-Type: application/json');
header('Content-Encoding: none');
header('X-Accel-Buffering: no');
// Инициализация буфера вывода
ob_start();
// Инициализация буфера ответа
$return = [
'updated' => false,
'errors' => self::parse_only_text($this->errors)
];
// Генерация ответа
echo json_encode($return);
// Запись заголовков ответа
header('Content-Length: ' . ob_get_length());
// Отправка и деинициализация буфера вывода
ob_end_flush();
flush();
}
// Возврат (провал) // Возврат (провал)
return null; return null;

View File

@ -147,13 +147,8 @@ final class operator extends core
$search_query, $search_query,
empty($filters) ? null : " && ($filters)" empty($filters) ? null : " && ($filters)"
), ),
after: <<<AQL
COLLECT x = account OPTIONS { method: "sorted" }
AQL,
page: (int) $this->session->buffer[$_SERVER['INTERFACE']]['operators']['page'], page: (int) $this->session->buffer[$_SERVER['INTERFACE']]['operators']['page'],
sort: 'x.created DESC, x._key DESC',
target: empty($search) ? account::COLLECTION : 'registry_accounts', target: empty($search) ? account::COLLECTION : 'registry_accounts',
return: '{account: x}',
binds: empty($search) ? [] : [ binds: empty($search) ? [] : [
'search' => $search 'search' => $search
] ]
@ -233,35 +228,12 @@ final class operator extends core
if (empty($account)) throw new exception('Не удалось создать аккаунт'); if (empty($account)) throw new exception('Не удалось создать аккаунт');
} catch (exception $e) { } catch (exception $e) {
// Write to the errors registry // Write to the errors registry
$this->errors['operator'][] = [ $this->errors['account'][] = [
'text' => $e->getMessage(), 'text' => $e->getMessage(),
'file' => $e->getFile(), 'file' => $e->getFile(),
'line' => $e->getLine(), 'line' => $e->getLine(),
'stack' => $e->getTrace() 'stack' => $e->getTrace()
]; ];
// Запись заголовков ответа
header('Content-Type: application/json');
header('Content-Encoding: none');
header('X-Accel-Buffering: no');
// Инициализация буфера вывода
ob_start();
// Инициализация буфера ответа
$return = [
'errors' => self::parse_only_text($this->errors)
];
// Генерация ответа
echo json_encode($return);
// Запись заголовков ответа
header('Content-Length: ' . ob_get_length());
// Отправка и деинициализация буфера вывода
ob_end_flush();
flush();
} }
// Инициализация идентификатора аккаунта (ключ документа инстанции аккаунта в базе данных) // Инициализация идентификатора аккаунта (ключ документа инстанции аккаунта в базе данных)

View File

@ -34,8 +34,8 @@ final class payments extends core
public function workers(array $parameters = []): void public function workers(array $parameters = []): void
{ {
try { try {
if ($this->account->status() && ($this->account->type === 'administrator' || ($this->account->type === 'operator' && $this->account->transactions))) { if ($this->account->status() && ($this->account->type === 'administrator' || $this->account->type === 'operator')) {
// Авторизован аккаунт администратора или оператора (с доступом к транзакциям) // Авторизован аккаунт администратора или оператора
// Инициализация буфера ошибок // Инициализация буфера ошибок
$this->errors['export'] ??= []; $this->errors['export'] ??= [];
@ -76,7 +76,7 @@ final class payments extends core
} else throw new exception('Вы не авторизованы'); } else throw new exception('Вы не авторизованы');
} catch (exception $e) { } catch (exception $e) {
// Запись в реестр ошибок // Запись в реестр ошибок
$this->errors['export'][] = [ $this->errors[] = [
'text' => $e->getMessage(), 'text' => $e->getMessage(),
'file' => $e->getFile(), 'file' => $e->getFile(),
'line' => $e->getLine(), 'line' => $e->getLine(),
@ -110,7 +110,7 @@ final class payments extends core
/** /**
* Магазины * Магазины
* *
* Расчитать прибыль с магазинов за выбранный период и сгенерировать excel-документ * Расчитать ... (сверку?) за выбранный период и сгенерировать excel-документ
* *
* @param array $parameters Параметры запроса * @param array $parameters Параметры запроса
* *
@ -119,8 +119,8 @@ final class payments extends core
public function markets(array $parameters = []): void public function markets(array $parameters = []): void
{ {
try { try {
if ($this->account->status() && ($this->account->type === 'administrator' || ($this->account->type === 'operator' && $this->account->transactions))) { if ($this->account->status() && ($this->account->type === 'administrator' || $this->account->type === 'operator')) {
// Авторизован аккаунт администратора или оператора (с доступом к транзакциям) // Авторизован аккаунт администратора или оператора
// Инициализация буфера ошибок // Инициализация буфера ошибок
$this->errors['export'] ??= []; $this->errors['export'] ??= [];
@ -161,7 +161,7 @@ final class payments extends core
} else throw new exception('Вы не авторизованы'); } else throw new exception('Вы не авторизованы');
} catch (exception $e) { } catch (exception $e) {
// Запись в реестр ошибок // Запись в реестр ошибок
$this->errors['export'][] = [ $this->errors[] = [
'text' => $e->getMessage(), 'text' => $e->getMessage(),
'file' => $e->getFile(), 'file' => $e->getFile(),
'line' => $e->getLine(), 'line' => $e->getLine(),
@ -192,74 +192,4 @@ final class payments extends core
} }
} }
/**
* Подтвердить
*
* Подтвердить выполнение операций с документом (магазины или сотрудники)
*
* @param array $parameters Параметры запроса
*
* @return void
*/
public function confirm(array $parameters = []): void
{
try {
if ($this->account->status() && ($this->account->type === 'administrator' || ($this->account->type === 'operator' && $this->account->transactions))) {
// Авторизован аккаунт администратора или оператора (с доступом к транзакциям)
// Инициализация буфера ошибок
$this->errors['confirm'] ??= [];
if (!empty($from = (int) ($_COOKIE["tasks_filter_from"] ?? @$this->session->buffer[$_SERVER['INTERFACE']]['tasks']['filters']['from']))) {
// Инициализирован параметр: from
if (!empty($to = (int) ($_COOKIE["tasks_filter_to"] ?? @$this->session->buffer[$_SERVER['INTERFACE']]['tasks']['filters']['to']))) {
// Инициализирован параметр: to
// Запуск процедуры подтверждения
model::confirm(
$from,
$to,
match ($parameters['type']) {
'workers' => 'workers',
'markets' => 'markets',
default => throw new exception('Для подтверждения обработки документа необходимо передать его тип: workers, markets')
},
$this->errors['confirm']
);
} else throw new exception('Не инициализирован параметр: to');
} else throw new exception('Не инициализирован параметр: from');
} else throw new exception('Вы не авторизованы');
} catch (exception $e) {
// Запись в реестр ошибок
$this->errors['confirm'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
// Запись заголовков ответа
header('Content-Type: application/json');
header('Content-Encoding: none');
header('X-Accel-Buffering: no');
// Инициализация буфера вывода
ob_start();
// Генерация ответа
echo json_encode(
[
'errors' => self::parse_only_text($this->errors)
]
);
// Запись заголовков ответа
header('Content-Length: ' . ob_get_length());
// Отправка и деинициализация буфера вывода
ob_end_flush();
flush();
}
}
} }

View File

@ -1,94 +0,0 @@
<?php
declare(strict_types=1);
namespace mirzaev\ebala\controllers;
// Файлы проекта
use mirzaev\ebala\controllers\core,
mirzaev\ebala\models\settings as model,
mirzaev\ebala\models\core as _core;
// Библиотека для ArangoDB
use ArangoDBClient\Document as _document;
// System libraries
use datetime,
datetimezone,
exception;
/**
* Контроллер настроек сайта
*
* @package mirzaev\ebala\controllers
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
final class settings extends core
{
/**
* Страница настроек
*
* @param array $parameters Параметры запроса
*/
public function index(array $parameters = []): ?string
{
if ($this->account->status() && $this->account->type === 'administrator') {
// Авторизован аккаунт (администратор)
// Чтение настроек
$this->view->settings = model::search(
before: 'FILTER setting.category != null'
);
// Генерация представления
$main = $this->view->render(DIRECTORY_SEPARATOR . 'pages' . DIRECTORY_SEPARATOR . 'settings.html');
// Возврат (успех)
if ($_SERVER['REQUEST_METHOD'] === 'GET') return $this->view->render(DIRECTORY_SEPARATOR . 'index.html', ['main' => $main]);
else if ($_SERVER['REQUEST_METHOD'] === 'POST') return $main;
}
// Возврат (провал)
return null;
}
/**
* Записать
*
* Записывает (обновляет) в ArangoDB
*
* @param array $parameters Параметры запроса
*
* @return void
*/
public function write(array $parameters = []): void
{
try {
if ($this->account->status() && $this->account->type === 'administrator') {
// Авторизован аккаунт администратора
// Инициализация инстанции настройки
$setting = model::read('d._key == "' . $parameters['id'] . '"');
if ($setting instanceof _document) {
// Найдена инстанция настройки
// Запись значения
$setting->value = $parameters['value'];
if (_core::update($setting)) {
// Записано в ArangoDB
} else throw new exception('Не удалось обновить заявку');
} else throw new exception('Не найдена заявка');
} else throw new exception('Вы не авторизованы');
} catch (exception $e) {
// Запись в реестр ошибок
$this->errors[] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
}
}

View File

@ -1,62 +0,0 @@
<?php
declare(strict_types=1);
namespace mirzaev\ebala\controllers;
// Файлы проекта
use mirzaev\ebala\controllers\core,
mirzaev\ebala\controllers\traits\errors,
mirzaev\ebala\models\socket as model,
mirzaev\ebala\models\task,
mirzaev\ebala\models\session,
mirzaev\ebala\models\registry,
mirzaev\ebala\models\core as _core;
// Фреймворк ArangoDB
use mirzaev\arangodb\document;
// Библиотека для ArangoDB
use ArangoDBClient\Document as _document;
// Встроенные библиотеки
use exception;
/**
* Контроллер сокета
*
* @package mirzaev\ebala\controllers
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
final class socket extends core
{
use errors;
/**
* Регистрация
*
* @param array $parameters Параметры запроса
*/
public function registration(array $parameters = []): ?string
{
try {
if (model::session($this->session->getId(), $parameters['key'], $this->errors)) {
// Инициализировано соединение
// @todo сделать например возврат того что соединение удалось и на клиенте что-то оптимизировать (или не удалось чтобы повторил)
return null;
} else throw new exception('Не удалось зарегистрировать сокет');
} catch (exception $e) {
// Write to the errors registry
$this->errors['socket'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
// Возврат (провал)
return null;
}
}

View File

@ -272,11 +272,8 @@ final class task extends core
$search_query, $search_query,
empty($filters) ? null : " && ($filters)" empty($filters) ? null : " && ($filters)"
), ),
after: 'COLLECT x = worker, y = market, z = task OPTIONS { method: "sorted" }',
page: (int) $this->session->buffer['worker']['tasks']['page'], page: (int) $this->session->buffer['worker']['tasks']['page'],
sort: 'z.date DESC, z.created DESC, z._key DESC, x.created DESC, y.created DESC, x._key DESC, y._key DESC',
target: empty($search) ? model::COLLECTION : 'registry_tasks', target: empty($search) ? model::COLLECTION : 'registry_tasks',
return: '{task: z, worker: x, market: y}',
binds: ['worker' => account::worker($this->account->getId())?->id] + (empty($search) ? [] : ['search' => $search]) binds: ['worker' => account::worker($this->account->getId())?->id] + (empty($search) ? [] : ['search' => $search])
); );
} else if ($_SERVER['INTERFACE'] === 'market') { } else if ($_SERVER['INTERFACE'] === 'market') {
@ -291,11 +288,8 @@ final class task extends core
$search_query, $search_query,
empty($filters) ? null : " && ($filters)" empty($filters) ? null : " && ($filters)"
), ),
after: 'COLLECT x = worker, y = market, z = task OPTIONS { method: "sorted" }',
page: (int) $this->session->buffer['market']['tasks']['page'], page: (int) $this->session->buffer['market']['tasks']['page'],
sort: 'z.date DESC, z.created DESC, z._key DESC, x.created DESC, y.created DESC, x._key DESC, y._key DESC',
target: empty($search) ? model::COLLECTION : 'registry_tasks', target: empty($search) ? model::COLLECTION : 'registry_tasks',
return: '{task: z, worker: x, market: y}',
binds: ['market' => account::market($this->account->getId())?->id] + (empty($search) ? [] : ['search' => $search]) binds: ['market' => account::market($this->account->getId())?->id] + (empty($search) ? [] : ['search' => $search])
); );
} else if ($_SERVER['INTERFACE'] === 'operator') { } else if ($_SERVER['INTERFACE'] === 'operator') {
@ -310,11 +304,8 @@ final class task extends core
$search_query, $search_query,
empty($filters) ? null : " && ($filters)" empty($filters) ? null : " && ($filters)"
), ),
after: 'COLLECT x = worker, y = market, z = task OPTIONS { method: "sorted" }',
page: (int) $this->session->buffer['operator']['tasks']['page'], page: (int) $this->session->buffer['operator']['tasks']['page'],
sort: 'z.date DESC, z.created DESC, z._key DESC, x.created DESC, y.created DESC, x._key DESC, y._key DESC',
target: empty($search) ? model::COLLECTION : 'registry_tasks', target: empty($search) ? model::COLLECTION : 'registry_tasks',
return: '{task: z, worker: x, market: y}',
binds: empty($search) ? [] : [ binds: empty($search) ? [] : [
'search' => $search 'search' => $search
] ]
@ -331,11 +322,8 @@ final class task extends core
$search_query, $search_query,
empty($filters) ? null : " && ($filters)" empty($filters) ? null : " && ($filters)"
), ),
after: 'COLLECT x = worker, y = market, z = task OPTIONS { method: "sorted" }',
page: (int) $this->session->buffer['administrator']['tasks']['page'], page: (int) $this->session->buffer['administrator']['tasks']['page'],
sort: 'z.date DESC, z.created DESC, z._key DESC, x.created DESC, y.created DESC, x._key DESC, y._key DESC',
target: empty($search) ? model::COLLECTION : 'registry_tasks', target: empty($search) ? model::COLLECTION : 'registry_tasks',
return: '{task: z, worker: x, market: y}',
binds: empty($search) ? [] : [ binds: empty($search) ? [] : [
'search' => $search 'search' => $search
] ]
@ -451,6 +439,7 @@ final class task extends core
// Перенос времени в дату // Перенос времени в дату
$start = $date->setTime((int) $start->format('H'), (int) $start->format('i')); $start = $date->setTime((int) $start->format('H'), (int) $start->format('i'));
// Запись в буфер // Запись в буфер
$link->task = ['start' => $start] + $link->task; $link->task = ['start' => $start] + $link->task;
} }
@ -471,11 +460,6 @@ final class task extends core
$link->task = ['end' => $end] + $link->task; $link->task = ['end' => $end] + $link->task;
} }
// Инициализация данных заблокировавшего аккаунта
if (isset($link->task['block']) && $link->task['block']['expires'] > time() && $link->task['block']['account'] !== (int) $account->getKey())
$link->task = ['block' => ['_account' => account::read('d._key == "' . $link->task['block']['account'] . '"')] + $link->task['block']] + $link->task;
else $link->task = ['block' => null] + $link->task;
// Инициализация буфера сгенерированных данных работы для шаблонизатора // Инициализация буфера сгенерированных данных работы для шаблонизатора
$generated = []; $generated = [];
@ -574,15 +558,15 @@ final class task extends core
$end = $date->setTime((int) $end->format('H'), (int) $end->format('i'))->format('U'); $end = $date->setTime((int) $end->format('H'), (int) $end->format('i'))->format('U');
// Заявка уже начата? // Заявка уже начата?
if (time() - $start > 0 && time() - $end < 0) if (time() - $start > 0)
throw new exception('Запрещено редактировать начатую заявку'); throw new exception('Запрещено редактировать начатую заявку');
// Заявка уже прошла? // Заявка уже прошла?
else if (time() - $end > 0 && $task->completed !== true) if (time() - $end > 0)
throw new exception('Запрещено редактировать прошедшую заявку'); throw new exception('Запрещено редактировать прошедшую заявку');
// Заявка уже завершена? // Заявка уже завершена?
else if ($task->completed === true) if ($task->completed === true)
throw new exception('Запрещено редактировать завершённую заявку'); throw new exception('Запрещено редактировать завершённую заявку');
// Прошло более 30 минут после создания заявки? (1800 секунд = 30 минут) // Прошло более 30 минут после создания заявки? (1800 секунд = 30 минут)
@ -648,15 +632,6 @@ final class task extends core
if (($worker = worker::read('d.id == "' . $parameters['worker'] . '" && d.active == true', amount: 1)) instanceof _document) { if (($worker = worker::read('d.id == "' . $parameters['worker'] . '" && d.active == true', amount: 1)) instanceof _document) {
// Найден сотрудник (запрашиваемый для записи сотрудник существует в базе данных) // Найден сотрудник (запрашиваемый для записи сотрудник существует в базе данных)
if (!$worker->fired) {
// Не уволен сотрудник
if (in_array($task->work, $worker->works, true)) {
// Работа соответствует подходящим сотруднику
if ((($age = (new DateTime)->diff(DateTime::createFromFormat('d.m.Y', $worker->birth))->y) > 15 && ($task->work === 'Выкладчик' || $task->work === 'Гастроном')) || $age > 17) {
// Подходит по возрасту сотрудник
if ($task->worker !== $parameters['worker']) { if ($task->worker !== $parameters['worker']) {
// Идентификатор запрашиваемого сотрудника не равен актуальному // Идентификатор запрашиваемого сотрудника не равен актуальному
@ -700,9 +675,6 @@ final class task extends core
flush(); flush();
} else throw new exception('Не удалось записать изменения в базу данных'); } else throw new exception('Не удалось записать изменения в базу данных');
} else throw new exception('Сотрудник уже назначен'); } else throw new exception('Сотрудник уже назначен');
} else throw new exception('Сотрудник не подходит по возрасту');
} else throw new exception('Заявка не подходит по типу работы для сотрудника');
} else throw new exception('Нельзя назначить уволенного сотрудника');
} else throw new exception('Не найден сотрудник'); } else throw new exception('Не найден сотрудник');
} }
} else if (!empty($parameters['market'])) { } else if (!empty($parameters['market'])) {
@ -851,11 +823,9 @@ final class task extends core
// Инициализация данных сотрудника // Инициализация данных сотрудника
$this->view->task = model::read( $this->view->task = model::read(
'd._key == "' . $parameters['task'] . '"', 'd._key == "' . $parameters['task'] . '"',
return: match ($this->account->type) { return: $this->account->type === 'market'
'market' => '{_key: d._key, created: d.created, updated: d.updated, date: d.date, start: d.start, end: d.end, market: d.market, confirmed: d.confirmed, completed: d.completed }', ? '{_key: d._key, created: d.created, updated: d.updated, date: d.date, start: d.start, end: d.end, market: d.market, confirmed: d.confirmed, completed: d.completed }'
'administrator', 'operator' => '{_key: d._key, created: d.created, updated: d.updated, date: d.date, start: d.start, end: d.end, market: d.market, confirmed: d.confirmed, completed: d.completed, hided: d.hided, updates: d.updates }', : '{_key: d._key, created: d.created, updated: d.updated, date: d.date, start: d.start, end: d.end, market: d.market, confirmed: d.confirmed, completed: d.completed, hided: d.hided, updates: d.updates }'
default => 'd'
}
)->getAll(); )->getAll();
// Заявка не принадлежит запросившему магазину? // Заявка не принадлежит запросившему магазину?
@ -891,7 +861,7 @@ final class task extends core
// Перевод ключей на русский язык // Перевод ключей на русский язык
foreach ($this->view->task as $key => $value) foreach ($this->view->task as $key => $value)
if ($key === 'updates') if ($key === 'updates')
foreach ($value ?? [] as $key => $value) $buffer['updates'][$key] = [ foreach ($value as $key => $value) $buffer['updates'][$key] = [
'label' => match ($key) { 'label' => match ($key) {
'operator' => 'Оператор', 'operator' => 'Оператор',
'market' => 'Магазин', 'market' => 'Магазин',
@ -899,9 +869,7 @@ final class task extends core
'worker' => 'Сотрудник', 'worker' => 'Сотрудник',
default => $key default => $key
}, },
'value' => [ 'value' => $value
'id' => $value
] + account::read("d._key == \"$value\"", amount: 1)?->name ?? []
]; ];
else if (match ($key) { else if (match ($key) {
'created', 'updated', 'confirmed', 'hided', 'completed', '_key' => true, 'created', 'updated', 'confirmed', 'hided', 'completed', '_key' => true,
@ -1039,7 +1007,7 @@ final class task extends core
'tax' => 'ИНН', 'tax' => 'ИНН',
'city' => 'Город', 'city' => 'Город',
'payment' => 'Форма оплаты', 'payment' => 'Форма оплаты',
'works' => 'Типы работ', 'works' => 'Формы работ',
default => $key default => $key
}, },
'value' => $value 'value' => $value
@ -1147,7 +1115,6 @@ final class task extends core
'number' => 'Номер', 'number' => 'Номер',
'mail' => 'Почта', 'mail' => 'Почта',
'commentary' => 'Комментарий', 'commentary' => 'Комментарий',
'bans' => 'Заблокированные',
default => $key default => $key
}, },
'value' => $value 'value' => $value
@ -1267,7 +1234,7 @@ final class task extends core
// Генерация ответа // Генерация ответа
echo json_encode( echo json_encode(
[ [
'confirmed' => $this->view->rows[0]->task['confirmed'] ?? null, 'confirmed' => $this->view->rows[0]->task['confirmed'],
'row' => $this->view->render(DIRECTORY_SEPARATOR . 'elements' . DIRECTORY_SEPARATOR . 'tasks.html'), 'row' => $this->view->render(DIRECTORY_SEPARATOR . 'elements' . DIRECTORY_SEPARATOR . 'tasks.html'),
'errors' => self::parse_only_text($this->errors) 'errors' => self::parse_only_text($this->errors)
] ]
@ -1506,41 +1473,31 @@ final class task extends core
// Иниализация сотрудника // Иниализация сотрудника
$worker = worker::read('d.id == "' . $task->worker . '"'); $worker = worker::read('d.id == "' . $task->worker . '"');
if ($worker instanceof _document) {
// Найден сотрудник
// Инициализация магазина // Инициализация магазина
$market = market::read('d.id == "' . $task->market . '"'); $market = market::read('d.id == "' . $task->market . '"');
if ($market instanceof _document) {
// Найден магазин
// Подсчёт часов работы // Подсчёт часов работы
$hours = model::hours($task->start, $task->end, $this->errors); $hours = model::hours($task->start, $task->end, $this->errors);
// Инициализация цены работы сотрудника за 1 час // Инициализация цены работы за 1 час
$hour = payments::hour('worker', $market->city, $task->work); $hour = payments::hour($market->city, $task->work);
// Подсчёт оплаты за работу // Подсчёт оплаты за работу
$payment = $hour * $hours; $payment = $hour * $hours;
// Инициализация штрафа // Инициализация штрафа
$penalty = payments::penalty($task->rating ?? null); $penalty = payments::penalty($task->rating ?? null);
if ($penalty === null) $penalty = -$payment;
// Инициализация премии // Инициализация премии
$bonus = payments::bonus($task->rating ?? null); $bonus = payments::bonus($task->rating ?? null);
// Запись результатов // Инициализация транзакции к оплате сотруднику
$task->result = [ model::transaction(
'hours' => $hours, $task->getId(),
'hour' => $hour, $worker->getId(),
'penalty' => $penalty, $payment - ($penalty === null ? $payment : -$penalty) + $bonus,
'bonus' => $bonus, $this->errors
'processed' => false );
];
}
}
} }
// Запись в реcстре последних обновивших // Запись в реcстре последних обновивших
@ -1666,7 +1623,7 @@ final class task extends core
// Генерация ответа // Генерация ответа
echo json_encode( echo json_encode(
[ [
'hided' => $this->view->rows[0]->task['hided'] ?? null, 'hided' => $this->view->rows[0]->task['hided'],
'row' => $this->view->render(DIRECTORY_SEPARATOR . 'elements' . DIRECTORY_SEPARATOR . 'tasks.html'), 'row' => $this->view->render(DIRECTORY_SEPARATOR . 'elements' . DIRECTORY_SEPARATOR . 'tasks.html'),
'errors' => self::parse_only_text($this->errors) 'errors' => self::parse_only_text($this->errors)
] ]
@ -1714,94 +1671,6 @@ final class task extends core
} }
} }
/**
* Сгенерировать строку
*
* Используется тогда, когда нужно получить HTML-код строки заявки
*
* @param array $parameters Параметры запроса
*
* @return void В буфер вывода JSON-документ с запрашиваемыми параметрами
*/
public function row(array $parameters = []): void
{
try {
if ($this->account->status()) {
// Авторизован аккаунт
// Инициализация строки в глобальную переменную шаблонизатора
if ($this->account->type === 'worker')
$this->view->rows = model::list(before: 'FILTER task._key == "' . $parameters['task'] . '" && task.worker == "' . account::worker($this->account->getId())?->id . '"');
else if ($this->account->type === 'operator')
$this->view->rows = model::list(before: 'FILTER task._key == "' . $parameters['task'] . '"');
else if ($this->account->type === 'market')
$this->view->rows = model::list(before: 'FILTER task._key == "' . $parameters['task'] . '" && task.market == "' . account::market($this->account->getId())?->id . '"');
else if ($this->account->type === 'administrator')
$this->view->rows = model::list(before: 'FILTER task._key == "' . $parameters['task'] . '"');
else $this->view->rows = [];
// Генерация данных для генерации строки
$this->view->rows = static::preprocessing($this->account, $this->view->rows);
// Запись в глобальную переменную шаблонизатора обрабатываемой страницы (отключение)
$this->view->page = null;
// Запись заголовков ответа
header('Content-Type: application/json');
header('Content-Encoding: none');
header('X-Accel-Buffering: no');
// Инициализация буфера вывода
ob_start();
// Генерация ответа
echo json_encode(
[
'row' => $this->view->render(DIRECTORY_SEPARATOR . 'elements' . DIRECTORY_SEPARATOR . 'tasks.html'),
'errors' => self::parse_only_text($this->errors)
]
);
// Запись заголовков ответа
header('Content-Length: ' . ob_get_length());
// Отправка и деинициализация буфера вывода
ob_end_flush();
flush();
} else throw new exception('Вы не авторизованы');
} catch (exception $e) {
// Запись в реестр ошибок
$this->errors[] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
// Запись заголовков ответа
header('Content-Type: application/json');
header('Content-Encoding: none');
header('X-Accel-Buffering: no');
// Инициализация буфера вывода
ob_start();
// Генерация ответа
echo json_encode(
[
'errors' => self::parse_only_text($this->errors)
]
);
// Запись заголовков ответа
header('Content-Length: ' . ob_get_length());
// Отправка и деинициализация буфера вывода
ob_end_flush();
flush();
}
}
/** /**
* Удалить * Удалить
* *
@ -1840,15 +1709,15 @@ final class task extends core
$end = $date->setTime((int) $end->format('H'), (int) $end->format('i'))->format('U'); $end = $date->setTime((int) $end->format('H'), (int) $end->format('i'))->format('U');
// Заявка уже начата? // Заявка уже начата?
if (time() - $start > 0 && time() - $end < 0) if (time() - $start > 0)
throw new exception('Запрещено удалять начатую заявку'); throw new exception('Запрещено удалять начатую заявку');
// Заявка уже прошла? // Заявка уже прошла?
else if (time() - $end > 0 && $task->completed !== true) if (time() - $end > 0)
throw new exception('Запрещено удалять прошедшую заявку'); throw new exception('Запрещено удалять прошедшую заявку');
// Заявка уже завершена? // Заявка уже завершена?
else if ($task->completed === true) if ($task->completed === true)
throw new exception('Запрещено удалять завершённую заявку'); throw new exception('Запрещено удалять завершённую заявку');
// Прошло более 30 минут после создания заявки? (1800 секунд = 30 минут) // Прошло более 30 минут после создания заявки? (1800 секунд = 30 минут)
@ -2047,8 +1916,7 @@ final class task extends core
$this->view->works = static::WORKS; $this->view->works = static::WORKS;
// Проверка на существование записанной в задаче работы в списке существующих работ и запись об этом в глобальную переменную шаблонизатора // Проверка на существование записанной в задаче работы в списке существующих работ и запись об этом в глобальную переменную шаблонизатора
foreach ($this->view->works as $work) foreach ($this->view->works as $work) if ($this->view->task->work === $work) $this->view->exist = true;
if (in_array($work, $this->view->worker->works)) $this->view->exist = true;
// Запись заголовков ответа // Запись заголовков ответа
header('Content-Type: application/json'); header('Content-Type: application/json');
@ -2094,8 +1962,7 @@ final class task extends core
$this->view->works = static::WORKS; $this->view->works = static::WORKS;
// Проверка на существование записанной в задаче работы в списке существующих работ и запись об этом в глобальную переменную шаблонизатора // Проверка на существование записанной в задаче работы в списке существующих работ и запись об этом в глобальную переменную шаблонизатора
foreach ($this->view->works as $work) foreach ($this->view->works as $work) if ($this->view->worker->work === $work) $this->view->exist = true;
if (in_array($work, $this->view->worker->works)) $this->view->exist = true;
// Запись заголовков ответа // Запись заголовков ответа
header('Content-Type: application/json'); header('Content-Type: application/json');
@ -2210,9 +2077,6 @@ final class task extends core
// Заявка подтверждена? // Заявка подтверждена?
if ($task->confirmed) throw new exception('Запрещено редактировать тип работы у подтверждённой заявки'); if ($task->confirmed) throw new exception('Запрещено редактировать тип работы у подтверждённой заявки');
if ($this->account->type === 'market') {
// Магазин
// Инициализация даты // Инициализация даты
$date = (new DateTime('@' . $task->date))->setTimezone(new DateTimeZone('Asia/Krasnoyarsk')); $date = (new DateTime('@' . $task->date))->setTimezone(new DateTimeZone('Asia/Krasnoyarsk'));
@ -2224,27 +2088,14 @@ final class task extends core
$start = $date->setTime((int) $start->format('H'), (int) $start->format('i'))->format('U'); $start = $date->setTime((int) $start->format('H'), (int) $start->format('i'))->format('U');
$end = $date->setTime((int) $end->format('H'), (int) $end->format('i'))->format('U'); $end = $date->setTime((int) $end->format('H'), (int) $end->format('i'))->format('U');
// Заявка уже начата? // Заявка уже начата
if (time() - $start > 0 && time() - $end < 0) if ($this->account->type === 'market' and time() - $start > 0)
throw new exception('Запрещено редактировать тип работы начатой заявки'); throw new exception('Запрещено редактировать тип работы начатой заявки');
// Заявка уже прошла? // Заявка уже завершена
else if (time() - $end > 0 && $task->completed !== true) if ($this->account->type === 'market' and $task->completed === true || time() - $end > 0)
throw new exception('Запрещено редактировать тип работы прошедшей заявки');
// Заявка уже завершена?
else if ($task->completed === true)
throw new exception('Запрещено редактировать тип работы завершённой заявки'); throw new exception('Запрещено редактировать тип работы завершённой заявки');
// Прошло более 30 минут после создания заявки? (1800 секунд = 30 минут)
/* if (time() - $task->created > 1800)
throw new exception('Запрещено редактировать заявку спустя 30 минут после создания'); */
// До начала заявки осталось менее 16 часов? (57600 секунд = 16 часов)
if ($start - time() < 57600)
throw new exception('Запрещено редактировать тип работы заявки за менее 16 часов до её начала');
}
if ($task instanceof _document) { if ($task instanceof _document) {
// Найдена заявка // Найдена заявка
@ -2466,9 +2317,6 @@ final class task extends core
// Заявка подтверждена? // Заявка подтверждена?
if ($task->confirmed) throw new exception('Запрещено редактировать дату и время у подтверждённой заявки'); if ($task->confirmed) throw new exception('Запрещено редактировать дату и время у подтверждённой заявки');
if ($this->account->type === 'market') {
// Магазин
// Инициализация даты // Инициализация даты
$date = (new DateTime('@' . $task->date))->setTimezone(new DateTimeZone('Asia/Krasnoyarsk')); $date = (new DateTime('@' . $task->date))->setTimezone(new DateTimeZone('Asia/Krasnoyarsk'));
@ -2480,27 +2328,14 @@ final class task extends core
$start = $date->setTime((int) $start->format('H'), (int) $start->format('i'))->format('U'); $start = $date->setTime((int) $start->format('H'), (int) $start->format('i'))->format('U');
$end = $date->setTime((int) $end->format('H'), (int) $end->format('i'))->format('U'); $end = $date->setTime((int) $end->format('H'), (int) $end->format('i'))->format('U');
// Заявка уже начата? // Заявка уже начата
if (time() - $start > 0 && time() - $end < 0) if ($this->account->type === 'market' and time() - $start > 0)
throw new exception('Запрещено редактировать дату и время начатой заявки'); throw new exception('Запрещено редактировать дату и время начатой заявки');
// Заявка уже прошла? // Заявка уже завершена
else if (time() - $end > 0 && $task->completed !== true) if ($this->account->type === 'market' and $task->completed === true || time() - $end > 0)
throw new exception('Запрещено редактировать дату и время прошедшей заявки');
// Заявка уже завершена?
else if ($task->completed === true)
throw new exception('Запрещено редактировать дату и время завершённой заявки'); throw new exception('Запрещено редактировать дату и время завершённой заявки');
// Прошло более 30 минут после создания заявки? (1800 секунд = 30 минут)
/* if (time() - $task->created > 1800)
throw new exception('Запрещено редактировать заявку спустя 30 минут после создания'); */
// До начала заявки осталось менее 16 часов? (57600 секунд = 16 часов)
if ($start - time() < 57600)
throw new exception('Запрещено редактировать дату и время заявки за менее 16 часов до её начала');
}
if ($task instanceof _document) { if ($task instanceof _document) {
// Найдена заявка // Найдена заявка

View File

@ -182,7 +182,8 @@ final class worker extends core
|| (LENGTH(@search) > 4 && LEVENSHTEIN_MATCH(a.requisites, TOKENS(@search, 'text_ru')[0], 1, true)) || (LENGTH(@search) > 4 && LEVENSHTEIN_MATCH(a.requisites, TOKENS(@search, 'text_ru')[0], 1, true))
|| (LENGTH(@search) > 7 && LEVENSHTEIN_MATCH(a.tax, TOKENS(@search, 'text_ru')[0], 1, true)) || (LENGTH(@search) > 7 && LEVENSHTEIN_MATCH(a.tax, TOKENS(@search, 'text_ru')[0], 1, true))
OPTIONS { collections: ["account", "worker"] } OPTIONS { collections: ["account", "worker"] }
AQL;; AQL;
// Инициализация данных для генерации HTML-документа с таблицей // Инициализация данных для генерации HTML-документа с таблицей
$this->view->rows = registry::workers( $this->view->rows = registry::workers(
before: sprintf( before: sprintf(
@ -199,15 +200,12 @@ final class worker extends core
FILTER account.type == 'worker' && b.deleted != true FILTER account.type == 'worker' && b.deleted != true
%s %s
%s %s
COLLECT x = account, y = worker OPTIONS { method: "sorted" }
AQL, AQL,
empty($filters_before) ? null : "FILTER $filters_before", empty($filters_before) ? null : "FILTER $filters_before",
empty($filters_after) ? null : "FILTER $filters_after" empty($filters_after) ? null : "FILTER $filters_after"
), ),
page: (int) $this->session->buffer[$_SERVER['INTERFACE']]['workers']['page'], page: (int) $this->session->buffer[$_SERVER['INTERFACE']]['workers']['page'],
sort: 'x.created DESC, y.created DESC, x._key DESC, y._key DESC',
target: empty($search) ? account::COLLECTION : 'registry_accounts', target: empty($search) ? account::COLLECTION : 'registry_accounts',
return: '{account: x, worker: y}',
binds: empty($search) ? [] : [ binds: empty($search) ? [] : [
'search' => $search 'search' => $search
] ]
@ -268,7 +266,7 @@ final class worker extends core
if (!empty($parameters['requisites']) && $parameters['worker_requisites'][-1] === '.') $parameters['worker_requisites'] .= '.'; if (!empty($parameters['requisites']) && $parameters['worker_requisites'][-1] === '.') $parameters['worker_requisites'] .= '.';
if (!empty($parameters['worker_birth'])) $parameters['worker_birth'] = DateTime::createFromFormat('Y-m-d', $parameters['worker_birth'])->getTimestamp(); if (!empty($parameters['worker_birth'])) $parameters['worker_birth'] = DateTime::createFromFormat('Y-m-d', $parameters['worker_birth'])->getTimestamp();
if (!empty($parameters['worker_issued'])) $parameters['worker_issued'] = DateTime::createFromFormat('Y-m-d', $parameters['worker_issued'])->getTimestamp(); if (!empty($parameters['worker_issued'])) $parameters['worker_issued'] = DateTime::createFromFormat('Y-m-d', $parameters['worker_issued'])->getTimestamp();
if (!empty($parameters['works'])) $parameters['works'] = in_array($parameters['works'], static::WORKS) ? $parameters['works'] : static::WORKS[0]; if (!empty($parameters['work'])) $parameters['work'] = in_array($parameters['work'], static::WORKS) ? $parameters['work'] : static::WORKS[0];
if (!empty($parameters['worker_hiring'])) $parameters['worker_hiring'] = DateTime::createFromFormat('Y-m-d', $parameters['worker_hiring'])->getTimestamp(); if (!empty($parameters['worker_hiring'])) $parameters['worker_hiring'] = DateTime::createFromFormat('Y-m-d', $parameters['worker_hiring'])->getTimestamp();
// Создание аккаунта // Создание аккаунта
@ -398,7 +396,7 @@ final class worker extends core
// Авторизован аккаунт администратора или оператора // Авторизован аккаунт администратора или оператора
// Инициализация данных сотрудника // Инициализация данных сотрудника
$worker = model::read('d.id == "' . urldecode($parameters['id']) . '"', return: '{ name: d.name, number: d.number, mail: d.mail, birth: d.birth, passport: d.passport, issued: d.issued, department: d.department, requisites: d.requisites, payment: d.payment, tax: d.tax, city: d.city, district: d.district, address: d.address, worl: d.work, hiring: d.hiring, registration: d.registration}')->getAll(); $worker = model::read('d.id == "' . $parameters['id'] . '"', return: '{ name: d.name, number: d.number, mail: d.mail, birth: d.birth, passport: d.passport, issued: d.issued, department: d.department, requisites: d.requisites, payment: d.payment, tax: d.tax, city: d.city, district: d.district, address: d.address, worl: d.work, hiring: d.hiring}')->getAll();
if (!empty($worker)) { if (!empty($worker)) {
// Найдены данные сотрудника // Найдены данные сотрудника
@ -438,7 +436,7 @@ final class worker extends core
// Авторизован аккаунт администратора или оператора // Авторизован аккаунт администратора или оператора
// Инициализация данных сотрудника // Инициализация данных сотрудника
$worker = model::read('d.id == "' . urldecode($parameters['id']) . '"'); $worker = model::read('d.id == "' . $parameters['id'] . '"');
if (!empty($worker)) { if (!empty($worker)) {
// Найден сотрудник // Найден сотрудник
@ -446,12 +444,8 @@ final class worker extends core
// Универсализация // Универсализация
if (!empty($parameters['birth'])) $parameters['birth'] = DateTime::createFromFormat('Y-m-d', $parameters['birth'])->getTimestamp(); if (!empty($parameters['birth'])) $parameters['birth'] = DateTime::createFromFormat('Y-m-d', $parameters['birth'])->getTimestamp();
if (!empty($parameters['issued'])) $parameters['issued'] = DateTime::createFromFormat('Y-m-d', $parameters['issued'])->getTimestamp(); if (!empty($parameters['issued'])) $parameters['issued'] = DateTime::createFromFormat('Y-m-d', $parameters['issued'])->getTimestamp();
if (!empty($parameters['work'])) $parameters['work'] = in_array($parameters['work'], static::WORKS) ? $parameters['work'] : static::WORKS[0];
if (!empty($parameters['hiring'])) $parameters['hiring'] = DateTime::createFromFormat('Y-m-d', $parameters['hiring'])->getTimestamp(); if (!empty($parameters['hiring'])) $parameters['hiring'] = DateTime::createFromFormat('Y-m-d', $parameters['hiring'])->getTimestamp();
if (!empty($buffer = explode(':', $parameters['works']))) {
$parameters['works'] = [];
foreach ($buffer ?? [] as $work)
if (in_array($work, static::WORKS)) array_push($parameters['works'], $work);
}
// Инициализация параметров (перезапись переданными значениями) // Инициализация параметров (перезапись переданными значениями)
if ($parameters['name_first'] !== $worker->name['first']) $worker->name = ['first' => $parameters['name_first']] + $worker->name; if ($parameters['name_first'] !== $worker->name['first']) $worker->name = ['first' => $parameters['name_first']] + $worker->name;
@ -472,9 +466,8 @@ final class worker extends core
if ($parameters['city'] !== $worker->city) $worker->city = $parameters['city']; if ($parameters['city'] !== $worker->city) $worker->city = $parameters['city'];
if ($parameters['district'] !== $worker->district) $worker->district = $parameters['district']; if ($parameters['district'] !== $worker->district) $worker->district = $parameters['district'];
if ($parameters['address'] !== $worker->address) $worker->address = $parameters['address']; if ($parameters['address'] !== $worker->address) $worker->address = $parameters['address'];
if ($parameters['works'] !== $worker->works) $worker->works = $parameters['works']; if ($parameters['work'] !== $worker->work) $worker->work = $parameters['work'];
if ($parameters['hiring'] !== $worker->hiring) $worker->hiring = $parameters['hiring']; if ($parameters['hiring'] !== $worker->hiring) $worker->hiring = $parameters['hiring'];
if ($parameters['registration'] !== $worker->registration) $worker->registration = $parameters['registration'];
if (_core::update($worker)) { if (_core::update($worker)) {
// Записаны данные сотрудника // Записаны данные сотрудника
@ -540,7 +533,7 @@ final class worker extends core
// Авторизован аккаунт администратора или оператора // Авторизован аккаунт администратора или оператора
// Инициализация данных сотрудника // Инициализация данных сотрудника
$worker = model::read('d.id == "' . urldecode($parameters['id']) . '"'); $worker = model::read('d.id == "' . $parameters['id'] . '"');
if (!empty($worker)) { if (!empty($worker)) {
// Найден сотрудник // Найден сотрудник
@ -594,7 +587,7 @@ final class worker extends core
// Авторизован аккаунт администратора или оператора // Авторизован аккаунт администратора или оператора
// Инициализация данных сотрудника // Инициализация данных сотрудника
$worker = model::read('d.id == "' . urldecode($parameters['id']) . '"'); $worker = model::read('d.id == "' . $parameters['id'] . '"');
if (!empty($worker)) { if (!empty($worker)) {
// Найден сотрудник // Найден сотрудник

View File

@ -60,7 +60,7 @@ final class account extends core
$this->document = $account->document; $this->document = $account->document;
// Связь сессии с аккаунтом // Связь сессии с аккаунтом
self::session($session->getId(), $this->document->getId(), $errors); session::connect($session->getId(), $this->document->getId(), $errors);
// Блокировка доступа // Блокировка доступа
if ($account?->active !== true) throw new exception('Свяжитесь с оператором'); if ($account?->active !== true) throw new exception('Свяжитесь с оператором');
@ -96,7 +96,7 @@ final class account extends core
$this->document = $account; $this->document = $account;
// Связь сессии с аккаунтом // Связь сессии с аккаунтом
self::session($session->getId(), $this->document->getId(), $errors); session::connect($session->getId(), $this->document->getId(), $errors);
// Удаление использованных данных из буфера сессии // Удаление использованных данных из буфера сессии
$session->write(['entry' => ['number' => null, 'password' => null]]); $session->write(['entry' => ['number' => null, 'password' => null]]);
@ -129,7 +129,7 @@ final class account extends core
$this->document = $account; $this->document = $account;
// Связь сессии с аккаунтом // Связь сессии с аккаунтом
self::session($session->getId(), $this->document->getId(), $errors); session::connect($session->getId(), $this->document->getId(), $errors);
// Удаление использованных данных из буфера сессии // Удаление использованных данных из буфера сессии
$session->write(['entry' => ['_key' => null, 'password' => null]]); $session->write(['entry' => ['_key' => null, 'password' => null]]);
@ -155,7 +155,7 @@ final class account extends core
$this->document = $account; $this->document = $account;
// Связь сессии с аккаунтом // Связь сессии с аккаунтом
self::session($session->getId(), $this->document->getId(), $errors); session::connect($session->getId(), $this->document->getId(), $errors);
// Удаление использованных данных из буфера сессии // Удаление использованных данных из буфера сессии
$session->write(['entry' => ['_key' => null, 'password' => null]]); $session->write(['entry' => ['_key' => null, 'password' => null]]);
@ -181,7 +181,7 @@ final class account extends core
$this->document = $account; $this->document = $account;
// Связь сессии с аккаунтом // Связь сессии с аккаунтом
self::session($session->getId(), $this->document->getId(), $errors); session::connect($session->getId(), $this->document->getId(), $errors);
// Удаление использованных данных из буфера сессии // Удаление использованных данных из буфера сессии
$session->write(['entry' => ['_key' => null, 'password' => null]]); $session->write(['entry' => ['_key' => null, 'password' => null]]);
@ -318,7 +318,7 @@ final class account extends core
} }
/** /**
* Подключить к сотруднику * Инициализировать связь аккаунта с сотрудником
* *
* Ищет связь аккаунта с сотрудником, если не находит, то создаёт её * Ищет связь аккаунта с сотрудником, если не находит, то создаёт её
* *
@ -328,9 +328,6 @@ final class account extends core
* @param array &$errors Реестр ошибок * @param array &$errors Реестр ошибок
* *
* @return bool Связан аккаунт с сотрудником? * @return bool Связан аккаунт с сотрудником?
*
* @todo
* 1. Переделать на подобие account::session и перенести в mirzaev/ebala/models/worker
*/ */
public static function connect(string $account, string $target, string $type = 'worker', array &$errors = []): bool public static function connect(string $account, string $target, string $type = 'worker', array &$errors = []): bool
{ {
@ -406,65 +403,6 @@ final class account extends core
return null; return null;
} }
/**
* Подключить к сессии
*
* Ищет связь сессии с аккаунтом, если не находит, то создаёт её
*
* @param string $session Идентификатор сессии
* @param string $account Идентификатор аккаунта
* @param array &$errors Реестр ошибок
*
* @return bool Аккаунт подключен к сессии?
*/
public static function session(string $session, string $account, array &$errors = []): bool
{
try {
if (
collection::init(static::$arangodb->session, self::COLLECTION)
&& collection::init(static::$arangodb->session, session::COLLECTION)
&& collection::init(static::$arangodb->session, session::COLLECTION . '_edge_' . self::COLLECTION, true)
) {
// Инициализированы коллекции
if (
collection::search(static::$arangodb->session, sprintf(
<<<AQL
FOR document IN %s
FILTER document._from == '%s' && document._to == '%s'
LIMIT 1
RETURN document
AQL,
session::COLLECTION . '_edge_' . self::COLLECTION,
$session,
$account
)) instanceof _document
|| document::write(static::$arangodb->session, session::COLLECTION . '_edge_' . self::COLLECTION, [
'_from' => $session,
'_to' => $account
])
) {
// Найдено, либо создано ребро: session -> account
// Возврат (успех)
return true;
} else throw new exception('Не удалось создать ребро: session -> account');
} else throw new exception('Не удалось инициализировать коллекции');
} catch (exception $e) {
// Запись в реестр ошибок
$errors['account'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
// Возврат (провал)
return false;
}
/** /**
* Записать * Записать
* *

View File

@ -35,7 +35,7 @@ class core extends model
/** /**
* Путь до файла с настройками подключения к базе данных ArangoDB * Путь до файла с настройками подключения к базе данных ArangoDB
*/ */
final public const ARANGODB = __DIR__ . '/../settings/arangodb.php'; final public const ARANGODB = '../settings/arangodb.php';
/** /**
* Соединение с базой данных ArangoDB * Соединение с базой данных ArangoDB
@ -203,8 +203,7 @@ class core extends model
* *
* @return int|null Количество документов в базе данных, если найдены * @return int|null Количество документов в базе данных, если найдены
*/ */
public static function count(?string $collection = null, array &$errors = []): int|null public static function count(?string $collection = null, array &$errors = []): int|null {
{
try { try {
if (collection::init(static::$arangodb->session, static::COLLECTION)) { if (collection::init(static::$arangodb->session, static::COLLECTION)) {
// Инициализирована коллекция // Инициализирована коллекция

View File

@ -46,7 +46,7 @@ final class payments extends core
{ {
try { try {
// Чтение заявок // Чтение заявок
$tasks = @task::read("d.date >= $from && d.date <= $to && d.problematic == false && d.completed == true && d.result.processed != true", amount: 999999, return: '{worker: d.worker, market: d.market, date: d.date, work: d.work, start: d.start, end: d.end, commentary: d.commentary, rating: d.rating, review: d.review}', errors: $errors); $tasks = @task::read("d.date >= $from && d.date <= $to && d.problematic == false && d.completed == true", amount: 999999, return: '{worker: d.worker, market: d.market, date: d.date, work: d.work, start: d.start, end: d.end, commentary: d.commentary, rating: d.rating, review: d.review}', errors: $errors);
if (is_array($tasks) && count($tasks) > 0) { if (is_array($tasks) && count($tasks) > 0) {
// Найдены заявки // Найдены заявки
@ -208,9 +208,9 @@ final class payments extends core
->setCellValue("M$row", $worker->name['second'] . ' ' . $worker->name['first'] . ' ' . $worker->name['last']) ->setCellValue("M$row", $worker->name['second'] . ' ' . $worker->name['first'] . ' ' . $worker->name['last'])
->setCellValue("N$row", $hour = static::hour('worker', $market->city, $task->work)) ->setCellValue("N$row", $hour = static::hour('worker', $market->city, $task->work))
->setCellValue("O$row", $payment = $hour * $hours) ->setCellValue("O$row", $payment = $hour * $hours)
->setCellValue("P$row", ($penalty = static::penalty($task->rating ?? null)) === null ? -$payment : $penalty) ->setCellValue("P$row", ($penalty = static::penalty($task->rating ?? null)) === null ? $payment : $penalty)
->setCellValue("Q$row", $bonus = static::bonus($task->rating ?? null)) ->setCellValue("Q$row", $bonus = static::bonus($task->rating ?? null))
->setCellValue("R$row", $payment + ($penalty === null ? -$payment : $penalty) + $bonus) ->setCellValue("R$row", $payment + (($penalty = static::penalty($task->rating ?? null)) === null ? $payment : $penalty) + $bonus)
->setCellValue("S$row", '') ->setCellValue("S$row", '')
->setCellValue("T$row", $worker->payment) // Наличные? ->setCellValue("T$row", $worker->payment) // Наличные?
->setCellValue("U$row", '') ->setCellValue("U$row", '')
@ -253,7 +253,7 @@ final class payments extends core
/** /**
* Магазины * Магазины
* *
* Расчитать прибыль с магазинов и сгенерировать excel-документ * Расчитать ... и сгенерировать excel-документ
* *
* @param int $from Начальная дата для выборки заявок (unixtime) * @param int $from Начальная дата для выборки заявок (unixtime)
* @param int $to Конечная дата для выборки заявок (unixtime) * @param int $to Конечная дата для выборки заявок (unixtime)
@ -431,15 +431,6 @@ final class payments extends core
// Инициализация счётчика строк // Инициализация счётчика строк
$row = 9; $row = 9;
// Инициализация буфера объединённых данных всех магазинов
$total = [
'workers' => 0,
'hours' => 0,
'hour' => [],
'payment' => 0,
'vat' => 0
];
foreach ($merged as $id => $dates) { foreach ($merged as $id => $dates) {
// Перебор магазинов // Перебор магазинов
@ -488,15 +479,7 @@ final class payments extends core
// Инкрементация счётчика для генерации следующей строки // Инкрементация счётчика для генерации следующей строки
++$row; ++$row;
} }
} // Чтение заявок }
$tasks = @task::collect(
"d.date >= $from && d.date <= $to && d.problematic == false && d.completed == true",
sort: 'd.date DESC',
amount: 999999,
index: 'd.date',
return: '{worker: d.worker, market: d.market, date: d.date, work: d.work, start: d.start, end: d.end, commentary: d.commentary, rating: d.rating, review: d.review}',
errors: $errors
);
// Запись строки с общими данными магазина // Запись строки с общими данными магазина
$spreadsheet $spreadsheet
@ -508,17 +491,10 @@ final class payments extends core
->setCellValue("E$row", '') ->setCellValue("E$row", '')
->setCellValue("F$row", $result['workers']) ->setCellValue("F$row", $result['workers'])
->setCellValue("G$row", $result['hours']) ->setCellValue("G$row", $result['hours'])
->setCellValue("H$row", $hour = array_sum($result['hour']) / count($result['hour'])) ->setCellValue("H$row", array_sum($result['hour']) / count($result['hour']))
->setCellValue("I$row", $result['payment']) ->setCellValue("I$row", $result['payment'])
->setCellValue("J$row", $result['vat']); ->setCellValue("J$row", $result['vat']);
// Запись в буфер объединённых данных всех магазинов
$total['workers'] += $result['workers'];
$total['hours'] += $result['hours'];
$total['hour'][] = $hour;
$total['payment'] += $result['payment'];
$total['vat'] += $result['vat'];
// Запись цвета строки с общими данными магазина // Запись цвета строки с общими данными магазина
$spreadsheet $spreadsheet
->getActiveSheet() ->getActiveSheet()
@ -532,36 +508,6 @@ final class payments extends core
} }
} }
// Запись строки с общими данными всех магазинов
$spreadsheet
->setActiveSheetIndex(0)
->setCellValue("A$row", "Итого")
->setCellValue("B$row", '')
->setCellValue("C$row", '')
->setCellValue("D$row", '')
->setCellValue("E$row", '')
->setCellValue("F$row", $total['workers'])
->setCellValue("G$row", $total['hours'])
->setCellValue("H$row", array_sum($total['hour']) / count($total['hour']))
->setCellValue("I$row", $total['payment'])
->setCellValue("J$row", $total['vat']);
// Запись цвета строки с общими данными всех магазинов
$spreadsheet
->getActiveSheet()
->getStyle("A$row:J$row")
->getFill()
->setFillType(Fill::FILL_SOLID)
->getStartColor()
->setARGB('ffdfe4ec');
// Запись жирного текста для строки с общими данными всех магазинов
$spreadsheet
->getActiveSheet()
->getStyle("A$row:J$row")
->getFont()
->setBold(true);
// Write to output buffer // Write to output buffer
IOFactory::createWriter($spreadsheet, 'Xlsx')->save('php://output'); IOFactory::createWriter($spreadsheet, 'Xlsx')->save('php://output');
@ -583,60 +529,6 @@ final class payments extends core
return false; return false;
} }
/**
* Подтвердить обработку
*
* Отметить в базе данных то, что выбранные заявки были обработаны
*
* @param int $from Начальная дата для выборки заявок (unixtime)
* @param int $to Конечная дата для выборки заявок (unixtime)
* @param string $type Тип документа для подтверждения (workers, markets)
* @param array $errors Errors registry
*
* @return void
*/
public static function confirm(int $from, int $to, string $type, array &$errors = []): bool
{
try {
// Чтение заявок
$tasks = @task::read("d.date >= $from && d.date <= $to && d.problematic == false && d.completed == true && d.result.processed != true", amount: 999999, errors: $errors);
if (is_array($tasks) && count($tasks) > 0) {
// Найдены заявки
if ($type === 'workers') {
// Подтверждена обработка зарплат сотрудников за выбранный период
foreach ($tasks as $task) {
// Перебор заявок
// Подтверждение того, что заявка обработана (выплачены деньги сотруднику)
$task->result = ['processed' => true] + ($task->result ?? []);
// Запись обновления в базу данных
core::update($task);
}
}
// Exit (success)
return true;
}
throw new exception('Не найдены заявки');
} catch (exception $e) {
// Write to the errors registry
$errors[] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
// Exit (fail)
return false;
}
/** /**
* Determine tariff * Determine tariff
@ -651,8 +543,72 @@ final class payments extends core
{ {
return return
match (mb_strtolower($type)) { match (mb_strtolower($type)) {
'market', 'магазин' => settings::read("d.category == 'market_hour' && d.city == '$city' && d.work == '$work'")?->value ?? 0, 'market', 'магазин' => match (mb_strtolower($city)) {
'worker', 'сотрудник' => settings::read("d.category == 'worker_hour' && d.city == '$city' && d.work == '$work'")?->value ?? 0, 'красноярск' => match (mb_strtolower($work)) {
'cashiers', 'cashier', 'кассиры', 'кассир' => 257.07,
'displayers', 'displayer', 'выкладчики', 'выкладчик' => 257.07,
'gastronomes', 'gastronome', 'гастрономы', 'гастроном' => 257.07,
'brigadiers', 'brigadier', 'бригадиры', 'бригадир' => 360,
'loaders', 'loader', 'грузчики', 'грузчик' => 255.645,
'loaders_mobile', 'loader_mobile', 'мобильные грузчики', 'мобильный грузчик' => 305,
'universals_mobile', 'universal_mobile', 'мобильные универсалы', 'мобильный универсал' => 305,
default => 0
},
'железногорск', 'сосновоборск', 'тыва' => match (mb_strtolower($work)) {
'cashiers', 'cashier', 'кассиры', 'кассир' => 263.34,
'displayers', 'displayer', 'выкладчики', 'выкладчик' => 263.34,
'gastronomes', 'gastronome', 'гастрономы', 'гастроном' => 263.34,
'brigadiers', 'brigadier', 'бригадиры', 'бригадир' => 360,
'loaders', 'loader', 'грузчики', 'грузчик' => 255.645,
'loaders_mobile', 'loader_mobile', 'мобильные грузчики', 'мобильный грузчик' => 305,
'universals_mobile', 'universal_mobile', 'мобильные универсалы', 'мобильный универсал' => 305,
default => 0
},
'хакасия', 'иркутск' => match (mb_strtolower($work)) {
'cashiers', 'cashier', 'кассиры', 'кассир' => 245.385,
'displayers', 'displayer', 'выкладчики', 'выкладчик' => 245.385,
'gastronomes', 'gastronome', 'гастрономы', 'гастроном' => 245.385,
'brigadiers', 'brigadier', 'бригадиры', 'бригадир' => 360,
'loaders', 'loader', 'грузчики', 'грузчик' => 255.645,
'loaders_mobile', 'loader_mobile', 'мобильные грузчики', 'мобильный грузчик' => 305,
'universals_mobile', 'universal_mobile', 'мобильные универсалы', 'мобильный универсал' => 305,
default => 0
},
default => 0
},
'worker', 'сотрудник' => match (mb_strtolower($city)) {
'красноярск' => match (mb_strtolower($work)) {
'cashiers', 'cashier', 'кассиры', 'кассир' => 190.91,
'displayers', 'displayer', 'выкладчики', 'выкладчик' => 190.91,
'gastronomes', 'gastronome', 'гастрономы', 'гастроном' => 190.91,
'brigadiers', 'brigadier', 'бригадиры', 'бригадир' => 250,
'loaders', 'loader', 'грузчики', 'грузчик' => 177.27,
'loaders_mobile', 'loader_mobile', 'мобильные грузчики', 'мобильный грузчик' => 250,
'universals_mobile', 'universal_mobile', 'мобильные универсалы', 'мобильный универсал' => 250,
default => 0
},
'железногорск', 'сосновоборск', 'тыва' => match (mb_strtolower($work)) {
'cashiers', 'cashier', 'кассиры', 'кассир' => 190.91,
'displayers', 'displayer', 'выкладчики', 'выкладчик' => 190.91,
'gastronomes', 'gastronome', 'гастрономы', 'гастроном' => 190.91,
'brigadiers', 'brigadier', 'бригадиры', 'бригадир' => 250,
'loaders', 'loader', 'грузчики', 'грузчик' => 177.27,
'loaders_mobile', 'loader_mobile', 'мобильные грузчики', 'мобильный грузчик' => 250,
'universals_mobile', 'universal_mobile', 'мобильные универсалы', 'мобильный универсал' => 250,
default => 0
},
'хакасия', 'иркутск' => match (mb_strtolower($work)) {
'cashiers', 'cashier', 'кассиры', 'кассир' => 181.82,
'displayers', 'displayer', 'выкладчики', 'выкладчик' => 181.82,
'gastronomes', 'gastronome', 'гастрономы', 'гастроном' => 181.82,
'brigadiers', 'brigadier', 'бригадиры', 'бригадир' => 250,
'loaders', 'loader', 'грузчики', 'грузчик' => 168.18,
'loaders_mobile', 'loader_mobile', 'мобильные грузчики', 'мобильный грузчик' => 250,
'universals_mobile', 'universal_mobile', 'мобильные универсалы', 'мобильный универсал' => 250,
default => 0
},
default => 0
},
default => 0 default => 0
}; };
} }
@ -666,7 +622,10 @@ final class payments extends core
*/ */
public static function bonus(int $rating): int public static function bonus(int $rating): int
{ {
return settings::read("d.category == 'worker_bonus' && d.rating == $rating")?->value ?? 0; return match ($rating) {
5 => 100,
default => 0
};
} }
/** /**
@ -678,8 +637,11 @@ final class payments extends core
*/ */
public static function penalty(int $rating): ?int public static function penalty(int $rating): ?int
{ {
$penalty = settings::read("d.category == 'worker_penalty' && d.rating == $rating")?->value ?? 0; return match ($rating) {
3 => -100,
return $penalty === 1 ? null : $penalty; 2 => -500,
1 => null,
default => 0
};
} }
} }

View File

@ -36,9 +36,7 @@ final class registry extends core
* @param ?string $after Injection of AQL-code after search of edges * @param ?string $after Injection of AQL-code after search of edges
* @param int $amount Amount of workers * @param int $amount Amount of workers
* @param int $page Offset by amount * @param int $page Offset by amount
* @param string $sort Sort
* @param string $target Collection or view name * @param string $target Collection or view name
* @param string $return Data for return
* @param array $binds Binds for query * @param array $binds Binds for query
* @param array $errors Errors registry * @param array $errors Errors registry
* *
@ -51,7 +49,6 @@ final class registry extends core
int $page = 1, int $page = 1,
string $sort = 'account.created DESC, account._key DESC', string $sort = 'account.created DESC, account._key DESC',
string $target = account::COLLECTION, string $target = account::COLLECTION,
string $return = '{account, worker}',
array $binds = [], array $binds = [],
array &$errors = [] array &$errors = []
): array { ): array {
@ -72,15 +69,14 @@ final class registry extends core
%s %s
SORT %s SORT %s
LIMIT %d, %d LIMIT %d, %d
RETURN %s RETURN {account, worker}
AQL, AQL,
$target, $target,
$before, $before,
$after, $after,
$sort, $sort,
--$page <= 0 ? 0 : $amount * $page, --$page <= 0 ? 0 : $amount * $page,
$amount, $amount
$return
), $binds); ), $binds);
// Exit (success) // Exit (success)
@ -108,7 +104,6 @@ final class registry extends core
* @param int $amount Amount of markets * @param int $amount Amount of markets
* @param int $page Offset by amount * @param int $page Offset by amount
* @param string $target Collection or view name * @param string $target Collection or view name
* @param string $return Data for return
* @param array $binds Binds for query * @param array $binds Binds for query
* @param array $errors Errors registry * @param array $errors Errors registry
* *
@ -121,7 +116,6 @@ final class registry extends core
int $page = 1, int $page = 1,
string $sort = 'account.created DESC, account._key DESC', string $sort = 'account.created DESC, account._key DESC',
string $target = account::COLLECTION, string $target = account::COLLECTION,
string $return = '{account, market}',
array $binds = [], array $binds = [],
array &$errors = [] array &$errors = []
): array { ): array {
@ -142,15 +136,14 @@ final class registry extends core
%s %s
SORT %s SORT %s
LIMIT %d, %d LIMIT %d, %d
RETURN %s RETURN {account, market}
AQL, AQL,
$target, $target,
$before, $before,
$after, $after,
$sort, $sort,
--$page <= 0 ? 0 : $amount * $page, --$page <= 0 ? 0 : $amount * $page,
$amount, $amount
$return
), $binds); ), $binds);
// Exit (success) // Exit (success)
@ -174,11 +167,9 @@ final class registry extends core
* Generate operators list * Generate operators list
* *
* @param ?string $before Injection of AQL-code before search of edges * @param ?string $before Injection of AQL-code before search of edges
* @param ?string $after Injection of AQL-code after search of edges
* @param int $amount Amount of operators * @param int $amount Amount of operators
* @param int $page Offset by amount * @param int $page Offset by amount
* @param string $target Collection or view name * @param string $target Collection or view name
* @param string $return Data for return
* @param array $binds Binds for query * @param array $binds Binds for query
* @param array $errors Errors registry * @param array $errors Errors registry
* *
@ -186,12 +177,10 @@ final class registry extends core
*/ */
public static function operators( public static function operators(
?string $before = '', ?string $before = '',
?string $after = '',
int $amount = 100, int $amount = 100,
int $page = 1, int $page = 1,
string $sort = 'account.created DESC, account._key DESC', string $sort = 'account.created DESC, account._key DESC',
string $target = account::COLLECTION, string $target = account::COLLECTION,
string $return = '{account}',
array $binds = [], array $binds = [],
array &$errors = [] array &$errors = []
): array { ): array {
@ -203,19 +192,16 @@ final class registry extends core
$operators = collection::search(static::$arangodb->session, sprintf( $operators = collection::search(static::$arangodb->session, sprintf(
<<<AQL <<<AQL
FOR account IN %s FOR account IN %s
%s
%s %s
SORT %s SORT %s
LIMIT %d, %d LIMIT %d, %d
RETURN %s RETURN {account}
AQL, AQL,
$target, $target,
$before, $before,
$after,
$sort, $sort,
--$page <= 0 ? 0 : $amount * $page, --$page <= 0 ? 0 : $amount * $page,
$amount, $amount
$return
), $binds); ), $binds);
// Exit (success) // Exit (success)
@ -239,11 +225,9 @@ final class registry extends core
* Generate administrators list * Generate administrators list
* *
* @param ?string $before Injection of AQL-code before search of edges * @param ?string $before Injection of AQL-code before search of edges
* @param ?string $after Injection of AQL-code after search of edges
* @param int $amount Amount of administrators * @param int $amount Amount of administrators
* @param int $page Offset by amount * @param int $page Offset by amount
* @param string $target Collection or view name * @param string $target Collection or view name
* @param string $return Data for return
* @param array $binds Binds for query * @param array $binds Binds for query
* @param array $errors Errors registry * @param array $errors Errors registry
* *
@ -251,12 +235,10 @@ final class registry extends core
*/ */
public static function administrators( public static function administrators(
?string $before = '', ?string $before = '',
?string $after = '',
int $amount = 100, int $amount = 100,
int $page = 1, int $page = 1,
string $sort = 'account.created DESC, account._key DESC', string $sort = 'account.created DESC, account._key DESC',
string $target = account::COLLECTION, string $target = account::COLLECTION,
string $return = '{account}',
array $binds = [], array $binds = [],
array &$errors = [] array &$errors = []
): array { ): array {
@ -268,19 +250,16 @@ final class registry extends core
$administrators = collection::search(static::$arangodb->session, sprintf( $administrators = collection::search(static::$arangodb->session, sprintf(
<<<AQL <<<AQL
FOR account IN %s FOR account IN %s
%s
%s %s
SORT %s SORT %s
LIMIT %d, %d LIMIT %d, %d
RETURN %s RETURN {account}
AQL, AQL,
$target, $target,
$before, $before,
$after,
$sort, $sort,
--$page <= 0 ? 0 : $amount * $page, --$page <= 0 ? 0 : $amount * $page,
$amount, $amount
$return
), $binds); ), $binds);
// Exit (success) // Exit (success)
@ -294,6 +273,7 @@ final class registry extends core
'line' => $e->getLine(), 'line' => $e->getLine(),
'stack' => $e->getTrace() 'stack' => $e->getTrace()
]; ];
var_dump($errors);
} }
// Exit (fail) // Exit (fail)

View File

@ -164,12 +164,67 @@ final class session extends core
// Закрыть сессию // Закрыть сессию
} }
/**
* Инициализировать связь сессии с аккаунтом
*
* Ищет связь сессии с аккаунтом, если не находит, то создаёт её
*
* @param account $account Инстанция аккаунта
* @param array &$errors Реестр ошибок
*
* @return bool Связана сессия с аккаунтом?
*/
public static function connect(string $session, string $account, array &$errors = []): bool
{
try {
if (
collection::init(static::$arangodb->session, self::COLLECTION)
&& collection::init(static::$arangodb->session, account::COLLECTION)
&& collection::init(static::$arangodb->session, self::COLLECTION . '_edge_' . account::COLLECTION, true)
) {
// Инициализированы коллекции
if (
collection::search(static::$arangodb->session, sprintf(
<<<AQL
FOR document IN %s
FILTER document._from == '%s' && document._to == '%s'
LIMIT 1
RETURN document
AQL,
self::COLLECTION . '_edge_' . account::COLLECTION,
$session,
$account
)) instanceof _document
|| document::write(static::$arangodb->session, self::COLLECTION . '_edge_' . account::COLLECTION, [
'_from' => $session,
'_to' => $account
])
) {
// Найдено, либо создано ребро: session -> account
return true;
} else throw new exception('Не удалось создать ребро: session -> account');
} else throw new exception('Не удалось инициализировать коллекции');
} catch (exception $e) {
// Запись в реестр ошибок
$errors[] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
return false;
}
/** /**
* Найти связанный аккаунт * Найти связанный аккаунт
* *
* @param array &$errors Реестр ошибок * @param array &$errors Реестр ошибок
* *
* @return account|null Инстанция аккаунта, если удалось найти * @return ?account Инстанция аккаунта, если удалось найти
*/ */
public function account(array &$errors = []): ?account public function account(array &$errors = []): ?account
{ {
@ -218,7 +273,6 @@ final class session extends core
]; ];
} }
// Возврат (провал)
return null; return null;
} }

View File

@ -1,111 +0,0 @@
<?php
declare(strict_types=1);
namespace mirzaev\ebala\models;
// Project files
use mirzaev\ebala\models\traits\instance,
mirzaev\ebala\models\traits\status,
mirzaev\ebala\models\account,
mirzaev\ebala\models\worker,
mirzaev\ebala\models\market;
// Библиотека для ArangoDB
use ArangoDBClient\Document as _document;
// Фреймворк ArangoDB
use mirzaev\arangodb\collection,
mirzaev\arangodb\document;
// Встроенные библиотеки
use exception;
/**
* Модель настроек
*
* Управляет записью и чтением настроек сайта из ArangoDB
*
* @package mirzaev\ebala\models
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
final class settings extends core
{
use instance, status;
/**
* Collection name in ArangoDB
*/
final public const COLLECTION = 'settings';
/**
* Инстанция документа в базе данных
*/
protected readonly _document $document;
/**
* Read (search)
*
* @param ?string $before Injection of AQL-code before search of edges
* @param int $amount Amount of administrators
* @param int $page Offset by amount
* @param string $target Collection or view name
* @param array $binds Binds for query
* @param array $errors Errors registry
*
* @return array Instances from ArangoDB
*/
public static function search(
?string $before = '',
int $amount = 1000,
int $page = 1,
string $sort = 'setting.category ASC, setting.city ASC, setting.work ASC, setting.rating DESC, setting.created DESC, setting._key DESC',
string $target = settings::COLLECTION,
array $binds = [],
array &$errors = []
): array {
try {
if (collection::init(static::$arangodb->session, settings::COLLECTION)) {
// Инициализирована коллекция
// Search the session data in ArangoDB
$settings = collection::search(static::$arangodb->session, sprintf(
<<<AQL
FOR setting IN %s
%s
SORT %s
LIMIT %d, %d
LET d = setting.category
COLLECT x = setting.category INTO groups
RETURN { [x]: groups[*]['setting'] }
AQL,
$target,
$before,
$sort,
--$page <= 0 ? 0 : $amount * $page,
$amount
), $binds);
// Универсализация значений
$buffer = [];
foreach (is_array($settings) ? $settings : [$settings] as $setting) foreach ($setting->getAll() ?? [] as $category => $data) $buffer[$category] = $data;
$settings = $buffer;
// Exit (success)
return $settings;
} else throw new exception('Не удалось инициализировать коллекции');
} catch (exception $e) {
// Write to the errors registry
$errors[] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
var_dump($errors);
}
// Exit (fail)
return [];
}
}

View File

@ -1,164 +0,0 @@
<?php
declare(strict_types=1);
namespace mirzaev\ebala\models;
// Project files
use mirzaev\ebala\models\traits\instance,
mirzaev\ebala\models\traits\status,
mirzaev\ebala\models\account,
mirzaev\ebala\models\worker,
mirzaev\ebala\models\market;
// Библиотека для ArangoDB
use ArangoDBClient\Document as _document;
// Фреймворк ArangoDB
use mirzaev\arangodb\collection,
mirzaev\arangodb\document;
// Встроенные библиотеки
use exception;
/**
* Модель сокета
*
* Управляет записью и чтением настроек сайта из ArangoDB
*
* @package mirzaev\ebala\models
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
final class socket extends core
{
use instance, status;
/**
* Collection name in ArangoDB
*/
final public const COLLECTION = 'socket';
/**
* Инстанция документа в базе данных
*/
protected readonly _document $document;
/**
* Подключение к сессии
*
* @param string $session Идентификатор сессии
* @param string $key Ключ для регистрации (из документа в static::COLLECTION)
* @param array &$errors Реестр ошибок
*
* @return bool Сокет подключен к сессии?
*/
public static function session(string $session, string $key, array &$errors = []): bool
{
try {
if (
collection::init(static::$arangodb->session, self::COLLECTION)
&& collection::init(static::$arangodb->session, session::COLLECTION)
&& collection::init(static::$arangodb->session, $edge = session::COLLECTION . '_edge_' . self::COLLECTION, true)
) {
// Инициализирована коллекция
// Чтение сокета
$socket = self::read(
filter: "d.key == \"$key\" && d.expires > DATE_NOW() / 1000",
sort: 'd.created desc, d.expires desc',
amount: 1,
);
if ($socket instanceof _document) {
// Найден сокет
if (document::write(static::$arangodb->session, $edge, [
'_from' => $session,
'_to' => $socket->getId()
])) {
// Записано ребро: СЕССИЯ -> СОКЕТ
// Возврат (успех)
return true;
} else throw new exception('Не удалось записать изменения в базу данных');
} else throw new exception('Не удалось найти сокет');
} else throw new exception('Не удалось инициализировать коллекции');
} catch (exception $e) {
// Write to the errors registry
$errors['socket'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
// Возврат (провал)
return false;
}
/**
* Найти аккаунт
*
* Ищет аккаунт по идентификатору подключения к сокету
*
* @param int $socket Идентификатор подключения к сокету (во внутренней базе данных OpenSwoole)
* @param array &$errors Реестр ошибок
*
* @returnaccount|null Аккаунт, если найден
*/
public static function account(int $socket, array &$errors = []): ?account
{
try {
if (
collection::init(static::$arangodb->session, self::COLLECTION)
&& collection::init(static::$arangodb->session, session::COLLECTION)
&& collection::init(static::$arangodb->session, account::COLLECTION)
&& collection::init(static::$arangodb->session, session::COLLECTION . '_edge_' . self::COLLECTION, true)
&& collection::init(static::$arangodb->session, session::COLLECTION . '_edge_' . account::COLLECTION, true)
) {
// Инициализированы коллекции
// Инициализация инстанции аккаунта
$account = new account;
// Поиск инстанции аккаунта в базе данных
$instance = $account->instance(collection::search(static::$arangodb->session, sprintf(
<<<AQL
FOR a IN 1 OUTBOUND
(FOR s IN 1 INBOUND
(FOR s IN %s
FILTER s.id == %s && s.expires > DATE_NOW() / 1000
SORT s.created desc, s.expires desc
LIMIT 1
RETURN s
)[0]._id
%s
RETURN s
)[0]._id
%s
RETURN a
AQL,
socket::COLLECTION,
$socket,
session::COLLECTION . '_edge_' . socket::COLLECTION,
session::COLLECTION . '_edge_' . account::COLLECTION,
)));
// Возврат (успех)
return $instance instanceof _document ? $account : throw new exception('Не удалось найти инстанцию аккаунта в базе данных');
} else throw new exception('Не удалось инициализировать коллекцию');
} catch (exception $e) {
// Запись в реестр ошибок
$errors['socket'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
// Возврат (провал)
return null;
}
}

View File

@ -118,7 +118,6 @@ final class task extends core
* @param int $amount Amount of tasks * @param int $amount Amount of tasks
* @param int $page Offset by amount * @param int $page Offset by amount
* @param string $target Collection or view name * @param string $target Collection or view name
* @param string $return Data for return
* @param array $binds Binds for query * @param array $binds Binds for query
* @param array $errors Errors registry * @param array $errors Errors registry
* *
@ -134,7 +133,6 @@ final class task extends core
int $page = 1, int $page = 1,
string $sort = 'task.date DESC, task.created DESC, task._key DESC', string $sort = 'task.date DESC, task.created DESC, task._key DESC',
string $target = self::COLLECTION, string $target = self::COLLECTION,
string $return = '{task, worker, market}',
array $binds = [], array $binds = [],
array &$errors = [] array &$errors = []
): array { ): array {
@ -156,7 +154,7 @@ final class task extends core
%s %s
SORT %s SORT %s
LIMIT %d, %d LIMIT %d, %d
RETURN %s RETURN {task, worker, market}
AQL, AQL,
$target, $target,
$before, $before,
@ -165,8 +163,7 @@ final class task extends core
$after, $after,
$sort, $sort,
--$page <= 0 ? 0 : $amount * $page, --$page <= 0 ? 0 : $amount * $page,
$amount, $amount
$return
), $binds); ), $binds);
// Exit (success) // Exit (success)
@ -262,7 +259,7 @@ final class task extends core
public static function transaction( public static function transaction(
string $task, string $task,
string $worker, string $worker,
int|float $amount = 0, int $amount = 0,
array &$errors = [] array &$errors = []
): ?string { ): ?string {
try { try {
@ -295,99 +292,4 @@ final class task extends core
return null; return null;
} }
/**
* Block by account
*
* @param int $task (_key)
* @param int $account (_key)
* @param array $errors
*
* @return bool Task is blocked?
*/
public static function block(
int $task,
int $account,
array &$errors = []
): bool {
try {
if (collection::init(static::$arangodb->session, self::COLLECTION)) {
// Инициализирована коллекция
if (($task = static::read('d._key == "' . $task . '"')) instanceof _document) {
// Найдена заявка
if ($task->block === null || $task->block['expires'] < time()) {
// Не заблокирована заявка
// Блокировка
$task->block = ['account' => $account, 'expires' => (int) strtotime('+1 minute')];
// Запись обновления в базу данных и возврат (успех)
return core::update($task);
} else throw new exception('Заявка уже заблокирована: ' . $task->block['account']);
} else throw new exception('Не удалось инициализировать коллекции');
} else throw new exception('Не удалось инициализировать коллекции');
} catch (exception $e) {
// Write to the errors registry
$errors['task'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
// Exit (fail)
return false;
}
/**
* Unblock by account
*
* @param int $task (_key)
* @param int $account (_key)
* @param array $errors
*
* @return bool Task is blocked?
*/
public static function unblock(
int $task,
int $account,
array &$errors = []
): bool {
try {
if (collection::init(static::$arangodb->session, self::COLLECTION)) {
// Инициализирована коллекция
if (($task = static::read('d._key == "' . $task . '"')) instanceof _document) {
// Найдена заявка
if ($task->block !== null) {
// Заблокирована заявка
if ($task->block['account'] === $account || $task->block['expires'] > time()) {
// Аккаунт отменяет свою блокировку или истекло время блокировки
// Разблокировка
$task->block = null;
// Запись обновления в базу данных и возврат (успех)
return core::update($task);
}
} else throw new exception('Заявка не заблокирована');
} else throw new exception('Не удалось инициализировать коллекции');
} else throw new exception('Не удалось инициализировать коллекции');
} catch (exception $e) {
// Write to the errors registry
$errors['task'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
// Exit (fail)
return false;
}
} }

View File

@ -1,35 +0,0 @@
@charset "UTF-8";
#connection {
z-index: 999999;
position: fixed;
bottom: 20px;
left: 20px;
height: 16px;
display: flex;
}
#connection > i#indicator {
width: 16px;
height: 16px;
display: block;
cursor: help;
border-radius: 100%;
}
#connection > small {
margin-left: 7px;
height: 16px;
display: flex;
align-items: center;
font-weight: bold;
color: var(--socket-text);
}
#connection > i#indicator.disconnected:not(.connected) {
background-color: var(--socket-disconnected);
}
#connection > i#indicator.connected:not(.disconnected) {
background-color: var(--socket-connected);
}

0
mirzaev/ebala/system/public/css/fonts/dejavu.css Executable file → Normal file
View File

0
mirzaev/ebala/system/public/css/fonts/fira.css Executable file → Normal file
View File

0
mirzaev/ebala/system/public/css/fonts/hack.css Executable file → Normal file
View File

0
mirzaev/ebala/system/public/css/icons/home.css Executable file → Normal file
View File

View File

0
mirzaev/ebala/system/public/css/icons/smartphone.css Executable file → Normal file
View File

0
mirzaev/ebala/system/public/css/icons/timer.css Executable file → Normal file
View File

0
mirzaev/ebala/system/public/css/icons/user.css Executable file → Normal file
View File

0
mirzaev/ebala/system/public/css/icons/work_alt.css Executable file → Normal file
View File

View File

@ -44,12 +44,6 @@ div#popup>section.list>div.row.endless {
height: auto; height: auto;
} }
section.panel.list> :is(form, search).row.menu>label>div:has(>button) {
position: relative;
display: flex;
height: 30px;
}
section.panel.list> :is(form, search).row.menu>label>button { section.panel.list> :is(form, search).row.menu>label>button {
position: relative; position: relative;
display: flex; display: flex;
@ -112,14 +106,13 @@ section.panel.list>div#title>span {
} }
section.panel.list>div.row { section.panel.list>div.row {
--width: calc(100% - 24px);
--gap: 12px; --gap: 12px;
--background: var(--cloud); --background: var(--cloud);
position: relative; position: relative;
left: 0px; left: 0px;
width: calc(100% - 24px);
height: 35px; height: 35px;
display: flex; display: flex;
width: var(--width, calc(100% - 24px));
gap: var(--gap, 12px); gap: var(--gap, 12px);
padding: 0 var(--gap, 12px); padding: 0 var(--gap, 12px);
border-radius: 0px; border-radius: 0px;
@ -139,7 +132,7 @@ section.panel.list>div.row:not(:nth-of-type(1))>span {
-moz-box-shadow: var(--box-shadow); -moz-box-shadow: var(--box-shadow);
} }
section.panel.list>div.row:not(:nth-of-type(1)):not([data-blocked]):is(:hover, :focus) { section.panel.list>div.row:not(:nth-of-type(1)):is(:hover, :focus) {
--padding-left: 24px; --padding-left: 24px;
--padding-right: 24px; --padding-right: 24px;
left: -12px; left: -12px;
@ -282,7 +275,7 @@ section.panel.list>div.row>span.field {
cursor: text; cursor: text;
} }
section.panel.list>div.row:not(:nth-of-type(1)):not([data-blocked])>span:is(.important, .interactive:is(:hover, :focus)) { section.panel.list>div.row:not(:nth-of-type(1))>span:is(.important, .interactive:is(:hover, :focus)) {
--margin: calc(var(--gap) / 2); --margin: calc(var(--gap) / 2);
--border-left: calc(var(--padding-left, var(--margin, 0px)) * -1); --border-left: calc(var(--padding-left, var(--margin, 0px)) * -1);
--border-right: var(--padding-right, var(--margin, 0px)); --border-right: var(--padding-right, var(--margin, 0px));
@ -483,29 +476,3 @@ section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)).fired>span:is
section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)):nth-child(2n + 1).fired>span:is(.important, .interactive:is(:hover, :focus)) { section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)):nth-child(2n + 1).fired>span:is(.important, .interactive:is(:hover, :focus)) {
--background: var(--magma-important-above); --background: var(--magma-important-above);
} }
section.panel.list>div.row[data-blocked] {
margin-left: 8px;
width: calc(var(--width) - 16px);
cursor: progress;
opacity: 70% !important;
}
section.panel.list>div.row[data-blocked]:before {
content: attr(data-blocked) !important;
color: var(--earth-text-important-below);
}
section.panel.list>div.row[data-blocked] * {
pointer-events: none;
}
section.panel.list>div.row:not([data-blocked]):has(+ div.row[data-blocked]) {
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
}
section.panel.list>div.row[data-blocked]+div.row:not([data-blocked]) {
border-top-left-radius: 10px;
border-top-right-radius: 10px;
}

View File

@ -58,8 +58,7 @@ input[type="range"] {
button, button,
input[type="submit"], input[type="submit"],
input[type="range"], input[type="range"] {
input[type="checkbox"] {
cursor: pointer; cursor: pointer;
} }

View File

@ -59,19 +59,3 @@ section#operators.panel.list > div.row > span[data-column="commentary"] {
min-width: unset; min-width: unset;
width: 100%; width: 100%;
} }
section#operators.panel.list>div.row[data-row="operator"]:not(:nth-of-type(1)).transactions {
--background: var(--magma);
}
section#operators.panel.list>div.row[data-row="operator"]:not(:nth-of-type(1)):nth-child(2n + 1).transactions {
--background: var(--magma-above);
}
section#operators.panel.list>div.row[data-row="operator"]:not(:nth-of-type(1)).transactions>span:is(.important, .interactive:is(:hover, :focus)) {
--background: var(--magma-important);
}
section#operators.panel.list>div.row[data-row="operator"]:not(:nth-of-type(1)):nth-child(2n + 1).transactions>span:is(.important, .interactive:is(:hover, :focus)) {
--background: var(--magma-important-above);
}

View File

@ -1,73 +0,0 @@
@charset "UTF-8";
main>section#settings.panel {
z-index: 1000;
width: 800px;
position: relative;
margin-bottom: calc(15vh - 45px);
display: flex;
flex-direction: column;
gap: 60px;
border-radius: 3px;
}
main>section#settings.panel>section.category {
display: flex;
flex-direction: column;
gap: 20px;
padding: 30px 40px;
border-radius: 3px;
background-color: var(--snow);
}
main>section#settings.panel>section.category>div {
padding-bottom: 6px;
display: flex;
flex-direction: column;
}
main>section#settings.panel>section.category>div>div {
margin: 0;
margin-left: 30px;
margin-bottom: 6px;
display: inline-flex;
align-items: center;
}
main>section#settings.panel>section.category>div>div>h2 {
margin: 0;
}
main>section#settings.panel>section.category>div>div>i {
position: relative;
margin-left: auto;
margin-right: 20px;
}
main>section#settings.panel>section.category>div>small {
margin-left: 20px;
width: 100%;
}
main>section#settings.panel>section.category>section.subcategory {
padding: 20px 20px;
display: flex;
flex-direction: column;
gap: 8px;
border-radius: 3px;
background-color: var(--snow-deep);
}
main>section#settings.panel>section.category>section.subcategory>h3 {
margin: 6px 0px 3px 25px;
}
main>section#settings.panel>section.category>section.subcategory>label>input {
width: 90px;
}
main>section#settings.panel>section.category>section.subcategory>p.empty {
text-align: center;
padding: 0 20%;
font-weight: bold;
}

19
mirzaev/ebala/system/public/css/popup.css Executable file → Normal file
View File

@ -141,25 +141,6 @@ div#popup>section.list>section.main>div.column>:is(div, section).row>label>input
text-align: center; text-align: center;
} }
div#popup>section.list>section.main>div.column> :is(div, select).row:has(>label>select[multiple]) {
height: auto;
max-height: 60px;
}
div#popup>section.list>section.main>div.column> :is(div, select).row>label>select[multiple] {
height: auto;
padding: 0px;
border-radius: 3px;
}
div#popup>section.list>section.main>div.column> :is(div, select).row>label>select[multiple]>option {
padding: 5px 10px;
}
/* div#popup>section.list>section.main>div.column> :is(div, select).row>label>select[multiple]>option[selected] {
background-color: var(--background-above-5);
} */
div#popup>section.list>section.main>div.column>:is(div, section).row>label> :is(input, button):only-child { div#popup>section.list>section.main>div.column>:is(div, section).row>label> :is(input, button):only-child {
width: 100%; width: 100%;
} }

View File

@ -167,10 +167,6 @@
--link: #3c76ff; --link: #3c76ff;
--link-hover: #6594ff; --link-hover: #6594ff;
--link-active: #3064dd; --link-active: #3064dd;
--socket-connected: #2be851;
--socket-disconnected: #8e8181;
--socket-text: #b09999;
} }
body { body {

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

Some files were not shown because too many files have changed in this diff Show More