From 4c91c3192a9808f6ed5cc553eba79999fb6ccfd2 Mon Sep 17 00:00:00 2001 From: Arsen Mirzaev Tatyano-Muradovich Date: Mon, 7 Feb 2022 14:29:18 +1000 Subject: [PATCH] =?UTF-8?q?=D0=90=D0=BA=D1=82=D0=B8=D0=B2=D0=BD=D1=8B?= =?UTF-8?q?=D0=B5=20=D0=B8=20=D0=BD=D0=B5=D0=B0=D0=BA=D1=82=D0=B8=D0=B2?= =?UTF-8?q?=D0=BD=D1=8B=D0=B5=20=D1=82=D0=BE=D0=B2=D0=B0=D1=80=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/controllers/OrderController.php | 26 ++- .../system/controllers/ProductController.php | 183 +++++++++++++++++- .../system/controllers/SearchController.php | 2 +- mirzaev/skillparts/system/models/Document.php | 4 +- mirzaev/skillparts/system/models/Product.php | 34 +++- mirzaev/skillparts/system/models/Search.php | 3 +- mirzaev/skillparts/system/models/Supply.php | 40 ++-- .../skillparts/system/views/product/index.php | 59 +++--- .../skillparts/system/views/product/list.php | 50 +++++ .../skillparts/system/views/profile/panel.php | 46 +---- mirzaev/skillparts/system/web/css/main.css | 19 ++ .../skillparts/system/web/js/product_panel.js | 22 ++- .../skillparts/system/web/js/profile_panel.js | 60 +++++- 13 files changed, 443 insertions(+), 105 deletions(-) create mode 100644 mirzaev/skillparts/system/views/product/list.php diff --git a/mirzaev/skillparts/system/controllers/OrderController.php b/mirzaev/skillparts/system/controllers/OrderController.php index 95ec031..2ccf0fd 100644 --- a/mirzaev/skillparts/system/controllers/OrderController.php +++ b/mirzaev/skillparts/system/controllers/OrderController.php @@ -589,21 +589,27 @@ class OrderController extends Controller $model = Order::searchByType(supplies: true); // Поиск ребра - $edge = AccountEdgeOrder::searchByVertex(yii::$app->user->id, $model->readId(), 'current'); + $account_edge_order = AccountEdgeOrder::searchByVertex(yii::$app->user->id, $model->readId(), 'current')[0]; - if (count($edge) > 1) { + if ($supplies = OrderEdgeSupply::searchByDirection($account_edge_order->to)) { + // Поставки найдены + + // Добавить проверку на то, что товары активны + + } + + var_dump($supplies); die; + + if (count($account_edge_order) > 1) { // Найден более чем 1 заказ return null; } - // Инициализация - $edge = $edge[0]; - // Запись - $edge->type = 'requested'; + $account_edge_order->type = 'requested'; - if ($edge->update()) { + if ($account_edge_order->update()) { // Удалось сохранить изменения // Запись в журнал @@ -613,6 +619,8 @@ class OrderController extends Controller $supplies = []; foreach ($model['supplies'] as $supply) { + // Перебор поставок + $supplies[] = [ 'title' => $supply['supply']['catn'], 'amount' => [ @@ -634,13 +642,13 @@ class OrderController extends Controller ], 'order' => [ 'id' => $model->_key, - 'date' => $edge->date ?? time(), + 'date' => $account_edge_order->date ?? time(), 'entries' => $supplies ] ])); // Отправка уведомлений модераторам - Notification::_write($this->renderPartial('/notification/system/orders/new', ['id' => $edge->_key]), true, '@auth', Notification::TYPE_MODERATOR_ORDER_NEW); + Notification::_write($this->renderPartial('/notification/system/orders/new', ['id' => $account_edge_order->_key]), true, '@auth', Notification::TYPE_MODERATOR_ORDER_NEW); } return $this->actionIndex(); diff --git a/mirzaev/skillparts/system/controllers/ProductController.php b/mirzaev/skillparts/system/controllers/ProductController.php index 3596f79..b36479c 100644 --- a/mirzaev/skillparts/system/controllers/ProductController.php +++ b/mirzaev/skillparts/system/controllers/ProductController.php @@ -5,18 +5,82 @@ declare(strict_types=1); namespace app\controllers; use yii; -use yii\filters\AccessControl; 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 ProductController extends Controller { + public function behaviors() + { + return [ + 'access' => [ + 'class' => AccessControl::class, + 'rules' => [ + [ + 'allow' => true, + 'actions' => [ + 'index', + ] + ], + [ + 'allow' => true, + 'roles' => ['@'], + 'actions' => [] + ], + [ + 'allow' => true, + 'actions' => [ + 'read', + 'write', + 'delete', + 'connect', + 'disconnect', + 'edit-title', + 'edit-catn', + 'edit-dscr', + 'edit-dmns', + 'edit-wght', + 'write-image', + 'delete-image', + 'write-cover', + 'write-image', + 'status' + ], + '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 actionIndex(string $catn): array|string|null { if ($model = Product::searchByCatn($catn)) { @@ -143,6 +207,44 @@ class ProductController extends Controller return $this->redirect("/"); } + /** + * Чтение товаров + * + * @param string $stts Статус + * + * @return string|array|null + */ + public function actionRead(string $stts = 'all'): string|array|null + { + if (yii::$app->request->isPost) { + // POST-запрос + + // Инициализация входных параметров + $amount = yii::$app->request->post('amount') ?? yii::$app->request->get('amount') ?? 50; + $order = yii::$app->request->post('order') ?? yii::$app->request->get('order') ?? ['DESC']; + + // Инициализация cookie + $cookies = yii::$app->response->cookies; + + + // Инициализация аккаунта + $account ?? $account = Account::initAccount(); + + // Чтение товаров + $products = Product::read(where: $stts === 'all' || $stts === 'inactive' ? [] : ['stts' => $stts], limit: $amount, order: $order); + + // Запись формата ответа + yii::$app->response->format = Response::FORMAT_JSON; + + return [ + 'products' => $this->renderPartial('/product/list', compact('account', 'products')), + '_csrf' => yii::$app->request->getCsrfToken() + ]; + } + + return false; + } + /** * Удаление товара * @@ -307,7 +409,7 @@ class ProductController extends Controller yii::$app->response->statusCode = 500; // Запись в буфер возврата - $return['alert'] = "Не удалось найти товар к которому требуется соединение: $catn"; + $return['alert'] = "Не удалось найти товар: $catn"; // Переход в конец алгоритма goto end; @@ -848,4 +950,81 @@ class ProductController extends Controller return $this->redirect('/'); } } + + /** + * Изменение статуса + * + * @param string $catn Артикул + */ + public function actionStatus(string $catn): array|string|null + { + if (yii::$app->request->isPost) { + // POST-запрос + + // Запись заголовка с форматом ответа + yii::$app->response->format = Response::FORMAT_JSON; + + // Инициализация буфера ответа + $return = [ + '_csrf' => yii::$app->request->getCsrfToken() + ]; + + if (empty($catn)) { + // Не получен артикул + + // Запись кода ответа + yii::$app->response->statusCode = 500; + + // Переход в конец алгоритма + goto end; + } + + if ($product = Product::searchByCatn($catn)) { + // Найден товар + + // Запись старого статуса + $old = $product->stts; + + // Запись параметров + $product->stts = $stts = yii::$app->request->post('stts') ?? 'inactive'; + + if ($product->update() > 0) { + // Записаны изменения + + // Запись в журнал + $product->journal(data: [ + 'stts' => [ + 'old' => $old, + 'new' => $stts + ] + ]); + + $return['main'] = $this->renderPartial('index', ['model' => $product]); + } else { + // Не записаны изменения + + // Отправка уведомления + Notification::_write("Не удалось изменить статус на $stts у товара $catn", type: Notification::TYPE_ERROR); + } + } else { + // Не найден товар + + // Запись кода ответа + yii::$app->response->statusCode = 500; + + // Отправка уведомления + Notification::_write("Не удалось найти товар $catn", type: Notification::TYPE_ERROR); + + // Переход в конец алгоритма + goto end; + } + + // Конец алгоритма + end: + + return $return; + } + + return null; + } } diff --git a/mirzaev/skillparts/system/controllers/SearchController.php b/mirzaev/skillparts/system/controllers/SearchController.php index 790bd4e..f70e2ae 100644 --- a/mirzaev/skillparts/system/controllers/SearchController.php +++ b/mirzaev/skillparts/system/controllers/SearchController.php @@ -134,7 +134,7 @@ class SearchController extends Controller $limit = yii::$app->request->isPost ? 10 : 20; - if ($response = Product::searchByPartialCatn($query, $limit, [ + if ($response = Product::searchByPartialCatn($query, 'active', $limit, [ '_key' => '_key', 'catn' => 'catn', 'prod' => 'prod', diff --git a/mirzaev/skillparts/system/models/Document.php b/mirzaev/skillparts/system/models/Document.php index 3d3c089..c6528d1 100644 --- a/mirzaev/skillparts/system/models/Document.php +++ b/mirzaev/skillparts/system/models/Document.php @@ -168,9 +168,9 @@ abstract class Document extends ActiveRecord /** * Чтение записей по максимальному ограничению */ - public static function read(int $limit = 100, array|null $order = null): array + public static function read(?array $where = [], int $limit = 100, ?array $order = null): array { - return static::find()->limit($limit)->orderby($order)->all(); + return static::find()->where($where)->orderby($order)->limit($limit)->all(); } /** diff --git a/mirzaev/skillparts/system/models/Product.php b/mirzaev/skillparts/system/models/Product.php index ac10f31..32d5c33 100644 --- a/mirzaev/skillparts/system/models/Product.php +++ b/mirzaev/skillparts/system/models/Product.php @@ -89,6 +89,7 @@ class Product extends Document 'imgs', 'time', 'bffr', + 'stts' ] ); } @@ -109,6 +110,7 @@ class Product extends Document 'imgs' => 'Изображения (imgs)', 'time' => 'Срок доставки (time)', 'bffr' => 'Буфер', + 'stts' => 'Статус', 'file_excel' => 'Документ (file_excel)', 'file_image' => 'Изображение (file_image)', 'group' => 'Группа (group)', @@ -168,6 +170,12 @@ class Product extends Document 'max' => 30000, 'message' => '{attribute} должен иметь значение от 0 до 30000' ], + [ + 'stts', + 'string', + 'length' => [4, 20], + 'message' => '{attribute} должен быть строкой от 4 до 20 символов' + ], [ 'file_excel', 'file', @@ -201,6 +209,29 @@ class Product extends Document ); } + /** + * Перед сохранением + * + * @todo Подождать обновление от ебаного Yii2 и добавить + * проверку типов передаваемых параметров + */ + public function beforeSave($create): bool + { + if (parent::beforeSave($create)) { + // Пройдена родительская проверка + + if ($this->isNewRecord) { + // Новая запись + + $this->stts = 'inactive'; + } + + return true; + } + + return false; + } + /** * Запись пустого продукта */ @@ -346,11 +377,12 @@ class Product extends Document * * @todo Переделать нормально */ - public static function searchByPartialCatn(string $catn, int $limit = 1, array $select = []): static|array|null + public static function searchByPartialCatn(string $catn, string $stts = 'active', int $limit = 1, array $select = []): static|array|null { $query = self::find() ->for('product') ->in('product_search') + ->where(['stts' => $stts]) ->filter(['catn' => $catn], 'START_SENSETIVE') ->limit($limit) ->orderBy(['catn' => 'ASC']) diff --git a/mirzaev/skillparts/system/models/Search.php b/mirzaev/skillparts/system/models/Search.php index e1821ea..9774e77 100644 --- a/mirzaev/skillparts/system/models/Search.php +++ b/mirzaev/skillparts/system/models/Search.php @@ -118,7 +118,7 @@ class Search extends Document /** - * Поиск содержимого поиска + * Поиск содержимого поиска (продуктов) * * @todo В будущем возможно заказ не только поставок реализовать * Переписать реестр и проверку на дубликаты, не понимаю как они работают @@ -343,6 +343,7 @@ class Search extends Document } } + // Запись обработанных данных $_row['supplies'] = array_merge($connections, $buffer_connections); diff --git a/mirzaev/skillparts/system/models/Supply.php b/mirzaev/skillparts/system/models/Supply.php index 85ba571..90d6087 100644 --- a/mirzaev/skillparts/system/models/Supply.php +++ b/mirzaev/skillparts/system/models/Supply.php @@ -459,7 +459,7 @@ class Supply extends Product implements ProductInterface, OfferInterface $analogs = explode(',', $row['Артикул'] ?? $row['артикул'] ?? $row['Article'] ?? $row['article'] ?? $row['catn'], 50); // Инициализация функции создания поставки - $create = function (string $_supply) use ($row, $analogs, &$created, &$updated, &$imported, $amount, $account) { + $create = function (string $_supply) use ($row, $analogs, &$created, &$updated, &$imported, $amount, $account): bool { // Очистка $_supply = trim($_supply); @@ -591,21 +591,35 @@ class Supply extends Product implements ProductInterface, OfferInterface if ($product = Product::searchByCatn($supply->catn)) { // Найден товар подходящий для привязки с только что созданной поставкой - if (isset($product->prod) && $product->prod === $supply->prod) { - // Производитель совпадает с тем, что указан в товаре - - for ($i = 0; $i++ < $amount;) { - // Перебор создаваемых рёбер (так работает обозначение количества товаров в наличии) - - // Запись ребра (с проверкой на дубликат) - SupplyEdgeProduct::writeSafe($supply->readId(), $product->readId(), data: ['type' => 'connect']); - } - } + // Приведение типа (для анализатора) + if (is_array($product)) $product = $product[0]; } else { // Не найден товар подходящий для привязки с только что созданной поставкой - // Отправка уведомления - Notification::_write("Не найден товар подходящий для связи с поставкой: $supply->catn", account: '@authorized'); + if ($product = Product::writeEmpty($supply->catn)) { + // Удалось записать новый товар (НЕАКТИВНЫЙ) + + // Отправка уведомления + // Notification::_write("Не найден товар подходящий для связи с поставкой: $supply->catn", account: '@authorized'); + } else { + // Не удалось записать новый товар + + // Отправка уведомления + Notification::_write("Не удалось создать новый товар: $supply->catn", account: '@authorized'); + + return false; + } + } + + if (isset($product->prod) && $product->prod === $supply->prod) { + // Производитель совпадает с тем, что указан в товаре + + for ($i = 0; $i++ < $amount;) { + // Перебор создаваемых рёбер (так работает обозначение количества товаров в наличии) + + // Запись ребра (с проверкой на дубликат) + SupplyEdgeProduct::writeSafe($supply->readId(), $product->readId(), data: ['type' => 'connect']); + } } } else { // Проверка не пройдена diff --git a/mirzaev/skillparts/system/views/product/index.php b/mirzaev/skillparts/system/views/product/index.php index b7518fe..46a013d 100644 --- a/mirzaev/skillparts/system/views/product/index.php +++ b/mirzaev/skillparts/system/views/product/index.php @@ -87,6 +87,7 @@ use app\models\Product; && (yii::$app->user->identity->type === 'administrator' || yii::$app->user->identity->type === 'moderator') ) { + // Инициализация артикула $catn = $model['catn']; echo <<
user->isGuest - && yii::$app->user->identity->type === 'administrator' - ) : ?> - - + !yii::$app->user->isGuest + && yii::$app->user->identity->type === 'administrator' + ) : ?> + +
user->isGuest @@ -219,24 +220,22 @@ use app\models\Product; ?>

+ 'form_product_cart', - 'action' => false, - 'fieldConfig' => [ - 'template' => '{input}', - ], - 'options' => [ - 'onsubmit' => 'return false;', - 'class' => 'row mt-auto' - ] - ]); + if (isset($model['stts']) && $model['stts'] === 'active') { + // Товар активен - // Просто для теста - $model = new Product(); + echo <<Деактивировать + HTML; + } else { + // Товар неактивен, либо что-то с ним ещё + + echo <<Активировать + HTML; + } ?> - -
diff --git a/mirzaev/skillparts/system/views/product/list.php b/mirzaev/skillparts/system/views/product/list.php new file mode 100644 index 0000000..5b6f260 --- /dev/null +++ b/mirzaev/skillparts/system/views/product/list.php @@ -0,0 +1,50 @@ +zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone); +$timezone = $timezone[1][0]; +?> + + + jrnl ?? [] as $jrnl) { + // Перебор записей в журнале + + if ($jrnl['action'] === 'create') { + // Найдена дата создания + + // Инициализация даты + $create = (new DateTime())->setTimestamp($jrnl['date'])->setTimezone(new DateTimeZone($timezone))->format('H:i d.m.Y') ?? 'Неизвестно'; + + // Выход из цикла + break; + } + } + ?> + +
+
.
+ + catn ?? 'Неизвестно' ?> + +
+ +
+ +
+ + + + + diff --git a/mirzaev/skillparts/system/views/profile/panel.php b/mirzaev/skillparts/system/views/profile/panel.php index 6fbd5d2..a21beac 100644 --- a/mirzaev/skillparts/system/views/profile/panel.php +++ b/mirzaev/skillparts/system/views/profile/panel.php @@ -159,47 +159,13 @@ $timezone = $timezone[1][0]; />
Список товаров
+ - - - jrnl ?? [] as $jrnl) { - // Перебор записей в журнале - - if ($jrnl['action'] === 'create') { - // Найдена дата создания - - // Инициализация даты - $create = (new DateTime())->setTimestamp($jrnl['date'])->setTimezone(new DateTimeZone($timezone))->format('H:i d.m.Y') ?? 'Неизвестно'; - - // Выход из цикла - break; - } - } - ?> - - - - - - - +
/> diff --git a/mirzaev/skillparts/system/web/css/main.css b/mirzaev/skillparts/system/web/css/main.css index 7564ef2..ed1c915 100644 --- a/mirzaev/skillparts/system/web/css/main.css +++ b/mirzaev/skillparts/system/web/css/main.css @@ -178,6 +178,25 @@ main { transition: 0s; } +.button_green { + color: #eee; + background-color: #00c431; + transition: 0s; +} + +.button_green:hover { + color: #fff; + background-color: #04d639; + transition: 0s; +} + +.button_green:active, +.button_green:focus { + color: #ddd; + background-color: #01ae2c; + transition: 0s; +} + .button_white, .button_white_small { background-color: #fff; diff --git a/mirzaev/skillparts/system/web/js/product_panel.js b/mirzaev/skillparts/system/web/js/product_panel.js index be0dab3..4f77238 100644 --- a/mirzaev/skillparts/system/web/js/product_panel.js +++ b/mirzaev/skillparts/system/web/js/product_panel.js @@ -437,7 +437,7 @@ function product_panel_images_cover_write(catn, index) { dataType: 'json', data: { '_csrf': yii.getCsrfToken(), - 'index': index + index }, success: product_response_success, error: product_response_error @@ -461,3 +461,23 @@ function product_panel_handler_save(save, catn, element, ...vars) { document.body.addEventListener('click', product_panel_handler_save_function, true); }; }; + +function product_panel_product_stts(catn, stts) { + if (catn !== null && catn !== undefined && stts !== null && stts !== undefined) { + $.ajax({ + url: '/product/' + catn + '/status', + type: 'post', + dataType: 'json', + data: { + '_csrf': yii.getCsrfToken(), + stts + }, + success: product_response_success, + error: product_response_error + }); + + return false; + }; + + return true; +}; diff --git a/mirzaev/skillparts/system/web/js/profile_panel.js b/mirzaev/skillparts/system/web/js/profile_panel.js index f2da3e5..f272088 100644 --- a/mirzaev/skillparts/system/web/js/profile_panel.js +++ b/mirzaev/skillparts/system/web/js/profile_panel.js @@ -72,23 +72,32 @@ function page_profile_panel_choose(button = 'profile_panel_input_accounts') { document.querySelector('[for="profile_panel_input_notifications"]').classList.remove('active'); document.querySelector('[for="profile_panel_input_settings"]').classList.remove('active'); + // Активация запрошенной вкладки + document.getElementById(button).checked = true; + document.getElementById(button).removeAttribute('onclick'); + document.querySelector('[for="' + button + '"]').classList.add('active'); + + if (button === 'profile_panel_input_products') { + // Открытие вкладки с товарами + + profile_panel_products_read('@last', 'all'); + } + if (button === 'disable') { // Инициализация активной подвкладки вкладки "Аккаунты" + page_profile_panel_accounts_choose('disable', true); return; } else if (button === 'profile_panel_input_accounts') { // Инициализация активной подвкладки вкладки "Аккаунты" + page_profile_panel_accounts_choose(undefined, true); } else if (button !== 'profile_panel_input_accounts') { // Инициализация активной подвкладки вкладки "Аккаунты" + page_profile_panel_accounts_choose('disable', true); } - - // Инициализация запрошенной вкладки - document.getElementById(button).checked = true; - document.getElementById(button).removeAttribute('onclick'); - document.querySelector('[for="' + button + '"]').classList.add('active'); } function page_profile_panel_accounts_choose(button = 'profile_panel_input_accounts_control', active = false) { @@ -729,3 +738,44 @@ function profile_panel_input_suppliers_accounts_create_product(button, _key) { return false; } + +// Прочитать товары +function profile_panel_products_read(search = '@last', type = '@last', from = '@last', to = '@last') { + // '@last' - оставить без изменений и взять данные из cookie + + if (search.length > 1) { + // Проверка на длину запроса пройдена + + // Инициализация буфера с данными запроса + let data = { + '_csrf': yii.getCsrfToken(), + search, + from, + to + }; + + // Запрос + $.ajax({ + url: '/products/read/' + type, + type: 'post', + dataType: 'json', + data: data, + success: (data, status, xhr) => { + // Инициализация оболочки + let element = document.getElementById('profile_panel_input_products_wrap'); + + if (data.products !== undefined && element !== null) { + // Передан список продуктов и найден элемент-оболочка продуктов + + // Запись полученного содержимого + element.innerHTML = data.products; + } + + return page_profile_response_success(data, status, xhr); + }, + error: page_profile_response_error + }); + }; + + return false; +}