From b08f7f7d0a4a4d6f1a7bc273320ed458d29e6b0d Mon Sep 17 00:00:00 2001 From: Arsen Mirzaev Tatyano-Muradovich Date: Mon, 27 Dec 2021 14:03:15 +1000 Subject: [PATCH] =?UTF-8?q?=D0=A1=D0=BA=D0=BB=D0=B0=D0=B4=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controllers/AuthenticationController.php | 25 -- .../system/controllers/OrderController.php | 7 +- .../system/controllers/ProfileController.php | 32 ++- .../controllers/RegistrationController.php | 13 - ...221_183410_create_warehouse_collection.php | 20 ++ ...reate_warehouse_edge_import_collection.php | 20 ++ ...eate_account_edge_warehouse_collection.php | 20 ++ mirzaev/skillparts/system/models/Account.php | 43 +-- .../system/models/AccountEdgeWarehouse.php | 21 ++ .../skillparts/system/models/AccountForm.php | 40 +-- mirzaev/skillparts/system/models/Import.php | 33 +-- mirzaev/skillparts/system/models/Product.php | 33 +-- mirzaev/skillparts/system/models/Supply.php | 117 ++++----- .../skillparts/system/models/Warehouse.php | 246 ++++++++++++++++++ .../system/models/WarehouseEdgeImport.php | 51 ++++ .../skillparts/system/views/profile/index.php | 1 - .../system/views/profile/monitoring.php | 1 - .../skillparts/system/views/profile/panel.php | 1 - .../system/views/profile/supplies.php | 153 ++++++----- mirzaev/skillparts/system/web/.htaccess | 4 - .../web/{assets => files/20827450}/.gitignore | 0 mirzaev/skillparts/system/web/js/profile.js | 18 +- 22 files changed, 574 insertions(+), 325 deletions(-) create mode 100644 mirzaev/skillparts/system/migrations/arangodb/m211221_183410_create_warehouse_collection.php create mode 100644 mirzaev/skillparts/system/migrations/arangodb/m211221_183447_create_warehouse_edge_import_collection.php create mode 100644 mirzaev/skillparts/system/migrations/arangodb/m211221_193454_create_account_edge_warehouse_collection.php create mode 100644 mirzaev/skillparts/system/models/AccountEdgeWarehouse.php create mode 100644 mirzaev/skillparts/system/models/Warehouse.php create mode 100644 mirzaev/skillparts/system/models/WarehouseEdgeImport.php delete mode 100644 mirzaev/skillparts/system/web/.htaccess rename mirzaev/skillparts/system/web/{assets => files/20827450}/.gitignore (100%) diff --git a/mirzaev/skillparts/system/controllers/AuthenticationController.php b/mirzaev/skillparts/system/controllers/AuthenticationController.php index e8d8170..e60dbb9 100644 --- a/mirzaev/skillparts/system/controllers/AuthenticationController.php +++ b/mirzaev/skillparts/system/controllers/AuthenticationController.php @@ -58,21 +58,9 @@ class AuthenticationController extends Controller // Настройка кода ответа yii::$app->response->format = Response::FORMAT_JSON; - // Валидация формы - // if (!empty($errors = ActiveForm::validate($model))) { - - // // Настройка кода ответа - // yii::$app->response->statusCode = 401; - - // return $errors; - // }; - if (!yii::$app->user->isGuest || $model->authentication()) { // Аккаунт аутентифицирован - // Создание сессии - // yii::$app->session->open(); - // Инициализация $notifications_button = $this->renderPartial('/notification/button'); $notifications_panel = $this->renderPartial('/notification/panel', ['notifications_panel_full' => true]); @@ -94,19 +82,6 @@ class AuthenticationController extends Controller // Запись ответа $return['redirect'] = '/' . $cookies['redirect']; - // try { - // if (empty($return['main'] = $this->renderPartial($return['redirect']))) { - // throw new Exception('Представление найдено, но вернуло пустой результат'); - // } - // } catch (Throwable $t) { - // $return['main'] = $this->renderPartial($return['redirect'] . '/index'); - // } - - // Генерация и запись - // $controller = 'app\\controllers\\' . ucfirst($cookies['redirect']) . 'Controller'; - // $action = 'action' . ucfirst($cookies['redirect_action']); - // $return['main'] = (new $controller())->$action(); - // Очистка cookie unset(yii::$app->response->cookies['redirect']); diff --git a/mirzaev/skillparts/system/controllers/OrderController.php b/mirzaev/skillparts/system/controllers/OrderController.php index fedd9fa..95ec031 100644 --- a/mirzaev/skillparts/system/controllers/OrderController.php +++ b/mirzaev/skillparts/system/controllers/OrderController.php @@ -298,13 +298,16 @@ class OrderController extends Controller if (yii::$app->request->isPost) { // POST-запрос - // Настройка - yii::$app->response->format = Response::FORMAT_JSON; + // Инициализация аккаунта + $account ?? $account = Account::initAccount(); // Конвертация из UNIXTIME в формат поддерживаемый календарём по спецификации HTML $from = DateTime::createFromFormat('U', (string) $from)->format('Y-m-d'); $to = DateTime::createFromFormat('U', (string) $to)->format('Y-m-d'); + // Запись формата ответа + yii::$app->response->format = Response::FORMAT_JSON; + return [ 'main' => $this->renderPartial('/orders/index', compact('orders', 'moderator_orders', 'search', 'from', 'to', 'window') + ['panel' => $this->renderPartial('/orders/search/panel', compact('account') + ['response' => @$orders[0]['supplies']] ?? null)]), diff --git a/mirzaev/skillparts/system/controllers/ProfileController.php b/mirzaev/skillparts/system/controllers/ProfileController.php index ffbb421..5eb89ac 100644 --- a/mirzaev/skillparts/system/controllers/ProfileController.php +++ b/mirzaev/skillparts/system/controllers/ProfileController.php @@ -20,7 +20,7 @@ use app\models\Settings; use app\models\Dellin; use app\models\SettingsEdgeSettings; use app\models\Terminal; - +use app\models\Warehouse; use Dadata\DadataClient as Dadata; use Throwable; @@ -453,6 +453,7 @@ class ProfileController extends Controller $help = (bool) (yii::$app->request->post('help') ?? yii::$app->request->get('help')); $target = yii::$app->request->post('account') ?? yii::$app->request->get('account'); $number = yii::$app->request->post('number') ?? yii::$app->request->get('number'); + $warehouse = yii::$app->request->post('warehouse') ?? yii::$app->request->get('warehouse'); $sidebar = $this->renderPartial('sidebar'); $groups = self::readGroups(); @@ -474,6 +475,9 @@ class ProfileController extends Controller ]; } + // Инициализация файла + $supply->file_excel = UploadedFile::getInstance($supply, 'file_excel'); + if (!empty($target)) { // Получен аккаунт для которого необходимо загрузить каталог @@ -489,9 +493,9 @@ class ProfileController extends Controller if (Account::isMinimalAuthorized()) { // Авторизован доступ к выполнению этого действия - $supply->{"file_excel_$number"} = UploadedFile::getInstance($supply, 'file_excel'); + if ($supply->importExcel((int) $warehouse, $target)) { + // Импорт успешно завершён - if ($supply->importExcel($target)) { return [ 'main' => $this->renderPartial('supplies', compact( 'supply', @@ -515,12 +519,9 @@ class ProfileController extends Controller } else { // Не получен аккаунт для которого необходимо загрузить каталог - // Инициализация файлов - $supply->file_excel_1 = UploadedFile::getInstance($supply, 'file_excel_1'); - $supply->file_excel_2 = UploadedFile::getInstance($supply, 'file_excel_2'); - $supply->file_excel_3 = UploadedFile::getInstance($supply, 'file_excel_3'); - if ($supply->importExcel()) { + if ($supply->importExcel((int) $warehouse)) { + return [ 'main' => $this->renderPartial('supplies', compact( 'supply', @@ -536,12 +537,15 @@ class ProfileController extends Controller } } - return $this->render('supplies', compact( - 'supply', - 'groups', - 'sidebar', - 'panel' - )); + return [ + 'main' => $this->renderPartial('supplies', compact( + 'supply', + 'groups', + 'sidebar', + 'panel' + )), + '_csrf' => yii::$app->request->getCsrfToken() + ]; } public static function readGroups() diff --git a/mirzaev/skillparts/system/controllers/RegistrationController.php b/mirzaev/skillparts/system/controllers/RegistrationController.php index 7336cc3..8d0c878 100644 --- a/mirzaev/skillparts/system/controllers/RegistrationController.php +++ b/mirzaev/skillparts/system/controllers/RegistrationController.php @@ -78,19 +78,6 @@ class RegistrationController extends Controller // Запись ответа $return['redirect'] = '/' . $cookies['redirect']; - // try { - // if (empty($return['main'] = $this->renderPartial($return['redirect']))) { - // throw new Exception('Представление найдено, но вернуло пустой результат'); - // } - // } catch (Throwable $t) { - // $return['main'] = $this->renderPartial($return['redirect'] . '/index'); - // } - - // Генерация и запись - // $controller = 'app\\controllers\\' . ucfirst($cookies['redirect']) . 'Controller'; - // $action = 'action' . ucfirst($cookies['redirect_action']); - // $return['main'] = (new $controller())->$action(); - // Очистка cookie unset(yii::$app->response->cookies['redirect']); diff --git a/mirzaev/skillparts/system/migrations/arangodb/m211221_183410_create_warehouse_collection.php b/mirzaev/skillparts/system/migrations/arangodb/m211221_183410_create_warehouse_collection.php new file mode 100644 index 0000000..f054f34 --- /dev/null +++ b/mirzaev/skillparts/system/migrations/arangodb/m211221_183410_create_warehouse_collection.php @@ -0,0 +1,20 @@ +createCollection('warehouse', ['type' => 2]); + } + + public function down() + { + $this->dropCollection('warehouse'); + } +} diff --git a/mirzaev/skillparts/system/migrations/arangodb/m211221_183447_create_warehouse_edge_import_collection.php b/mirzaev/skillparts/system/migrations/arangodb/m211221_183447_create_warehouse_edge_import_collection.php new file mode 100644 index 0000000..cd10a19 --- /dev/null +++ b/mirzaev/skillparts/system/migrations/arangodb/m211221_183447_create_warehouse_edge_import_collection.php @@ -0,0 +1,20 @@ +createCollection('warehouse_edge_import', ['type' => 3]); + } + + public function down() + { + $this->dropCollection('warehouse_edge_import'); + } +} diff --git a/mirzaev/skillparts/system/migrations/arangodb/m211221_193454_create_account_edge_warehouse_collection.php b/mirzaev/skillparts/system/migrations/arangodb/m211221_193454_create_account_edge_warehouse_collection.php new file mode 100644 index 0000000..79dca2f --- /dev/null +++ b/mirzaev/skillparts/system/migrations/arangodb/m211221_193454_create_account_edge_warehouse_collection.php @@ -0,0 +1,20 @@ +createCollection('account_edge_warehouse', ['type' => 3]); + } + + public function down() + { + $this->dropCollection('account_edge_warehouse'); + } +} diff --git a/mirzaev/skillparts/system/models/Account.php b/mirzaev/skillparts/system/models/Account.php index ac322fb..adc3192 100644 --- a/mirzaev/skillparts/system/models/Account.php +++ b/mirzaev/skillparts/system/models/Account.php @@ -11,6 +11,7 @@ use carono\exchange1c\interfaces\PartnerInterface; use app\models\Dellin; use app\models\traits\SearchByEdge; + use yii\web\UploadedFile; /** @@ -455,40 +456,6 @@ class Account extends Document implements IdentityInterface, PartnerInterface return $this->syncListWithSettings($list, 'import_supplies_oem'); } - /** - * Генерация списка терминалов из ДеловыеЛинии для отправителя - * - * Актуальное (выбранное, активное) значение записывается первым - * - * @param array Необработанный список терминалов - */ - public function genListTerminalsFrom(): array - { - // Инициализация - $list = []; - - $cities = Dellin::readAll(); - - foreach ($cities as $city) { - // Перебор городов - - foreach ($city->data['terminals']['terminal'] as $termial) { - // Перебор терминалов - - if (in_array($termial['id'], $list, true)) { - // Если встретился дубликат (исполняется очень часто) - - continue; - } - - // Запись - $list[$termial['id']] = $city->data['name'] . ' (' . $termial['address'] . ')'; - } - } - - return $this->syncListWithSettings($list, 'delivery_from_terminal'); - } - /** * Генерация списка терминалов из ДеловыеЛинии для получателя * @@ -901,7 +868,7 @@ class Account extends Document implements IdentityInterface, PartnerInterface * * @param static|null $account Аккаунт */ - public static function initAccount($account = null): ?static + public static function initAccount(Account|int $account = null): ?static { if (is_null($account)) { // Данные аккаунта не переданы @@ -917,7 +884,11 @@ class Account extends Document implements IdentityInterface, PartnerInterface return $account; } } else { - if (is_int($account)) { + if ($account instanceof Account) { + // Передана инстанция аккаунта + + return $account; + } else if (is_int($account)) { // Передан идентификатор (_key) аккаунта (подразумевается) // Инициализация (поиск в базе данных) diff --git a/mirzaev/skillparts/system/models/AccountEdgeWarehouse.php b/mirzaev/skillparts/system/models/AccountEdgeWarehouse.php new file mode 100644 index 0000000..4caedce --- /dev/null +++ b/mirzaev/skillparts/system/models/AccountEdgeWarehouse.php @@ -0,0 +1,21 @@ + 'Заполните поле', 'on' => self::SCENARIO_AUTHENTICATION ], - // Обязательные поля для регистрации - // [ - // [ - // 'rept', - // 'pols' - // ], - // 'required', - // 'message' => 'Заполните поле', - // 'on' => self::SCENARIO_REGISTRATION - // ], - // Повтор пароля - // [ - // 'rept', - // 'compare', - // 'compareAttribute' => 'pswd', - // 'message' => "Пароли не совпадают", - // 'on' => self::SCENARIO_REGISTRATION, - // ], - // Принятие политики конфидециальности - // [ - // 'pols', - // 'compare', - // 'compareValue' => 'on', - // 'message' => "Чтобы продолжить примите нашу политику конфидециальности", - // 'on' => self::SCENARIO_REGISTRATION, - // ], // Функция "Запомнить меня" [ 'auto', @@ -151,12 +125,20 @@ class AccountForm extends Model // Удалось инициализировать аккаунт try { - $account->validatePasswordWithHash($this->pswd); + if (!$account->validatePasswordWithHash($this->pswd)) { + // Не пройдена проверка с хешем + + throw new exception; + } } catch (Exception $e) { - // Проверка с хешем не пройдена + // Не пройдена проверка с хешем try { - $account->validatePasswordWithoutHash($this->pswd); + if (!$account->validatePasswordWithoutHash($this->pswd)) { + // Не пройдена проверка с паролем + + throw new exception; + } } catch (Exception $e) { // Проверка без хеша не пройдена diff --git a/mirzaev/skillparts/system/models/Import.php b/mirzaev/skillparts/system/models/Import.php index 6b87caa..d7180e5 100644 --- a/mirzaev/skillparts/system/models/Import.php +++ b/mirzaev/skillparts/system/models/Import.php @@ -12,7 +12,7 @@ use app\models\Account; /** * Импорт поставок * - * Хранит себе связи с поставками которые были загружены вместе + * Хранит в себе связи с поставками которые были загружены вместе */ class Import extends Document { @@ -34,7 +34,6 @@ class Import extends Document return array_merge( parent::attributes(), [ - 'pstn', 'name', 'file' ] @@ -49,7 +48,6 @@ class Import extends Document return array_merge( parent::attributeLabels(), [ - 'pstn' => 'Позиция', 'name' => 'Название', 'file' => 'Файл' ] @@ -64,14 +62,6 @@ class Import extends Document return array_merge( parent::rules(), [ - [ - 'pstn', - 'required' - ], - [ - 'pstn', - 'integer' - ], [ [ 'file', @@ -83,15 +73,26 @@ class Import extends Document ); } - public static function searchByPosition(int $position = 1, Account $account = null, int $limit = 1): array + /** + * Поиск по складу + * + * @param Warehouse $warehouse Инстанция склада + * @param int $limit Ограничение по максимальному количеству + * + * @return array Инстанции испортов + */ + public static function searchByWarehouse(Warehouse $warehouse, int $limit = 10): array { return self::searchByEdge( - from: 'account', + from: 'warehouse', to: 'import', - edge: 'import_edge_account', + edge: 'warehouse_edge_import', direction: 'INBOUND', - subquery_where: 'account._key == "' . Account::initAccount($account)->_key . '" && import_edge_account.type == "loaded"', - where: ['import.pstn' => $position], + subquery_where: [ + ['warehouse_edge_import._from' => $warehouse->readId()], + ['warehouse_edge_import.type' => 'loaded'] + ], + where: 'warehouse_edge_import[0] != null', limit: $limit ); } diff --git a/mirzaev/skillparts/system/models/Product.php b/mirzaev/skillparts/system/models/Product.php index 1e425d7..202a141 100644 --- a/mirzaev/skillparts/system/models/Product.php +++ b/mirzaev/skillparts/system/models/Product.php @@ -51,32 +51,9 @@ class Product extends Document * Файл .excel для импорта товаров * * Универсальный, когда неизвестно на какую позицию загружать каталог - * - * @todo Избавиться от свойств и сделать бесконечное количество места под новые каталоги */ public Excel|UploadedFile|string|null $file_excel = null; - /** - * Файл .excel для импорта товаров - * - * @todo Избавиться от свойств и сделать бесконечное количество места под новые каталоги - */ - public Excel|UploadedFile|string|null $file_excel_1 = null; - - /** - * Файл .excel для импорта товаров - * - * @todo Избавиться от свойств и сделать бесконечное количество места под новые каталоги - */ - public Excel|UploadedFile|string|null $file_excel_2 = null; - - /** - * Файл .excel для импорта товаров - * - * @todo Избавиться от свойств и сделать бесконечное количество места под новые каталоги - */ - public Excel|UploadedFile|string|null $file_excel_3 = null; - /** * Изображение для импорта */ @@ -132,9 +109,7 @@ class Product extends Document 'imgs' => 'Изображения (imgs)', 'time' => 'Срок доставки (time)', 'bffr' => 'Буфер', - 'file_excel_1' => 'Документ (file_excel_1)', - 'file_excel_2' => 'Документ (file_excel_2)', - 'file_excel_3' => 'Документ (file_excel_3)', + 'file_excel' => 'Документ (file_excel)', 'file_image' => 'Изображение (file_image)', 'group' => 'Группа (group)', 'account' => 'Аккаунт' @@ -194,11 +169,7 @@ class Product extends Document 'message' => '{attribute} должен иметь значение от 0 до 30000' ], [ - [ - 'file_excel_1', - 'file_excel_2', - 'file_excel_3' - ], + 'file_excel', 'file', 'skipOnEmpty' => true, 'extensions' => 'xlsx', diff --git a/mirzaev/skillparts/system/models/Supply.php b/mirzaev/skillparts/system/models/Supply.php index ae8a4ac..89476b7 100644 --- a/mirzaev/skillparts/system/models/Supply.php +++ b/mirzaev/skillparts/system/models/Supply.php @@ -13,7 +13,7 @@ use app\models\SupplyEdgeProduct; use app\models\Settings; use app\models\Import; use app\models\ImportEdgeSupply; -use app\models\ImportEdgeAccount; +use app\models\WarehouseEdgeImport; use carono\exchange1c\interfaces\OfferInterface; use carono\exchange1c\interfaces\ProductInterface; @@ -379,8 +379,11 @@ class Supply extends Product implements ProductInterface, OfferInterface * * На данный момент обрабатывает только импорт из * файлов с расширением .excel + * + * @param int $warehouse Идентификатор склада (_key) + * @param Account|int|null $account Аккаунт */ - public function importExcel(Account|int|null $account = null): bool + public function importExcel(int $warehouse, Account|int|null $account = null): bool { // Инициализация $data = []; @@ -391,49 +394,26 @@ class Supply extends Product implements ProductInterface, OfferInterface if ($this->validate()) { // Пройдена проверка - if (isset($this->file_excel_1)) { - // Найден файл в позиции 1 - - // Инициализация позиции - $position = 1; - - // Запись в буфер - $file = $this->file_excel_1; - } else if (isset($this->file_excel_2)) { - // Найден файл в позиции 2 - - // Инициализация позиции - $position = 2; - - // Запись в буфер - $file = $this->file_excel_2; - } else if (isset($this->file_excel_3)) { - // Найден файл в позиции 3 - - // Инициализация позиции - $position = 3; - - // Запись в буфер - $file = $this->file_excel_3; - } else { - // Не найден ни один файл + if (!isset($this->file_excel)) { + // Не найден файл // Запись ошибки - $this->addError('erros', 'Файл для импорта не найден'); + $this->addError('errors', 'Файл для импорта не найден'); + + return false; } - // Инициализация + // Инициализация хранилища файлов preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone); $timezone = $timezone[1][0]; - // $path = YII_PATH_PUBLIC . "/../assets/accounts/$account->_key/files/" . (new DateTime('now', new DateTimeZone($timezone)))->getTimestamp(); - $path = YII_PATH_PUBLIC . "/files/$account->_key/" . (new DateTime('now', new DateTimeZone($timezone)))->getTimestamp(); + $path = YII_PATH_PUBLIC . "/files/$account->_key/$warehouse/" . (new DateTime('now', new DateTimeZone($timezone)))->getTimestamp(); // Сохранение на диск if (!file_exists($path)) if (!mkdir($path, 0775, true)) throw new Exception('Не удалось создать директорию', 500); - $file->saveAs($path = "$path/" . $filename = $file->baseName . '.' . $file->extension); + $this->file_excel->saveAs($path = "$path/" . $filename = $this->file_excel->baseName . '.' . $this->file_excel->extension); $data[] = Excel::import($path, [ 'setFirstRecordAsKeys' => true, @@ -449,7 +429,7 @@ class Supply extends Product implements ProductInterface, OfferInterface if (count($data) < 1) { // Не найдены строки с товарами - $this->addError('erros', 'Не удалось найти данные товаров'); + $this->addError('errors', 'Не удалось найти данные товаров'); } else { // Найдены строки с товарами @@ -542,17 +522,16 @@ class Supply extends Product implements ProductInterface, OfferInterface $import->file = $path; $import->name = $filename; - $import->pstn = $position; if ($import->save()) { // Инстанция импорта успешно загружена - if (ImportEdgeAccount::write(yii::$app->user->identity->collectionName() . '/' . yii::$app->user->identity->_key, $import->collectionName() . "/$import->_key", data: ['type' => 'loaded'])) { - // Записано ребро: АККАУНТ -> ИНСТАНЦИЯ ПОСТАВОК + if (WarehouseEdgeImport::write(Warehouse::collectionName() . "/$warehouse", $import->readId(), data: ['type' => 'loaded'])) { + // Записано ребро: СКЛАД -> ИНСТАНЦИЯ ПОСТАВОК // Запись в журнал инстанции импорта - $import->journal('connect_with_account', [ - 'target' => yii::$app->user->identity->collectionName() . '/' . yii::$app->user->identity->_key + $import->journal('connect_with_warehouse', [ + 'target' => Warehouse::collectionName() . "/$warehouse" ]); } @@ -564,7 +543,7 @@ class Supply extends Product implements ProductInterface, OfferInterface // Запись в журнал инстанции импорта $import->journal('connect_with_supply', [ - 'target' => $supply->collectionName() . "/$supply->_key" + 'target' => $supply->readId() ]); } } @@ -575,19 +554,19 @@ class Supply extends Product implements ProductInterface, OfferInterface static::afterImportExcel($created, $updated); // Удаление (важно именно задать null для формы в представлении) - $this->file_excel_1 = $this->file_excel_2 = $this->file_excel_3 = null; + $this->file_excel = null; return true; } // Запись ошибки - $this->addError('erros', 'Не пройдена проверка параметров'); + $this->addError('errors', 'Не пройдена проверка параметров'); // Макрос действий после импорта static::afterImportExcel($created, $updated); // Удаление (важно именно задать null для формы в представлении) - $this->file_excel_1 = $this->file_excel_2 = $this->file_excel_3 = null; + $this->file_excel = null; return false; } @@ -757,34 +736,34 @@ class Supply extends Product implements ProductInterface, OfferInterface return []; } - // /** - // * Прочитать стоимость - // * - // * @param Product|null $product Товар для поиска по вершинам - // * - // * @return array|null Данные о ценах - // */ - // public function readCost(Product $product = null): ?array - // { - // return static::readCostById($this->readId(), $product); - // } + /** + * Прочитать стоимость + * + * @param Product|null $product Товар для поиска по вершинам + * + * @return array|null Данные о ценах + */ + public function readCost(Product $product = null): ?array + { + return static::readCostById($this->readId(), $product); + } - // /** - // * Прочитать стоимость по идентификатору поставки - // * - // * @param string $_id Идентификатор поставки - // * @param Product|null $product Товар для поиска по вершинам - // * - // * @return array|null Данные о ценах - // */ - // public static function readCostById(string $_id, Product $product = null): ?array - // { - // if (isset($product)) { - // return SupplyEdgeProduct::searchByVertex($_id, $product->readId(), type: 'connect', limit: 1)['onec']['Цены']['Цена']; - // } + /** + * Прочитать стоимость по идентификатору поставки + * + * @param string $_id Идентификатор поставки + * @param Product|null $product Товар для поиска по вершинам + * + * @return array|null Данные о ценах + */ + public static function readCostById(string $_id, Product $product = null): ?array + { + if (isset($product)) { + return SupplyEdgeProduct::searchByVertex($_id, $product->readId(), type: 'connect', limit: 1)['onec']['Цены']['Цена']; + } - // return SupplyEdgeProduct::searchByDirection($_id, type: 'connect', limit: 1)['onec']['Цены']['Цена']; - // } + return SupplyEdgeProduct::searchByDirection($_id, type: 'connect', limit: 1)['onec']['Цены']['Цена']; + } /** * Найти аккаунт владельца diff --git a/mirzaev/skillparts/system/models/Warehouse.php b/mirzaev/skillparts/system/models/Warehouse.php new file mode 100644 index 0000000..53df396 --- /dev/null +++ b/mirzaev/skillparts/system/models/Warehouse.php @@ -0,0 +1,246 @@ + 'Название', + 'addr' => 'Адрес', + 'trmn' => 'Терминал', + 'actv' => 'Активность' + ] + ); + } + + /** + * Правила + */ + public function rules(): array + { + return array_merge( + parent::rules(), + [ + [ + [ + 'name', + 'addr' + ], + 'string' + ], + [ + 'actv', + 'boolean' + ] + ] + ); + } + + /** + * Запись по аккаунту + * + * @param Account|null $account Аккаунт + * + * @return static|null Записанный склад + */ + public static function writeByAccount(Account|null $account = null): ?static + { + // Инициализация аккаунта + $account = Account::initAccount($account); + + // Инициализация склада + $warehouse = new static; + + // Запись параметров склада + $warehouse->actv = true; + + if ($warehouse->save()) { + // Удалось записать склад в базу данных + + // Инициализация ребра: АККАУНТ -> СКЛАД + AccountEdgeWarehouse::writeSafe($account->readId(), $warehouse->readId(), data: ['type' => 'connected']); + + return $warehouse; + } + + return null; + } + + /** + * Найти по аккаунту + * + * @param Account|null $account Аккаунт + * @param int $limit Ограничение по максимальному количеству + * + * @return mixed Склады + */ + public static function searchByAccount(Account|null $account = null, int $limit = 10): mixed + { + if ($account = Account::initAccount($account)) { + // Инициализирован аккаунт + + return static::searchByEdge( + from: 'account', + to: 'warehouse', + edge: 'account_edge_warehouse', + direction: 'INBOUND', + subquery_where: [ + [ + 'account_edge_warehouse._from == "' . $account->readId() . '"' + ], + [ + 'account_edge_warehouse.type == "connected"' + ] + ], + where: 'account_edge_warehouse[0] != null', + limit: $limit + ); + } + + return null; + } + + /** + * Инициализация с записью + * + * Читает все склады привязанные к аккаунту, либо создает новый склад + * + * @param Account|null $account Аккаунт + * @param int $limit — Ограничение по максимальному количеству + * + * @return array Склады + */ + public static function initWithWrite(Account|null $account = null, int $limit = 10): array + { + if ($account = Account::initAccount($account)) { + // Инициализирован аккаунт + + if ($warehouses = static::searchByAccount($account, $limit)) { + // Найдены склады + + return $warehouses; + } + + return [static::writeByAccount()]; + } + + return []; + } + + /** + * Генерация списка терминалов из ДеловыеЛинии для отправителя + * + * Актуальное (выбранное, активное) значение записывается первым + * + * @param array Необработанный список терминалов + */ + public function genListTerminalsFrom(): array + { + // Инициализация + $list = []; + + $cities = Dellin::read(9999); + + foreach ($cities as $city) { + // Перебор городов + + foreach ($city->data['terminals']['terminal'] as $termial) { + // Перебор терминалов + + if (in_array($termial['id'], $list, true)) { + // Если встретился дубликат (исполняется очень часто) + + continue; + } + + // Запись + $list[$termial['id']] = $city->data['name'] . ' (' . $termial['address'] . ')'; + } + } + + return $this->syncListWithSettings($list, 'trmn'); + } + + /** + * Синхронизация списка вариантов параметра с текущим значением из настроек + * + * @param array &$list Список + * @param string $var Название параметра + * + * @return array Сортированный список + */ + protected function syncListWithSettings(array &$list, string $var): array + { + // Инициализация текущего значения параметра в начале массива + if (isset($this->$var)) { + // Параметр найден в настройках аккаунта + + if (isset($list[$this->$var])) { + // Найдено совпадение сохранённого параметра с полученным списком из поставок + + // Буфер для сохранения параметра + $buffer = $list[$this->$var]; + + // Удаление параметра + unset($list[$this->$var]); + + // Сохранение параметра в начале массива + $list = [$this->$var => $buffer] + $list; + } else { + // Совпадение не найдено + + // Сохранение параметра из данных аккаунта в начале массива + $list = [$this->$var => $this->$var] + $list; + } + } else { + // Параметр $var не найден в настройках аккаунта + + // Сохранение параметра из данных аккаунта в начале массива + $list = ['Выберите' => 'Выберите'] + $list; + } + + return $list; + } +} diff --git a/mirzaev/skillparts/system/models/WarehouseEdgeImport.php b/mirzaev/skillparts/system/models/WarehouseEdgeImport.php new file mode 100644 index 0000000..4406922 --- /dev/null +++ b/mirzaev/skillparts/system/models/WarehouseEdgeImport.php @@ -0,0 +1,51 @@ +where(['_from' => $warehouse->readId()])->limit($limit)->all(); + } + + /** + * Поиск по инстанции импорта + * + * @param Import $import Инстанция импорта + * @param int $limit Ограничение по максимальному количеству + * + * @return array Связи склада и инстанций поставок + * + * @deprecated Бесполезно + */ + public static function searchByImport(Import $import, int $limit = 1): array + { + return static::find()->where(['_to' => $import->readId()])->limit($limit)->all(); + } +} diff --git a/mirzaev/skillparts/system/views/profile/index.php b/mirzaev/skillparts/system/views/profile/index.php index 6f10ce9..5023bb2 100644 --- a/mirzaev/skillparts/system/views/profile/index.php +++ b/mirzaev/skillparts/system/views/profile/index.php @@ -25,7 +25,6 @@ if (
-

Настройки

user->isGuest) : ?> diff --git a/mirzaev/skillparts/system/views/profile/monitoring.php b/mirzaev/skillparts/system/views/profile/monitoring.php index 600769e..fbb9265 100644 --- a/mirzaev/skillparts/system/views/profile/monitoring.php +++ b/mirzaev/skillparts/system/views/profile/monitoring.php @@ -15,7 +15,6 @@ $panel ?? $panel = 'profile_panel_monitoring_input_search_history';
-

Мониторинг

diff --git a/mirzaev/skillparts/system/views/profile/panel.php b/mirzaev/skillparts/system/views/profile/panel.php index ff75e1c..6e83b7d 100644 --- a/mirzaev/skillparts/system/views/profile/panel.php +++ b/mirzaev/skillparts/system/views/profile/panel.php @@ -34,7 +34,6 @@ $timezone = $timezone[1][0];
-

Панель управления

diff --git a/mirzaev/skillparts/system/views/profile/supplies.php b/mirzaev/skillparts/system/views/profile/supplies.php index 2178dbf..52718af 100644 --- a/mirzaev/skillparts/system/views/profile/supplies.php +++ b/mirzaev/skillparts/system/views/profile/supplies.php @@ -6,9 +6,9 @@ use yii; use yii\bootstrap\ActiveForm; use app\models\Account; -use app\models\Document; use app\models\Import; use app\models\Settings; +use app\models\Warehouse; use DateTime; use DateTimeZone; @@ -27,11 +27,10 @@ $panel ?? $panel = 'profile_panel_supplies_input_import';
-

Управление поставками

- +
@@ -42,10 +41,10 @@ $panel ?? $panel = 'profile_panel_supplies_input_import'; />
-
Импорт из Excel-документа
+
Управление складами
- + 'form_product_import_excel', @@ -62,7 +61,7 @@ $panel ?? $panel = 'profile_panel_supplies_input_import'; ?> field($supply, 'account', ['options' => ['class' => "ml-auto mb-4 pr-0 col-4 d-flex"]])->input('text', ['placeholder' => yii::$app->user->identity->_key])->label(options: ['class' => 'mr-2 my-auto font-weight-bold']); ?> - field($supply, 'file_excel', ['enableLabel' => false, 'options' => ['class' => 'mr-auto mb-4 pr-0 col-5 d-flex flex-column']])->fileInput(['class' => 'my-auto', 'multiple' => true, 'onChange' => 'page_profile_supplies_import_excel_moderator(this.parentElement.parentElement, \'profile_panel_supplies_input_import\', this.parentElement.parentElement.getElementsByTagName(\'input\')[0].value)']) ?> + field($supply, 'file_excel', ['enableLabel' => false, 'options' => ['class' => 'mr-auto mb-4 pr-0 col-5 d-flex flex-column']])->fileInput(['class' => 'my-auto', 'multiple' => true, 'onChange' => 'page_profile_supplies_import_excel(this.parentElement.parentElement, this.parentElement.parentElement.getElementsByTagName(\'input\')[0].value, \'profile_panel_supplies_input_import\')']) ?> 'form_product_import_excel', - 'action' => false, - 'fieldConfig' => [ - 'template' => '{label}{input}', - 'options' => ['class' => ''] - ], - 'options' => [ - 'class' => 'px-3 mb-3', - 'onsubmit' => 'return false;' - ] - ]); + // Инициализация складов + $warehouses = Warehouse::initWithWrite(); + + // Инициализация итератора + $amount_warehouses = 0; ?> - -
-
1.
-
- name ?? 'Без названия' ?> + +
+
name ?? 'Без названия' ?>
+ + 'form_warehouse_settings', + 'action' => false, + 'fieldConfig' => [ + 'template' => '{label}{input}', + ], + 'options' => [ + 'onsubmit' => 'return false;' + ] + ]); + + $list = $warehouse->genListTerminalsFrom(); + ?> + + field($warehouse, 'trmn', ['options' => ['class' => "mb-3"]]) + ->dropDownList($list, [ + 'onChange' => 'page_profile_settings(this.parentElement.parentElement, \'profile_panel_settings_company\')', + 'disabled' => count($list) <= 1 + ])->label(false); ?> + + + + + + +
+
.
+
+ name ?? 'Без названия' ?> +
+ + +
+ + + 'form_warehouse_supplies', + 'action' => false, + 'fieldConfig' => [ + 'template' => '{label}{input}', + 'options' => ['class' => ''] + ], + 'options' => [ + 'class' => 'px-3 mb-3', + 'onsubmit' => 'return false;' + ] + ]); + ?> + +
+ field($supply, 'file_excel', ['enableLabel' => false])->fileInput(['multiple' => true, 'onChange' => 'page_profile_supplies_import_excel(this.parentElement.parentElement.parentElement, ' . $warehouse->_key . ', undefined, \'profile_panel_supplies_input_import\')']) ?>
- - -
- -
-
1.
-
- field($supply, 'file_excel_1', ['enableLabel' => false])->fileInput(['multiple' => true, 'onChange' => 'page_profile_supplies_import_excel(this.parentElement.parentElement.parentElement.parentElement, \'profile_panel_supplies_input_import\')']) ?> -
-
- - + errorSummary($supply, ['header' => 'В документе были допущены ошибки:' /*, 'footer' => 'Исправьте их и попробуйте снова'*/]); ?> - -
-
2.
-
- name ?? 'Без названия' ?> -
- - -
- -
-
2.
-
- field($supply, 'file_excel_2', ['enableLabel' => false])->fileInput(['multiple' => true, 'onChange' => 'page_profile_supplies_import_excel(this.parentElement.parentElement.parentElement.parentElement, \'profile_panel_supplies_input_import\')']) ?> -
-
- - - - - -
-
3.
-
- name ?? 'Без названия' ?> -
- - -
- -
-
3.
-
- field($supply, 'file_excel_3', ['enableLabel' => false])->fileInput(['multiple' => true, 'onChange' => 'page_profile_supplies_import_excel(this.parentElement.parentElement.parentElement.parentElement, \'profile_panel_supplies_input_import\')']) ?> -
-
- - - errorSummary($supply, ['header' => 'В документе были допущены ошибки:' /*, 'footer' => 'Исправьте их и попробуйте снова'*/]); ?> - - + + + + + + -
diff --git a/mirzaev/skillparts/system/web/.htaccess b/mirzaev/skillparts/system/web/.htaccess deleted file mode 100644 index 197199e..0000000 --- a/mirzaev/skillparts/system/web/.htaccess +++ /dev/null @@ -1,4 +0,0 @@ -RewriteEngine on -RewriteCond %{REQUEST_FILENAME} !-d -RewriteCond %{REQUEST_FILENAME} !-f -RewriteRule . index.php [L] diff --git a/mirzaev/skillparts/system/web/assets/.gitignore b/mirzaev/skillparts/system/web/files/20827450/.gitignore similarity index 100% rename from mirzaev/skillparts/system/web/assets/.gitignore rename to mirzaev/skillparts/system/web/files/20827450/.gitignore diff --git a/mirzaev/skillparts/system/web/js/profile.js b/mirzaev/skillparts/system/web/js/profile.js index 84412bf..708d2fb 100644 --- a/mirzaev/skillparts/system/web/js/profile.js +++ b/mirzaev/skillparts/system/web/js/profile.js @@ -27,34 +27,40 @@ function page_profile_supplies(form, panel) { return false; }; -function page_profile_supplies_import_excel(form, panel, account) { +function page_profile_supplies_import_excel(form, warehouse, account, panel) { function send(help = false) { if (form === undefined) { form = { '_csrf': yii.getCsrfToken() }; + form.help = +help; + if (panel !== undefined) { form.panel = panel; }; - if (account !== undefined) { - form.number = prompt('Номер позиции в которую загружать каталог', 1); + if (warehouse !== undefined) { + form.warehouse = warehouse; + }; + if (account !== undefined) { form.account = account; }; } else { form = new FormData(form); - form.append('help', help); + form.append('help', +help); if (panel !== undefined) { form.append('panel', panel); }; - if (account !== undefined) { - form.append('number', prompt('Номер позиции в которую загружать каталог', 1)); + if (warehouse !== undefined) { + form.append('warehouse', warehouse); + }; + if (account !== undefined) { form.append('account', account); }; };