diff --git a/mirzaev/skillparts/system/models/Account.php b/mirzaev/skillparts/system/models/Account.php index 51062ea..3451df7 100644 --- a/mirzaev/skillparts/system/models/Account.php +++ b/mirzaev/skillparts/system/models/Account.php @@ -143,6 +143,50 @@ class Account extends Document implements IdentityInterface, PartnerInterface [ 'vrfy', 'validateVrfyUnique' + ], + [ + 'taxn', + 'integer', + 'min' => 0, + 'max' => 999999999999 + ], + [ + 'cntg', + 'integer', + 'min' => 0, + 'max' => 99999999999999999999 + ], + [ + 'ladd', + 'string', + 'length' => [0, 200] + ], + [ + [ + 'desc', + 'cntc' + ], + 'string', + 'length' => [0, 500] + ], + [ + 'simc', + 'integer', + 'min' => 0, + 'max' => 999999999999999999999999999999 + ], + [ + 'comp', + 'string', + 'length' => [0, 40] + ], + [ + [ + 'name', + 'boss' + ], + 'string', + 'length' => [0, 100] ] ] ); @@ -711,73 +755,88 @@ class Account extends Document implements IdentityInterface, PartnerInterface */ public static function passwordGenerate(): ?string { - return match (rand(1, 35)) { - 1 => 'салазки', - 2 => 'запчасти', - 3 => 'инструменты', - 4 => 'детали', - 5 => 'компоненты', - 6 => 'ремни', - 7 => 'шестерни', - 8 => 'блоки', - 9 => 'коронки', - 10 => 'вал', - 11 => 'пыльник', - 12 => 'шкив', - 13 => 'станок', - 14 => 'сальник', - 15 => 'кольцо', - 16 => 'цепь', - 17 => 'редуктор', - 18 => 'фильтр', - 19 => 'клапан', - 20 => 'фару', - 21 => 'мотор', - 22 => 'подшипник', - 23 => 'болт', - 24 => 'стартер', - 25 => 'двигатель', - 26 => 'трубку', - 27 => 'прокладку', - 28 => 'помпу', - 29 => 'запчасть', - 30 => 'втулку', - 31 => 'уплотнение', - 32 => 'ролик', - 33 => 'датчик', - 34 => 'насос', - default => 'машину' + $password = ''; + + $arr = array( + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' + ); + + for ($i = 0; $i < 6; $i++) { + $password .= $arr[random_int(0, count($arr) - 1)]; } - . ' ' . match (rand(1, 15)) { - 1 => 'забыли', - 2 => 'испортили', - 3 => 'забрали', - 4 => 'порвали', - 5 => 'украли', - 6 => 'обменяли', - 7 => 'угнали', - 8 => 'взорвали', - 9 => 'поломали', - 1 => 'доломали', - 11 => 'утопили', - 12 => 'испортили', - 13 => 'добили', - 14 => 'разбили', - 15 => 'сорвали', - default => 'сломали' - } - . ' ' . match (rand(1, 9)) { - 1 => 'закажу', - 2 => 'найду', - 3 => 'отыщу', - 4 => 'запрошу', - 5 => 'поищу', - 6 => 'оформлю', - 7 => 'заменю', - 8 => 'поменяю', - default => 'куплю' - } - . ' в скиллпартс'; + + return $password; + // return match (rand(1, 35)) { + // 1 => 'салазки', + // 2 => 'запчасти', + // 3 => 'инструменты', + // 4 => 'детали', + // 5 => 'компоненты', + // 6 => 'ремни', + // 7 => 'шестерни', + // 8 => 'блоки', + // 9 => 'коронки', + // 10 => 'вал', + // 11 => 'пыльник', + // 12 => 'шкив', + // 13 => 'станок', + // 14 => 'сальник', + // 15 => 'кольцо', + // 16 => 'цепь', + // 17 => 'редуктор', + // 18 => 'фильтр', + // 19 => 'клапан', + // 20 => 'фару', + // 21 => 'мотор', + // 22 => 'подшипник', + // 23 => 'болт', + // 24 => 'стартер', + // 25 => 'двигатель', + // 26 => 'трубку', + // 27 => 'прокладку', + // 28 => 'помпу', + // 29 => 'запчасть', + // 30 => 'втулку', + // 31 => 'уплотнение', + // 32 => 'ролик', + // 33 => 'датчик', + // 34 => 'насос', + // default => 'машину' + // } + // . ' ' . match (rand(1, 15)) { + // 1 => 'забыли', + // 2 => 'испортили', + // 3 => 'забрали', + // 4 => 'порвали', + // 5 => 'украли', + // 6 => 'обменяли', + // 7 => 'угнали', + // 8 => 'взорвали', + // 9 => 'поломали', + // 1 => 'доломали', + // 11 => 'утопили', + // 12 => 'испортили', + // 13 => 'добили', + // 14 => 'разбили', + // 15 => 'сорвали', + // default => 'сломали' + // } + // . ' ' . match (rand(1, 9)) { + // 1 => 'закажу', + // 2 => 'найду', + // 3 => 'отыщу', + // 4 => 'запрошу', + // 5 => 'поищу', + // 6 => 'оформлю', + // 7 => 'заменю', + // 8 => 'поменяю', + // default => 'куплю' + // } + // . ' в скиллпартс'; } /** diff --git a/mirzaev/skillparts/system/models/Document.php b/mirzaev/skillparts/system/models/Document.php index 7bbc430..3d3c089 100644 --- a/mirzaev/skillparts/system/models/Document.php +++ b/mirzaev/skillparts/system/models/Document.php @@ -20,7 +20,9 @@ abstract class Document extends ActiveRecord */ public static function collectionName(): string { - return throw new Exception('Не инициализировано название коллекции'); + throw new Exception('Не инициализировано название коллекции'); + + return 'document'; } /** diff --git a/mirzaev/skillparts/system/models/Product.php b/mirzaev/skillparts/system/models/Product.php index 202a141..ac10f31 100644 --- a/mirzaev/skillparts/system/models/Product.php +++ b/mirzaev/skillparts/system/models/Product.php @@ -142,7 +142,7 @@ class Product extends Document [ 'prod', 'string', - 'length' => [3, 80], + 'length' => [2, 80], 'message' => '{attribute} должен быть строкой от 3 до 80 символов' ], [ @@ -624,13 +624,18 @@ class Product extends Document /** * Проверка на уникальность * + * @param static|null $account — Аккаунт + * * @return bool|static true если создать новую запись, static если найден дубликат * * @todo * 1. Обработка дубликатов */ - public function validateForUniqueness(): bool|static + public function validateForUniqueness(Account|int|null $account = null): bool|static { + // Инициализация аккаунта + $account = Account::initAccount($account); + if ($supplies = self::search(['catn' => $this->catn, 'prod' => $this->prod], limit: 100)) { // Найдены поставки с таким же артикулом (catn) и производителем (prod) diff --git a/mirzaev/skillparts/system/models/Settings.php b/mirzaev/skillparts/system/models/Settings.php index 9ffc31e..aa6ec2a 100644 --- a/mirzaev/skillparts/system/models/Settings.php +++ b/mirzaev/skillparts/system/models/Settings.php @@ -27,7 +27,9 @@ class Settings extends Document [ 'search_period', 'search_connect_keep', - 'delivery_from_default' + 'delivery_from_default', + 'addition_global', + 'delivery_addition_global' ] ); } @@ -42,7 +44,9 @@ class Settings extends Document [ 'search_period' => 'Поисковый период', 'search_connect_keep' => 'Режим удержания', - 'delivery_from_default' => 'Место отправки поставки по умолчанию' + 'delivery_from_default' => 'Место отправки поставки по умолчанию', + 'addition_global' => 'Глобальная наценка', + 'delivery_addition_global' => 'Глобальная надбавка к доставке' ] ); } @@ -58,14 +62,16 @@ class Settings extends Document [ [ 'search_period', - 'delivery_from_default' + 'delivery_from_default', + 'delivery_addition_global' ], 'integer', 'message' => '{attribute} должен хранить цифровое значение' ], [ [ - 'search_connect_keep' + 'search_connect_keep', + 'addition_global' ], 'string', 'message' => '{attribute} должен хранить строковый тип' diff --git a/mirzaev/skillparts/system/models/Supply.php b/mirzaev/skillparts/system/models/Supply.php index 3046010..85ba571 100644 --- a/mirzaev/skillparts/system/models/Supply.php +++ b/mirzaev/skillparts/system/models/Supply.php @@ -446,85 +446,190 @@ class Supply extends Product implements ProductInterface, OfferInterface foreach ($data as $doc) { // Перебор полученных документов - // Инициализация буфера документов - $_doc = $doc; + foreach ($doc as $row) { + // Перебор строк - // Поиск всех артикулов (каталожных номеров) - $supplies = explode(',', $doc['catn'], 300); + // Поиск артикула + $article = $row['Артикул'] ?? $row['артикул'] ?? $row['Article'] ?? $row['article'] ?? $row['catn']; - // Поиск количества товаров - $amount = $doc['amnt'] ?? 1; + // Поиск количества товаров + $amount = $row['Количество'] ?? $row['количество'] ?? $row['Amount'] ?? $row['amount'] ?? $row['amnt'] ?? 1; - foreach ($supplies as $_supply) { - // Перебор продуктов (если catn перечислены через запятую) + // Поиск аналогов + $analogs = explode(',', $row['Артикул'] ?? $row['артикул'] ?? $row['Article'] ?? $row['article'] ?? $row['catn'], 50); - $_supply = trim($_supply); + // Инициализация функции создания поставки + $create = function (string $_supply) use ($row, $analogs, &$created, &$updated, &$imported, $amount, $account) { + // Очистка + $_supply = trim($_supply); - // Запись артикула (каталожного номера) в буфер - $_doc['catn'] = $_supply; + // Инициализация буфера документов + $_row = []; - // Инициализация продукта - $supply = new static($_doc); - $supply->scenario = $supply::SCENARIO_WRITE; + // Запись артикула (каталожного номера) в буфер + $_row['catn'] = $_supply; + $_row['cost'] = (float) preg_replace('/[^\d\.]+/', '', preg_replace('/\,+/', ' ', $row['Стоимость'] ?? $row['стоимость'] ?? $row['Цена'] ?? $row['цена'] ?? $row['Cost'] ?? $row['cost'] ?? $row['Price'] ?? $row['price'])); + $_row['prod'] = $row['Производитель'] ?? $row['производитель'] ?? $row['Production'] ?? $row['production'] ?? $row['prod']; + $_row['oemn'] = $analogs; - if ($supply->validate()) { - // Проверка пройдена + // Инициализация буфера поставки + $supply = new static($_row); - if (($_supply = $supply->validateForUniqueness()) instanceof static) { - // Найден документ с такими параметрами + $supply->scenario = $supply::SCENARIO_WRITE; - // Инициализация буфера с параметрами загружаемого товара - $vars = $supply->getAttributes(); + if ($supply->validate()) { + // Проверка пройдена - // Удаление _key, чтобы не перезаписать его при замене параметров документа в буфере - unset($vars['_key']); + if (($_supply = $supply->validateForUniqueness($account)) instanceof static) { + // Найден документ с такими параметрами - // Перенос данных в буфер (существующий в базе данных дубликат) - $_supply->setAttributes($vars, false); + if ($_supply->cost === $_row['cost']) { + // Стоимость не изменилась - // Перезапись существующего документа - $_supply->update(); + if ($product = Product::searchByCatn($_supply->catn)) { + // Найден товар подходящий для привязки с этой поставкой - // Обновление счётчика - $updated++; + for ($i = 0; $i++ < $amount;) { + // Перебор создаваемых рёбер (так работает обозначение количества товаров в наличии) - // Запись поставки в буфер - $imported[] = $_supply; - } else { - // Не найден документ с такими параметрами + // Поиск ребёр + $edges = SupplyEdgeProduct::searchByVertex($supply->readId(), $product->readId(), limit: 50); - if ($supply->save()) { - // Поставка записана в базу данных + if ($amount === $edges) { + // Количество товаров в поставке не изменилось + + // Раз изменений нет, то обновлять ничего не нужно + continue; + } else if ($amount < $edges) { + // Количество товаров в поставке стало МЕНЬШЕ + + // Расчёт разницы + $delete = $edges - $amount; + + // Инициализация количества рёбер которые не удалось удалить + $failed = 0; + + for ($i = 0; $i < $delete; $i++) { + // Перебор рёбер на удаление (синхронизация) + + if ($edges[$i]->delete() >= 1) { + // Удалено ребро + } else { + // Не удалено ребро + + // Обновление количества рёбер которые не удалось удалить + ++$failed; + } + } + + // Отправка уведомления + Notification::_write("Не удалось удалить $failed рёбер у поставки $supply->catn"); + } else if ($amount > $edges) { + // Количество товаров в поставке стало БОЛЬШЕ + + // Расчёт разницы + $write = $amount - $edges; + + // Инициализация количества рёбер которые не удалось записать + $failed = 0; + + for ($i = 0; $i < $write; $i++) { + // Перебор рёбер на запись (синхронизация) + + if (SupplyEdgeProduct::write($supply->readId(), $product->readId(), data: ['type' => 'connect'])) { + // Записано ребро + } else { + // Не записано ребро + + // Обновление количества рёбер которые не удалось записать + ++$failed; + } + } + + // Отправка уведомления + Notification::_write("Не удалось записать $failed рёбер у поставки $supply->catn"); + } + } + } + } + + // Инициализация буфера с параметрами загружаемого товара + $vars = $supply->getAttributes(); + + // Удаление _key, чтобы не перезаписать его при замене параметров документа в буфере + unset($vars['_key']); + + // Перенос данных в буфер (существующий в базе данных дубликат) + $_supply->setAttributes($vars, false); + + // Перезапись существующего документа + $_supply->update(); // Обновление счётчика - $created++; + $updated++; // Запись поставки в буфер - $imported[] = $supply; - }; - } + $imported[] = $_supply; - if (Product::searchByCatn($supply->catn)) { - // Найден товар подходящий для привязки с только что созданной поставкой + // Запись в буфер (для универсальной обработки) + $supply = $_supply; + } else { + // Не найден документ с такими параметрами + + if ($supply->save()) { + // Поставка записана в базу данных + + // Обновление счётчика + $created++; + + // Запись поставки в буфер + $imported[] = $supply; + }; + } + + 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']); + } + } + } else { + // Не найден товар подходящий для привязки с только что созданной поставкой + + // Отправка уведомления + Notification::_write("Не найден товар подходящий для связи с поставкой: $supply->catn", account: '@authorized'); + } } else { - // Не найден товар подходящий для привязки с только что созданной поставкой + // Проверка не пройдена - // Отправка уведомления - Notification::_write("Не найден товар подходящий для связи с поставкой: $supply->catn", account: '@authorized'); + // Добавление ошибок + foreach ($supply->errors as $attribute => $error) $this->addError($attribute, $error); } - } else { - // Проверка не пройдена + }; - // Добавление ошибок - foreach ($supply->errors as $attribute => $error) $this->addError($attribute, $error); + // Запись поставки + $create($article); + + foreach ($analogs as $_supply) { + // Перебор аналогов (если найдены) + + // Запись поставки + $create($_supply); } } } } } - if ($imported > 0) { + if (count($imported) > 0) { // Успешно записана минимум 1 поставка // Инициализация инстанции импорта diff --git a/mirzaev/skillparts/system/models/SupplyEdgeProduct.php b/mirzaev/skillparts/system/models/SupplyEdgeProduct.php index efa6a39..1df2f8c 100644 --- a/mirzaev/skillparts/system/models/SupplyEdgeProduct.php +++ b/mirzaev/skillparts/system/models/SupplyEdgeProduct.php @@ -5,9 +5,10 @@ declare(strict_types=1); namespace app\models; use app\models\traits\Xml2Array; + use carono\exchange1c\interfaces\OfferInterface; -class SupplyEdgeProduct extends Edge implements OfferInterface +class SupplyEdgeProduct extends Edge implements OfferInterface { use Xml2Array; diff --git a/mirzaev/skillparts/system/models/Warehouse.php b/mirzaev/skillparts/system/models/Warehouse.php index 53df396..6db6036 100644 --- a/mirzaev/skillparts/system/models/Warehouse.php +++ b/mirzaev/skillparts/system/models/Warehouse.php @@ -181,7 +181,7 @@ class Warehouse extends Document // Инициализация $list = []; - $cities = Dellin::read(9999); + $cities = Dellin::read(9999, order: ['dellin.data.name' => 'DESC']); foreach ($cities as $city) { // Перебор городов @@ -196,7 +196,7 @@ class Warehouse extends Document } // Запись - $list[$termial['id']] = $city->data['name'] . ' (' . $termial['address'] . ')'; + $list[$termial['id']] = $city->data['name']; } } @@ -238,7 +238,7 @@ class Warehouse extends Document // Параметр $var не найден в настройках аккаунта // Сохранение параметра из данных аккаунта в начале массива - $list = ['Выберите' => 'Выберите'] + $list; + $list = ['Город отправления' => 'Город отправления'] + $list; } return $list; diff --git a/mirzaev/skillparts/system/views/account/panel/authenticated.php b/mirzaev/skillparts/system/views/account/panel/authenticated.php index e664a07..35fd1fc 100644 --- a/mirzaev/skillparts/system/views/account/panel/authenticated.php +++ b/mirzaev/skillparts/system/views/account/panel/authenticated.php @@ -11,7 +11,7 @@ use yii; = $cart_button ?>