Compare commits
155 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
761db76970 | ||
![]() |
9ebb4385cb | ||
|
1918db868d | ||
|
ec2d478a62 | ||
![]() |
bfb0fbe4de | ||
![]() |
f57d7f6460 | ||
![]() |
2488594d81 | ||
![]() |
ebf21a0642 | ||
![]() |
c41e5d4c1c | ||
![]() |
b3f2ef72da | ||
![]() |
d21c6ce0ed | ||
![]() |
a11a21d1ab | ||
![]() |
c11cac01aa | ||
![]() |
fc38285d06 | ||
![]() |
4fafe85639 | ||
![]() |
3ec9b920d2 | ||
![]() |
33cc3efc7b | ||
![]() |
2c2e830f0a | ||
![]() |
e1fa1c1f5a | ||
![]() |
79773503eb | ||
![]() |
68d26118ab | ||
![]() |
ab97036822 | ||
![]() |
4f80a465bc | ||
![]() |
e8454defc2 | ||
![]() |
bcc60fcd41 | ||
![]() |
675c6cbc39 | ||
![]() |
16ce1ccf59 | ||
![]() |
4da846825b | ||
![]() |
82d6747425 | ||
![]() |
a31214ad6a | ||
![]() |
c5e24d7838 | ||
![]() |
856d4f1995 | ||
![]() |
2f4f38b2aa | ||
![]() |
4683cf51db | ||
![]() |
e941fbd782 | ||
![]() |
24f079f622 | ||
![]() |
4c91c3192a | ||
![]() |
a971aef392 | ||
![]() |
ab3c3b8b05 | ||
![]() |
8fda1af398 | ||
![]() |
953f99245c | ||
![]() |
8abdaf4626 | ||
![]() |
bc98da67ce | ||
![]() |
70d2ae2935 | ||
![]() |
913a67d400 | ||
![]() |
b08f7f7d0a | ||
![]() |
7a4f12aa94 | ||
![]() |
9fb2e4dc90 | ||
![]() |
3f0b342d48 | ||
![]() |
6daa3112b6 | ||
![]() |
8f32df518f | ||
![]() |
29ea6a9a79 | ||
![]() |
1a1392d950 | ||
![]() |
1d06acf2e0 | ||
![]() |
e6944c9b6b | ||
![]() |
2b194457f5 | ||
![]() |
95b5d920b9 | ||
![]() |
53281ee422 | ||
![]() |
a235ed25ac | ||
![]() |
6bab42ac33 | ||
![]() |
f76f15b503 | ||
![]() |
dbd2982115 | ||
![]() |
2a90f36f0c | ||
![]() |
43272d051e | ||
![]() |
7e63c8be97 | ||
![]() |
8c53872955 | ||
![]() |
134ce8f162 | ||
![]() |
a36f62e510 | ||
![]() |
3cb2aa1a15 | ||
![]() |
d9337944b1 | ||
![]() |
fab247b4bc | ||
![]() |
96d9a0307c | ||
![]() |
42d20fd313 | ||
![]() |
57710d8a96 | ||
![]() |
044d80ef3e | ||
![]() |
dc30b8c6bb | ||
![]() |
5e01240938 | ||
![]() |
b7c271141f | ||
![]() |
d087256181 | ||
![]() |
8270eaed11 | ||
![]() |
7647ca69d5 | ||
![]() |
b80b887a11 | ||
![]() |
49ed9bf59e | ||
![]() |
a6d8ee5e59 | ||
![]() |
b2b5b0737c | ||
![]() |
5f3623a258 | ||
![]() |
177de6b3ef | ||
![]() |
b3b5111006 | ||
![]() |
bf821a9819 | ||
![]() |
2ca929e122 | ||
![]() |
26686374f0 | ||
![]() |
d5bb9137f7 | ||
![]() |
fc59eff6db | ||
![]() |
83295650c9 | ||
![]() |
c4035d8ad3 | ||
![]() |
cc1e7e7d66 | ||
![]() |
8c4ca42d3c | ||
![]() |
cb315a9fcf | ||
![]() |
9e120afc24 | ||
![]() |
44ca2e9f92 | ||
![]() |
0fa1c977ca | ||
![]() |
0d654ad790 | ||
![]() |
4f898bf796 | ||
![]() |
21cec0c5b4 | ||
![]() |
fab290eacd | ||
![]() |
4f8a99d8e2 | ||
![]() |
248f5470f9 | ||
![]() |
7e5f39c8e9 | ||
![]() |
5d9228ec1b | ||
![]() |
3cf9f24a20 | ||
![]() |
03b52d071d | ||
![]() |
3ea7a9e1eb | ||
![]() |
85e3d5f1bd | ||
![]() |
0a8c74a9a3 | ||
![]() |
ada91bd0b7 | ||
![]() |
7865cac5d4 | ||
![]() |
d4bc3e2263 | ||
![]() |
fe0453f91b | ||
![]() |
a11a5da2e1 | ||
![]() |
b44194d5a3 | ||
![]() |
874d5c3f55 | ||
![]() |
b50049eb67 | ||
![]() |
c169347687 | ||
![]() |
912b25bea2 | ||
![]() |
7ca19da826 | ||
![]() |
4c61ccbb65 | ||
![]() |
a9259eb7dc | ||
![]() |
6dc1b081f9 | ||
![]() |
3fea918255 | ||
![]() |
722bf6c378 | ||
![]() |
8cbe77e354 | ||
![]() |
b71f6e8efc | ||
![]() |
1fac5cdfc1 | ||
![]() |
081a34a8f4 | ||
![]() |
53d7e2a048 | ||
![]() |
b8c1f7cef0 | ||
![]() |
b91ef68091 | ||
![]() |
301b2945bc | ||
![]() |
78ae20cdac | ||
![]() |
65c2e19e55 | ||
![]() |
c9e3b542b7 | ||
![]() |
8a3897ad8f | ||
![]() |
0f8e6a7a6a | ||
![]() |
6a7f8897d5 | ||
![]() |
706c9b0743 | ||
![]() |
25709ee380 | ||
![]() |
5d18c95dc4 | ||
![]() |
aaec25f64c | ||
![]() |
9887be35f9 | ||
![]() |
c2afcfcc5a | ||
![]() |
212694c917 | ||
![]() |
94b719b67e | ||
![]() |
ac48e8e064 | ||
![]() |
d8a1284cc5 | ||
![]() |
fbd64ecb96 |
|
@ -1,2 +1,3 @@
|
|||
vendor/
|
||||
cache/
|
||||
/vendor
|
||||
/cache
|
||||
/.vscode
|
|
@ -8,41 +8,39 @@
|
|||
{
|
||||
"name": "Arsen Mirzaev Tatyano-Muradovich",
|
||||
"email": "red@hood.su",
|
||||
"homepage": "https://hood.su/mirzaev",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.4.0",
|
||||
"twbs/bootstrap": ">=4.5",
|
||||
"yiisoft/yii2": ">=2.0.14",
|
||||
"php": "^8.1.0",
|
||||
"ext-intl": "~8.0",
|
||||
"twbs/bootstrap": "4.6.0",
|
||||
"yiisoft/yii2": "2.*",
|
||||
"yiisoft/yii2-bootstrap": ">=2.0.0",
|
||||
"yiisoft/yii2-swiftmailer": ">=2.0.0",
|
||||
"bower-asset/bootstrap": "*",
|
||||
"npm-asset/jquery": "^3.5",
|
||||
"bower-asset/jquery": "^3.5",
|
||||
"explosivebit/arangodb": "^2.0",
|
||||
"triagens/arangodb": "^3.6"
|
||||
"triagens/arangodb": "^3.6",
|
||||
"moonlandsoft/yii2-phpexcel": ">=2.0",
|
||||
"carono/yii2-1c-exchange": "^0.3.1",
|
||||
"yiisoft/yii2-imagine": "*",
|
||||
"mirzaev/yii2-arangodb": ">=2.1.x-dev",
|
||||
"mirzaev/yii2-arangodb-sessions": ">=1.1.x-dev",
|
||||
"guzzlehttp/guzzle": "^7.3",
|
||||
"phpoffice/phpspreadsheet": "^1.18",
|
||||
"hflabs/dadata": "^20.12"
|
||||
},
|
||||
"require-dev": {
|
||||
"codeception/codeception": ">=4.1",
|
||||
"codeception/module-webdriver": ">=1.0.0",
|
||||
"yiisoft/yii2-debug": ">=2.1.0",
|
||||
"yiisoft/yii2-gii": ">=2.1.0",
|
||||
"yiisoft/yii2-faker": ">=2.0.0",
|
||||
"codeception/verify": ">=1.1.0",
|
||||
"codeception/specify": ">=0.4.6",
|
||||
"symfony/browser-kit": ">=2.7",
|
||||
"codeception/module-filesystem": ">=1.0.0",
|
||||
"codeception/module-yii2": ">=1.0.0",
|
||||
"codeception/module-asserts": ">=1.0.0"
|
||||
"yiisoft/yii2-faker": ">=2.0.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"mirzaev\\skillparts\\": "mirzaev/skillparts/system"
|
||||
},
|
||||
"classmap": [
|
||||
"vendor/explosivebit"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
|
@ -85,18 +83,6 @@
|
|||
{
|
||||
"type": "composer",
|
||||
"url": "https://asset-packagist.org"
|
||||
},
|
||||
{
|
||||
"type": "package",
|
||||
"package": {
|
||||
"name": "explosivebit/arangodb",
|
||||
"version": "2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pBazsi/yii2-arangodb.git",
|
||||
"reference": "master"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,3 @@
|
|||
/import/*
|
||||
/invoices/*
|
||||
/accounts/*
|
|
@ -1,21 +1,10 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace app\assets;
|
||||
|
||||
use yii;
|
||||
use yii\web\AssetBundle;
|
||||
|
||||
/**
|
||||
* Main application asset bundle.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class AppAsset extends AssetBundle
|
||||
{
|
||||
public $basePath = '@webroot';
|
||||
|
@ -25,23 +14,35 @@ class AppAsset extends AssetBundle
|
|||
'css/bootstrap/bootstrap.min.css',
|
||||
'css/main.css',
|
||||
'css/header.css',
|
||||
'css/notification.css',
|
||||
'css/info_panel.css',
|
||||
'css/categories_blocks_panel.css',
|
||||
'css/ticker.css',
|
||||
'css/footer.css'
|
||||
];
|
||||
public $js = [
|
||||
'https://kit.fontawesome.com/d7e922c226.js',
|
||||
'https://code.jquery.com/jquery-3.5.1.min.js',
|
||||
'js/bootstrap/popper.min.js',
|
||||
'js/bootstrap/bootstrap.min.js',
|
||||
'https://cdn.jsdelivr.net/bxslider/4.1.1/jquery.bxslider.min.js',
|
||||
'https://unpkg.com/cookielib/src/cookie.min.js',
|
||||
'https://api-maps.yandex.ru/2.1/?apikey=ff21ed7c-2d34-4f91-8d7f-2144ec3e4397&lang=ru_RU',
|
||||
'js/moment.min.js',
|
||||
'js/menu.js',
|
||||
'js/main.js',
|
||||
'js/account.js',
|
||||
'js/ticker.js',
|
||||
'js/reinitialization.js'
|
||||
'js/search.js',
|
||||
'js/notification.js',
|
||||
'js/reinitialization.js',
|
||||
'js/yandex/metrika.js',
|
||||
'js/yandex/geolocation.js',
|
||||
'https://www.googletagmanager.com/gtag/js?id=G-6XYKBJJWR4',
|
||||
'js/google/analytics.js'
|
||||
];
|
||||
public $jsOptions = [
|
||||
// 'position' => View::POS_HEAD
|
||||
];
|
||||
public $depends = [
|
||||
'yii\web\YiiAsset',
|
||||
'yii\web\YiiAsset'
|
||||
// 'yii\bootstrap\BootstrapAsset'
|
||||
];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace app\commands;
|
||||
|
||||
use yii\console\Controller;
|
||||
use yii\console\ExitCode;
|
||||
|
||||
use app\models\Account;
|
||||
|
||||
class AccountController extends Controller
|
||||
{
|
||||
/**
|
||||
* Сгенерировать уникальные идентификаторы
|
||||
*
|
||||
* @param int|string $_key Ключ аккаунта (оставить пустым или отправить "all", если для всех)
|
||||
* @param bool $init Параметр обозначающий изменение только для тех у кого ранее идентификатор задан не был (без перезаписи)
|
||||
*/
|
||||
public function actionGenerateIndex(int|string $_key = null, bool $init = true)
|
||||
{
|
||||
// Инициализация
|
||||
$accounts = empty($_key) || strcasecmp($_key, 'all') === 0 ? Account::readAll() : [Account::searchById($_key)];
|
||||
|
||||
// Генерация
|
||||
$amount = Account::generateIndexes($accounts, $init);
|
||||
|
||||
echo 'Обработано аккаунтов: ' . $amount;
|
||||
|
||||
if ($amount > 0) {
|
||||
// Был успешно обработан минимум 1 аккаунт
|
||||
|
||||
return ExitCode::OK;
|
||||
}
|
||||
|
||||
return ExitCode::UNSPECIFIED_ERROR;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace app\commands;
|
||||
|
||||
use yii\console\Controller;
|
||||
use yii\console\ExitCode;
|
||||
|
||||
use app\models\connection\Dellin;
|
||||
|
||||
class DellinController extends Controller
|
||||
{
|
||||
/**
|
||||
* Импортировать города из ДеловыеЛинии
|
||||
*/
|
||||
public function actionImportCities()
|
||||
{
|
||||
if (Dellin::importCities()) {
|
||||
return ExitCode::OK;
|
||||
}
|
||||
|
||||
return ExitCode::UNSPECIFIED_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Импортировать терминалы из ДеловыеЛинии
|
||||
*/
|
||||
public function actionImportTerminals(?int $account = null)
|
||||
{
|
||||
if (Dellin::importTerminals($account)) {
|
||||
return ExitCode::OK;
|
||||
}
|
||||
|
||||
return ExitCode::UNSPECIFIED_ERROR;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
namespace app\commands;
|
||||
|
||||
use yii\console\Controller;
|
||||
use yii\console\ExitCode;
|
||||
|
||||
use moonland\phpexcel\Excel;
|
||||
|
||||
use app\models\Supply;
|
||||
use app\models\File;
|
||||
|
||||
class ImportController extends Controller
|
||||
{
|
||||
/**
|
||||
* Импортировать города из ДеловыеЛинии
|
||||
*/
|
||||
public function actionCities()
|
||||
{
|
||||
if (Dellin::importCities()) {
|
||||
return ExitCode::OK;
|
||||
}
|
||||
|
||||
return ExitCode::UNSPECIFIED_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Импортировать терминалы из ДеловыеЛинии
|
||||
*/
|
||||
public function actionTerminals()
|
||||
{
|
||||
if (Dellin::importTerminals()) {
|
||||
return ExitCode::OK;
|
||||
}
|
||||
|
||||
return ExitCode::UNSPECIFIED_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Импортировать поставки из файлов
|
||||
*/
|
||||
public function actionSupplies(int $amount = 3)
|
||||
{
|
||||
try {
|
||||
$files = File::searchSuppliesNeededToLoad($amount);
|
||||
|
||||
if ($files > 0) {
|
||||
// Найдены файлы
|
||||
|
||||
foreach ($files as $file) {
|
||||
// Перебор файлов для загрузки
|
||||
|
||||
// Загрузка в базу данных
|
||||
Supply::loadExcel($file);
|
||||
}
|
||||
}
|
||||
} catch (exception $e) {
|
||||
return ExitCode::UNSPECIFIED_ERROR;
|
||||
}
|
||||
|
||||
return ExitCode::OK;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace app\commands;
|
||||
|
||||
use yii\console\Controller;
|
||||
use yii\console\ExitCode;
|
||||
|
||||
use app\models\Supply;
|
||||
use app\models\File;
|
||||
|
||||
class SuppliesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Импортировать города из ДеловыеЛинии
|
||||
*/
|
||||
public function actionImport(int $amount = 3)
|
||||
{
|
||||
if (Dellin::importCities($amount)) {
|
||||
return ExitCode::OK;
|
||||
}
|
||||
|
||||
return ExitCode::UNSPECIFIED_ERROR;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
|
||||
namespace app\commands;
|
||||
|
||||
use yii\console\Controller;
|
||||
use yii\console\ExitCode;
|
||||
|
||||
use app\models\Invoice;
|
||||
use app\models\Product;
|
||||
use app\models\ProductGroup;
|
||||
use app\models\ImportEdgeSupply;
|
||||
|
||||
class TestController extends Controller
|
||||
{
|
||||
public function actionInvoice($buyer = 123123, $order = 0)
|
||||
{
|
||||
// Генерация счета
|
||||
Invoice::generate($order, $this->renderPartial('/invoice/order/pattern', [
|
||||
'buyer' => [
|
||||
'id' => $buyer,
|
||||
'info' => 'Неизвестно'
|
||||
],
|
||||
'order' => [
|
||||
'id' => $order,
|
||||
'date' => time(),
|
||||
'entries' => [
|
||||
[
|
||||
'title' => 'Тестовое вхождение',
|
||||
'amount' => [
|
||||
'value' => 1,
|
||||
'unit' => 'шт'
|
||||
],
|
||||
'cost' => [
|
||||
'value' => 1000,
|
||||
'unit' => 'руб'
|
||||
],
|
||||
'type' => 'supply'
|
||||
],
|
||||
[
|
||||
'title' => 'Тестовое вхождение',
|
||||
'amount' => [
|
||||
'value' => 1,
|
||||
'unit' => 'шт'
|
||||
],
|
||||
'cost' => [
|
||||
'value' => 1000,
|
||||
'unit' => 'руб'
|
||||
],
|
||||
'type' => 'supply'
|
||||
],
|
||||
[
|
||||
'title' => 'Тестовое вхождение',
|
||||
'amount' => [
|
||||
'value' => 1,
|
||||
'unit' => 'шт'
|
||||
],
|
||||
'cost' => [
|
||||
'value' => 1000,
|
||||
'unit' => 'руб'
|
||||
],
|
||||
'type' => 'supply'
|
||||
],
|
||||
[
|
||||
'title' => 'Тестовое вхождение',
|
||||
'amount' => [
|
||||
'value' => 5,
|
||||
'unit' => 'шт'
|
||||
],
|
||||
'cost' => [
|
||||
'value' => 1000,
|
||||
'unit' => 'руб'
|
||||
],
|
||||
'type' => 'supply'
|
||||
]
|
||||
]
|
||||
]
|
||||
]));
|
||||
|
||||
return ExitCode::OK;
|
||||
}
|
||||
|
||||
|
||||
public function actionAnalogs($_id = 'product/51987159')
|
||||
{
|
||||
|
||||
|
||||
return ExitCode::OK;
|
||||
}
|
||||
|
||||
public function actionWriteAnalog($_id = 'product/51987159', $analog = 'product/12051485')
|
||||
{
|
||||
// Инициализация товара
|
||||
$product = Product::searchById($_id);
|
||||
|
||||
// Инициализация аналога
|
||||
$analog = Product::searchById($analog);
|
||||
|
||||
if (!$group = ProductGroup::searchByProduct($product)) {
|
||||
// Не найдена группа товаров
|
||||
|
||||
// Запись новой группы
|
||||
$group = ProductGroup::writeEmpty(active: true);
|
||||
|
||||
// Запись товара в группу
|
||||
$group->writeProduct($product);
|
||||
}
|
||||
|
||||
if ($_group = ProductGroup::searchByProduct($analog)) {
|
||||
// Найдена друга группа у товара который надо добавить в группу
|
||||
|
||||
// Перенос всех участников (включая целевой товар)
|
||||
return $group->transfer($_group);
|
||||
} else {
|
||||
// Не найдена группа у товара который надо добавить в группу
|
||||
|
||||
// Запись целевого товара в группу
|
||||
return $group->writeProduct($analog);
|
||||
}
|
||||
|
||||
return ExitCode::OK;
|
||||
}
|
||||
|
||||
public function actionReadAnalog($_id = 'product/51987159')
|
||||
{
|
||||
var_dump((ProductGroup::searchByProduct(Product::searchById($_id))->searchProducts()));
|
||||
|
||||
return ExitCode::OK;
|
||||
}
|
||||
|
||||
public function actionEdgeMax()
|
||||
{
|
||||
var_dump(ImportEdgeSupply::generateVersion());
|
||||
|
||||
return ExitCode::OK;
|
||||
}
|
||||
}
|
|
@ -1,15 +1,16 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
$config = [
|
||||
'id' => 'basic-console',
|
||||
'id' => 'skillparts-console',
|
||||
'basePath' => dirname(__DIR__),
|
||||
'bootstrap' => ['log'],
|
||||
'controllerNamespace' => 'app\commands',
|
||||
'aliases' => [
|
||||
'@vendor' => dirname(__DIR__) . '../../../../vendor',
|
||||
'@vendor' => dirname(__DIR__) . '/../../../vendor',
|
||||
'@bower' => '@vendor/bower-asset',
|
||||
'@npm' => '@vendor/npm-asset',
|
||||
'@explosivebit' => '@vendor/explosivebit',
|
||||
'@tests' => '@app/tests',
|
||||
],
|
||||
'components' => [
|
||||
|
@ -28,13 +29,14 @@ $config = [
|
|||
],
|
||||
'params' => require __DIR__ . '/params.php',
|
||||
'controllerMap' => [
|
||||
'arangodb-migrate' => 'explosivebit\arangodb\console\controllers\MigrateController',
|
||||
'arangodb-migrate' => 'mirzaev\yii2\arangodb\console\controllers\MigrateController',
|
||||
'fixture' => [
|
||||
'class' => 'yii\faker\FixtureController',
|
||||
],
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
if (YII_ENV_DEV) {
|
||||
// configuration adjustments for 'dev' environment
|
||||
$config['bootstrap'][] = 'gii';
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use ArangoDBClient\ConnectionOptions;
|
||||
|
||||
return [
|
||||
'class' => '\explosivebit\arangodb\Connection',
|
||||
'class' => '\mirzaev\yii2\arangodb\Connection',
|
||||
'connectionOptions' => [
|
||||
ConnectionOptions::OPTION_DATABASE => '',
|
||||
ConnectionOptions::OPTION_ENDPOINT => 'tcp://127.0.0.1:8529',
|
||||
|
|
|
@ -1,7 +1,28 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'adminEmail' => 'admin@example.com',
|
||||
'senderEmail' => 'noreply@example.com',
|
||||
'senderName' => 'Example.com mailer',
|
||||
'captcha' => [
|
||||
'suppliers' => [
|
||||
'public' => null,
|
||||
'secret' => null
|
||||
]
|
||||
],
|
||||
'mail' => [
|
||||
'system' => null,
|
||||
'info' => null
|
||||
],
|
||||
'dellin' => [
|
||||
'nickname' => null,
|
||||
'password' => null,
|
||||
'key' => null
|
||||
],
|
||||
'cdek' => [
|
||||
'nickname' => null,
|
||||
'password' => null,
|
||||
'key' => null
|
||||
],
|
||||
'dadata' => [
|
||||
'key' => null,
|
||||
'secret' => null
|
||||
]
|
||||
];
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Application configuration shared by all test types
|
||||
*/
|
||||
return [
|
||||
'id' => 'basic-tests',
|
||||
'basePath' => dirname(__DIR__),
|
||||
'aliases' => [
|
||||
'@bower' => '@vendor/bower-asset',
|
||||
'@npm' => '@vendor/npm-asset',
|
||||
],
|
||||
'language' => 'en-US',
|
||||
'components' => [
|
||||
'db' => require __DIR__ . '/test_db.php',
|
||||
'mailer' => [
|
||||
'useFileTransport' => true,
|
||||
],
|
||||
'assetManager' => [
|
||||
'basePath' => __DIR__ . '/../web/assets',
|
||||
],
|
||||
'urlManager' => [
|
||||
'showScriptName' => true,
|
||||
],
|
||||
'user' => [
|
||||
'identityClass' => 'app\models\Account',
|
||||
],
|
||||
'request' => [
|
||||
'cookieValidationKey' => 'test',
|
||||
'enableCsrfValidation' => false,
|
||||
// but if you absolutely need it set cookie domain to localhost
|
||||
/*
|
||||
'csrfCookie' => [
|
||||
'domain' => 'localhost',
|
||||
],
|
||||
*/
|
||||
],
|
||||
],
|
||||
'params' => require __DIR__ . '/params.php',
|
||||
];
|
|
@ -1,6 +0,0 @@
|
|||
<?php
|
||||
$db = require __DIR__ . '/db.php';
|
||||
// test database! Important not to run tests on production or development databases
|
||||
$db['dsn'] = 'mysql:host=localhost;dbname=yii2basic_test';
|
||||
|
||||
return $db;
|
|
@ -1,14 +1,14 @@
|
|||
<?php
|
||||
|
||||
$config = [
|
||||
'id' => 'basic',
|
||||
'id' => 'skillparts',
|
||||
'basePath' => dirname(__DIR__),
|
||||
'bootstrap' => ['log'],
|
||||
'defaultRoute' => 'main',
|
||||
'aliases' => [
|
||||
'@vendor' => dirname(__DIR__) . '/../../../vendor',
|
||||
'@bower' => '@vendor/bower-asset',
|
||||
'@npm' => '@vendor/npm-asset',
|
||||
'@explosivebit' => '@vendor/explosivebit',
|
||||
'@npm' => '@vendor/npm-asset'
|
||||
],
|
||||
'components' => [
|
||||
'request' => [
|
||||
|
@ -21,23 +21,60 @@ $config = [
|
|||
],
|
||||
'user' => [
|
||||
'identityClass' => 'app\models\Account',
|
||||
'enableAutoLogin' => true,
|
||||
'loginUrl' => ['/authentication'],
|
||||
// 'enableAutoLogin' => true,
|
||||
'enableSession' => true
|
||||
],
|
||||
// 'session' => [
|
||||
// 'class' => 'yii\web\Session',
|
||||
// 'cookieParams' => ['lifetime' => 3600 * 24 * 30 * 12],
|
||||
// 'timeout' => 3600 * 24 * 30 * 12,
|
||||
// 'useCookies' => true,
|
||||
// 'authManager' => [
|
||||
// 'class' => 'mirzaev\yii2\arangodb\rbac\DbManager',
|
||||
// ],
|
||||
'errorHandler' => [
|
||||
'errorAction' => 'site/error',
|
||||
'session' => [
|
||||
'class' => 'mirzaev\yii2\arangodb\sessions\ArangoDbSession',
|
||||
'document' => 'session',
|
||||
'cookieParams' => [
|
||||
// 'lifetime' => 3600 * 24 * 30 * 12
|
||||
'lifetime' => 3600 * 24 * 3
|
||||
],
|
||||
'mailer' => [
|
||||
'writeCallback' => function($session): array {
|
||||
// Инициализация
|
||||
$data = [];
|
||||
|
||||
yii::$app->request->userIP and $data['ip'] = yii::$app->request->userIP;
|
||||
Yii::$app->user->id and $data['account'] = Yii::$app->user->id;
|
||||
|
||||
return $data ?? [];
|
||||
},
|
||||
'timeout' => 3600 * 24 * 3,
|
||||
'useStrictMode' => false,
|
||||
'useCookies' => true
|
||||
],
|
||||
'errorHandler' => [
|
||||
'errorAction' => 'error',
|
||||
],
|
||||
'mail_info' => [
|
||||
'class' => 'yii\swiftmailer\Mailer',
|
||||
// send all mails to a file by default. You have to set
|
||||
// 'useFileTransport' to false and configure a transport
|
||||
// for the mailer to send real emails.
|
||||
'useFileTransport' => true,
|
||||
'useFileTransport' => false,
|
||||
'transport' => [
|
||||
'class' => 'Swift_SmtpTransport',
|
||||
'host' => 'smtp.yandex.com',
|
||||
'username' => 'info@skillparts.ru',
|
||||
'password' => 'SkillParts_1337',
|
||||
'port' => '465',
|
||||
'encryption' => 'ssl',
|
||||
|
||||
],
|
||||
],
|
||||
'mail_system' => [
|
||||
'class' => 'yii\swiftmailer\Mailer',
|
||||
'useFileTransport' => false,
|
||||
'transport' => [
|
||||
'class' => 'Swift_SmtpTransport',
|
||||
'host' => 'smtp.yandex.com',
|
||||
'username' => 'system@skillparts.ru',
|
||||
'password' => 'System01001010Null',
|
||||
'port' => '465',
|
||||
'encryption' => 'ssl',
|
||||
],
|
||||
],
|
||||
'log' => [
|
||||
'traceLevel' => YII_DEBUG ? 3 : 0,
|
||||
|
@ -53,13 +90,174 @@ $config = [
|
|||
'enablePrettyUrl' => true,
|
||||
'showScriptName' => false,
|
||||
'rules' => [
|
||||
['class' => 'yii\rest\UrlRule', 'controller' => 'site'],
|
||||
'<action>' => 'site/<action>'
|
||||
[
|
||||
'class' => 'yii\rest\UrlRule',
|
||||
'controller' => 'main'
|
||||
],
|
||||
'<_key:[0-9]+>' => 'account/index',
|
||||
'<_key:[0-9]+>/<target:[^/]+>/<action:(read|edit|delete|regenerate)>' => 'account/<action>',
|
||||
'<_key:[0-9]+>/files/<file:[^/]+>' => 'account/file',
|
||||
'<_key:[0-9]+>/<action:(accept|decline|data)>' => 'account/<action>',
|
||||
'product/<prod:[^/]+>/<catn:[^/]+>' => 'product/index',
|
||||
'product/<prod:[^/]+>/<catn:[^/]+>/<action:(write|delete|connect|disconnect|status)>' => 'product/<action>',
|
||||
'<section:(product|cart)>/<prod:[^/]+>/<catn:[^/]+>/<action:(read|write|edit|delete)>/<target:(title|catn|name|dscr|prod|dmns|wght|image|cover|comm)>' => '<section>/<action>-<target>',
|
||||
'products/<action:(read)>/<stts:[^/]+>/' => 'product/<action>',
|
||||
'profile/geolocation/<action:(init|write)>' => 'profile/geolocation-<action>',
|
||||
'profile/panel/<panel:(suppliers)>/<block:(requests)>/<action:(search)>' => 'profile/panel-<panel>-<block>-<action>',
|
||||
'profile/imports/<action:(delete)>' => 'profile/imports-<action>',
|
||||
'profile/warehouses/<action:(write|delete|rename|close|open)>' => 'profile/warehouses-<action>',
|
||||
'orders' => 'order/index',
|
||||
'orders/<filter:[^/]+>' => 'order/index',
|
||||
'orders/<catn:[^/]+>/<action:(accept)>' => 'order/<action>',
|
||||
'orders/supply/<catn:[^/]+>/<action:(read|write|edit|delete)>' => 'order/supply-<action>',
|
||||
'orders/supply/<catn:[^/]+>/<action:(read|write|edit|delete)>/<target:(stts|cost|time|comm)>' => 'order/supply-<action>-<target>',
|
||||
'invoices/<order:[^/]+>' => 'invoice/index',
|
||||
'invoices/<order:[^/]+>/<action:(download)>' => 'invoice/<action>',
|
||||
'verify/send' => 'verify/send',
|
||||
'verify/<vrfy:[^/]+>' => 'verify/index',
|
||||
'terminals/<action:(read|write)>' => 'terminal/<action>'
|
||||
],
|
||||
],
|
||||
|
||||
],
|
||||
'modules' => [
|
||||
'exchange' => [
|
||||
'class' => 'carono\exchange1c\ExchangeModule',
|
||||
'exchangeDocuments' => true,
|
||||
'validateModelOnSave' => true,
|
||||
'groupClass' => 'app\models\SupplyGroup',
|
||||
'productClass' => 'app\models\Supply',
|
||||
'offerClass' => 'app\models\SupplyEdgeProduct',
|
||||
'partnerClass' => 'app\models\Account',
|
||||
'documentClass' => 'app\models\Order',
|
||||
'auth' => function ($mail, $pswd) {
|
||||
// Необходимо уничтожить AccountForm
|
||||
// return (new \app\models\AccountForm())->authentication($mail, $pswd);
|
||||
|
||||
if ($user = \app\models\Account::findByMail($mail)) {
|
||||
if ($user->validatePassword($pswd)) {
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
]
|
||||
],
|
||||
'params' => require __DIR__ . '/params.php',
|
||||
'on beforeAction' => function ($event) {
|
||||
if (yii::$app->user->isGuest) {
|
||||
// Гость
|
||||
} else {
|
||||
// Пользователь
|
||||
|
||||
// Подтверждение почты
|
||||
if (yii::$app->user->identity->vrfy !== true) {
|
||||
// Почта не подтверждена
|
||||
|
||||
if (!(str_starts_with(yii::$app->request->getPathInfo(), 'verify')
|
||||
|| match (yii::$app->request->getPathInfo()) {
|
||||
'policy', 'notification', 'identification' => true,
|
||||
default => false
|
||||
})) {
|
||||
// Фильтрация страниц
|
||||
|
||||
if (yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
yii::$app->response->statusCode = 401;
|
||||
|
||||
return [
|
||||
'main' => yii::$app->controller->renderPartial('/account/verify'),
|
||||
'redirect' => '/registration',
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
} else {
|
||||
// Подразумевается как GET-запрос
|
||||
|
||||
// Переадресация на страницу указывающую на необходимость подтвердить почту
|
||||
yii::$app->response->redirect('/verify')->send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Согласие с офертой
|
||||
if (
|
||||
!(isset(yii::$app->session['offer_buyer_accepted'])
|
||||
&& yii::$app->session['offer_buyer_accepted'] === true)
|
||||
&& (!isset(yii::$app->user->identity->acpt['buyer'])
|
||||
|| yii::$app->user->identity->acpt['buyer'] === false)
|
||||
) {
|
||||
// Нет подтверждения офферты пользователя
|
||||
|
||||
if (!(str_starts_with(yii::$app->request->getPathInfo(), 'verify')
|
||||
|| str_starts_with(yii::$app->request->getPathInfo(), 'offer')
|
||||
|| match (yii::$app->request->getPathInfo()) {
|
||||
'notification', 'identification' => true,
|
||||
default => false
|
||||
})) {
|
||||
// Фильтрация страниц
|
||||
|
||||
if (yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
yii::$app->response->statusCode = 401;
|
||||
|
||||
return [
|
||||
'main' => yii::$app->controller->renderPartial('/offer/index'),
|
||||
'redirect' => '/registration',
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
} else {
|
||||
// Подразумевается как GET-запрос
|
||||
|
||||
// Переадресация на оферту
|
||||
yii::$app->response->redirect('/offer')->send();
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
(isset(yii::$app->user->identity->agnt)
|
||||
&& yii::$app->user->identity->agnt === true)
|
||||
&& !(isset(yii::$app->session['offer_supplier_accepted'])
|
||||
&& yii::$app->session['offer_supplier_accepted'] === true)
|
||||
&& (!isset(yii::$app->user->identity->acpt['supplier'])
|
||||
|| yii::$app->user->identity->acpt['supplier'] === false)
|
||||
) {
|
||||
// Нет подтверждения офферты поставщика
|
||||
|
||||
if (!(str_starts_with(yii::$app->request->getPathInfo(), 'verify')
|
||||
|| str_starts_with(yii::$app->request->getPathInfo(), 'offer')
|
||||
|| match (yii::$app->request->getPathInfo()) {
|
||||
'notification', 'identification' => true,
|
||||
default => false
|
||||
})) {
|
||||
// Фильтрация страниц
|
||||
|
||||
if (yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
yii::$app->response->statusCode = 401;
|
||||
|
||||
return [
|
||||
'main' => $this->renderPartial('/offer/supplier'),
|
||||
'redirect' => '/registration',
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
} else {
|
||||
// Подразумевается как GET-запрос
|
||||
|
||||
// Переадресация на оферту
|
||||
yii::$app->response->redirect('/offer/suppliers')->send();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
if (YII_ENV_DEV) {
|
||||
|
@ -68,18 +266,9 @@ if (YII_ENV_DEV) {
|
|||
'class' => 'yii\debug\Module',
|
||||
'panels' => [
|
||||
'ArangoDB' => [
|
||||
'class' => 'explosivebit\arangodb\panels\arangodb\ArangoDbPanel'
|
||||
'class' => 'mirzaev\yii2\arangodb\panels\arangodb\ArangoDbPanel'
|
||||
]
|
||||
]
|
||||
],
|
||||
// uncomment the following to add your IP if you are not connecting from localhost.
|
||||
//'allowedIPs' => ['127.0.0.1', '::1'],
|
||||
];
|
||||
|
||||
$config['bootstrap'][] = 'gii';
|
||||
$config['modules']['gii'] = [
|
||||
'class' => 'yii\gii\Module',
|
||||
// uncomment the following to add your IP if you are not connecting from localhost.
|
||||
//'allowedIPs' => ['127.0.0.1', '::1'],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,484 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controllers;
|
||||
|
||||
use yii;
|
||||
use yii\web\Controller;
|
||||
use yii\web\Response;
|
||||
use yii\web\Cookie;
|
||||
use yii\filters\AccessControl;
|
||||
|
||||
use app\models\Account;
|
||||
use app\models\AccountForm;
|
||||
|
||||
class AccountController extends Controller
|
||||
{
|
||||
public function behaviors()
|
||||
{
|
||||
return [
|
||||
'access' => [
|
||||
'class' => AccessControl::class,
|
||||
'rules' => [
|
||||
[
|
||||
'allow' => true,
|
||||
'actions' => [
|
||||
'file',
|
||||
'data',
|
||||
'restore',
|
||||
'generate-password'
|
||||
]
|
||||
],
|
||||
[
|
||||
'allow' => true,
|
||||
'roles' => ['@'],
|
||||
'actions' => [
|
||||
'index',
|
||||
'edit',
|
||||
'regenerate'
|
||||
]
|
||||
],
|
||||
[
|
||||
'allow' => true,
|
||||
'actions' => [
|
||||
'read',
|
||||
'accept',
|
||||
'decline'],
|
||||
'matchCallback' => function ($rule, $action): bool {
|
||||
if (
|
||||
!yii::$app->user->isGuest
|
||||
&& (yii::$app->user->identity->type === 'administrator'
|
||||
|| yii::$app->user->identity->type === 'moderator')
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
],
|
||||
[
|
||||
'allow' => false,
|
||||
'roles' => ['?'],
|
||||
'denyCallback' => [$this, 'accessDenied']
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function accessDenied()
|
||||
{
|
||||
// Инициализация
|
||||
$cookies = yii::$app->response->cookies;
|
||||
|
||||
// Запись cookie с редиректом, который выполнится после авторизации
|
||||
$cookies->add(new Cookie([
|
||||
'name' => 'redirect',
|
||||
'value' => yii::$app->request->pathInfo
|
||||
]));
|
||||
|
||||
if (Yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
// Настройка
|
||||
Yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
// Генерация ответа
|
||||
Yii::$app->response->content = json_encode([
|
||||
'main' => $this->renderPartial('/account/index'),
|
||||
'redirect' => yii::$app->request->pathInfo,
|
||||
'_csrf' => Yii::$app->request->getCsrfToken()
|
||||
]);
|
||||
} else if (Yii::$app->request->isGet) {
|
||||
// GET-запрос
|
||||
|
||||
$this->redirect('/authentication');
|
||||
}
|
||||
}
|
||||
|
||||
public function actionIndex()
|
||||
{
|
||||
return $this->renderPartial('/accounts/index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Подтверждение
|
||||
*
|
||||
* @param int $_key Идентификатор аккаунта
|
||||
*/
|
||||
public function actionAccept(string $_key)
|
||||
{
|
||||
if (yii::$app->user->isGuest) {
|
||||
// Аккаунт не аутентифицирован
|
||||
} else {
|
||||
if (yii::$app->request->isPost) {
|
||||
// AJAX-POST-запрос
|
||||
|
||||
if (
|
||||
yii::$app->user->identity->type === 'administrator'
|
||||
|| yii::$app->user->identity->type === 'moderator'
|
||||
) {
|
||||
// Запрос произведен уполномоченным
|
||||
|
||||
if ($account = Account::searchById(Account::collectionName() . '/' . $_key)) {
|
||||
// Аккаунт найден
|
||||
|
||||
$account->type = 'user';
|
||||
|
||||
if ($account->update() > 0) {
|
||||
// Удалось перезаписать данные в хранилище
|
||||
|
||||
// Запись в журнал
|
||||
$account->journal('accepted into suppliers');
|
||||
|
||||
// Отправка письма с подтверждением аккаунта
|
||||
$account->sendMailVerify();
|
||||
|
||||
// Настройка формата ответа
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Запись кода ответа
|
||||
yii::$app->response->statusCode = 500;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Отказ
|
||||
*
|
||||
* @param int $_key Идентификатор аккаунта
|
||||
*/
|
||||
public function actionDecline(string $_key)
|
||||
{
|
||||
if (yii::$app->user->isGuest) {
|
||||
// Аккаунт не аутентифицирован
|
||||
} else {
|
||||
if (yii::$app->request->isPost) {
|
||||
// AJAX-POST-запрос
|
||||
|
||||
if (
|
||||
yii::$app->user->identity->type === 'administrator'
|
||||
|| yii::$app->user->identity->type === 'moderator'
|
||||
) {
|
||||
// Запрос произведен уполномоченным
|
||||
|
||||
if ($account = Account::searchById(Account::collectionName() . '/' . $_key)) {
|
||||
// Аккаунт найден
|
||||
|
||||
// Отправка письма с отказом и причиной
|
||||
$account->sendMailDecline(yii::$app->request->post('reason') ?? yii::$app->request->get('reason'));
|
||||
|
||||
// Настройка формата ответа
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
// Удаление аккаунта
|
||||
return $account->delete() > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Запись кода ответа
|
||||
yii::$app->response->statusCode = 500;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Запрос файла
|
||||
*
|
||||
* @param int $_key Идентификатор аккаунта
|
||||
* @param string $file Путь до файла от каталога аккаунта
|
||||
*/
|
||||
public function actionFile(string $_key, string $file)
|
||||
{
|
||||
// Инициализация файла
|
||||
$file = YII_PATH_PUBLIC . "/../assets/accounts/$_key/files/$file";
|
||||
|
||||
if (file_exists($file)) {
|
||||
// Удалось найти файл
|
||||
|
||||
return $this->response->sendFile($file);
|
||||
} else {
|
||||
// Не удалось найти файл
|
||||
|
||||
// Запись кода ответа
|
||||
yii::$app->response->statusCode = 500;
|
||||
|
||||
// Перенаправление на страницу аккаунта
|
||||
return yii::$app->response->redirect("/$_key");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Редактирование параметра
|
||||
*
|
||||
* @param int $_key
|
||||
* @param string $target
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function actionEdit(int $_key, string $target)
|
||||
{
|
||||
if (yii::$app->user->isGuest) {
|
||||
// Аккаунт не аутентифицирован
|
||||
} else {
|
||||
if (yii::$app->request->isPost) {
|
||||
// AJAX-POST-запрос
|
||||
|
||||
if (
|
||||
$_key === yii::$app->user->identity->_key ||
|
||||
(yii::$app->user->identity->type === 'administrator'
|
||||
|| yii::$app->user->identity->type === 'moderator')
|
||||
) {
|
||||
// Запрос произведен с изменяемого аккаунта, либо уполномоченным
|
||||
|
||||
if ($account = Account::searchById(Account::collectionName() . '/' . $_key)) {
|
||||
// Аккаунт найден
|
||||
|
||||
// Запись параметра
|
||||
$account->{$target} = yii::$app->request->post('value') ?? yii::$app->request->get('value') ?? 'Неизвестно';
|
||||
|
||||
// Настройка формата ответа
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
return $account->update() > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Запись кода ответа
|
||||
yii::$app->response->statusCode = 500;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Регенерация параметра
|
||||
*
|
||||
* @param int $_key Идентификатор
|
||||
* @param string $target
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function actionRegenerate(int $_key, string $target)
|
||||
{
|
||||
if (yii::$app->user->isGuest) {
|
||||
// Аккаунт не аутентифицирован
|
||||
} else {
|
||||
if (yii::$app->request->isPost) {
|
||||
// AJAX-POST-запрос
|
||||
|
||||
if ($account = Account::searchById(Account::collectionName() . '/' . $_key)) {
|
||||
// Аккаунт найден
|
||||
|
||||
if (
|
||||
$account->_key === yii::$app->user->identity->_key ||
|
||||
(yii::$app->user->identity->type === 'administrator'
|
||||
|| yii::$app->user->identity->type === 'moderator')
|
||||
) {
|
||||
// Запрос произведен с изменяемого аккаунта, либо уполномоченным
|
||||
|
||||
if ($target === 'indx') {
|
||||
// Запрошена регенерация индекса
|
||||
|
||||
// Настройка формата ответа
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
// Регенерация индекса
|
||||
return Account::generateIndexes([$account], force: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Запись кода ответа
|
||||
yii::$app->response->statusCode = 500;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Информация
|
||||
*
|
||||
* @param int $_key Идентификатор
|
||||
*/
|
||||
public function actionData(int $_key)
|
||||
{
|
||||
if (yii::$app->request->isPost) {
|
||||
// AJAX-POST-запрос
|
||||
|
||||
// Инициализация аккаунта (тот кто выполняет запрос)
|
||||
$account = account::initAccount();
|
||||
|
||||
// Поиск данных об аккаунта (запрашиваемом)
|
||||
$data = account::initAccount($_key)->getAttributes();
|
||||
|
||||
if ($account->isAdmin() || $account->isModer()) {
|
||||
// Авторизован как работник
|
||||
} else if ((int) $account->_key === $_key) {
|
||||
// Авторизован как владелец аккаунта
|
||||
|
||||
unset(
|
||||
$data['vrfy'],
|
||||
$data['geol'],
|
||||
$data['auth'],
|
||||
$data['jrnl'],
|
||||
$data['acpt'],
|
||||
$data['pswd']
|
||||
);
|
||||
} else {
|
||||
// Не авторизован
|
||||
|
||||
// Очистка от защищенных свойств
|
||||
$data = [
|
||||
'_key' => $data['_key'],
|
||||
'indx' => $data['indx'],
|
||||
'agnt' => $data['agnt'],
|
||||
'type' => $data['type']
|
||||
];
|
||||
}
|
||||
|
||||
// Настройка формата ответа
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
return [
|
||||
'data' => $data,
|
||||
'_csrf' => Yii::$app->request->getCsrfToken()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Восстановление пароля
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function actionRestore()
|
||||
{
|
||||
// Инициализация
|
||||
$model = new AccountForm(yii::$app->request->post('AccountForm'));
|
||||
$type = yii::$app->request->post('type') ?? yii::$app->request->get('type');
|
||||
$target = yii::$app->request->post('target') ?? yii::$app->request->get('target');
|
||||
|
||||
// Фильтрация
|
||||
$target = match ($target) {
|
||||
'panel' => 'panel',
|
||||
'main' => 'main',
|
||||
default => 'main'
|
||||
};
|
||||
|
||||
// Рендер для всплывающей панели
|
||||
$panel = $target === 'panel';
|
||||
|
||||
if (yii::$app->request->isPost) {
|
||||
// AJAX-POST-запрос
|
||||
|
||||
// Настройка кода ответа
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
if (yii::$app->user->isGuest || $model->validate()) {
|
||||
// Аккаунт не аутентифицирован и проверка пройдена
|
||||
|
||||
// Отправка запроса на генерацию пароля и запись ответа
|
||||
$return = [
|
||||
'status' => Account::restoreSend($model->mail),
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
|
||||
return $return;
|
||||
} else {
|
||||
// Аккаунт аутентифицирован
|
||||
|
||||
// Настройка кода ответа
|
||||
yii::$app->response->statusCode = 400;
|
||||
|
||||
return [
|
||||
'redirect' => '/',
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Генерация нового пароля
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function actionGeneratePassword(string $id, string $key)
|
||||
{
|
||||
if ($account = Account::searchById(Account::collectionName() . "/$id")) {
|
||||
// Найден аккаунт
|
||||
|
||||
if ($account->chpk === $key) {
|
||||
// Ключи совпадают
|
||||
|
||||
// Инициализация буфера пароля
|
||||
$old = $account->pswd;
|
||||
|
||||
// Генерация пароля
|
||||
$account->restoreGenerate();
|
||||
|
||||
if ($account->pswd !== $old) {
|
||||
// Успешно сгенерирован новый пароль
|
||||
|
||||
// Инициализация формы аутентификации
|
||||
$form = new AccountForm;
|
||||
|
||||
// Запись параметров
|
||||
$form->mail = $account->mail;
|
||||
$form->pswd = $account->pswd;
|
||||
|
||||
// Аутентификация
|
||||
$form->authentication();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Перенаправление на главную страницу
|
||||
$this->redirect('/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Генерация нового пароля
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function actionRead(int $page = 1): string|array|null
|
||||
{
|
||||
if (yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
// Инициализация входных параметров
|
||||
$amount = yii::$app->request->post('amount') ?? yii::$app->request->get('amount') ?? 20;
|
||||
$order = yii::$app->request->post('order') ?? yii::$app->request->get('order') ?? ['DESC'];
|
||||
|
||||
// Инициализация cookie
|
||||
$cookies = yii::$app->response->cookies;
|
||||
|
||||
// Чтение аккаунтов
|
||||
$accounts = Account::read(limit: $amount, page: $page, order: $order);
|
||||
|
||||
// Запись формата ответа
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
return [
|
||||
'accounts' => $this->renderPartial('/account/list', compact('accounts', 'amount', 'page')),
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
<?php
|
||||
|
||||
namespace app\controllers;
|
||||
|
||||
use app\models\AccountForm;
|
||||
use app\models\Order;
|
||||
use app\models\Notification;
|
||||
use yii;
|
||||
use yii\web\Controller;
|
||||
use yii\web\Response;
|
||||
use yii\filters\AccessControl;
|
||||
|
||||
use Throwable;
|
||||
use Exception;
|
||||
use yii\bootstrap\ActiveForm;
|
||||
|
||||
class AuthenticationController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function behaviors()
|
||||
{
|
||||
return [
|
||||
'access' => [
|
||||
'class' => AccessControl::class,
|
||||
'rules' => [
|
||||
[
|
||||
'allow' => true,
|
||||
'roles' => ['?'],
|
||||
]
|
||||
],
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function actionIndex()
|
||||
{
|
||||
// Инициализация
|
||||
$model = new AccountForm(yii::$app->request->post('AccountForm'));
|
||||
$type = yii::$app->request->post('type') ?? yii::$app->request->get('type');
|
||||
$target = yii::$app->request->post('target') ?? yii::$app->request->get('target');
|
||||
$model->scenario = $model::SCENARIO_AUTHENTICATION;
|
||||
|
||||
// Фильтрация
|
||||
$target = match ($target) {
|
||||
'panel' => 'panel',
|
||||
'main' => 'main',
|
||||
default => 'main'
|
||||
};
|
||||
|
||||
// Рендер для всплывающей панели
|
||||
$panel = $target === 'panel';
|
||||
|
||||
if (yii::$app->request->isPost) {
|
||||
// AJAX-POST-запрос
|
||||
|
||||
// Настройка кода ответа
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
if (!yii::$app->user->isGuest || $model->authentication()) {
|
||||
// Аккаунт аутентифицирован
|
||||
|
||||
// Отправка уведомления
|
||||
Notification::_write('Вы аутентифицированы с устройства ' . $_SERVER['HTTP_USER_AGENT'] . ' ' . $_SERVER['REMOTE_ADDR'], true, yii::$app->user->identity->_key, Notification::TYPE_NOTICE);
|
||||
|
||||
// Инициализация
|
||||
$notifications_button = $this->renderPartial('/notification/button');
|
||||
$notifications_panel = $this->renderPartial('/notification/panel', ['notifications_panel_full' => true]);
|
||||
$cart_button = $this->renderPartial('/cart/button', ['cart_amount' => Order::count(supplies: true)]);
|
||||
|
||||
// Запись ответа
|
||||
$return = [
|
||||
'menu' => $this->renderPartial('/account/panel/authenticated', compact(
|
||||
'notifications_button',
|
||||
'notifications_panel',
|
||||
'cart_button'
|
||||
)),
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
|
||||
if (($cookies = yii::$app->request->cookies)->has('redirect')) {
|
||||
// Найдено cookie с переадресацией
|
||||
|
||||
// Запись ответа
|
||||
$return['redirect'] = '/' . $cookies['redirect'];
|
||||
|
||||
// Очистка cookie
|
||||
unset(yii::$app->response->cookies['redirect']);
|
||||
|
||||
yii::$app->response->format = Response::FORMAT_HTML;
|
||||
|
||||
// Переадресация
|
||||
return $this->redirect($return['redirect']);
|
||||
} else {
|
||||
// Не найдено cookie с переадресацией
|
||||
|
||||
if (yii::$app->request->pathInfo === 'authentication' || yii::$app->request->pathInfo === 'registration') {
|
||||
// Если клиент на промежуточном URI
|
||||
|
||||
// Запись ответа
|
||||
$return['redirect'] = '/';
|
||||
$return['main'] = $this->renderPartial('/index');
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
} else {
|
||||
// Аккаунт не аутентифицирован
|
||||
|
||||
// Настройка кода ответа
|
||||
yii::$app->response->statusCode = 400;
|
||||
|
||||
return [
|
||||
$target => $this->renderPartial('/account/index', compact('model', 'panel')),
|
||||
'redirect' => '/authentication',
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (!yii::$app->user->isGuest) {
|
||||
yii::$app->response->redirect('/');
|
||||
} else {
|
||||
return $this->render('/account/index', compact('model', 'panel'));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controllers;
|
||||
|
||||
use yii\web\Controller;
|
||||
|
||||
class BuyersController extends Controller
|
||||
{
|
||||
public function actionIndex()
|
||||
{
|
||||
return $this->renderPartial('/buyers/index');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controllers;
|
||||
|
||||
use app\models\Account;
|
||||
use yii;
|
||||
use yii\filters\AccessControl;
|
||||
use yii\web\Controller;
|
||||
use yii\web\Response;
|
||||
use yii\web\Cookie;
|
||||
|
||||
use app\models\Product;
|
||||
use app\models\Order;
|
||||
use app\models\OrderEdgeSupply;
|
||||
use app\models\Notification;
|
||||
|
||||
use Exception;
|
||||
|
||||
class CartController extends Controller
|
||||
{
|
||||
public function behaviors()
|
||||
{
|
||||
return [
|
||||
'access' => [
|
||||
'class' => AccessControl::class,
|
||||
'rules' => [
|
||||
[
|
||||
'allow' => true,
|
||||
'roles' => ['@'],
|
||||
'actions' => [
|
||||
'index',
|
||||
'edit-comm',
|
||||
'count'
|
||||
]
|
||||
],
|
||||
[
|
||||
'allow' => false,
|
||||
'roles' => ['?'],
|
||||
'denyCallback' => [$this, 'accessDenied']
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function accessDenied()
|
||||
{
|
||||
// Инициализация
|
||||
$cookies = yii::$app->response->cookies;
|
||||
|
||||
// Запись cookie с редиректом, который выполнится после авторизации
|
||||
$cookies->add(new Cookie([
|
||||
'name' => 'redirect',
|
||||
'value' => yii::$app->request->pathInfo
|
||||
]));
|
||||
|
||||
if (yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
// Настройка
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
// Генерация ответа
|
||||
yii::$app->response->content = json_encode([
|
||||
'main' => $this->renderPartial('/account/index'),
|
||||
'redirect' => '/cart',
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
]);
|
||||
} else if (yii::$app->request->isGet) {
|
||||
// GET-запрос
|
||||
|
||||
$this->redirect('/authentication');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Страница: "Корзина"
|
||||
*
|
||||
* @see $this->behaviors Доступ только аутентифицированным
|
||||
*/
|
||||
public function actionIndex(): string|array|null|Response
|
||||
{
|
||||
// Инициализация
|
||||
$page = yii::$app->request->get('page') ?? yii::$app->request->post('page') ?? 1;
|
||||
$account = Account::initAccount();
|
||||
|
||||
// Поиск корзины (текущего заказа)
|
||||
$data = Order::searchSmart()[0] ?? null;
|
||||
|
||||
if (empty($data['order'])) {
|
||||
// Корзина не инициализирована
|
||||
|
||||
// Инициализация
|
||||
$data['order'] = new Order();
|
||||
|
||||
if ($data['order']->save()) {
|
||||
// Удалось инициализировать заказ
|
||||
|
||||
// Подключение заказа к аккаунту
|
||||
$data['order']->connect($account);
|
||||
} else {
|
||||
throw new Exception('Не удалось инициализировать заказ');
|
||||
}
|
||||
}
|
||||
|
||||
// Инициализация содержимого корзины
|
||||
$data['supplies'] = $data['order']->supplies(10, $page);
|
||||
|
||||
// Инициализация данных списка для выбора терминала
|
||||
$delivery_to_terminal_list = $account->genListTerminalsTo();
|
||||
$array_unshift_in_start = function (array &$array, string|int $key, mixed $value) {
|
||||
$array = array_reverse($array, true);
|
||||
$array[$key] = $value;
|
||||
return $array = array_reverse($array, true);
|
||||
};
|
||||
$array_write_default_value = function (array &$array, string $key = 'Выберите', string $value = 'Выберите') use ($array_unshift_in_start) {
|
||||
if (isset($array[$key])) {
|
||||
// Смещение или ассоциация найдена
|
||||
|
||||
// Деинициализация
|
||||
unset($array[$key]);
|
||||
|
||||
// Инициализация
|
||||
$array_unshift_in_start($array, $key, $value);
|
||||
}
|
||||
};
|
||||
|
||||
// Сортировка по алфавиту
|
||||
asort($delivery_to_terminal_list);
|
||||
|
||||
// Перемещение в начало массива значения "Выберите"
|
||||
$array_write_default_value($delivery_to_terminal_list);
|
||||
|
||||
if (yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
return [
|
||||
'main' => $this->renderPartial('index', compact('account', 'data', 'delivery_to_terminal_list')),
|
||||
'title' => 'Корзина',
|
||||
'redirect' => '/cart',
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
}
|
||||
|
||||
return $this->render('index', compact('account', 'data', 'delivery_to_terminal_list'));
|
||||
}
|
||||
|
||||
public function actionEditComm(string $catn, string $prod): array|string|null
|
||||
{
|
||||
// Инициализация
|
||||
$return = [
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
|
||||
if (is_null($catn) || is_null($prod)) {
|
||||
// Не получен артикул
|
||||
|
||||
yii::$app->response->statusCode = 500;
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ($edges = OrderEdgeSupply::searchBySupplyCatnAndProd($catn, $prod, Order::searchByType()[0]['order'])) {
|
||||
// Рёбра найдены (связи заказа с поставкой)
|
||||
|
||||
// Инициализация
|
||||
$amount = 0;
|
||||
|
||||
foreach ($edges as $edge) {
|
||||
// Перебор рёбер (связей заказа с поставкой)
|
||||
|
||||
// Инициализация
|
||||
$text = yii::$app->request->post('text') ?? yii::$app->request->get('text') ?? 'Комментарий к заказу';
|
||||
|
||||
$comm = $edge->comm ?? null;
|
||||
$edge->comm = empty($text) ? 'Комментарий к заказу' : $text;
|
||||
|
||||
if ($edge->save()) {
|
||||
// Ребро обновлено
|
||||
|
||||
// Запись в журнал
|
||||
$edge->journal('update', ['comm' => ['from' => $comm, 'to' => $edge->comm]]);
|
||||
|
||||
// Обновление счётчика
|
||||
++$amount;
|
||||
|
||||
// Запись в буфер ответа
|
||||
$return['comm'] = $edge->comm;
|
||||
}
|
||||
}
|
||||
|
||||
if ($amount > 0) {
|
||||
// Удалось записать минимум 1 связь с поставкой
|
||||
|
||||
Notification::_write("Обновлён комментарий к товару $catn ($amount шт)");
|
||||
} else {
|
||||
// Не удалось записать минимум 1 связь с поставкой
|
||||
|
||||
Notification::_write("Не удалось обновить комментарий к товару $catn");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Конец алгоритма
|
||||
*/
|
||||
end:
|
||||
|
||||
if (yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
if ($model = Product::searchByCatnAndProd($catn, $prod)) {
|
||||
return $this->render('index', compact('model'));
|
||||
} else {
|
||||
return $this->redirect('/');
|
||||
}
|
||||
}
|
||||
|
||||
public function actionCount(): array|string|null
|
||||
{
|
||||
if (yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
// Настройка типа ответа
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
return [
|
||||
'button' => $this->renderPartial('/cart/button', ['cart_amount' => Order::count(supplies: true)]),
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace app\controllers;
|
||||
|
||||
use yii;
|
||||
use yii\web\Controller;
|
||||
use yii\web\Response;
|
||||
use yii\filters\AccessControl;
|
||||
use yii\filters\VerbFilter;
|
||||
use app\models\AccountForm;
|
||||
|
||||
class DeauthenticationController extends Controller
|
||||
{
|
||||
public function behaviors()
|
||||
{
|
||||
return [
|
||||
'access' => [
|
||||
'class' => AccessControl::class,
|
||||
'rules' => [
|
||||
[
|
||||
'allow' => true,
|
||||
'roles' => ['@'],
|
||||
]
|
||||
],
|
||||
],
|
||||
'verbs' => [
|
||||
'class' => VerbFilter::class,
|
||||
'actions' => [
|
||||
'index' => ['post'],
|
||||
],
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function actionIndex()
|
||||
{
|
||||
// Инициализация
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
// Удаление сессии
|
||||
yii::$app->session['status'] = 'inactive';
|
||||
// yii::$app->session->close();
|
||||
|
||||
// Выход из аккаунта
|
||||
yii::$app->user->logout();
|
||||
|
||||
|
||||
// Инициализация
|
||||
$model = new AccountForm(yii::$app->request->post('AccountForm') ?? yii::$app->request->get('AccountForm') ?? null);
|
||||
|
||||
// Ответа
|
||||
return [
|
||||
'menu' => $this->renderPartial('/account/panel/deauthenticated', compact('model')),
|
||||
'main' => $this->renderPartial('/index'),
|
||||
'redirect' => '/',
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace app\controllers;
|
||||
|
||||
use Yii;
|
||||
use yii\web\Controller;
|
||||
|
||||
class ErrorController extends Controller
|
||||
{
|
||||
public function actionIndex(): string
|
||||
{
|
||||
$exception = Yii::$app->errorHandler->exception;
|
||||
|
||||
if ($exception !== null) {
|
||||
// Исключение не выброшено
|
||||
|
||||
// Запись кода ошибки
|
||||
$code = $exception->statusCode ?? $exception->getCode() ?? 0;
|
||||
|
||||
// Запись названия ошибки
|
||||
$title = match ($code) {
|
||||
404 => '404 (Не найдено)',
|
||||
default => '500 (Ошибка сервера)'
|
||||
};
|
||||
|
||||
// Запись сообщения об ошибке
|
||||
$description = match ($code) {
|
||||
404 => 'Страница не найдена',
|
||||
default => $exception->getMessage()
|
||||
};
|
||||
|
||||
return $this->render('/error', compact('exception', 'code', 'title', 'description'));
|
||||
}
|
||||
}
|
||||
|
||||
public static function throw(string $title, string $description): string {
|
||||
|
||||
return yii::$app->controller->render('/error', compact('title', 'description'));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controllers;
|
||||
|
||||
use yii;
|
||||
use yii\web\Controller;
|
||||
use yii\web\Response;
|
||||
|
||||
use app\models\AccountForm;
|
||||
use app\models\Order;
|
||||
|
||||
class IdentificationController extends Controller
|
||||
{
|
||||
public function actionIndex()
|
||||
{
|
||||
if (yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
if (yii::$app->user->isGuest) {
|
||||
// Аккаунт не аутентифицирован
|
||||
|
||||
// Инициализация
|
||||
$model = new AccountForm(yii::$app->request->post('AccountForm') ?? yii::$app->request->get('AccountForm') ?? null);
|
||||
|
||||
// Запись ответа
|
||||
$return = [
|
||||
'menu' => $this->renderPartial('/account/panel/deauthenticated', compact('model')),
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
} else {
|
||||
// Аккаунт аутентифицирован
|
||||
|
||||
// Инициализация
|
||||
$model = yii::$app->user;
|
||||
|
||||
// Инициализация
|
||||
$notifications_button = $this->renderPartial('/notification/button');
|
||||
$notifications_panel = $this->renderPartial('/notification/panel', ['notifications_panel_full' => true]);
|
||||
$cart_button = $this->renderPartial('/cart/button', ['cart_amount' => Order::count(supplies: true)]);
|
||||
|
||||
// Запись ответа
|
||||
$return = [
|
||||
'menu' => $this->renderPartial('/account/panel/authenticated', compact(
|
||||
'notifications_button',
|
||||
'notifications_panel',
|
||||
'cart_button'
|
||||
)),
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
}
|
||||
|
||||
if (($cookies = yii::$app->request->cookies)->has('redirect')) {
|
||||
// Найдено cookie с переадресацией
|
||||
|
||||
// Запись ответа
|
||||
$return['redirect'] = '/' . $cookies['redirect'];
|
||||
|
||||
// Очистка cookie
|
||||
unset(yii::$app->response->cookies['redirect']);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controllers;
|
||||
|
||||
use yii;
|
||||
use yii\web\Controller;
|
||||
|
||||
use app\models\Order;
|
||||
|
||||
class InvoiceController extends Controller
|
||||
{
|
||||
public function actionIndex(int $order)
|
||||
{
|
||||
if ($order = Order::searchById(Order::collectionName() . '/' . $order)) {
|
||||
|
||||
return $this->renderPartial('/invoice/order/pattern', [
|
||||
'account' => yii::$app->user->identity,
|
||||
'order' => [
|
||||
'id' => $order->_key,
|
||||
'date' => $order->date ?? time() // @todo доделать
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function actionDownload(int $order)
|
||||
{
|
||||
// Инициализация файла
|
||||
$file = YII_PATH_PUBLIC . '/../assets/invoices/' . $order . '/invoice.xlsx';
|
||||
|
||||
if (file_exists($file)) {
|
||||
// Удалось найти файл
|
||||
|
||||
return $this->response->sendFile($file);
|
||||
} else {
|
||||
// Не удалось найти файл
|
||||
|
||||
// Запись кода ответа
|
||||
yii::$app->response->statusCode = 500;
|
||||
|
||||
return yii::$app->response->redirect('/orders');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controllers;
|
||||
|
||||
use Yii;
|
||||
use yii\web\Controller;
|
||||
use yii\web\Response;
|
||||
|
||||
class MainController extends Controller
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function actions()
|
||||
{
|
||||
return [
|
||||
'captcha' => [
|
||||
'class' => 'yii\captcha\CaptchaAction',
|
||||
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Главная страница
|
||||
*/
|
||||
public function actionIndex(): string|array
|
||||
{
|
||||
if (Yii::$app->request->isAjax) {
|
||||
// AJAX-POST-запрос
|
||||
|
||||
Yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
return [
|
||||
'main' => $this->renderPartial('/index'),
|
||||
'redirect' => '/',
|
||||
'_csrf' => Yii::$app->request->getCsrfToken()
|
||||
];
|
||||
}
|
||||
|
||||
return $this->render('/index');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controllers;
|
||||
|
||||
use app\models\AccountEdgeNotification;
|
||||
use yii;
|
||||
use yii\filters\AccessControl;
|
||||
use yii\web\Controller;
|
||||
use yii\web\Response;
|
||||
|
||||
use app\models\Notification;
|
||||
|
||||
class NotificationController extends Controller
|
||||
{
|
||||
public function behaviors()
|
||||
{
|
||||
return [
|
||||
'access' => [
|
||||
'class' => AccessControl::class,
|
||||
'rules' => [
|
||||
[
|
||||
'allow' => true,
|
||||
'roles' => ['@'],
|
||||
'actions' => ['index']
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo Перенести логику в модель
|
||||
*/
|
||||
public function actionIndex()
|
||||
{
|
||||
if (yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
// Инициализация
|
||||
$model = new Notification(yii::$app->request->post('Notification'));
|
||||
$preload = (bool) (int) yii::$app->request->post('preload');
|
||||
$account = yii::$app->user->identity;
|
||||
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
$return = [
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
|
||||
if (yii::$app->request->post('last')) {
|
||||
// Запрос последнего уведомлений (всплывающее окно)
|
||||
|
||||
// Инициализация
|
||||
$limit = 1;
|
||||
} else if (yii::$app->request->post('stream')) {
|
||||
// Запрос последних уведомлений (панель)
|
||||
$limit = 10;
|
||||
}
|
||||
|
||||
if (isset($limit)) {
|
||||
// Обработка для всплывающего окна или панель
|
||||
|
||||
// Подзапрос для проверки статуса уведомления относительно пользователя
|
||||
// Поиск рёбер: ПОЛЬЗОВАТЕЛЬ -> УВЕДОМЛЕНИЕ
|
||||
$let = $model::find()
|
||||
->for(['account', $model::collectionName() . '_edge_account'])
|
||||
->traversal($model::collectionName(), 'OUTBOUND')
|
||||
->in('account_edge_' . $model::collectionName())
|
||||
->where(['account._id == "' . $account->readId() . '" && notification_edge_account._from != account_edge_notification[0]._to'])
|
||||
->select($model::collectionName() . '_edge_account');
|
||||
|
||||
if (yii::$app->request->post('last')) {
|
||||
// Запрос последнего уведомлений (всплывающее окно)
|
||||
|
||||
// Уведомление которое не выводилось на мониторе пользователя
|
||||
$type = 'received';
|
||||
} else if (yii::$app->request->post('stream')) {
|
||||
// Запрос последних уведомлений (панель)
|
||||
|
||||
// Уведомление которое не было прочитано в окне уведомний
|
||||
$type = 'checked';
|
||||
}
|
||||
|
||||
// Генерация
|
||||
$let = $let->createCommand();
|
||||
|
||||
/**
|
||||
* Поиск рёбер: (УВЕДОМЛЕНИЕ)? -> ПОЛЬЗОВАТЕЛЬ
|
||||
*
|
||||
* @param bool $new Активация проверки на то, что уведомление не получено
|
||||
* @param bool $count Посчитать
|
||||
*/
|
||||
$search = function (bool $new = false, bool $count = false) use ($model, $account, $type, $let, $limit): array|int|null|Notification {
|
||||
if ($count) {
|
||||
// Запрошен подсчёт непрочитанных уведомлений
|
||||
|
||||
// Реинициализация
|
||||
$type = 'checked';
|
||||
$limit = null;
|
||||
}
|
||||
|
||||
return $model::searchByEdge(
|
||||
from: 'account',
|
||||
to: 'notification',
|
||||
params: $new ? $let->getBindVars() : [],
|
||||
subquery_where: [
|
||||
[
|
||||
'account._id' => $account->readId()
|
||||
],
|
||||
[
|
||||
[
|
||||
'notification.html' => null
|
||||
],
|
||||
'operator' => '!='
|
||||
],
|
||||
[
|
||||
'account_edge_notification.type' => $type
|
||||
]
|
||||
],
|
||||
let: [
|
||||
'notification_edge_account',
|
||||
'(' . (string) $let . ')'
|
||||
],
|
||||
foreach: [
|
||||
'edge' => 'notification_edge_account'
|
||||
],
|
||||
where: $new ? [
|
||||
'edge != null'
|
||||
] : [],
|
||||
limit: $limit,
|
||||
sort: ['DESC'],
|
||||
direction: 'INBOUND',
|
||||
handle: $count ? function ($request) {
|
||||
// Посчитать рёбра (информация о количестве непрочитанных уведомлений)
|
||||
return $request->count();
|
||||
} : null
|
||||
);
|
||||
};
|
||||
|
||||
// Поиск новых (непрочитанных) уведомлений пользователя
|
||||
// Если заккоментировать, то вместо только новых отправит все последние уведомления
|
||||
$notifications = $search(true);
|
||||
|
||||
// Подсчёт новых (непрочитанных) уведомлений
|
||||
$return['button'] = $this->renderPartial('button', ['notifications_new_amount' => $search(new: true, count: true)]);
|
||||
|
||||
if (!yii::$app->request->post('last') && empty($notifications)) {
|
||||
// Запрошены НЕ ВСПЛЫВАЮЩИЕ уведомления и новые уведомления не найдены
|
||||
|
||||
// Поиск уведомлений пользователя
|
||||
$notifications = $search();
|
||||
}
|
||||
|
||||
if (empty($notifications)) {
|
||||
// Уведомления не найдены
|
||||
|
||||
/**
|
||||
* @todo Определить какой код лучше использовать (404 не подходит)
|
||||
*/
|
||||
yii::$app->response->statusCode = 200;
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
foreach (is_array($notifications) ? $notifications : [$notifications] as $notification) {
|
||||
// Перебор найденных уведомлений
|
||||
|
||||
if ($preload) {
|
||||
// Запрошены уведомления для предзагрузки (их ещё не увидели)
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Запись ребра: ПОЛЬЗОВАТЕЛЬ -> УВЕДОМЛЕНИЕ (о том, что уведомление прочитано)
|
||||
AccountEdgeNotification::write($account->readId(), $notification->readId(), $type);
|
||||
}
|
||||
|
||||
if (yii::$app->request->post('last')) {
|
||||
// Запрос последнего уведомлений (всплывающее окно)
|
||||
|
||||
// Реинициализация
|
||||
$notification = $notifications[0];
|
||||
|
||||
$return['popup'] = [
|
||||
'html' => $this->renderPartial('popup', compact('model', 'notification', 'account')),
|
||||
'id' => 'popup/' . $notification->readId()
|
||||
];
|
||||
} else if (yii::$app->request->post('stream')) {
|
||||
// Запрос последних уведомлений (панель)
|
||||
|
||||
$return['panel'] = $this->renderPartial('panel', compact('model', 'notifications'));
|
||||
}
|
||||
} else {
|
||||
// Иначе обрабатывается как запрос страницы уведомлений
|
||||
|
||||
$return['main'] = $this->renderPartial('index', compact('model'));
|
||||
$return['redirect'] = '/notification';
|
||||
}
|
||||
|
||||
/**
|
||||
* Конец алгоритма
|
||||
*/
|
||||
end:
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
return $this->render('index', ['model' => new Notification(yii::$app->request->get('Notification'))]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controllers;
|
||||
|
||||
use yii;
|
||||
use yii\filters\AccessControl;
|
||||
use yii\web\Cookie;
|
||||
use yii\web\Response;
|
||||
use yii\web\Controller;
|
||||
|
||||
class OfferController extends Controller
|
||||
{
|
||||
public function behaviors()
|
||||
{
|
||||
return [
|
||||
'access' => [
|
||||
'class' => AccessControl::class,
|
||||
'rules' => [
|
||||
[
|
||||
'allow' => true,
|
||||
'actions' => ['index', 'suppliers'],
|
||||
],
|
||||
[
|
||||
'allow' => true,
|
||||
'roles' => ['@'],
|
||||
'actions' => ['accept', 'accept-suppliers']
|
||||
],
|
||||
[
|
||||
'allow' => false,
|
||||
'roles' => ['?'],
|
||||
'denyCallback' => [$this, 'accessDenied']
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function accessDenied()
|
||||
{
|
||||
// Инициализация
|
||||
$cookies = yii::$app->response->cookies;
|
||||
|
||||
// Запись cookie с редиректом, который выполнится после авторизации
|
||||
$cookies->add(new Cookie([
|
||||
'name' => 'offer',
|
||||
'value' => yii::$app->request->pathInfo
|
||||
]));
|
||||
|
||||
if (yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
// Настройка
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
// Генерация ответа
|
||||
yii::$app->response->content = json_encode([
|
||||
'redirect' => '/authentication',
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
]);
|
||||
} else if (Yii::$app->request->isGet) {
|
||||
// GET-запрос
|
||||
|
||||
$this->redirect('/authentication');
|
||||
}
|
||||
}
|
||||
|
||||
public function actionIndex()
|
||||
{
|
||||
return $this->render('/offer/index');
|
||||
}
|
||||
|
||||
public function actionSuppliers()
|
||||
{
|
||||
return $this->render('/offer/supplier');
|
||||
}
|
||||
|
||||
public function actionAccept()
|
||||
{
|
||||
// Инициализация
|
||||
yii::$app->user->identity->acpt ?? yii::$app->user->identity->acpt = [];
|
||||
|
||||
// Запись
|
||||
yii::$app->user->identity->acpt += ['buyer' => true];
|
||||
|
||||
if (yii::$app->user->identity->save()) {
|
||||
// Удалось записать данные
|
||||
|
||||
// Запись в сессию
|
||||
yii::$app->session['offer_buyer_accepted'] = true;
|
||||
|
||||
|
||||
yii::$app->response->redirect('/');
|
||||
}
|
||||
}
|
||||
|
||||
public function actionAcceptSuppliers()
|
||||
{
|
||||
// Инициализация
|
||||
yii::$app->user->identity->acpt ?? yii::$app->user->identity->acpt = [];
|
||||
|
||||
yii::$app->user->identity->acpt += ['supplier' => true];
|
||||
|
||||
if (yii::$app->user->identity->save()) {
|
||||
// Удалось записать данные
|
||||
|
||||
// Запись в сессию
|
||||
yii::$app->session['offer_supplier_accepted'] = true;
|
||||
|
||||
|
||||
yii::$app->response->redirect('/');
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controllers;
|
||||
|
||||
use yii\web\Controller;
|
||||
|
||||
use app\models\Terminal;
|
||||
|
||||
class PartnersController extends Controller
|
||||
{
|
||||
public function actionIndex()
|
||||
{
|
||||
$terminals = Terminal::read(500);
|
||||
return $this->render('/partners/index', compact('terminals'));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controllers;
|
||||
|
||||
use yii\web\Controller;
|
||||
|
||||
class PolicyController extends Controller
|
||||
{
|
||||
public function actionIndex()
|
||||
{
|
||||
return $this->render('/policy/index');
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controllers;
|
||||
|
||||
use yii;
|
||||
use yii\filters\AccessControl;
|
||||
use yii\web\Controller;
|
||||
use yii\web\Response;
|
||||
|
||||
use app\models\AccountForm;
|
||||
use app\models\Order;
|
||||
use yii\bootstrap\ActiveForm;
|
||||
|
||||
class RegistrationController extends Controller
|
||||
{
|
||||
public function actionIndex()
|
||||
{
|
||||
// Инициализация
|
||||
$model = new AccountForm(yii::$app->request->post('AccountForm') ?? yii::$app->request->get('AccountForm'));
|
||||
$type = yii::$app->request->post('type') ?? yii::$app->request->get('type');
|
||||
$target = yii::$app->request->post('target') ?? yii::$app->request->get('target');
|
||||
$model->scenario = $model::SCENARIO_REGISTRATION;
|
||||
|
||||
// Фильтрация
|
||||
$target = match ($target) {
|
||||
'panel' => 'panel',
|
||||
'main' => 'main',
|
||||
default => 'main'
|
||||
};
|
||||
|
||||
// Рендер для всплывающей панели
|
||||
$panel = $target === 'panel';
|
||||
|
||||
if (yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
if ($type === 'registration' && (!yii::$app->user->isGuest || $model->registration())) {
|
||||
// Данные прошли проверку и аккаунт был создан
|
||||
|
||||
// Аутентификация
|
||||
$model->scenario = $model::SCENARIO_AUTHENTICATION;
|
||||
|
||||
if (!$model->authentication()) {
|
||||
// Не удалось аутентифицироваться
|
||||
|
||||
yii::$app->response->statusCode = 401;
|
||||
|
||||
$model->scenario = $model::SCENARIO_REGISTRATION;
|
||||
|
||||
return [
|
||||
$target => $this->renderPartial('/account/index', compact('model', 'panel') + ['registration' => true]),
|
||||
'redirect' => '/registration',
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
}
|
||||
|
||||
// Инициализация
|
||||
$notifications_button = $this->renderPartial('/notification/button');
|
||||
$notifications_panel = $this->renderPartial('/notification/panel', ['notifications_panel_full' => true]);
|
||||
$cart_button = $this->renderPartial('/cart/button', ['cart_amount' => Order::count(supplies: true)]);
|
||||
|
||||
// Запись ответа
|
||||
$return = [
|
||||
'menu' => $this->renderPartial('/account/panel/authenticated', compact(
|
||||
'notifications_button',
|
||||
'notifications_panel',
|
||||
'cart_button'
|
||||
)),
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
|
||||
if (($cookies = yii::$app->response->cookies)->has('redirect')) {
|
||||
// Найдено cookie с переадресацией
|
||||
|
||||
// Запись ответа
|
||||
$return['redirect'] = '/' . $cookies['redirect'];
|
||||
|
||||
// Очистка cookie
|
||||
unset(yii::$app->response->cookies['redirect']);
|
||||
|
||||
yii::$app->response->format = Response::FORMAT_HTML;
|
||||
|
||||
// Переадресация
|
||||
return $this->redirect($return['redirect']);
|
||||
} else {
|
||||
// Не найдено cookie с переадресацией
|
||||
|
||||
if (yii::$app->request->pathInfo === 'authentication' || yii::$app->request->pathInfo === 'registration') {
|
||||
// Если клиент на промежуточном URI
|
||||
|
||||
// Запись ответа
|
||||
$return['redirect'] = '/';
|
||||
$return['main'] = $this->renderPartial('/index');
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
} else {
|
||||
// Данные не прошли проверку
|
||||
|
||||
yii::$app->response->statusCode = 400;
|
||||
|
||||
return [
|
||||
$target => $this->renderPartial('/account/index', compact('model', 'panel') + ['registration' => true]),
|
||||
'redirect' => '/registration',
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (!yii::$app->user->isGuest) {
|
||||
yii::$app->response->redirect('/');
|
||||
} else {
|
||||
return $this->render('/account/index', compact('model', 'panel') + ['registration' => true]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,234 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controllers;
|
||||
|
||||
use yii;
|
||||
use yii\web\Controller;
|
||||
use yii\web\Response;
|
||||
|
||||
use app\models\Product;
|
||||
use app\models\Search;
|
||||
|
||||
/**
|
||||
* @todo
|
||||
* 1. Ограничение доступа
|
||||
*/
|
||||
class SearchController extends Controller
|
||||
{
|
||||
/**
|
||||
* @todo
|
||||
* 1. Сессию привязать к аккаунту и проверку по нему делать, иначе её можно просто сбрасывать
|
||||
* 2. Пагинация
|
||||
*/
|
||||
public function actionIndex(): array|string
|
||||
{
|
||||
// Инициализация параметров
|
||||
$auth_only = false;
|
||||
$account = yii::$app->user->identity;
|
||||
|
||||
if ($auth_only && yii::$app->user->isGuest) {
|
||||
// Если активирован режим "Поиск только аутентифицированным" и запрос пришел не от аутентифицированного
|
||||
|
||||
|
||||
// Запись кода ответа: 401 (необходима авторизация)
|
||||
yii::$app->response->statusCode = 401;
|
||||
|
||||
// Переход к концу обработки
|
||||
goto skip_search;
|
||||
}
|
||||
|
||||
// Инициализация
|
||||
$query = yii::$app->request->post('request') ?? yii::$app->request->get('q');
|
||||
|
||||
if (yii::$app->request->post('type') === 'product' || yii::$app->request->get('type') === 'product') {
|
||||
// Поиск по продуктам
|
||||
|
||||
if (yii::$app->request->post('history')) {
|
||||
// Запрошена история
|
||||
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
return [
|
||||
'panel' => $this->renderPartial('/search/panel', compact('account') + ['history' => true]),
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
}
|
||||
|
||||
// Инициализация сессии
|
||||
$session = yii::$app->session;
|
||||
|
||||
// Инициализация ответа
|
||||
$response = null;
|
||||
|
||||
// Инициализация параметров
|
||||
$timer = 0;
|
||||
|
||||
// Период пропуска запросов (в секундах)
|
||||
$period = 3;
|
||||
$keep_connect = false;
|
||||
$sanction = false;
|
||||
$sanction_condition = ($session['last_request'] + $period - time()) < $period;
|
||||
$sanction_time = 2;
|
||||
$query_min = 2;
|
||||
$query_max = 20;
|
||||
|
||||
if (isset($session['last_request'])) {
|
||||
// Данные о времени последнего запроса не найдены
|
||||
|
||||
if ($sanction && $sanction_condition) {
|
||||
// Наказание за повторный запрос при условии задержки
|
||||
|
||||
$session['last_request'] += $sanction_time;
|
||||
}
|
||||
} else {
|
||||
// Это первый запрос
|
||||
|
||||
// Инициализация
|
||||
$session['last_request'] = time();
|
||||
|
||||
// Пропуск проверок
|
||||
goto first_request;
|
||||
}
|
||||
|
||||
// Метка: "Повтор обработки поиска" (для создания непрерывного соединения)
|
||||
keep_connect_wait:
|
||||
|
||||
// Запись времени последнего запроса и вычисление об истечении таймера
|
||||
$timer = $session['last_request'] + $period - time();
|
||||
|
||||
if ($timer > 0) {
|
||||
// Время блокировки не истекло
|
||||
|
||||
// Запись кода ответа: 202 (запрос не обработан)
|
||||
yii::$app->response->statusCode = 202;
|
||||
|
||||
$return = [
|
||||
'timer' => $timer,
|
||||
'search_line_window_show' => 1,
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
} else {
|
||||
// Запрос
|
||||
|
||||
// Очистка времени последнего запроса
|
||||
unset($session['last_request']);
|
||||
|
||||
// Метка: "Первый запрос"
|
||||
first_request:
|
||||
|
||||
if (strlen($query) < $query_min) {
|
||||
// Выход за ограничения длины с недостатком
|
||||
|
||||
// Пропуск поиска
|
||||
goto skip_query;
|
||||
} else if (strlen($query) > $query_max) {
|
||||
// Выход за ограничения длины с превышением
|
||||
|
||||
// Пропуск поиска
|
||||
goto skip_query;
|
||||
}
|
||||
|
||||
// Запись в историю
|
||||
Search::write($query);
|
||||
|
||||
$limit = yii::$app->request->isPost ? 10 : 20;
|
||||
|
||||
if ($response = Product::searchByPartialCatn($query, 'active', $limit, [
|
||||
'_key' => '_key',
|
||||
'catn' => 'catn',
|
||||
'prod' => 'prod',
|
||||
// Баг с названием DESC
|
||||
'dscr' => 'dscr',
|
||||
'catg' => 'catg',
|
||||
'imgs' => 'imgs',
|
||||
'name' => 'name',
|
||||
'prod' => 'prod',
|
||||
'dmns' => 'dmns',
|
||||
'stts' => 'stts'
|
||||
])) {
|
||||
// Данные найдены по поиску в полях Каталожного номера
|
||||
|
||||
// Генерация данных для представления
|
||||
$response = Search::content(products: $response);
|
||||
|
||||
if (yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
// Запись ответа
|
||||
$return = [
|
||||
'panel' => $this->renderPartial('/search/panel', compact('response', 'query')),
|
||||
'search_line_window_show' => 1,
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
|
||||
if ((int) yii::$app->request->post('advanced')) {
|
||||
// Полноценный поиск
|
||||
|
||||
// Запись ответа
|
||||
$return['main'] = $this->renderPartial('/search/index', compact('response', 'query'));
|
||||
$return['search_line_window_show'] = 1;
|
||||
$return['redirect'] = '/search?type=product&q=' . $query;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Данные не найдены
|
||||
|
||||
// Запись кода ответа: 404 (запрашиваемые данные не найдены)
|
||||
yii::$app->response->statusCode = 404;
|
||||
}
|
||||
}
|
||||
|
||||
// Метка: "Пропуск запроса" (для пропуска самого поиска и возврата ответа)
|
||||
skip_query:
|
||||
|
||||
if (yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
return $return ?? [
|
||||
'panel' => $this->renderPartial('/search/panel'),
|
||||
'search_line_window_show' => 1,
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
} else {
|
||||
// GET-запрос
|
||||
|
||||
if (empty($return['main']) && $keep_connect && $timer > 0) {
|
||||
// Режим непрерывного соединения
|
||||
|
||||
// Ожидание
|
||||
sleep($timer);
|
||||
|
||||
// Повтор обработки
|
||||
goto keep_connect_wait;
|
||||
}
|
||||
|
||||
$advanced = true;
|
||||
|
||||
return $this->render('/search/index', compact('response', 'timer', 'advanced', 'query'));
|
||||
}
|
||||
}
|
||||
|
||||
// Метка: "Пропуск обработки"
|
||||
skip_search:
|
||||
|
||||
if (yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
return [
|
||||
'panel' => $this->renderPartial('/search/panel'),
|
||||
'hide' => (int) $auth_only,
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
} else {
|
||||
// GET-запрос
|
||||
|
||||
return $this->render('/search/index');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,285 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace app\controllers;
|
||||
|
||||
use Yii;
|
||||
use yii\filters\AccessControl;
|
||||
use yii\web\Controller;
|
||||
use yii\web\Response;
|
||||
use yii\filters\VerbFilter;
|
||||
use app\models\AccountForm;
|
||||
use app\models\ContactForm;
|
||||
|
||||
class SiteController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function behaviors()
|
||||
{
|
||||
return [
|
||||
'access' => [
|
||||
'class' => AccessControl::class,
|
||||
'only' => ['logout'],
|
||||
'rules' => [
|
||||
[
|
||||
'actions' => ['logout'],
|
||||
'allow' => true,
|
||||
'roles' => ['@'],
|
||||
],
|
||||
],
|
||||
],
|
||||
'verbs' => [
|
||||
'class' => VerbFilter::class,
|
||||
'actions' => [
|
||||
'logout' => ['post'],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function actions()
|
||||
{
|
||||
return [
|
||||
'error' => [
|
||||
'class' => 'yii\web\ErrorAction',
|
||||
],
|
||||
'captcha' => [
|
||||
'class' => 'yii\captcha\CaptchaAction',
|
||||
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays homepage.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function actionIndex()
|
||||
{
|
||||
return $this->render('index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Identification action.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function actionIdentification()
|
||||
{
|
||||
if (Yii::$app->request->isAjax) {
|
||||
Yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
if (Yii::$app->user->isGuest) {
|
||||
return [
|
||||
'menu' => '<a onclick="authentication()">Вход</a>',
|
||||
'_csrf' => Yii::$app->request->getCsrfToken()
|
||||
];
|
||||
} else {
|
||||
$mail = Yii::$app->user->identity->mail;
|
||||
|
||||
return [
|
||||
'menu' => <<<HTML
|
||||
<p class="m-0">
|
||||
<a class="text-dark" href="/cart"><i class="fas fa-shopping-cart mr-4"></i></a>
|
||||
<a class="text-dark" href="/orders"><i class="fas fa-list mr-4"></i></a>
|
||||
<a class="text-dark" onclick="deauthentication()">Выход ($mail)</a>
|
||||
</p>
|
||||
HTML,
|
||||
'_csrf' => Yii::$app->request->getCsrfToken()
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Login action.
|
||||
*
|
||||
* @return Response|string
|
||||
*/
|
||||
public function actionAuthentication()
|
||||
{
|
||||
$model = new AccountForm(Yii::$app->request->post()['AccountForm'] ?? Yii::$app->request->get()['AccountForm'] ?? null);
|
||||
|
||||
if (Yii::$app->request->isAjax) {
|
||||
// AJAX-POST-запрос
|
||||
|
||||
Yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
if (!Yii::$app->user->isGuest) {
|
||||
// Аккаунт уже аутентифицирован
|
||||
Yii::$app->response->statusCode = 403;
|
||||
return [
|
||||
'form' => $this->renderPartial('index'),
|
||||
'_csrf' => Yii::$app->request->getCsrfToken()
|
||||
];
|
||||
}
|
||||
|
||||
if ($model->authentication()) {
|
||||
// Данные прошли проверку
|
||||
|
||||
return [
|
||||
'menu' => <<<HTML
|
||||
<p class="m-0">
|
||||
<a class="text-dark" href="/cart"><i class="fas fa-shopping-cart mr-4"></i></a>
|
||||
<a class="text-dark" href="/orders"><i class="fas fa-list mr-4"></i></a>
|
||||
<a class="text-dark" onclick="deauthentication()">Выход ($model->mail)</a>
|
||||
</p>
|
||||
HTML,
|
||||
'form' => $this->renderPartial('index'),
|
||||
'_csrf' => Yii::$app->request->getCsrfToken()
|
||||
];
|
||||
} else {
|
||||
// Данные не прошли проверку
|
||||
|
||||
Yii::$app->response->statusCode = 400;
|
||||
|
||||
return [
|
||||
'form' => $this->renderPartial('account', compact('model')),
|
||||
'_csrf' => Yii::$app->request->getCsrfToken()
|
||||
];
|
||||
}
|
||||
} else if (Yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
} else {
|
||||
// GET-запрос и прочие
|
||||
|
||||
if (!Yii::$app->user->isGuest) {
|
||||
// Аккаунт уже аутентифицирован
|
||||
Yii::$app->response->redirect('/');
|
||||
}
|
||||
}
|
||||
|
||||
return $this->render('authentication', compact('model'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout action.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function actionDeauthentication()
|
||||
{
|
||||
if (Yii::$app->request->isAjax) {
|
||||
// AJAX-POST-запрос
|
||||
|
||||
Yii::$app->response->format = Response::FORMAT_JSON;
|
||||
Yii::$app->user->logout();
|
||||
|
||||
return [
|
||||
'menu' => '<a onclick="authentication()">Вход</a>',
|
||||
'_csrf' => Yii::$app->request->getCsrfToken()
|
||||
];
|
||||
}
|
||||
|
||||
Yii::$app->response->redirect('/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Login action.
|
||||
*
|
||||
* @return Response|string
|
||||
*/
|
||||
public function actionRegistration()
|
||||
{
|
||||
$model = new AccountForm(Yii::$app->request->post()['AccountForm'] ?? Yii::$app->request->get()['AccountForm'] ?? null);
|
||||
$model->type = 0;
|
||||
|
||||
if (Yii::$app->request->isAjax) {
|
||||
// AJAX-POST-запрос
|
||||
|
||||
Yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
if (!Yii::$app->user->isGuest) {
|
||||
// Аккаунт уже аутентифицирован
|
||||
Yii::$app->response->statusCode = 302;
|
||||
return [
|
||||
'form' => $this->renderPartial('index'),
|
||||
'_csrf' => Yii::$app->request->getCsrfToken()
|
||||
];
|
||||
}
|
||||
|
||||
if ($model->registration()) {
|
||||
// Данные прошли проверку и аккаунт был создан
|
||||
|
||||
return [
|
||||
'menu' => <<<HTML
|
||||
<p class="m-0">
|
||||
<a class="text-dark" href="/cart"><i class="fas fa-shopping-cart mr-4"></i></a>
|
||||
<a class="text-dark" href="/orders"><i class="fas fa-list mr-4"></i></a>
|
||||
<a class="text-dark" onclick="deauthentication()">Выход ($model->mail)</a>
|
||||
</p>
|
||||
HTML,
|
||||
'form' => $this->renderPartial('index'),
|
||||
'_csrf' => Yii::$app->request->getCsrfToken()
|
||||
];
|
||||
} else {
|
||||
// Данные не прошли проверку
|
||||
|
||||
Yii::$app->response->statusCode = 400;
|
||||
|
||||
return [
|
||||
'form' => $this->renderPartial('account', compact('model')),
|
||||
'_csrf' => Yii::$app->request->getCsrfToken()
|
||||
];
|
||||
}
|
||||
} else if (Yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
return;
|
||||
} else {
|
||||
// GET-запрос и прочие
|
||||
|
||||
if (!Yii::$app->user->isGuest) {
|
||||
// Аккаунт уже аутентифицирован
|
||||
Yii::$app->response->redirect('/');
|
||||
}
|
||||
}
|
||||
|
||||
return $this->render('registration', compact('model'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays профиль
|
||||
*
|
||||
* @return Response|string
|
||||
*/
|
||||
public function actionProfile()
|
||||
{
|
||||
$model = new Account();
|
||||
|
||||
return $this->render('profile', compact('model'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays contact page.
|
||||
*
|
||||
* @return Response|string
|
||||
*/
|
||||
public function actionContact()
|
||||
{
|
||||
$model = new ContactForm();
|
||||
if ($model->load(Yii::$app->request->post()) && $model->contact(Yii::$app->params['adminEmail'])) {
|
||||
Yii::$app->session->setFlash('contactFormSubmitted');
|
||||
|
||||
return $this->refresh();
|
||||
}
|
||||
return $this->render('contact', [
|
||||
'model' => $model,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays about page.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function actionAbout()
|
||||
{
|
||||
return $this->render('about');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controllers;
|
||||
|
||||
use yii;
|
||||
use yii\web\Controller;
|
||||
use yii\web\UploadedFile;
|
||||
|
||||
use app\models\Request;
|
||||
use app\models\Account;
|
||||
|
||||
class SuppliersController extends Controller
|
||||
{
|
||||
public function actionIndex()
|
||||
{
|
||||
return $this->renderPartial('/suppliers/index');
|
||||
}
|
||||
|
||||
public function actionRequest()
|
||||
{
|
||||
return $this->renderPartial('/suppliers/request');
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo Сделать отправку только назначенным модераторам
|
||||
*/
|
||||
public function actionRequestSend()
|
||||
{
|
||||
// Инициализация данных запроса
|
||||
$request = yii::$app->request->post('Request') ?? yii::$app->request->get('Request');
|
||||
|
||||
// Запись поставщика
|
||||
Account::writeSupplier($request['name'], $request['phon'], $request['mail'], $file = UploadedFile::getInstance(new Request($request), 'file'));
|
||||
|
||||
yii::$app->mail_system->compose()
|
||||
->setFrom(yii::$app->params['mail']['system'])
|
||||
->setTo(yii::$app->params['mail']['info'])
|
||||
->setSubject('Регистрация поставщика')
|
||||
->setHtmlBody($this->renderPartial('/mails/supplier', $request))
|
||||
->attach($file->tempName, ['fileName' => $file->name])
|
||||
->send();
|
||||
|
||||
return $this->renderPartial('/suppliers/requested');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controllers;
|
||||
|
||||
use yii;
|
||||
use yii\web\Controller;
|
||||
use yii\web\Response;
|
||||
use yii\web\HttpException;
|
||||
use yii\web\UploadedFile;
|
||||
use yii\filters\AccessControl;
|
||||
|
||||
use app\models\Product;
|
||||
use app\models\Settings;
|
||||
use app\models\SupplyEdgeProduct;
|
||||
use app\models\Supply;
|
||||
use app\models\Account;
|
||||
use app\models\Notification;
|
||||
use app\models\OrderEdgeSupply;
|
||||
|
||||
use Exception;
|
||||
|
||||
class SupplyController extends Controller
|
||||
{
|
||||
public function behaviors()
|
||||
{
|
||||
return [
|
||||
'access' => [
|
||||
'class' => AccessControl::class,
|
||||
'rules' => [
|
||||
[
|
||||
'allow' => true,
|
||||
'actions' => [
|
||||
'index',
|
||||
]
|
||||
],
|
||||
[
|
||||
'allow' => true,
|
||||
'roles' => ['@'],
|
||||
'actions' => []
|
||||
],
|
||||
[
|
||||
'allow' => true,
|
||||
'actions' => [
|
||||
'read'
|
||||
],
|
||||
'matchCallback' => function ($rule, $action): bool {
|
||||
if (
|
||||
!yii::$app->user->isGuest
|
||||
&& (yii::$app->user->identity->type === 'administrator'
|
||||
|| yii::$app->user->identity->type === 'moderator')
|
||||
) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
],
|
||||
[
|
||||
'allow' => false,
|
||||
'roles' => ['?'],
|
||||
'denyCallback' => [$this, 'accessDenied']
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Чтение поставок
|
||||
*
|
||||
* @param int $page Страница
|
||||
*
|
||||
* @return string|array|null
|
||||
*/
|
||||
public function actionRead(int $page = 1): string|array|null
|
||||
{
|
||||
if (yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
// Инициализация входных параметров
|
||||
$amount = yii::$app->request->post('amount') ?? yii::$app->request->get('amount') ?? 20;
|
||||
$order = yii::$app->request->post('order') ?? yii::$app->request->get('order') ?? ['DESC'];
|
||||
|
||||
// Инициализация cookie
|
||||
$cookies = yii::$app->response->cookies;
|
||||
|
||||
// Чтение поставок
|
||||
$supplies = Supply::read(limit: $amount, page: $page, order: $order);
|
||||
|
||||
// Запись формата ответа
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
return [
|
||||
'supplies' => $this->renderPartial('/supply/list', compact('supplies', 'amount', 'page')),
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controllers;
|
||||
|
||||
use yii;
|
||||
use yii\web\Controller;
|
||||
use yii\web\Response;
|
||||
|
||||
use app\models\Terminal;
|
||||
|
||||
class TerminalController extends Controller
|
||||
{
|
||||
public function actionRead(): ?array
|
||||
{
|
||||
// Инициализация входных параметров
|
||||
$amount = (int) yii::$app->request->post('amount') ?? yii::$app->request->get('amount');
|
||||
|
||||
if ($amount < 501) {
|
||||
// Пройдена проверка
|
||||
|
||||
if (yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
// Запись формата ответа
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
return [
|
||||
'terminals' => Terminal::read($amount),
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
}
|
||||
} else {
|
||||
// Не пройдена проверка
|
||||
|
||||
// Запись кода ответа
|
||||
yii::$app->response->statusCode = 500;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controllers;
|
||||
|
||||
use yii;
|
||||
use yii\web\Controller;
|
||||
use yii\web\Response;
|
||||
|
||||
use app\models\Account;
|
||||
|
||||
class VerifyController extends Controller
|
||||
{
|
||||
public function actionIndex(string $vrfy = null): string|Response
|
||||
{
|
||||
if (isset($vrfy)) {
|
||||
// Подтверждение регистрации
|
||||
|
||||
if (Account::verification($vrfy, auth: true)) {
|
||||
// Успешно подтверждена регистрация
|
||||
|
||||
return $this->redirect('/profile');
|
||||
}
|
||||
|
||||
return ErrorController::throw('Ошибка подтверждения', 'Код не совпадает с тем, что мы отправили вам на почту, либо регистрация уже была подтверждена.\n Свяжитесь с администрацией');
|
||||
} else {
|
||||
// Простой запрос
|
||||
|
||||
if (yii::$app->user->isGuest) {
|
||||
// Пользователь не аутентифицирован
|
||||
|
||||
return yii::$app->response->redirect('/registration');
|
||||
} else {
|
||||
// Пользователь аутентифицирован
|
||||
|
||||
if (yii::$app->user->identity->vrfy === true) {
|
||||
// Регистрация аккаунта уже подтверждена
|
||||
|
||||
// Генерация хеша пароля
|
||||
yii::$app->user->identity->pswd = yii::$app->security->generatePasswordHash(yii::$app->user->identity->pswd);
|
||||
|
||||
// Запись в хранилище
|
||||
yii::$app->user->identity->update();
|
||||
|
||||
if (yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
// Запись формата ответа
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
return [
|
||||
'main' => $this->renderPartial('/profile/index'),
|
||||
'title' => 'Профиль',
|
||||
'redirect' => '/profile',
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
} else {
|
||||
// GET-запрос (подразумевается)
|
||||
|
||||
return $this->render('/profile/index');
|
||||
}
|
||||
} else {
|
||||
// Регистрация аккаунта ещё не подтверждена
|
||||
|
||||
if (yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
// Запись формата ответа
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
return $this->genPostVerify();
|
||||
} else {
|
||||
// GET-запрос (подразумевается)
|
||||
|
||||
return $this->render('/account/verify');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Отправить запрос на активацию
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function actionSend(): string|array
|
||||
{
|
||||
if (!yii::$app->user->isGuest) {
|
||||
// Пользователь аутентифицирован
|
||||
|
||||
// Регенерация кода подтверждения
|
||||
yii::$app->user->identity->verifyRegenerate();
|
||||
|
||||
// Отправка кода подтверждения на почту
|
||||
yii::$app->user->identity->sendMailVerify();
|
||||
|
||||
if (yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
// Запись формата ответа
|
||||
yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
return $this->genPostVerify();
|
||||
} else {
|
||||
// GET-запрос (подразумевается)
|
||||
|
||||
return $this->render('/account/verify');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Генерация данных для POST-запроса с переадресацией на страницу подтверждения
|
||||
*/
|
||||
function genPostVerify(): array {
|
||||
return [
|
||||
'main' => $this->renderPartial('/account/verify'),
|
||||
'title' => 'Подтверждение аккаунта',
|
||||
'redirect' => '/account/verify',
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
use explosivebit\arangodb\Migration;
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m201219_074926_create_account_collection extends Migration
|
||||
{
|
||||
|
@ -11,10 +11,6 @@ class m201219_074926_create_account_collection extends Migration
|
|||
|
||||
public function down()
|
||||
{
|
||||
// $this->delete('accounts', 'mail');
|
||||
// $this->delete('accounts', 'name');
|
||||
// $this->delete('accounts', 'pswd');
|
||||
|
||||
$this->dropCollection('account');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210101_092505_create_product_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('product');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('product');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210107_163448_create_supply_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('supply');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('supply');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210108_014505_create_account_edge_supply_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('account_edge_supply', ['Type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('account_edge_supply');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210108_212826_create_product_group_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('product_group');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('product_group');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210108_221446_create_product_edge_product_group_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('product_edge_product_group', ['Type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('product_edge_product_group');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210108_222132_create_supply_edge_product_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('supply_edge_product', ['Type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('supply_edge_product');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210108_222740_create_product_edge_product_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('product_edge_product', ['Type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('product_edge_product');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210109_214817_create_supply_group_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('supply_group');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('supply_group');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210109_214833_create_supply_edge_supply_group_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('supply_edge_supply_group', ['Type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('supply_edge_supply_group');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210111_044635_create_supply_edge_supply_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('supply_edge_supply', ['Type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('supply_edge_supply');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210112_010347_create_product_group_edge_product_group_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('product_group_edge_product_group', ['Type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('product_group_edge_product_group');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210112_010411_create_supply_group_edge_supply_group_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('supply_group_edge_supply_group', ['Type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('supply_group_edge_supply_group');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210112_034135_create_requisite_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('requisite');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('requisite');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210112_034232_create_supply_edge_requisite_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('supply_edge_requisite', ['Type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('supply_edge_requisite');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210113_021800_create_purchase_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('purchase');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('purchase');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210113_021905_create_account_edge_purchase_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('account_edge_purchase', ['Type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('account_edge_purchase');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210113_021917_create_purchase_edge_supply_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('purchase_edge_supply', ['Type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('purchase_edge_supply');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210206_154140_create_search_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('search', []);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('search');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210206_154210_create_account_edge_search_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('account_edge_search', ['Type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('account_edge_search');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210209_185314_create_notification_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('notification', []);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('notification');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210209_185328_create_account_edge_notification_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('account_edge_notification', ['type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('account_edge_notification');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210223_121142_create_settings_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('settings', []);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('settings');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210223_145042_create_settings_edge_settings_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('settings_edge_settings', ['type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('settings_edge_settings');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210303_192326_create_order_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('order', []);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('order');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210303_192451_create_order_edge_supply_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('order_edge_supply', ['type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('order_edge_supply');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210307_000210_create_account_edge_order_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('account_edge_order', ['type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('account_edge_order');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210314_133722_create_session_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('session', []);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('session');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210314_133926_create_account_edge_session_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createCollection('account_edge_session', ['type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('account_edge_session');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210502_102203_create_terminal_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
/**
|
||||
* @param string Название коллекции
|
||||
* @param array Тип коллекции (2 - документ, 3 - ребро)
|
||||
*/
|
||||
$this->createCollection('terminal', ['type' => 2]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('terminal');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210502_102358_create_dellin_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
/**
|
||||
* @param string Название коллекции
|
||||
* @param array Тип коллекции (2 - документ, 3 - ребро)
|
||||
*/
|
||||
$this->createCollection('dellin', ['type' => 2]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('dellin');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210510_180939_create_request_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
/**
|
||||
* @param string Название коллекции
|
||||
* @param array Тип коллекции (2 - документ, 3 - ребро)
|
||||
*/
|
||||
$this->createCollection('request', ['type' => 2]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('request');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m210512_121658_create_cdek_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
/**
|
||||
* @param string Название коллекции
|
||||
* @param array Тип коллекции (2 - документ, 3 - ребро)
|
||||
*/
|
||||
$this->createCollection('cdek', ['type' => 2]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('cdek');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m211123_114511_create_import_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
/**
|
||||
* @param string Название коллекции
|
||||
* @param array Тип коллекции (2 - документ, 3 - ребро)
|
||||
*/
|
||||
$this->createCollection('import', ['type' => 2]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('import');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m211123_120136_create_import_edge_supply_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
/**
|
||||
* @param string Название коллекции
|
||||
* @param array Тип коллекции (2 - документ, 3 - ребро)
|
||||
*/
|
||||
$this->createCollection('import_edge_supply', ['type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('import_edge_supply');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m211123_173801_create_import_edge_account_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
/**
|
||||
* @param string Название коллекции
|
||||
* @param array Тип коллекции (2 - документ, 3 - ребро)
|
||||
*/
|
||||
$this->createCollection('import_edge_account', ['type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('import_edge_account');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m211221_183410_create_warehouse_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
/**
|
||||
* @param string Название коллекции
|
||||
* @param array Тип коллекции (2 - документ, 3 - ребро)
|
||||
*/
|
||||
$this->createCollection('warehouse', ['type' => 2]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('warehouse');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m211221_183447_create_warehouse_edge_import_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
/**
|
||||
* @param string Название коллекции
|
||||
* @param array Тип коллекции (2 - документ, 3 - ребро)
|
||||
*/
|
||||
$this->createCollection('warehouse_edge_import', ['type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('warehouse_edge_import');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m211221_193454_create_account_edge_warehouse_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
/**
|
||||
* @param string Название коллекции
|
||||
* @param array Тип коллекции (2 - документ, 3 - ребро)
|
||||
*/
|
||||
$this->createCollection('account_edge_warehouse', ['type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('account_edge_warehouse');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m220808_185553_create_file_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
/**
|
||||
* @param string Название коллекции
|
||||
* @param array Тип коллекции (2 - документ, 3 - ребро)
|
||||
*/
|
||||
$this->createCollection('file', ['type' => 2]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('file');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
use mirzaev\yii2\arangodb\Migration;
|
||||
|
||||
class m220817_210350_create_import_edge_file_collection extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
/**
|
||||
* @param string Название коллекции
|
||||
* @param array Тип коллекции (2 - документ, 3 - ребро)
|
||||
*/
|
||||
$this->createCollection('import_edge_file', ['type' => 3]);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropCollection('import_edge_file');
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\models;
|
||||
|
||||
class AccountEdgeNotification extends Edge
|
||||
{
|
||||
public static function collectionName(): string
|
||||
{
|
||||
return 'account_edge_notification';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\models;
|
||||
|
||||
class AccountEdgeOrder extends Edge
|
||||
{
|
||||
public static function collectionName(): string
|
||||
{
|
||||
return 'account_edge_order';
|
||||
}
|
||||
|
||||
/**
|
||||
* Свойства
|
||||
*/
|
||||
public function attributes(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::attributes(),
|
||||
[
|
||||
'stts'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метки свойств
|
||||
*/
|
||||
public function attributeLabels(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::attributeLabels(),
|
||||
[
|
||||
'stts' => 'Статус'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Правила
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::rules(),
|
||||
[
|
||||
[
|
||||
[
|
||||
'stts'
|
||||
],
|
||||
'string'
|
||||
]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Перед сохранением
|
||||
*
|
||||
* @todo Подождать обновление от ебаного Yii2 и добавить
|
||||
* проверку типов передаваемых параметров
|
||||
*/
|
||||
public function beforeSave($data): bool
|
||||
{
|
||||
if (parent::beforeSave($data)) {
|
||||
if ($this->isNewRecord) {
|
||||
$this->stts = 'current';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Поиск по идентификатору заказа
|
||||
*
|
||||
* @param string $order_id Идентификатор записи заказа в базе данных
|
||||
* @param int $limit Ограничение
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public static function searchByOrder(string $order_id, int $limit = 1): ?array
|
||||
{
|
||||
return self::find()->where(['_to' => $order_id])->limit($limit)->all();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\models;
|
||||
|
||||
class AccountEdgePurchase extends Edge
|
||||
{
|
||||
public static function collectionName(): string
|
||||
{
|
||||
return 'account_edge_purchase';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\models;
|
||||
|
||||
class AccountEdgeSearch extends Edge
|
||||
{
|
||||
public static function collectionName(): string
|
||||
{
|
||||
return 'account_edge_search';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\models;
|
||||
|
||||
class AccountEdgeSupply extends Edge
|
||||
{
|
||||
public static function collectionName(): string
|
||||
{
|
||||
return 'account_edge_supply';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\models;
|
||||
|
||||
use app\models\Account;
|
||||
|
||||
/**
|
||||
* Связь аккаунтов и складов
|
||||
*/
|
||||
class AccountEdgeWarehouse extends Edge
|
||||
{
|
||||
/**
|
||||
* Имя коллекции
|
||||
*/
|
||||
public static function collectionName(): string
|
||||
{
|
||||
return 'account_edge_warehouse';
|
||||
}
|
||||
}
|
|
@ -1,10 +1,14 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\models;
|
||||
|
||||
use Yii;
|
||||
use yii;
|
||||
use yii\base\Model;
|
||||
|
||||
use app\models\Account;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* AccountForm is the model behind the login form.
|
||||
|
@ -14,37 +18,62 @@ use app\models\Account;
|
|||
*/
|
||||
class AccountForm extends Model
|
||||
{
|
||||
const SCENARIO_REGISTRATION = 'registration';
|
||||
const SCENARIO_REGISTRATION_END = 'registration_end';
|
||||
const SCENARIO_AUTHENTICATION = 'authentication';
|
||||
|
||||
public $mail;
|
||||
public $pswd;
|
||||
public $auto = true;
|
||||
|
||||
/**
|
||||
* Тип обработки
|
||||
*
|
||||
* Регистрация: 0
|
||||
* Аутентификация: 1
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $type = 1;
|
||||
public $auto = false;
|
||||
public $rept;
|
||||
public $pols;
|
||||
|
||||
private $account = false;
|
||||
|
||||
|
||||
/**
|
||||
* @return array the validation rules.
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
// Обязательные поля
|
||||
[['mail', 'pswd'], 'required', 'message' => 'Заполните поле'],
|
||||
[
|
||||
[
|
||||
'mail',
|
||||
],
|
||||
'required',
|
||||
'message' => 'Заполните поле'
|
||||
],
|
||||
// Обязательные поля для аутентификации
|
||||
[
|
||||
[
|
||||
'pswd',
|
||||
],
|
||||
'required',
|
||||
'message' => 'Заполните поле',
|
||||
'on' => self::SCENARIO_AUTHENTICATION
|
||||
],
|
||||
// Функция "Запомнить меня"
|
||||
['auto', 'boolean'],
|
||||
// Проверка почты
|
||||
['mail', 'validateMail', 'message'=>'Неправильная почта'],
|
||||
[
|
||||
'auto',
|
||||
'boolean',
|
||||
'on' => self::SCENARIO_AUTHENTICATION
|
||||
],
|
||||
// Проверка почты,
|
||||
[
|
||||
'mail',
|
||||
'email',
|
||||
'message' => 'Проверьте почту'
|
||||
],
|
||||
[
|
||||
'mail',
|
||||
'validateMail',
|
||||
'on' => self::SCENARIO_REGISTRATION
|
||||
],
|
||||
// Проверка пароля
|
||||
['pswd', 'validatePassword', 'message'=>'Неправильный пароль'],
|
||||
[
|
||||
'pswd',
|
||||
'validatePassword',
|
||||
'on' => self::SCENARIO_AUTHENTICATION
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -53,46 +82,71 @@ class AccountForm extends Model
|
|||
return [
|
||||
'mail' => 'Почта',
|
||||
'pswd' => 'Пароль',
|
||||
'auto' => 'Запомнить'
|
||||
'auto' => '<i class="fas fa-unlock"></i>',
|
||||
'pols' => 'Политика конфедециальности'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $attribute the attribute currently being validated
|
||||
* @param array $params the additional name-value pairs given in the rule
|
||||
*/
|
||||
public function validateMail($attribute, $params)
|
||||
{
|
||||
if (!$this->hasErrors() && $this->type === 0) {
|
||||
if (!$this->hasErrors()) {
|
||||
// Проблем нет, обрабатывается событие регистрации
|
||||
|
||||
$account = $this->getAccount();
|
||||
|
||||
if (!$account || !$account->validateMail($this->mail)) {
|
||||
if (is_null($account)) {
|
||||
// Не удалось проверить аккаунт
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$account || $account->validateMail($this->mail)) {
|
||||
// Проверка не пройдена
|
||||
$this->addError($attribute, 'Почта уже привязана к другому аккаунту');
|
||||
|
||||
$this->addError($attribute, 'Почта уже привязана');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the password.
|
||||
* This method serves as the inline validation for password.
|
||||
*
|
||||
* @param string $attribute the attribute currently being validated
|
||||
* @param array $params the additional name-value pairs given in the rule
|
||||
*/
|
||||
public function validatePassword($attribute, $params)
|
||||
{
|
||||
if (!$this->hasErrors() && $this->type === 1) {
|
||||
if (!$this->hasErrors()) {
|
||||
// Проблем нет, обрабатывается событие аутентификации
|
||||
|
||||
$account = $this->getAccount();
|
||||
|
||||
if (!$account || !$account->validatePassword($this->pswd)) {
|
||||
// Проверка не пройдена
|
||||
if (is_null($account)) {
|
||||
// Не удалось проверить аккаунт
|
||||
|
||||
$this->addError($attribute, 'Проверьте входные данные');
|
||||
return;
|
||||
}
|
||||
|
||||
if ($account) {
|
||||
// Удалось инициализировать аккаунт
|
||||
|
||||
try {
|
||||
if (!$account->validatePasswordWithHash($this->pswd)) {
|
||||
// Не пройдена проверка с хешем
|
||||
|
||||
throw new exception;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// Не пройдена проверка с хешем
|
||||
|
||||
try {
|
||||
if (!$account->validatePasswordWithoutHash($this->pswd)) {
|
||||
// Не пройдена проверка с паролем
|
||||
|
||||
throw new exception;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// Проверка без хеша не пройдена
|
||||
|
||||
$this->addError($attribute, 'Проверьте пароль');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->addError($attribute, 'Не удалось идентифицировать аккаунт');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,13 +155,21 @@ class AccountForm extends Model
|
|||
* Logs in a account using the provided accountname and password.
|
||||
* @return bool whether the account is logged in successfully
|
||||
*/
|
||||
public function authentication()
|
||||
public function authentication(string $mail = null, string $pswd = null)
|
||||
{
|
||||
if (isset($mail, $pswd)) {
|
||||
$this->mail = $mail;
|
||||
$this->pswd = $pswd;
|
||||
}
|
||||
|
||||
// Регистронезависимая почта
|
||||
$this->mail = mb_strtolower($this->mail);
|
||||
|
||||
if (isset($this->mail, $this->pswd) && $this->validate()) {
|
||||
// Проверка пройдена
|
||||
|
||||
// Аутентификация
|
||||
return Yii::$app->user->login($this->getAccount(), $this->auto ? 3600*24*30 : 0);
|
||||
return yii::$app->user->login($this->getAccount(), $this->auto ? 3600 * 24 * 30 : 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -121,15 +183,33 @@ class AccountForm extends Model
|
|||
// Инициализация нового аккаунта
|
||||
$this->account = new Account();
|
||||
|
||||
if (isset($this->mail, $this->pswd) && $this->validate()) {
|
||||
if ($this->validate()) {
|
||||
// Проверка пройдена
|
||||
|
||||
// Запись параметров
|
||||
$this->account->mail = $this->mail;
|
||||
$this->account->pswd = Yii::$app->security->generatePasswordHash($this->pswd);
|
||||
// $this->account->pswd = yii::$app->security->generatePasswordHash(Account::passwordGenerate());
|
||||
$this->account->pswd = $this->pswd = Account::passwordGenerate();
|
||||
|
||||
if (($account = Account::findByMail($this->mail)) || isset($account) && $account->vrfy !== true) {
|
||||
// Аккаунт найден, но не подтверждён
|
||||
|
||||
// Удаление аккаунта (сейчас его создадим снова)
|
||||
$account->delete();
|
||||
}
|
||||
|
||||
// Регистрация
|
||||
return $this->account->save();
|
||||
if ($this->account->save()) {
|
||||
// Успешно завершена регистрация или обновлены данные не до конца зарегистрировавшегося пользователя
|
||||
|
||||
// Генерация индекса
|
||||
Account::generateIndexes([$this->account]);
|
||||
|
||||
// Отправка письма для подтверждения почты
|
||||
$this->account->sendMailVerify();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\models;
|
||||
|
||||
use CdekSDK2\Client;
|
||||
|
||||
class Cdek extends Document
|
||||
{
|
||||
public static function collectionName(): string
|
||||
{
|
||||
return 'cdek';
|
||||
}
|
||||
|
||||
public function attributes(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::attributes(),
|
||||
[
|
||||
'data'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function attributeLabels(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::attributeLabels(),
|
||||
[
|
||||
'data' => 'Данные ДеловыеЛинии',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Поиск по идентификатору города
|
||||
*/
|
||||
public static function searchByCityId(string $id): ?static
|
||||
{
|
||||
return static::findOne(['data["id"]' => $id]);
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace app\models;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Model;
|
||||
|
||||
/**
|
||||
* ContactForm is the model behind the contact form.
|
||||
*/
|
||||
class ContactForm extends Model
|
||||
{
|
||||
public $name;
|
||||
public $email;
|
||||
public $subject;
|
||||
public $body;
|
||||
public $verifyCode;
|
||||
|
||||
|
||||
/**
|
||||
* @return array the validation rules.
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
// name, email, subject and body are required
|
||||
[['name', 'email', 'subject', 'body'], 'required'],
|
||||
// email has to be a valid email address
|
||||
['email', 'email'],
|
||||
// verifyCode needs to be entered correctly
|
||||
['verifyCode', 'captcha'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array customized attribute labels
|
||||
*/
|
||||
public function attributeLabels()
|
||||
{
|
||||
return [
|
||||
'verifyCode' => 'Verification Code',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an email to the specified email address using the information collected by this model.
|
||||
* @param string $email the target email address
|
||||
* @return bool whether the model passes validation
|
||||
*/
|
||||
public function contact($email)
|
||||
{
|
||||
if ($this->validate()) {
|
||||
Yii::$app->mailer->compose()
|
||||
->setTo($email)
|
||||
->setFrom([Yii::$app->params['senderEmail'] => Yii::$app->params['senderName']])
|
||||
->setReplyTo([$this->email => $this->name])
|
||||
->setSubject($this->subject)
|
||||
->setTextBody($this->body)
|
||||
->send();
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\models;
|
||||
|
||||
use ArangoDBClient\Document as ArangoDBDocument;
|
||||
|
||||
class Dellin extends Document
|
||||
{
|
||||
public static function collectionName(): string
|
||||
{
|
||||
return 'dellin';
|
||||
}
|
||||
|
||||
public function attributes(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::attributes(),
|
||||
[
|
||||
'data'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function attributeLabels(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::attributeLabels(),
|
||||
[
|
||||
'data' => 'Данные ДеловыеЛинии',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Поиск по идентификатору города
|
||||
*
|
||||
* @param string $id Идентификатор города
|
||||
*/
|
||||
public static function searchByCityId(string $id): ?static
|
||||
{
|
||||
return static::findOne(['data["id"]' => $id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Поиск по КЛАДР-коду города
|
||||
*
|
||||
* @param string $id Код КЛАДР города
|
||||
*/
|
||||
public static function searchByCityKladr(string $code): ?static
|
||||
{
|
||||
return static::findOne(['data["code"]' => $code]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Поиск по идентификатору терминала
|
||||
*
|
||||
* @param int $id Идентификатор терминала
|
||||
* @param bool $terminal_data_only Запрос только данных терминала
|
||||
*/
|
||||
public static function searchByTerminalId(int $id, bool $terminal_data_only = false): bool|static|array|null|ArangoDBDocument
|
||||
{
|
||||
if ($terminal_data_only) {
|
||||
return static::find()->foreach(['terminal' => self::collectionName() . '.data["terminals"]["terminal"]'])->where(['terminal["id"] == "' . $id . '"'])->select('terminal')->createCommand()->execute()->getAll()[0];
|
||||
}
|
||||
|
||||
return static::find()->foreach(['terminal' => self::collectionName() . '.data["terminals"]["terminal"]'])->where(['terminal["id"] == "' . $id . '"'])->one();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,244 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\models;
|
||||
|
||||
use yii;
|
||||
|
||||
use mirzaev\yii2\arangodb\ActiveRecord;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Документ
|
||||
*/
|
||||
abstract class Document extends ActiveRecord
|
||||
{
|
||||
/**
|
||||
* Имя коллекции
|
||||
*/
|
||||
public static function collectionName(): string
|
||||
{
|
||||
throw new Exception('Не инициализировано название коллекции');
|
||||
|
||||
return 'document';
|
||||
}
|
||||
|
||||
/**
|
||||
* Свойства
|
||||
*/
|
||||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'_key',
|
||||
'jrnl'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Метки свойств
|
||||
*/
|
||||
public function attributeLabels(): array
|
||||
{
|
||||
return [
|
||||
'_key' => 'Ключ',
|
||||
'jrnl' => 'Журнал'
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Правила
|
||||
*
|
||||
* @todo Добавить проверку существования аккаунта
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Перед сохранением
|
||||
*
|
||||
* @todo Подождать обновление от ебаного Yii2 и добавить
|
||||
* проверку типов передаваемых параметров
|
||||
*/
|
||||
public function beforeSave($create): bool
|
||||
{
|
||||
if (parent::beforeSave($create)) {
|
||||
// Пройдена родительская проверка
|
||||
|
||||
if ($this->isNewRecord) {
|
||||
// Новая запись
|
||||
|
||||
// Запись в журнал
|
||||
$this->jrnl = array_merge(
|
||||
[[
|
||||
'date' => time(),
|
||||
'account' => yii::$app->user->id ?? 'system',
|
||||
'action' => 'create'
|
||||
]],
|
||||
$this->jrnl ?? []
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Журнал
|
||||
*
|
||||
* Записывает данные в журнал
|
||||
*
|
||||
* @param string $action
|
||||
*
|
||||
* @return int|bool Время записанное в журнале или false, если не удалось записать
|
||||
*/
|
||||
public function journal(string $action = 'update', array ...$data): int|bool
|
||||
{
|
||||
// Инициализация
|
||||
if (isset($this->jrnl) && is_array($this->jrnl)) {
|
||||
} else {
|
||||
$this->jrnl = [];
|
||||
}
|
||||
|
||||
// Генерация
|
||||
$this->jrnl = array_merge(
|
||||
$this->jrnl,
|
||||
[array_merge(
|
||||
[
|
||||
'date' => $time = time(),
|
||||
'account' => yii::$app->user->id ?? 'system',
|
||||
'action' => $action
|
||||
],
|
||||
[
|
||||
'data' => $data
|
||||
]
|
||||
)]
|
||||
);
|
||||
|
||||
// Запись и возврат
|
||||
return $this->update() ? $time : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Чтение идентификатора
|
||||
*/
|
||||
public function readId(): ?string
|
||||
{
|
||||
return isset($this->_key) && static::collectionName() ? static::collectionName() . '/' . $this->_key : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Поиск
|
||||
*/
|
||||
public static function search(array $where, $limit = 1): array
|
||||
{
|
||||
return static::find()->where($where)->limit($limit)->all();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Поиск по идентификатору
|
||||
*/
|
||||
public static function searchById(string $_id): ?static
|
||||
{
|
||||
return static::findOne(['_id' => $_id]);
|
||||
}
|
||||
|
||||
public static function readLast(): static|null|bool
|
||||
{
|
||||
return static::find()->orderBy(['DESC'])->one();
|
||||
}
|
||||
|
||||
/**
|
||||
* Чтение всех записей
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public static function readAll(): array
|
||||
{
|
||||
return static::find()->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Чтение записей по максимальному ограничению
|
||||
*/
|
||||
public static function read(?array $where = [], int $limit = 100, int $page = 1, ?array $order = null): array
|
||||
{
|
||||
return static::find()->where($where)->orderby($order)->limit($limit)->offset(($page - 1) * $limit)->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Чтение количества записей
|
||||
*/
|
||||
public static function readAmount(): int
|
||||
{
|
||||
return static::find()->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверка на то, что в свойство передан массив
|
||||
*/
|
||||
public function arrayValidator(string $attribute, array $params = null): void
|
||||
{
|
||||
if (is_array($this->$attribute)) {
|
||||
return;
|
||||
} else {
|
||||
$this->addError($attribute, 'Передан не массив');
|
||||
}
|
||||
|
||||
$this->addError($attribute, 'Не пройдена проверка: "arrayValidator"');
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверка на то, что в свойство передан массив и он хранит циферные значения
|
||||
*/
|
||||
public function arrayWithNumbersValidator(string $attribute, array $params = null): void
|
||||
{
|
||||
try {
|
||||
if (is_array($this->$attribute)) {
|
||||
|
||||
foreach ($this->$attribute as $value) {
|
||||
if (!(bool) preg_match('/^[0-9\.]*$/m', $value)) {
|
||||
$this->addError($attribute, 'В массиве найдены запрещённые символы');
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
} else {
|
||||
$this->addError($attribute, 'Передан не массив');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->addError($attribute, $e->getMessage());
|
||||
}
|
||||
|
||||
$this->addError($attribute, 'Не пройдена проверка: "arrayWithNumbersValidator"');
|
||||
}
|
||||
|
||||
/**
|
||||
* Конвертировать _id в _key
|
||||
*/
|
||||
private static function keyFromId(string $_id): ?string
|
||||
{
|
||||
preg_match_all('/\/([0-9]+)$/m', $_id, $mathes);
|
||||
|
||||
return $mathes[1][0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Статический вызов
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $args
|
||||
*/
|
||||
public static function __callStatic(string $name, array $args): mixed {
|
||||
return match ($name) {
|
||||
'keyFromId' => self::keyFromId(...$args)
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,220 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\models;
|
||||
|
||||
/**
|
||||
* Ребро
|
||||
*/
|
||||
abstract class Edge extends Document
|
||||
{
|
||||
/**
|
||||
* Свойства
|
||||
*/
|
||||
public function attributes(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::attributes(),
|
||||
[
|
||||
'_from',
|
||||
'_to',
|
||||
'type'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метки свойств
|
||||
*/
|
||||
public function attributeLabels(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::attributeLabels(),
|
||||
[
|
||||
'_from' => 'От кого',
|
||||
'_to' => 'К кому',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Правила
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::rules(),
|
||||
[
|
||||
[
|
||||
['_from', '_to'],
|
||||
'required',
|
||||
'message' => 'Заполните поле: {attribute}'
|
||||
],
|
||||
[
|
||||
'type',
|
||||
'string'
|
||||
]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Перед сохранением
|
||||
*
|
||||
* @todo Подождать обновление от ебаного Yii2 и добавить
|
||||
* проверку типов передаваемых параметров
|
||||
*/
|
||||
public function beforeSave($data): bool
|
||||
{
|
||||
if (parent::beforeSave($data)) {
|
||||
if ($this->isNewRecord) {
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Записать (с проверкой на существование)
|
||||
*
|
||||
* Создаст ребро только в том случае, если его аналога не существует
|
||||
*
|
||||
* @param string $_from Идентификатор отправителя (_id)
|
||||
* @param string $_from Идентификатор получетеля (_id)
|
||||
* @param string $type Дополнительное поле - тип взаимосвязи
|
||||
* @param string $data Дополнительные данные
|
||||
*
|
||||
* @todo
|
||||
* 1. Удалить $type и оставить только $data
|
||||
*/
|
||||
public static function writeSafe(string $_from, string $_to, string $type = '', array $data = []): ?static
|
||||
{
|
||||
if ($edge = self::searchByVertex($_from, $_to, limit: 1)) {
|
||||
// Найдено в базе данных
|
||||
|
||||
return $edge[0];
|
||||
}
|
||||
|
||||
return self::write($_from, $_to, $type, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Записать
|
||||
*
|
||||
* @param string $_from Идентификатор отправителя (_id)
|
||||
* @param string $_from Идентификатор получетеля (_id)
|
||||
* @param string $type Дополнительное поле - тип взаимосвязи @deprecated
|
||||
* @param string $data Дополнительные данные
|
||||
*
|
||||
* @todo
|
||||
* 1. Удалить $type и оставить только $data
|
||||
*/
|
||||
public static function write(string $_from, string $_to, string $type = '', array $data = []): ?static
|
||||
{
|
||||
// Инициализация
|
||||
$edge = new static;
|
||||
|
||||
// Настройка
|
||||
$edge->_from = $_from;
|
||||
$edge->_to = $_to;
|
||||
if (isset($type)) $edge->type = $type;
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
if (is_int($key)) {
|
||||
// Обычная запись
|
||||
|
||||
$edge->{$value} = true;
|
||||
} else {
|
||||
// Ассоциативная запись
|
||||
|
||||
$edge->{$key} = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $edge->save() ? $edge : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Поиск ребра по его вершинам
|
||||
*
|
||||
* @param string $_from Идентификатор исходящей вершины
|
||||
* @param string $_to Идентификатор входящей вершины
|
||||
* @param string|null $type deprecated
|
||||
* @param int $limit Ограничение по количеству
|
||||
* @param array|null $filter Фильтр (where())
|
||||
*/
|
||||
public static function searchByVertex(string $_from, string $_to, string|null $type = null, int $limit = 1, array|null $filter = null): array|null
|
||||
{
|
||||
$query = self::find()->where([
|
||||
'_from' => $_from,
|
||||
'_to' => $_to
|
||||
]);
|
||||
|
||||
if (isset($type)) {
|
||||
$query->where(['type' => $type]);
|
||||
}
|
||||
|
||||
if (isset($filter)) {
|
||||
$query->where($filter);
|
||||
}
|
||||
|
||||
return $query->limit($limit)->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Поиск рёбер по направлению
|
||||
*/
|
||||
public static function searchByDirection(string $_from, string $direction = 'OUTBOUND', string $type = '', array $where = [], int $limit = 1, int $page = 1): static|array|null
|
||||
{
|
||||
if (str_contains($direction, 'OUTBOUND')) {
|
||||
// Исходящие рёбра
|
||||
|
||||
if (isset($where)) {
|
||||
// Получен параметр $where
|
||||
|
||||
// Реинициализация
|
||||
$where = array_merge($where + ['_from' => $_from]);
|
||||
} else {
|
||||
// Не получен параметр $where
|
||||
|
||||
// Реинициализация
|
||||
$where = array_merge(['_from' => $_from, 'type' => $type]);
|
||||
}
|
||||
|
||||
$query = static::find()->where($where);
|
||||
} else if (str_contains($direction, 'INBOUND')) {
|
||||
// Входящие рёбра
|
||||
|
||||
if (isset($where)) {
|
||||
// Получен параметр $where
|
||||
|
||||
// Реинициализация
|
||||
$where = array_merge($where + ['_to' => $_from]);
|
||||
} else {
|
||||
// Не получен параметр $where
|
||||
|
||||
// Реинициализация
|
||||
$where = array_merge(['_to' => $_from, 'type' => $type]);
|
||||
}
|
||||
|
||||
$query = static::find()->where($where);
|
||||
} else if (str_contains($direction, 'ANY')) {
|
||||
// Исходящие и входящие рёбра
|
||||
|
||||
return static::searchByDirection(_from: $_from, direction: 'OUTBOUND', type: $type, where: $where, limit: $limit, page: $page) + static::searchByDirection(_from: $_from, direction: 'INBOUND', type: $type, where: $where, limit: $limit, page: $page);
|
||||
}
|
||||
|
||||
if ($limit < 2) {
|
||||
// Одно ребро или меньше
|
||||
|
||||
return $query->one();
|
||||
} else {
|
||||
// Несколько рёбер
|
||||
|
||||
return $query->limit($limit)->offset($limit * ($page - 1))->all();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\models;
|
||||
|
||||
use ArangoDBClient\Document as ArangoDBDocument;
|
||||
|
||||
use app\models\traits\SearchByEdge;
|
||||
use app\models\ImportEdgeFile;
|
||||
|
||||
class File extends Document
|
||||
{
|
||||
use SearchByEdge;
|
||||
|
||||
public static function collectionName(): string
|
||||
{
|
||||
return 'file';
|
||||
}
|
||||
|
||||
public function attributes(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::attributes(),
|
||||
[
|
||||
'type',
|
||||
'path',
|
||||
'name',
|
||||
'user',
|
||||
'stts',
|
||||
'meta'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function attributeLabels(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::attributeLabels(),
|
||||
[
|
||||
'type' => 'Тип файла',
|
||||
'path' => 'Относительный от хранилища путь до файла',
|
||||
'name' => 'Название файла',
|
||||
'user' => 'Пользователь управляющий файлом',
|
||||
'stts' => 'Статус',
|
||||
'meta' => 'Метаданные'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Перед сохранением
|
||||
*
|
||||
* @todo Подождать обновление от ебаного Yii2 и добавить
|
||||
* проверку типов передаваемых параметров
|
||||
*/
|
||||
public function beforeSave($data): bool
|
||||
{
|
||||
if (parent::beforeSave($data)) {
|
||||
if ($this->isNewRecord) {
|
||||
if ($this->type = 'supplies excel') {
|
||||
// Список поставок
|
||||
|
||||
$this->stts = 'needed to load';
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function searchSuppliesNeededToLoad(int $amount = 3): array
|
||||
{
|
||||
return static::find()->where(['stts' => 'needed to load'])->limit($amount)->all();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Поиск по инстанции импорта
|
||||
*
|
||||
* @param Import $import Инстанция импорта
|
||||
*/
|
||||
public static function searchByImport(Import $import): ?File
|
||||
{
|
||||
return new File(self::searchByEdge(
|
||||
from: 'import',
|
||||
to: 'file',
|
||||
subquery_where: [
|
||||
[
|
||||
'import._id' => $import->readId()
|
||||
]
|
||||
],
|
||||
where: 'import_edge_file[0]._id != null',
|
||||
select: 'file',
|
||||
limit: 1
|
||||
)[0]) ?? null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\models;
|
||||
|
||||
use yii;
|
||||
|
||||
use app\models\traits\SearchByEdge;
|
||||
use app\models\Account;
|
||||
|
||||
/**
|
||||
* Импорт поставок
|
||||
*
|
||||
* Хранит в себе связи с поставками которые были загружены вместе
|
||||
*/
|
||||
class Import extends Document
|
||||
{
|
||||
use SearchByEdge;
|
||||
|
||||
/**
|
||||
* Имя коллекции
|
||||
*/
|
||||
public static function collectionName(): string
|
||||
{
|
||||
return 'import';
|
||||
}
|
||||
|
||||
/**
|
||||
* Свойства
|
||||
*/
|
||||
public function attributes(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::attributes(),
|
||||
[
|
||||
'name',
|
||||
'file'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метки свойств
|
||||
*/
|
||||
public function attributeLabels(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::attributeLabels(),
|
||||
[
|
||||
'name' => 'Название',
|
||||
'file' => 'Файл'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Правила
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::rules(),
|
||||
[
|
||||
[
|
||||
[
|
||||
'file',
|
||||
'name'
|
||||
],
|
||||
'string'
|
||||
]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Поиск по складу
|
||||
*
|
||||
* @param Warehouse $warehouse Инстанция склада
|
||||
* @param int $limit Ограничение по максимальному количеству
|
||||
*
|
||||
* @return array Инстанции импортов
|
||||
*/
|
||||
public static function searchByWarehouse(Warehouse $warehouse, int $limit = 10): ?array
|
||||
{
|
||||
return self::searchByEdge(
|
||||
from: 'warehouse',
|
||||
to: 'import',
|
||||
edge: 'warehouse_edge_import',
|
||||
direction: 'INBOUND',
|
||||
subquery_where: [
|
||||
['warehouse_edge_import._from' => $warehouse->readId()],
|
||||
['warehouse_edge_import.type' => 'loaded']
|
||||
],
|
||||
where: 'warehouse_edge_import[0] != null',
|
||||
limit: $limit
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Поиск по поставке
|
||||
*
|
||||
* @param Supply $supply Поставка
|
||||
* @param int $limit Ограничение по максимальному количеству
|
||||
*
|
||||
* @return array Инстанции импортов
|
||||
*/
|
||||
public static function searchBySupply(Supply $supply, int $limit = 10): ?array
|
||||
{
|
||||
return self::searchByEdge(
|
||||
from: 'supply',
|
||||
to: 'import',
|
||||
edge: 'import_edge_supply',
|
||||
direction: 'OUTBOUND',
|
||||
subquery_where: [
|
||||
['import_edge_supply._to' => $supply->readId()],
|
||||
['import_edge_supply.type' => 'imported']
|
||||
],
|
||||
where: 'import_edge_supply[0] != null',
|
||||
limit: $limit
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Поиск по файлу
|
||||
*
|
||||
* @param File $file Файл
|
||||
*
|
||||
* @return Import|null Инстанция импорта
|
||||
*/
|
||||
public static function searchByFile(File $file): ?Import
|
||||
{
|
||||
return self::searchByEdge(
|
||||
from: 'file',
|
||||
to: 'import',
|
||||
edge: 'import_edge_file',
|
||||
direction: 'OUTBOUND',
|
||||
subquery_where: [
|
||||
['import_edge_file._to' => $file->readId()],
|
||||
['import_edge_supply.type' => 'connected']
|
||||
],
|
||||
where: 'import_edge_supply[0] != null',
|
||||
limit: 1
|
||||
)[0] ?? null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\models;
|
||||
|
||||
use app\models\Account;
|
||||
|
||||
/**
|
||||
* Связь инстанций импорта с поставками
|
||||
*/
|
||||
class ImportEdgeAccount extends Edge
|
||||
{
|
||||
/**
|
||||
* Имя коллекции
|
||||
*/
|
||||
public static function collectionName(): string
|
||||
{
|
||||
return 'import_edge_account';
|
||||
}
|
||||
|
||||
/**
|
||||
* Свойства
|
||||
*/
|
||||
public function attributes(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::attributes(),
|
||||
[
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метки свойств
|
||||
*/
|
||||
public function attributeLabels(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::attributeLabels(),
|
||||
[
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Правила
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::rules(),
|
||||
[
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Поиск по аккаунту
|
||||
*
|
||||
* @param Account $account Аккаунт
|
||||
* @param int $limit Ограничение по максимальному количеству
|
||||
*/
|
||||
public static function searchByAccount(Account $account, int $limit = 1): array
|
||||
{
|
||||
$account = Account::initAccount($account);
|
||||
|
||||
return static::find()->where(['_from' => $account->collectionName() . "$account->_key"])->limit($limit)->all();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\models;
|
||||
|
||||
use app\models\File;
|
||||
use app\models\Import;
|
||||
|
||||
/**
|
||||
* Связь инстанций импорта с поставками
|
||||
*/
|
||||
class ImportEdgeFile extends Edge
|
||||
{
|
||||
/**
|
||||
* Имя коллекции
|
||||
*/
|
||||
public static function collectionName(): string
|
||||
{
|
||||
return 'import_edge_file';
|
||||
}
|
||||
|
||||
/**
|
||||
* Свойства
|
||||
*/
|
||||
public function attributes(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::attributes(),
|
||||
[
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метки свойств
|
||||
*/
|
||||
public function attributeLabels(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::attributeLabels(),
|
||||
[
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Правила
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::rules(),
|
||||
[
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Поиск по файлу
|
||||
*
|
||||
* @param File $file Файл
|
||||
* @param int $limit Ограничение по максимальному количеству
|
||||
*/
|
||||
public static function searchByFile(File $file, int $limit = 1): array
|
||||
{
|
||||
return static::find()->where(['_to' => $file->readId(), 'type' => 'connected'])->limit($limit)->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Поиск по инстанции импорта
|
||||
*
|
||||
* @param Import $import Инстанция импорта
|
||||
* @param int $limit Ограничение по максимальному количеству
|
||||
*/
|
||||
public static function searchByImport(Import $import, int $limit = 1): array
|
||||
{
|
||||
return static::find()->where(['_from' => $import->readId(), 'type' => 'connected'])->limit($limit)->all();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\models;
|
||||
|
||||
use mirzaev\yii2\arangodb\Query;
|
||||
|
||||
/**
|
||||
* Связь инстанций импорта с поставками
|
||||
*/
|
||||
class ImportEdgeSupply extends Edge
|
||||
{
|
||||
/**
|
||||
* Имя коллекции
|
||||
*/
|
||||
public static function collectionName(): string
|
||||
{
|
||||
return 'import_edge_supply';
|
||||
}
|
||||
|
||||
/**
|
||||
* Свойства
|
||||
*/
|
||||
public function attributes(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::attributes(),
|
||||
[
|
||||
'vrsn'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метки свойств
|
||||
*/
|
||||
public function attributeLabels(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::attributeLabels(),
|
||||
[
|
||||
'vrsn' => 'Версия'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Правила
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::rules(),
|
||||
[
|
||||
[
|
||||
[
|
||||
'vrsn'
|
||||
],
|
||||
'integer',
|
||||
'message' => '{attribute} должен быть числом.'
|
||||
]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Перед сохранением
|
||||
*
|
||||
* @todo Подождать обновление от ебаного Yii2 и добавить
|
||||
* проверку типов передаваемых параметров
|
||||
*/
|
||||
public function beforeSave($data): bool
|
||||
{
|
||||
if (parent::beforeSave($data)) {
|
||||
if ($this->isNewRecord) {
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Поиск максимальной версии
|
||||
*
|
||||
* Ищет максимальную версию у поставок
|
||||
*
|
||||
* @param Supply $supply Поставка
|
||||
*
|
||||
* @return int Версия, если найдена
|
||||
*/
|
||||
public static function searchMaxVersion(Supply $supply): ?int
|
||||
{
|
||||
return static::find()->execute("RETURN MAX(
|
||||
FOR import_edge_supply IN import_edge_supply
|
||||
FILTER (import_edge_supply._to == 'supply/$supply->_key')
|
||||
LIMIT 0,999
|
||||
RETURN import_edge_supply.vrsn
|
||||
)")[0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Поиск по поставке
|
||||
*
|
||||
* @param Supply $supply
|
||||
*
|
||||
* @return static|null
|
||||
*/
|
||||
public static function searchBySupply(Supply $supply): ?static
|
||||
{
|
||||
return static::find()->where(['_to' => $supply->readId()])->one() ?? null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\models;
|
||||
|
||||
use yii;
|
||||
use yii\base\Model;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
||||
// use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
|
||||
// use PhpOffice\PhpSpreadsheet\Writer\Html;
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Html as HtmlReader;
|
||||
|
||||
use Exception;
|
||||
|
||||
class Invoice extends Model
|
||||
{
|
||||
public static function generate(string|int $order_key, string $html): void
|
||||
{
|
||||
// Инициализация директории
|
||||
$dir = YII_PATH_PUBLIC . '/../assets/invoices/' . $order_key;
|
||||
|
||||
// Сохранение на диск
|
||||
if (!file_exists($dir) && !mkdir($dir, 0775, true)) throw new Exception('Не удалось записать директорию:' . $dir);
|
||||
|
||||
$reader = new HtmlReader();
|
||||
$spreadsheet = $reader->loadFromString($html);
|
||||
|
||||
$writer = new Xlsx($spreadsheet);
|
||||
$writer->save($dir . '/invoice.xlsx');
|
||||
|
||||
// $reader = new XlsxReader();
|
||||
// $reader->setReadDataOnly(true);
|
||||
// $spreadsheet = $reader->load('../views/invoice/order/original.xlsx');
|
||||
|
||||
// $writer = new Html($spreadsheet);
|
||||
// $writer->save('hello world.html');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,299 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\models;
|
||||
|
||||
use yii;
|
||||
|
||||
use app\models\traits\SearchByEdge;
|
||||
|
||||
use app\models\Account;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Поиск
|
||||
*
|
||||
* @see Product Поиск по товарам
|
||||
*
|
||||
* @todo Нет смысла каждый раз возвращать кнопку, надо написать проверки
|
||||
*/
|
||||
class Notification extends Document
|
||||
{
|
||||
use SearchByEdge;
|
||||
|
||||
/**
|
||||
* Сценарий для доверенного пользователя с созданием уведомления
|
||||
*/
|
||||
const SCENARIO_TRUSTED_CREATE = 'create';
|
||||
|
||||
/**
|
||||
* Уведомление: "памятка"
|
||||
*/
|
||||
const TYPE_NOTICE = 'notice';
|
||||
|
||||
/**
|
||||
* Уведомление: "предупреждение"
|
||||
*/
|
||||
const TYPE_WARNING = 'warning';
|
||||
|
||||
/**
|
||||
* Уведомление: "ошибка"
|
||||
*/
|
||||
const TYPE_ERROR = 'error';
|
||||
|
||||
/**
|
||||
* Уведомление для модераторов: "новый заказ"
|
||||
*/
|
||||
const TYPE_MODERATOR_ORDER_NEW = 'new order';
|
||||
|
||||
/**
|
||||
* Цель для отправки уведомления
|
||||
*
|
||||
* Расшифровывается как $target
|
||||
*
|
||||
* @see SCENARIO_TRUSTED_CREATE
|
||||
*/
|
||||
public string|null $account;
|
||||
|
||||
/**
|
||||
* Текст уведомления
|
||||
*/
|
||||
public string $text;
|
||||
|
||||
/**
|
||||
* Разделитель получателей уведомлений
|
||||
*/
|
||||
public static string $delimiter = ',';
|
||||
|
||||
/**
|
||||
* Типы уведомлений
|
||||
*/
|
||||
public array $typs = [
|
||||
'notice' => 'Уведомление',
|
||||
'warning' => 'Предупреждение'
|
||||
];
|
||||
|
||||
/**
|
||||
* Имя коллекции
|
||||
*/
|
||||
public static function collectionName(): string
|
||||
{
|
||||
return 'notification';
|
||||
}
|
||||
|
||||
/**
|
||||
* Свойства
|
||||
*/
|
||||
public function attributes(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::attributes(),
|
||||
[
|
||||
'html',
|
||||
'type'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Метки свойств
|
||||
*/
|
||||
public function attributeLabels(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::attributeLabels(),
|
||||
[
|
||||
'html' => 'HTML',
|
||||
'type' => 'Тип',
|
||||
'trgt' => 'Получатели',
|
||||
'text' => 'Текст',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Правила
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::rules(),
|
||||
[
|
||||
[
|
||||
'html',
|
||||
'required'
|
||||
],
|
||||
[
|
||||
'type',
|
||||
'default',
|
||||
'value' => 'notice'
|
||||
]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Запись
|
||||
*/
|
||||
public function write(): self|array|null
|
||||
{
|
||||
return $this::_write($this->text, $this->html, $this->account ?? null, $this->type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Запись
|
||||
*
|
||||
* @param string $html Содержимое уведомления (HTML или текст)
|
||||
* @param bool|string|null $html Содержимое уведомления (HTML или текст)
|
||||
* @param string $account Получатель уведомления (_key или "@...")
|
||||
* @param string $type Тип уведомления
|
||||
*
|
||||
* @todo Намного удобнее будет заменить _key на _id, чтобы из рёбер сразу получать аккаунт без лишних операций
|
||||
*/
|
||||
public static function _write(string $text, bool|string|null $html = false, string $account = '', string $type = self::TYPE_NOTICE): self|array|null
|
||||
{
|
||||
// Инициализация
|
||||
$model = new self;
|
||||
$receiver = Account::initAccount($account)->_key ?? $account ?? throw new Exception('Не удалось инициализировать получателя');
|
||||
|
||||
if ((bool) (int) $html) {
|
||||
// Получен текст в формете HTML-кода
|
||||
|
||||
$model->html = $text ?? null;
|
||||
} else {
|
||||
// Получен необработанный текст
|
||||
|
||||
$text = htmlspecialchars(strip_tags($text ?? null));
|
||||
|
||||
$model->html = <<<HTML
|
||||
<p>$text</p>
|
||||
HTML;
|
||||
}
|
||||
|
||||
if ($model->save()) {
|
||||
// Уведомление записано
|
||||
|
||||
// Инициализация получателей и создание ребра
|
||||
self::searchReceiverAndConnect($model, $receiver, $type);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Поиск получателя
|
||||
*
|
||||
* @param self $model Уведомление
|
||||
* @param string $targets Необработанный текст с получателями
|
||||
* @param string $type Тип уведомления
|
||||
*/
|
||||
protected static function searchReceiverAndConnect(self $model, string $targets, string $type = self::TYPE_NOTICE): AccountEdgeNotification|array|null
|
||||
{
|
||||
// Инициализация
|
||||
$return = [];
|
||||
|
||||
// Конвертация
|
||||
$accounts = array_map('trim', explode(self::$delimiter, $targets));
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
if (in_array('@all', $accounts, true)) {
|
||||
// Всем пользователям
|
||||
|
||||
// Инициализация
|
||||
$return = [];
|
||||
|
||||
foreach (Account::readAll() as $account) {
|
||||
// Перебор всех аккаунтов
|
||||
|
||||
// Запись ребра: УВЕДОМЛЕНИЕ -> АККАУНТ
|
||||
$return[] = AccountEdgeNotification::writeSafe($model->readId(), $account->readId(), $type);
|
||||
}
|
||||
} else if (
|
||||
in_array('@authorized', $accounts, true)
|
||||
|| in_array('@authorizeds', $accounts, true)
|
||||
|| in_array('@authorised', $accounts, true)
|
||||
|| in_array('@authoriseds', $accounts, true)
|
||||
|| in_array('@auth', $accounts, true)
|
||||
|| in_array('@autheds', $accounts, true)
|
||||
) {
|
||||
// Всем авторизованным (админам и модераторам)
|
||||
|
||||
// Инициализация
|
||||
$return = [];
|
||||
|
||||
foreach (Account::readAllAuthorizeds() as $account) {
|
||||
// Перебор всех аккаунтов
|
||||
|
||||
// Запись ребра: УВЕДОМЛЕНИЕ -> АККАУНТ
|
||||
$return[] = AccountEdgeNotification::writeSafe($model->readId(), $account->readId(), $type);
|
||||
}
|
||||
} else if (
|
||||
in_array('@administrator', $accounts, true)
|
||||
|| in_array('@administrators', $accounts, true)
|
||||
|| in_array('@admin', $accounts, true)
|
||||
|| in_array('@admins', $accounts, true)
|
||||
) {
|
||||
// Администраторам
|
||||
|
||||
// Инициализация
|
||||
$return = [];
|
||||
|
||||
foreach (Account::readAllAdministrators() as $account) {
|
||||
// Перебор всех аккаунтов
|
||||
|
||||
// Запись ребра: УВЕДОМЛЕНИЕ -> АККАУНТ
|
||||
$return[] = AccountEdgeNotification::writeSafe($model->readId(), $account->readId(), $type);
|
||||
}
|
||||
} else if (
|
||||
in_array('@moderator', $accounts, true)
|
||||
|| in_array('@moderators', $accounts, true)
|
||||
|| in_array('@moder', $accounts, true)
|
||||
|| in_array('@moders', $accounts, true)
|
||||
) {
|
||||
// Модераторам
|
||||
|
||||
// Инициализация
|
||||
$return = [];
|
||||
|
||||
foreach (Account::readAllModerators() as $account) {
|
||||
// Перебор всех аккаунтов
|
||||
|
||||
// Запись ребра: УВЕДОМЛЕНИЕ -> АККАУНТ
|
||||
$return[] = AccountEdgeNotification::writeSafe($model->readId(), $account->readId(), $type);
|
||||
}
|
||||
} else if (in_array('@test', $accounts, true)) {
|
||||
// Тестирование (отправка самому себе)
|
||||
|
||||
$return[] = AccountEdgeNotification::writeSafe($model->readId(), yii::$app->user->id, $type);
|
||||
} else {
|
||||
// Найден идентификатор (подразумевается)
|
||||
|
||||
if ($account = Account::searchById(Account::collectionName() . '/' . $account)) {
|
||||
// Аккаунт найден
|
||||
|
||||
// Запись ребра: УВЕДОМЛЕНИЕ -> АККАУНТ
|
||||
$return[] = AccountEdgeNotification::writeSafe($model->readId(), $account->readId(), $type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $return ? $return : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Конвертация типа уведомления в версию для отображения
|
||||
*
|
||||
* @param string|null $type Тип уведомления
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function genTypeToRussian(string $type = null): string {
|
||||
return match($type ?? $this->type) {
|
||||
'notice' => 'Уведомление',
|
||||
'warning' => 'Предупреждение',
|
||||
'error' => 'Ошибка'
|
||||
};
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue