diff --git a/mirzaev/skillparts/system/config/web.php.example b/mirzaev/skillparts/system/config/web.php.example index d3e408a..cdd45b8 100644 --- a/mirzaev/skillparts/system/config/web.php.example +++ b/mirzaev/skillparts/system/config/web.php.example @@ -103,6 +103,8 @@ $config = [ '///' => '
/-', 'profile/geolocation/' => 'profile/geolocation-', 'profile/panel///' => 'profile/panel---', + 'profile/imports/' => 'profile/imports-', + 'profile/warehouses/' => 'profile/warehouses-', 'orders' => 'order/index', 'orders/' => 'order/index', 'orders//' => 'order/', diff --git a/mirzaev/skillparts/system/controllers/ProfileController.php b/mirzaev/skillparts/system/controllers/ProfileController.php index 9e1b9cd..99fb44a 100644 --- a/mirzaev/skillparts/system/controllers/ProfileController.php +++ b/mirzaev/skillparts/system/controllers/ProfileController.php @@ -20,7 +20,10 @@ use app\models\Settings; use app\models\Dellin; use app\models\SettingsEdgeSettings; use app\models\Terminal; +use app\models\Import; +use app\models\ImportEdgeSupply; use app\models\Warehouse; +use app\models\WarehouseEdgeImport; use Dadata\DadataClient as Dadata; use Throwable; @@ -49,7 +52,11 @@ class ProfileController extends Controller 'monitoring', 'readGroups', 'geolocation-write', - 'panel-suppliers-requests-search' + 'panel-suppliers-requests-search', + 'imports-delete', + 'warehouses-write', + 'warehouses-rename', + 'warehouses-delete' ] ], [ @@ -976,4 +983,340 @@ class ProfileController extends Controller return; } + + 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() + ]; + } + } + + /** + * Удалить инстанцию поставки + * + * @return array|string|null + */ + public function actionImportsDelete(): array|string|null + { + // Инициализация аккаунта + $account = Account::initAccount(); + + // Инициализация остальных входных параметров + $supply = new Supply(yii::$app->request->post('Supply') ?? yii::$app->request->get('Supply')); + $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel'); + $sidebar = $this->renderPartial('sidebar'); + $groups = self::readGroups(); + + if (yii::$app->request->isPost) { + // POST-запрос + + // Запись заголовка с типом ответа + yii::$app->response->format = Response::FORMAT_JSON; + + // Инициализация буфера вывода + $return = [ + '_csrf' => yii::$app->request->getCsrfToken() + ]; + + // Инициализация идентификатора + $_key = yii::$app->request->post('_key'); + + if (empty($_key)) { + // Не передан идентификатор + + // Запись кода ошибки + yii::$app->response->statusCode = 500; + + return $return; + } + + if ($import = Import::searchById(Import::collectionName() . "/$_key")) { + // Найдена инстанция поставки + + if ($edge = WarehouseEdgeImport::searchByImport($import)[0]) { + // Найдено ребро: СКЛАД -> ИНСТАНЦИЯ ПОСТАВКИ + + // Инициализация счётчика удалённых поставок + $deleted = 0; + + foreach (Supply::searchByImport($import->readId(), limit: 9999) as $supply) { + // Перебор найденных поставок + + if (ImportEdgeSupply::searchBySupply($supply, limit: 1)?->delete() === 1) { + // Удалено ребро: ИНСТАНЦИЯ ПОСТАВКИ -> ПОСТАВКА + + // Удаление поставки + if ($supply->delete() === 1) ++$deleted; + } + } + + // Отправка уведомления + Notification::_write("Удалено $deleted поставок из инстанции поставки $_key", account: $account->_key); + + if ($edge->delete()) { + // Удалено ребро: СКЛАД -> ИНСТАНЦИЯ ПОСТАВКИ + + if ($import->delete()) { + // Удалена инстанция поставки + + // Отправка уведомления + Notification::_write("Инстанция поставки $_key была удалена", account: $account->_key); + } + } + } + } else { + // Не найдена инстанция поставки + + // Отправка уведомления + Notification::_write("Не найдена инстанция поставки $_key", account: $account->_key); + } + + // Запись в буфер вывода реинициализированного элемента + $return['main'] = $this->renderPartial('supplies', compact( + 'supply', + 'groups', + 'sidebar', + 'panel' + )); + + return $return; + } + } + + /** + * Записать (создать) склад + * + * @return array|string|null + */ + public function actionWarehousesWrite(): array|string|null + { + // Инициализация аккаунта + $account = Account::initAccount(); + + // Инициализация остальных входных параметров + $supply = new Supply(yii::$app->request->post('Supply') ?? yii::$app->request->get('Supply')); + $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel'); + $sidebar = $this->renderPartial('sidebar'); + $groups = self::readGroups(); + + if (yii::$app->request->isPost) { + // POST-запрос + + // Запись заголовка с типом ответа + yii::$app->response->format = Response::FORMAT_JSON; + + // Инициализация буфера вывода + $return = [ + '_csrf' => yii::$app->request->getCsrfToken() + ]; + + // Запись склада + if (Warehouse::writeByAccount($account)) Notification::_write("Создан новый склад", account: $account->_key); + else Notification::_write("Не удалось создать новый склад", account: $account->_key); + + // Запись в буфер вывода реинициализированного элемента + $return['main'] = $this->renderPartial('supplies', compact( + 'supply', + 'groups', + 'sidebar', + 'panel' + )); + + return $return; + } + } + + + /** + * Переименовать склад + * + * @return array|string|null + */ + public function actionWarehousesRename(): array|string|null + { + // Инициализация аккаунта + $account = Account::initAccount(); + + // Инициализация остальных входных параметров + $supply = new Supply(yii::$app->request->post('Supply') ?? yii::$app->request->get('Supply')); + $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel'); + $sidebar = $this->renderPartial('sidebar'); + $groups = self::readGroups(); + + if (yii::$app->request->isPost) { + // POST-запрос + + // Запись заголовка с типом ответа + yii::$app->response->format = Response::FORMAT_JSON; + + // Инициализация буфера вывода + $return = [ + '_csrf' => yii::$app->request->getCsrfToken() + ]; + + // Инициализация идентификатора + $_key = yii::$app->request->post('_key'); + + // Инициализация названия\ + $name = yii::$app->request->post('name'); + + if (empty($_key) || empty($name)) { + // Не передан идентификатор или название + + // Запись кода ошибки + yii::$app->response->statusCode = 500; + + return $return; + } + + if ($warehouse = Warehouse::searchById(Warehouse::collectionName() . "/$_key")) { + // Найден склад + + // Запись старого названия + $old = $warehouse->name; + + // Запись параметров + $warehouse->name = $name; + + if ($warehouse->update() >= 1) { + // Обновлён склад + + // Отправка уведомления + Notification::_write("Склад $_key переименован: \"$old\" > \"$name\"", account: $account->_key); + } else { + // Не обновлён склад + + // Отправка уведомления + Notification::_write("Не удалось переименовать склад $_key", account: $account->_key); + } + } else { + // Не найден склад + + // Отправка уведомления + Notification::_write("Не найден склад $_key", account: $account->_key); + } + + // Запись в буфер вывода реинициализированного элемента + $return['main'] = $this->renderPartial('supplies', compact( + 'supply', + 'groups', + 'sidebar', + 'panel' + )); + + return $return; + } + } + + /** + * Удалить склад + * + * @return array|string|null + */ + public function actionWarehousesDelete(): array|string|null + { + // Инициализация аккаунта + $account = Account::initAccount(); + + // Инициализация остальных входных параметров + $supply = new Supply(yii::$app->request->post('Supply') ?? yii::$app->request->get('Supply')); + $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel'); + $sidebar = $this->renderPartial('sidebar'); + $groups = self::readGroups(); + + if (yii::$app->request->isPost) { + // POST-запрос + + // Запись заголовка с типом ответа + yii::$app->response->format = Response::FORMAT_JSON; + + // Инициализация буфера вывода + $return = [ + '_csrf' => yii::$app->request->getCsrfToken() + ]; + + // Инициализация идентификатора + $_key = yii::$app->request->post('_key'); + + if (empty($_key)) { + // Не передан идентификатор + + // Запись кода ошибки + yii::$app->response->statusCode = 500; + + return $return; + } + + if ($warehouse = Warehouse::searchById(Warehouse::collectionName() . "/$_key")) { + // Найден склад + + foreach (Import::searchByWarehouse($warehouse, limit: 100) as $import) { + // Найдены инстанции поставки + + if ($edge = WarehouseEdgeImport::searchByImport($import)[0]) { + // Найдено ребро: СКЛАД -> ИНСТАНЦИЯ ПОСТАВКИ + + // Инициализация счётчика удалённых поставок + $deleted = 0; + + foreach (Supply::searchByImport($import->readId(), limit: 9999) as $supply) { + // Перебор найденных поставок + + if (ImportEdgeSupply::searchBySupply($supply, limit: 1)?->delete() === 1) { + // Удалено ребро: ИНСТАНЦИЯ ПОСТАВКИ -> ПОСТАВКА + + // Удаление поставки + if ($supply->delete() === 1) ++$deleted; + } + } + + // Отправка уведомления + Notification::_write("Удалено $deleted поставок из инстанции поставки $_key", account: $account->_key); + + if ($edge->delete()) { + // Удалено ребро: СКЛАД -> ИНСТАНЦИЯ ПОСТАВКИ + + if ($import->delete()) { + // Удалена инстанция поставки + + // Отправка уведомления + Notification::_write("Инстанция поставки $_key была удалена", account: $account->_key); + } + } + } + } + + + if ($warehouse->delete()) { + // Удалён склад + + // Отправка уведомления + Notification::_write("Склад $_key был удалён", account: $account->_key); + } + } else { + // Не найден склад + + // Отправка уведомления + Notification::_write("Не найден склад $_key", account: $account->_key); + } + + // Запись в буфер вывода реинициализированного элемента + $return['main'] = $this->renderPartial('supplies', compact( + 'supply', + 'groups', + 'sidebar', + 'panel' + )); + + return $return; + } + } } diff --git a/mirzaev/skillparts/system/models/Account.php b/mirzaev/skillparts/system/models/Account.php index adc3192..51062ea 100644 --- a/mirzaev/skillparts/system/models/Account.php +++ b/mirzaev/skillparts/system/models/Account.php @@ -794,7 +794,7 @@ class Account extends Document implements IdentityInterface, PartnerInterface } /** - * Поиск заявок на регистрацию поставщиков + * Запись поставщика * * @return array */ diff --git a/mirzaev/skillparts/system/models/Supply.php b/mirzaev/skillparts/system/models/Supply.php index 89476b7..3046010 100644 --- a/mirzaev/skillparts/system/models/Supply.php +++ b/mirzaev/skillparts/system/models/Supply.php @@ -166,6 +166,16 @@ class Supply extends Product implements ProductInterface, OfferInterface ); } + /** + * Поиск через связь с инстанцией импорта + * + * @param string|null $id Идентификатор инстанции импорта + */ + public static function searchByImport(string|null $id = null, int|null $limit = 10): array + { + return static::find()->where(['_from' => $id])->limit($limit)->all(); + } + /** * Запись данных свойств по UUID 1C * @@ -623,14 +633,6 @@ class Supply extends Product implements ProductInterface, OfferInterface return null; } - /** - * - */ - public function write($context = null) - { - return $this->onec; - } - /** * @param mixed|null $context * @return array diff --git a/mirzaev/skillparts/system/models/WarehouseEdgeImport.php b/mirzaev/skillparts/system/models/WarehouseEdgeImport.php index 4406922..74baf0a 100644 --- a/mirzaev/skillparts/system/models/WarehouseEdgeImport.php +++ b/mirzaev/skillparts/system/models/WarehouseEdgeImport.php @@ -38,14 +38,11 @@ class WarehouseEdgeImport extends Edge * Поиск по инстанции импорта * * @param Import $import Инстанция импорта - * @param int $limit Ограничение по максимальному количеству * * @return array Связи склада и инстанций поставок - * - * @deprecated Бесполезно */ - public static function searchByImport(Import $import, int $limit = 1): array + public static function searchByImport(Import $import): array { - return static::find()->where(['_to' => $import->readId()])->limit($limit)->all(); + return static::find()->where(['_to' => $import->readId()])->limit(1)->all(); } } diff --git a/mirzaev/skillparts/system/views/cart/index.php b/mirzaev/skillparts/system/views/cart/index.php index 4b61362..d7991e9 100644 --- a/mirzaev/skillparts/system/views/cart/index.php +++ b/mirzaev/skillparts/system/views/cart/index.php @@ -230,8 +230,8 @@ use DateTime;
- - + +
@@ -260,6 +260,8 @@ use DateTime; $delivery_to_terminal_list ?? $delivery_to_terminal_list = ['Нет данных']; ?> + Терминал для получения + field($model_delivery, 'opts[delivery_to_terminal]', ['options' => ['class' => "mb-0"]]) ->dropDownList($delivery_to_terminal_list, [ 'onChange' => 'page_profile_settings(this.parentElement.parentElement, undefined, \'\'); cart_cost_calculate();', @@ -271,10 +273,11 @@ use DateTime;
@@ -291,11 +294,15 @@ use DateTime; cart_cost_calculate(); cart_registration_entity_init(); + + cart_registration_choose('cart_registration_entity', ); } else { document.addEventListener('DOMContentLoaded', function() { cart_cost_calculate(); cart_registration_entity_init(); + + cart_registration_choose('cart_registration_entity', ); }, false); } diff --git a/mirzaev/skillparts/system/views/profile/supplies.php b/mirzaev/skillparts/system/views/profile/supplies.php index a7906bf..cdcdc7a 100644 --- a/mirzaev/skillparts/system/views/profile/supplies.php +++ b/mirzaev/skillparts/system/views/profile/supplies.php @@ -40,7 +40,7 @@ $panel ?? $panel = 'profile_panel_supplies_input_import';
/> -
+
Управление складами
@@ -105,7 +105,9 @@ $panel ?? $panel = 'profile_panel_supplies_input_import'; ?>
-
.
+
+ . +
name ?? 'Без названия' ?>
@@ -113,8 +115,8 @@ $panel ?? $panel = 'profile_panel_supplies_input_import';
- - + +
@@ -130,8 +132,12 @@ $panel ?? $panel = 'profile_panel_supplies_input_import'; $amount_warehouses = 0; ?> -
-
name ?? 'Без названия' ?>
+
+
+ name ?? 'Без названия' ?> + + +
'form_warehouse_settings', @@ -161,13 +167,20 @@ $panel ?? $panel = 'profile_panel_supplies_input_import'; ?> + file, $matches); + $download = $matches[0][0]; + ?>
-
.
+
+ . +
name ?? 'Без названия' ?>
- - + +
@@ -180,13 +193,13 @@ $panel ?? $panel = 'profile_panel_supplies_input_import'; 'options' => ['class' => ''] ], 'options' => [ - 'class' => 'px-3 mb-3', + 'class' => 'px-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\')']) ?>
@@ -196,10 +209,39 @@ $panel ?? $panel = 'profile_panel_supplies_input_import';
- + + + +
+ + +
+
+ 1. Заполните Excel-документ, где в первой строке записаны названия колонок +
Артикул: "артикул", "article", "catn"
+
Производитель: "производитель", "production", "prod"
+
Стоимость: "стоимость", "cost"
+
Количество: "количество", "amount", "amnt"
+ +
+ 2. Выберите или создайте склад и настройте его +
1. Установите город в котором находится склад
+
2. Нажмите на кнопку "Обзор..." и выбирете Excel-документ
+
3. Вам предложит подтвердить отправку на сервер
+
4. Если вы не уверены, что правильно заполнили документ, то отклоните загрузку и вам предложит отправить документ модератору. Мы сами настроим и загрузим ваш документ, а так же пришлем исправления, если выявим ошибки
+ +
+ 3. Проверьте что все товары загрузились успешно +
1. Присутствуют в поиске
+
2. Отображаются в списке поставок склада
+
3. В полученном уведомлении не написано об ошибках или непривязанных поставках. Если поставка не привязалась, то модератор автоматически получает запрос на решение проблемы (отсутствие товара в базе данных, либо неподходящие данные в документе). После обработки вам придёт уведомление и письмо на почту
+ +
+
+
diff --git a/mirzaev/skillparts/system/web/files/20827450/.gitignore b/mirzaev/skillparts/system/web/files/.gitignore similarity index 100% rename from mirzaev/skillparts/system/web/files/20827450/.gitignore rename to mirzaev/skillparts/system/web/files/.gitignore diff --git a/mirzaev/skillparts/system/web/files/20827450/1637773114/Тест импорта.xlsx b/mirzaev/skillparts/system/web/files/20827450/1637773114/Тест импорта.xlsx deleted file mode 100644 index 861f742..0000000 Binary files a/mirzaev/skillparts/system/web/files/20827450/1637773114/Тест импорта.xlsx and /dev/null differ diff --git a/mirzaev/skillparts/system/web/js/cart.js b/mirzaev/skillparts/system/web/js/cart.js index 9f54461..0daf049 100644 --- a/mirzaev/skillparts/system/web/js/cart.js +++ b/mirzaev/skillparts/system/web/js/cart.js @@ -471,30 +471,6 @@ function cart_registration_entity_generate(account) { block_details.setAttribute('id', 'details'); block_details.setAttribute('class', 'pr-0 col-6 d-flex flex-column'); - // Инициализация ярлыка "INDX" - let label_indx = document.createElement('label'); - label_indx.setAttribute('class', 'control-label'); - label_indx.innerText = 'Индекс'; - - // Инициализация оболочки "INDX" - let wrap_indx = document.createElement('div'); - wrap_indx.setAttribute('class', 'row mx-0 mb-3'); - - // Инициализация поля "INDX" - let input_indx = document.createElement('input'); - input_indx.setAttribute('id', 'indx'); - input_indx.setAttribute('class', 'col form-control button_clean'); - input_indx.setAttribute('type', 'text'); - input_indx.setAttribute('onchange', 'return cart_registration_block_edit(' + account._key + ', "indx", this.value);'); - input_indx.value = account.indx ?? ''; - - // Инициализация кнопки "INDX" - let button_indx = document.createElement('a'); - button_indx.setAttribute('class', 'ml-2 my-auto text-dark'); - button_indx.setAttribute('type', 'button'); - button_indx.setAttribute('role', 'button'); - button_indx.innerHTML = ''; - // Инициализация ярлыка "TAXN" let label_taxn = document.createElement('label'); label_taxn.setAttribute('class', 'control-label'); @@ -563,7 +539,7 @@ function cart_registration_entity_generate(account) { // Инициализация ярлыка "CNTC" let label_cntc = document.createElement('label'); label_cntc.setAttribute('class', 'control-label'); - label_cntc.innerText = 'Контакты'; + label_cntc.innerText = 'Дополнительная информация'; // Инициализация поля "CNTC" let input_cntc = document.createElement('textarea'); @@ -598,11 +574,6 @@ function cart_registration_entity_generate(account) { block_info.appendChild(label_mail); block_info.appendChild(input_mail); - block_info.appendChild(label_indx); - wrap_indx.appendChild(input_indx); - wrap_indx.appendChild(button_indx); - block_info.appendChild(wrap_indx); - block_info.appendChild(label_cntc); block_info.appendChild(input_cntc); @@ -635,6 +606,23 @@ function cart_registration_entity_generate(account) { return html; }; +function cart_registration_choose(button = 'cart_registration_entity', account) { + // Деинициализация всех вкладок + document.getElementById('cart_registration_entity').checked = + document.getElementById('cart_registration_individual').checked = false; + + document.getElementById('cart_registration_entity').setAttribute('onclick', 'page_profile_panel_choose(\'cart_registration_entity\')'); + document.getElementById('cart_registration_individual').setAttribute('onclick', 'page_profile_panel_choose(\'cart_registration_individual\'); cart_registration_entity_init(' + account + ')'); + + document.querySelector('[for="cart_registration_entity"]').classList.remove('active'); + document.querySelector('[for="cart_registration_individual"]').classList.remove('active'); + + // Инициализация запрошенной вкладки + document.getElementById(button).checked = true; + document.getElementById(button + '_button').removeAttribute('onclick'); + document.querySelector('[for="' + button + '"]').classList.add('active'); +} + function cart_response(data, status, xhr) { // Обработка ответов diff --git a/mirzaev/skillparts/system/web/js/profile.js b/mirzaev/skillparts/system/web/js/profile.js index ce1e01a..a5b5e7a 100644 --- a/mirzaev/skillparts/system/web/js/profile.js +++ b/mirzaev/skillparts/system/web/js/profile.js @@ -83,6 +83,70 @@ function page_profile_supplies_import_excel(form, warehouse, account, panel) { return false; }; +function page_profile_imports_delete(_key) { + $.ajax({ + url: '/profile/imports/delete', + type: 'post', + dataType: 'json', + data: { + '_csrf': yii.getCsrfToken(), + _key + }, + success: page_profile_response_success, + error: page_profile_response_error + }); + + return false; +}; + +function page_profile_warehouses_write() { + $.ajax({ + url: '/profile/warehouses/write', + type: 'post', + dataType: 'json', + data: { + '_csrf': yii.getCsrfToken() + }, + success: page_profile_response_success, + error: page_profile_response_error + }); + + return false; +}; + +function page_profile_warehouses_delete(_key) { + $.ajax({ + url: '/profile/warehouses/delete', + type: 'post', + dataType: 'json', + data: { + '_csrf': yii.getCsrfToken(), + _key + }, + success: page_profile_response_success, + error: page_profile_response_error + }); + + return false; +}; + +function page_profile_warehouses_rename(_key, name) { + $.ajax({ + url: '/profile/warehouses/rename', + type: 'post', + dataType: 'json', + data: { + '_csrf': yii.getCsrfToken(), + _key, + name + }, + success: page_profile_response_success, + error: page_profile_response_error + }); + + return false; +}; + function page_supplies_settings(form, warehouse, panel) { if (form == undefined) { form = {