ПРОВЕРКА ПО CATN, PROD И ЦЕНЕ

This commit is contained in:
Arsen Mirzaev Tatyano-Muradovich 2021-10-27 11:26:03 +10:00
parent 1d06acf2e0
commit 1a1392d950
27 changed files with 341 additions and 271 deletions

View File

@ -85,7 +85,7 @@ class CartController extends Controller
$account = yii::$app->user->identity;
// Поиск корзины (текущего заказа)
$model = Order::search();
$model = Order::searchByType();
if (empty($model)) {
// Корзина не инициализирована
@ -137,7 +137,7 @@ class CartController extends Controller
goto end;
}
if ($edges = OrderEdgeSupply::searchBySupplyCatn($catn, Order::search())) {
if ($edges = OrderEdgeSupply::searchBySupplyCatn($catn, Order::searchByType())) {
// Рёбра найдены (связи заказа с поставкой)
// Инициализация

View File

@ -266,7 +266,7 @@ class OrderController extends Controller
}
// Инициализация заказов
$orders = Order::search(
$orders = Order::searchByType(
type: $type,
limit: 10,
page: 1,
@ -341,7 +341,7 @@ class OrderController extends Controller
Order::searchById($account_edge_order->_to)->journal('accepted');
// Инициализация
$orders = Order::search(type: 'all', limit: 10, page: 1, select: '{account_edge_order, order}', supplies: true);
$orders = Order::searchByType(type: 'all', limit: 10, page: 1, select: '{account_edge_order, order}', supplies: true);
$moderator_orders = self::genOrdersForModeration();
// Запись в буфер вывода
@ -391,7 +391,7 @@ class OrderController extends Controller
];
// Инициализация корзины
if (!$model = Order::search($account)) {
if (!$model = Order::searchByType($account)) {
// Корзина не найдена (текущий заказ)
// Инициализация
@ -424,7 +424,7 @@ class OrderController extends Controller
$targets = yii::$app->request->post('targets') ?? yii::$app->request->get('targets');
$page = yii::$app->request->get('page') ?? yii::$app->request->post('page') ?? 1;
$account = yii::$app->user->identity;
$order = Order::search();
$order = Order::searchByType();
if ($targets) {
// Удаление выбранных целей (удаление из заказа)
@ -466,7 +466,7 @@ class OrderController extends Controller
$edge->update();
// Реинициализация
$order = Order::search();
$order = Order::searchByType();
if (empty($order)) {
// Корзина не инициализирована
@ -509,7 +509,7 @@ class OrderController extends Controller
$targets = yii::$app->request->post('targets') ?? yii::$app->request->get('targets');
$page = yii::$app->request->get('page') ?? yii::$app->request->post('page') ?? 1;
$account = yii::$app->user->identity;
$order = Order::search();
$order = Order::searchByType();
$connections = $order->content(10, $page);
foreach (isset($targets[0]) && is_array($targets[0]) ? $targets : [$targets] as $target) {
@ -583,7 +583,7 @@ class OrderController extends Controller
public function actionRequest(): string|array|null
{
// Инициализация
$model = Order::search(supplies: true);
$model = Order::searchByType(supplies: true);
// Поиск ребра
$edge = AccountEdgeOrder::searchByVertex(yii::$app->user->id, $model->readId(), 'current');
@ -650,11 +650,11 @@ class OrderController extends Controller
*
* @return array ['order' => array, 'order_edge_account' => array, 'supplies' => array]
*
* @todo Уничтожить заменив на Order::search(supplies: true)
* @todo Уничтожить заменив на Order::searchByType(supplies: true)
*/
protected static function genOrdersForModeration(int $page = 1): array
{
$orders = Order::search(account: '@all', type: 'requested', limit: 10, page: 1, select: '{account_edge_order, order}');
$orders = Order::searchByType(account: '@all', type: 'requested', limit: 10, page: 1, select: '{account_edge_order, order}');
foreach ($orders as &$order) {
// Перебор заказов
@ -697,9 +697,9 @@ class OrderController extends Controller
try {
// Инициализация данных геолокации
try {
$from = (int) $account['opts']['delivery_from_terminal'] ?? Settings::search()->delivery_from_default ?? 36;
$from = (int) $account['opts']['delivery_from_terminal'] ?? Settings::searchActive()->delivery_from_default ?? 36;
} catch (Exception $e) {
$from = (int) Settings::search()->delivery_from_default ?? 36;
$from = (int) Settings::searchActive()->delivery_from_default ?? 36;
}
try {

View File

@ -84,7 +84,7 @@ class ProductController extends Controller
}
if ($from = Product::searchByCatn($catn)) {
// Товар найден
// Найден товар
if ($target = yii::$app->request->post('catn') ?? yii::$app->request->get('catn')) {
// Инициализирован артикул товара для связи
@ -97,6 +97,9 @@ class ProductController extends Controller
// Инициализация товара
if ($to = Product::writeEmpty((string) $target)) {
// Удалось записать товар
// Запись в буфер возврата
$return['alert'] = "Не удалось записать новый товар: $target";
} else {
// Не удалось записать товар
@ -111,14 +114,16 @@ class ProductController extends Controller
}
}
if (($edge = $from->synchronization($to)) instanceof ProductEdgeProduct) {
// Ребро создано
if ($from->synchronization($to) > 0) {
// Созданы рёбра
// Запись в буфер возврата
$return['alert'] = "Продукты успешно соединены ребром: $edge->_key";
$return['alert'] = 'Продукты успешно соединены';
}
}
} else {
// Не найден товар
// Запись кода ответа
yii::$app->response->statusCode = 500;
@ -129,9 +134,7 @@ class ProductController extends Controller
goto end;
}
/**
* Конец алгоритма
*/
// Конец алгоритма
end:
if (yii::$app->request->isPost) {
@ -180,42 +183,25 @@ class ProductController extends Controller
if ($from = Product::searchByCatn($catn)) {
// Товар найден
if ($target = yii::$app->request->post('catn') ?? yii::$app->request->get('catn')) {
// Инициализирован артикул товара для связи
// Инициализация цели
$target = yii::$app->request->post('catn') ?? yii::$app->request->get('catn');
if ($to = Product::searchByCatn($target)) {
// Существует товар который нужно отсоединить
if ($from->disconnect(Product::searchByCatn(empty($target) ? null : $target))) {
// Удалено ребро (связь)
if ($from->disconnect($to)) {
// Удалось удалить ребро (связь)
// Запись в буфер возврата
$return['alert'] = "Продукты успешно отсоединены";
} else {
// Не удалено ребро (связь)
// Запись в буфер возврата
$return['alert'] = "Продукты успешно отсоединены";
} else {
// Запись кода ответа
yii::$app->response->statusCode = 500;
// Не удалось удалить ребро (связь)
// Запись в буфер возврата
$return['alert'] = "Не удалось отсоединить $target от $catn";
// Запись кода ответа
yii::$app->response->statusCode = 500;
// Запись в буфер возврата
$return['alert'] = "Не удалось отсоединить $target от $catn";
// Переход в конец алгоритма
goto end;
}
} else {
// Не существует товар который нужно отсоединить
// Запись кода ответа
yii::$app->response->statusCode = 500;
// Запись в буфер возврата
$return['alert'] = "Не удалось найти товар который нужно отсоединить: $catn";
// Переход в конец алгоритма
goto end;
}
// Переход в конец алгоритма
goto end;
}
} else {
// Запись кода ответа
@ -228,9 +214,7 @@ class ProductController extends Controller
goto end;
}
/**
* Конец алгоритма
*/
// Конец алгоритма
end:
if (yii::$app->request->isPost) {
@ -279,20 +263,35 @@ class ProductController extends Controller
if ($product = Product::searchByCatn($catn)) {
// Товар найден
if ($product->delete() > 0) {
// Удалось удалить
if ($product->disconnect()) {
// Отсоединён от аналогов
// Запись в буфер возврата
$return['alert'] = "Товар удалён: $catn";
$return['location'] = '/';
if ($product->delete() > 0) {
// Удалён
// Запись в буфер возврата
$return['alert'] = "Товар удалён: $catn";
$return['location'] = '/';
} else {
// Не удалось удалить
// Запись кода ответа
yii::$app->response->statusCode = 500;
// Запись в буфер возврата
$return['alert'] = "Не удалось удалить товар: $catn";
// Переход в конец алгоритма
goto end;
}
} else {
// Не удалось удалить
// Не отсоединён от аналогов
// Запись кода ответа
yii::$app->response->statusCode = 500;
// Запись в буфер возврата
$return['alert'] = "Не удалось удалить товар: $catn";
$return['alert'] = "Не удалось отсоединить от аналогов перед удалением: $catn";
// Переход в конец алгоритма
goto end;
@ -355,12 +354,12 @@ class ProductController extends Controller
// Инициализация
$text = yii::$app->request->get('text') ?? yii::$app->request->post('text') ?? 'Без названия';
$model->name = $text;
$model->prod = $text;
if ($model->save()) {
// Товар обновлён
$return['name'] = $text;
$return['prod'] = $text;
}
}

View File

@ -488,7 +488,7 @@ class ProfileController extends Controller
// Инициализация
$groups = [];
foreach (SupplyGroup::readAll() as $group) {
foreach (SupplyGroup::read() as $group) {
// Перебор всех групп
// Генерация [КЛЮЧ => ИМЯ]

View File

@ -137,7 +137,7 @@ class SearchController extends Controller
if ($response = Product::searchByPartialCatn($query, $limit, [
'_key' => '_key',
'catn' => 'catn',
'name' => 'name',
'prod' => 'prod',
// Баг с названием DESC
'dscr' => 'dscr',
'catg' => 'catg',

View File

@ -103,16 +103,6 @@ class AccountForm extends Model
];
}
public function attributeLabels()
{
return [
'mail' => 'Почта',
'pswd' => 'Пароль',
'auto' => '<i class="fas fa-unlock"></i>',
'pols' => 'Политика конфедециальности'
];
}
public function validateMail($attribute, $params)
{
if (!$this->hasErrors()) {

View File

@ -62,10 +62,14 @@ abstract class Document extends ActiveRecord
* @todo Подождать обновление от ебаного Yii2 и добавить
* проверку типов передаваемых параметров
*/
public function beforeSave($data): bool
public function beforeSave($create): bool
{
if (parent::beforeSave($data)) {
if (parent::beforeSave($create)) {
// Пройдена родительская проверка
if ($this->isNewRecord) {
// Новая запись
// Запись в журнал
$this->jrnl = array_merge(
[[
@ -127,6 +131,15 @@ abstract class Document extends ActiveRecord
return isset($this->_key) && static::collectionName() ? static::collectionName() . '/' . $this->_key : null;
}
/**
* Поиск
*/
public static function search(array $where, $limit = 1): array
{
return static::find()->where($where)->limit($limit)->all();
}
/**
* Поиск по идентификатору
*/
@ -142,7 +155,7 @@ abstract class Document extends ActiveRecord
/**
* Чтение всех записей
*
*
* @deprecated
*/
public static function readAll(): array

View File

@ -161,7 +161,7 @@ abstract class Edge extends Document
/**
* Поиск рёбер по направлению
*/
public static function search(string $target, string $direction = 'OUTBOUND', string $type = '', int $limit = 1): static|array|null
public static function searchByDirection(string $target, string $direction = 'OUTBOUND', string $type = '', int $limit = 1): static|array|null
{
if (str_contains($direction, 'OUTBOUND')) {
// Исходящие рёбра
@ -174,7 +174,7 @@ abstract class Edge extends Document
} else if (str_contains($direction, 'ANY')) {
// Исходящие и входящие рёбра
return static::search(target: $target, direction: 'OUTBOUND', type: $type, limit: $limit) + static::search(target: $target, direction: 'INBOUND', type: $type, limit: $limit);
return static::searchByDirection(target: $target, direction: 'OUTBOUND', type: $type, limit: $limit) + static::searchByDirection(target: $target, direction: 'INBOUND', type: $type, limit: $limit);
}
if ($limit < 2) {

View File

@ -261,7 +261,7 @@ class Order extends Document implements DocumentInterface
*
* @todo Привести в порядок
*/
public static function search(
public static function searchByType(
Account|string $account = null,
string $type = 'current',
string|null $search = null,
@ -577,9 +577,9 @@ class Order extends Document implements DocumentInterface
try {
// Инициализация данных геолокации
try {
$from = (int) $connection['account']['opts']['delivery_from_terminal'] ?? empty(Settings::search()->delivery_from_default) ? 36 : (int) Settings::search()->delivery_from_default;
$from = (int) $connection['account']['opts']['delivery_from_terminal'] ?? empty(Settings::searchActive()->delivery_from_default) ? 36 : (int) Settings::searchActive()->delivery_from_default;
} catch (Exception $e) {
$from = empty(Settings::search()->delivery_from_default) ? 36 : (int) Settings::search()->delivery_from_default;
$from = empty(Settings::searchActive()->delivery_from_default) ? 36 : (int) Settings::searchActive()->delivery_from_default;
}
try {
@ -640,9 +640,9 @@ class Order extends Document implements DocumentInterface
try {
// Инициализация данных геолокации
try {
$from = (int) $connection['account']['opts']['delivery_from_terminal'] ?? empty(Settings::search()->delivery_from_default) ? 36 : (int) Settings::search()->delivery_from_default;
$from = (int) $connection['account']['opts']['delivery_from_terminal'] ?? empty(Settings::searchActive()->delivery_from_default) ? 36 : (int) Settings::searchActive()->delivery_from_default;
} catch (Exception $e) {
$from = empty(Settings::search()->delivery_from_default) ? 36 : (int) Settings::search()->delivery_from_default;
$from = empty(Settings::searchActive()->delivery_from_default) ? 36 : (int) Settings::searchActive()->delivery_from_default;
}
try {
@ -888,6 +888,6 @@ class Order extends Document implements DocumentInterface
*/
public static function count(int $limit = 500, bool $supplies = false): int
{
return (int) self::search(supplies: $supplies, type: $supplies ? 'current' : 'all', limit: $limit, count: true);
return (int) self::searchByType(supplies: $supplies, type: $supplies ? 'current' : 'all', limit: $limit, count: true);
}
}

View File

@ -16,8 +16,6 @@ use DateTime;
use DateTimeZone;
use Exception;
use phpDocumentor\Reflection\DocBlock\Tags\Var_;
use stdClass;
/**
* Продукт (в ассортименте магазина)
@ -81,7 +79,6 @@ class Product extends Document
parent::attributes(),
[
'catn',
'name',
// В библеотеке есть баг на название DESC (неизвестно в моей или нет)
'dscr',
'prod',
@ -103,7 +100,6 @@ class Product extends Document
parent::attributeLabels(),
[
'catn' => 'Каталожный номер (catn)',
'name' => 'Название (name)',
'dscr' => 'Описание (dscr)',
'prod' => 'Производитель (prod)',
'dmns' => 'Габариты (dmns)',
@ -140,16 +136,35 @@ class Product extends Document
'string',
'message' => '{attribute} должен быть строкой'
],
[
'prod',
'string',
'length' => [3, 80],
'message' => '{attribute} должен быть строкой от 3 до 80 символов'
],
[
'imgs',
'arrayValidator',
'message' => '{attribute} должен быть массивом'
],
[
'dscr',
'string',
'length' => [3, 256],
'message' => '{attribute} должен быть строкой от 3 до 256 символов'
],
[
'dmns',
'arrayWithNumbersValidator',
'message' => '{attribute} должен быть массивом и хранить циферные значения'
],
[
'wght',
'integer',
'min' => 0,
'max' => 30000,
'message' => '{attribute} должен иметь значение от 0 до 30000'
],
[
'file_excel',
'required',
@ -185,28 +200,6 @@ class Product extends Document
'wrongExtension' => 'Разрешены только изображения в формате: ".jpg", ".jpeg", ".png", ".gif", ".webp"',
'message' => 'Проблема при загрузке изображения',
'on' => self::SCENARIO_IMPORT_IMAGE
],
[
[
'name',
'prod'
],
'string',
'length' => [3, 80],
'message' => '{attribute} должен быть строкой от 3 до 80 символов'
],
[
'dscr',
'string',
'length' => [3, 256],
'message' => '{attribute} должен быть строкой от 3 до 256 символов'
],
[
'wght',
'integer',
'min' => 0,
'max' => 30000,
'message' => '{attribute} должен иметь значение от 0 до 30000'
]
]
);
@ -328,7 +321,8 @@ class Product extends Document
{
// Инициализация
$data = [];
$amount = 0;
$created = 0;
$updated = 0;
$account = Account::initAccount($account);
if ($this->validate()) {
@ -336,7 +330,7 @@ class Product extends Document
// Перебор файлов
// Инициализация
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone);
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();
@ -388,15 +382,29 @@ class Product extends Document
if ($product->validate()) {
// Проверка пройдена
// Запись документа
$product->save();
if (($_product = $product->validateForUniqueness()) instanceof static) {
// Найден документ с такими параметрами
// Постинкрементация счётчика
$amount++;
// Запись группы
// $group = static::class . 'Group';
// (new $group())->writeMember($product, $this->group);
// Инициализация буфера с параметрами загружаемого товара
$vars = $product->getAttributes();
// Удаление _key, чтобы не перезаписать его при замене параметров документа в буфере
unset($vars['_key']);
// Перенос данных в буфер (существующий в базе данных дубликат)
$_product->setAttributes($vars, false);
// Перезапись существующего документа
$_product->update();
$updated++;
} else {
// Не найден документ с такими параметрами
// Запись нового документа
if ($product->save()) $created++;
}
} else {
// Проверка не пройдена
@ -412,14 +420,16 @@ class Product extends Document
$this->file_excel = null;
// Макрос действий после импорта
static::afterImportExcel($amount);
static::afterImportExcel($created, $updated);
return true;
}
// Запись ошибки
$this->addError('erros', 'Неизвестная ошибка');
static::afterImportExcel($amount);
// Макрос действий после импорта
static::afterImportExcel($created, $updated);
return false;
}
@ -432,7 +442,7 @@ class Product extends Document
*
* @todo Переделать нормально
*/
public static function searchByCatn(string $catn, int $limit = 1, array $select = []): static|array|null
public static function searchByCatn(string|null $catn, int $limit = 1, array $select = []): static|array|null
{
if ($limit <= 1) {
return static::findOne(['catn' => $catn]);
@ -488,23 +498,24 @@ class Product extends Document
/**
* Вызывается после загрузки поставок из excel-документа
*
* @param int $amount Количество
* @param int $created Количество созданных документов
* @param int $updated Количество обновлённых документов
*/
public static function afterImportExcel(int $amount = 0): bool
public static function afterImportExcel(int $created = 0, int $updated = 0): bool
{
// Инициализация параметров
$model = new Notification;
$account = yii::$app->user->identity;
// Инициализация часового пояса
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone);
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone);
$timezone = $timezone[1][0];
// Инициализация даты
$date = (new DateTime('now', new DateTimeZone($timezone)))->format('H:i d.m.Y');
// Настройка
$model->text = yii::$app->controller->renderPartial('@app/views/notification/system/afterImportExcel', compact('amount', 'date'));
$model->text = yii::$app->controller->renderPartial('@app/views/notification/system/afterImportExcel', compact('created', 'updated', 'date'));
$model->type = $model::TYPE_NOTICE;
// Отправка
@ -546,7 +557,7 @@ class Product extends Document
}
// Инициализация часового пояса
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone);
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone);
$timezone = $timezone[1][0];
$date = (new DateTime('now', new DateTimeZone($timezone)))->format('H:i d.m.Y');
@ -685,20 +696,20 @@ class Product extends Document
/**
* Подключение аналога
*
* СВЯЗЫВАЕТ ТОЛЬКО ДВА ТОВАРА, ГРУППА ОСТАНЕТСЯ НЕИЗМЕННОЙ
*
* @param self $to Цель
*
* @return ProductEdgeProduct|null Ребро между товарами, если создалось
*/
public function connect(self $to): ?ProductEdgeProduct
{
if (ProductEdgeProduct::searchByVertex(Product::collectionName() . "/$this->_key", Product::collectionName() . "/$to->_key", limit: 1)) {
// Дубликат найден
} else if (ProductEdgeProduct::searchByVertex(Product::collectionName() . "/$to->_key", Product::collectionName() . "/$this->_key", limit: 1)) {
// Дубликат найден (наоборот)
if (ProductEdgeProduct::searchByVertex(Product::collectionName() . "/$this->_key", Product::collectionName() . "/$to->_key", type: 'analogue')) {
// Найдено ребро
} else if (ProductEdgeProduct::searchByVertex(Product::collectionName() . "/$to->_key", Product::collectionName() . "/$this->_key", type: 'analogue')) {
// Найдено ребро (наоборот)
// Вероятно эта проверка здесь не нужна, так как мы знаем входные данные
// !!! Вероятно эта проверка здесь не нужна, так как мы знаем входные данные
} else {
// Дубликаты не найдены
// Не найдены ребра
if ($edge = ProductEdgeProduct::write(Product::collectionName() . "/$this->_key", Product::collectionName() . "/$to->_key", data: ['type' => 'analogue'])) {
// Ребро сохранено
@ -723,24 +734,58 @@ class Product extends Document
/**
* Отключение аналога
*
* @param self $to Цель
* @param self|null $to Цель (если null, то целью являются все подключенные аналоги)
* @param bool $all Удалить соединения со всеми членами группы
*/
public function disconnect(self $to): bool
public function disconnect(self|null $to = null, bool $all = true): bool
{
// Поиск ребра
if ($edge = @ProductEdgeProduct::searchByVertex(Product::collectionName() . "/$this->_key", Product::collectionName() . "/$to->_key", type: 'analogue')[0]) {
// Найдено ребро (from: $this, to: $to)
} else if ($edge = @ProductEdgeProduct::searchByVertex(Product::collectionName() . "/$to->_key", Product::collectionName() . "/$this->_key", type: 'analogue')[0]) {
// Найдено ребро (from: $to, to: $this)
} else {
// Не найдены ребра
if (isset($to)) {
// Передана цель для удаления (из её группы)
return false;
if ($edge = @ProductEdgeProduct::searchByVertex(Product::collectionName() . "/$this->_key", Product::collectionName() . "/$to->_key", type: 'analogue')[0]) {
// Найдено ребро
} else if ($edge = @ProductEdgeProduct::searchByVertex(Product::collectionName() . "/$to->_key", Product::collectionName() . "/$this->_key", type: 'analogue')[0]) {
// Найдено ребро (наоборот)
} else {
// Не найдены ребра
return false;
}
} else {
// Не передана цель для удаления (из её группы)
foreach ($this->connections() as $edge) {
// Перебор всех рёбер
if (Product::collectionName() . "/$this->_key" !== $edge && $to = Product::searchById($edge)) {
// Найден товар (проверен на то, что не является самим собой)
// Разъединение
$this->disconnect($to, all: false);
}
}
return true;
}
if ($edge->delete() > 0) {
// Удалось удалить ребро (связь)
if ($all) {
// Запрошено удаление соединений со всеми членами группы
foreach ($to->connections() as $edge) {
// Перебор рёбер (найденных соединений с группой в которой находилась цель)
if (Product::collectionName() . "/$this->_key" !== $edge && $to = Product::searchById($edge)) {
// Найден товар (проверен на то, что не является самим собой)
// Разъединение
$this->disconnect($to, all: false);
}
}
}
// Запись в журнал о разъединении
$this->journal('disconnect analogue', [
'to' => Product::collectionName() . "/$to->_key"
@ -767,7 +812,7 @@ class Product extends Document
// Инициализация буфера связанных товаров
$products = [];
foreach (ProductEdgeProduct::search(self::collectionName() . "/$this->_key", direction: 'ANY', type: 'analogue', limit: $limit) as $edge) {
foreach (ProductEdgeProduct::searchByDirection(self::collectionName() . "/$this->_key", direction: 'ANY', type: 'analogue', limit: $limit) as $edge) {
// Перебор связей для создания списка товаров (вершин)
// Добавление товаров (вершин) в буфер (подразумевается, что без дубликатов)
@ -777,4 +822,31 @@ class Product extends Document
return $products;
}
/**
* Проверка на уникальность
*
* @return bool|static true если создать новую запись, static если найден дубликат
*
* @todo
* 1. Обработка дубликатов
*/
public function validateForUniqueness(): bool|static
{
if ($supplies = self::search(['catn' => $this->catn, 'prod' => $this->prod], limit: 100)) {
// Найдены поставки с таким же артикулом (catn) и производителем (prod)
// if (count($supplies) > 1) throw new exception ('В базе данных имеется более чем один дубликат', 500);
if (count($supplies) > 1) return false;
// Запись обрабатываемой поставки
$supply = $supplies[0];
// Возврат (найден дубликат в базе данных)
return $supply;
} else return true;
// Возврат (подразумевается ошибка)
return false;
}
}

View File

@ -197,9 +197,9 @@ class Search extends Document
// Инициализация данных геолокации
try {
$from = (int) $connection['account']['opts']['delivery_from_terminal'] ?? empty(Settings::search()->delivery_from_default) ? 36 : (int) Settings::search()->delivery_from_default;
$from = (int) $connection['account']['opts']['delivery_from_terminal'] ?? empty(Settings::searchActive()->delivery_from_default) ? 36 : (int) Settings::searchActive()->delivery_from_default;
} catch (exception $e) {
$from = empty(Settings::search()->delivery_from_default) ? 36 : (int) Settings::search()->delivery_from_default;
$from = empty(Settings::searchActive()->delivery_from_default) ? 36 : (int) Settings::searchActive()->delivery_from_default;
}
try {
@ -275,9 +275,9 @@ class Search extends Document
}
try {
$from = (int) $buffer_delivery_avia['account']['opts']['delivery_from_terminal'] ?? empty(Settings::search()->delivery_from_default) ? 36 : (int) Settings::search()->delivery_from_default;
$from = (int) $buffer_delivery_avia['account']['opts']['delivery_from_terminal'] ?? empty(Settings::searchActive()->delivery_from_default) ? 36 : (int) Settings::searchActive()->delivery_from_default;
} catch (Exception $e) {
$from = empty(Settings::search()->delivery_from_default) ? 36 : (int) Settings::search()->delivery_from_default;
$from = empty(Settings::searchActive()->delivery_from_default) ? 36 : (int) Settings::searchActive()->delivery_from_default;
}
try {
@ -357,42 +357,33 @@ class Search extends Document
* Генерация HTML-кода с найденным товаром
*
* @param array $row Товар сгенерированный через Search::content()
* @param string|null $cpny Компания (сейчас пока что это $name - Название)
* @param string|null $covr Обложка
* @param string|null $catg Категория
* @param string|null $catn Артикул
* @param string|null $cover Обложка
* @param array $empties Реестр не найденных товаров
*
* @return string HTML-элемент с товаром
*/
public static function generate(array &$row, string|null &$cpny = null, string|null &$covr = null, string|null &$catg = null, string|null &$catn = null, array &$empties = []): string
public static function generate(array &$row, string|null &$cover = null, array &$empties = []): string
{
// Инициализация
extract($row);
$cpny ?? $cpny = 'Без названия';
// $dscr ?? $dscr = 'Описание';
$catg ?? $catg = 'Категория';
$catn ?? $catn = 'Неизвестно';
foreach ($imgs ?? [] as $img) {
foreach ($row['imgs'] ?? [] as &$img) {
// Перебор изображений для обложки
if ($img['covr'] ?? false) {
// Обложка найдена
// Найдена обложка
$covr = $img['h150'];
$cover = $img['h150'];
break;
}
}
if (is_null($covr)) {
if (is_null($cover)) {
// Обложка не инициализирована
if (!$covr = $imgs[0]['h150'] ?? false) {
if (!$cover = $imgs[0]['h150'] ?? false) {
// Не удалось использовать первое изображение как обложку
// Запись обложки по умолчанию
$covr = '/img/covers/h150/product.png';
$cover = '/img/covers/h150/product.png';
}
}
@ -465,7 +456,7 @@ class Search extends Document
HTML;
// Запись в список ненайденных
$empties[] = $catn;
$empties[] = $row['catn'];
// Запись блокировщика
$empty_block = true;
@ -534,7 +525,7 @@ class Search extends Document
<small class="col-1 my-auto pl-2 pr-0 text-center">$amount</small>
<small class="col-auto mr-2 my-auto pl-2 pr-0 text-left" title="Ориентировочно">$delivery_icon $delivery дн</small>
<b class="col-auto my-auto my-auto text-center">$price</b>
<a class="col-1 ml-0 py-2 text-dark d-flex button_white rounded" title="Добавить $catn в корзину" role="button" onclick="return cart_write('{$supply['_id']}', '$delivery_type');">
<a class="col-1 ml-0 py-2 text-dark d-flex button_white rounded" title="Добавить {$row['catn']} в корзину" role="button" onclick="return cart_write('{$supply['_id']}', '$delivery_type');">
<i class="fas fa-cart-arrow-down pr-1 m-auto"></i>
</a>
</div>

View File

@ -79,7 +79,7 @@ class Settings extends Document
*
* @todo Доделать
*/
public static function search(): ?self
public static function searchActive(): ?self
{
return static::findOne(['active' => true]);
}

View File

@ -16,6 +16,7 @@ use carono\exchange1c\interfaces\ProductInterface;
use carono\exchange1c\controllers\ApiController;
use Exception;
use Throwable;
/**
* Поставка (выгрузка товаров от поставщиков)
@ -68,10 +69,10 @@ class Supply extends Product implements ProductInterface, OfferInterface
return array_merge(
parent::attributeLabels(),
[
'cost' => 'Стоимость (cost)',
'cost' => 'Стоимость',
'onec' => 'Данные 1С',
'oemn' => 'OEM-номера',
'ocid' => 'Идентификатор 1C (ocid)'
'ocid' => 'Идентификатор 1C'
]
);
}
@ -589,7 +590,7 @@ class Supply extends Product implements ProductInterface, OfferInterface
return SupplyEdgeProduct::searchByVertex($_id, $product->readId(), type: 'connect', limit: 1)['onec']['Цены']['Цена'];
}
return SupplyEdgeProduct::search($_id, type: 'connect', limit: 1)['onec']['Цены']['Цена'];
return SupplyEdgeProduct::searchByDirection($_id, type: 'connect', limit: 1)['onec']['Цены']['Цена'];
}
/**
@ -602,14 +603,15 @@ class Supply extends Product implements ProductInterface, OfferInterface
return static::searchAccountById($this->readId());
}
public static function DeliveryToRussian(string $dlvr, int $type = 1): string {
public static function DeliveryToRussian(string $dlvr, int $type = 1): string
{
if ($type === 1) {
return match($dlvr) {
return match ($dlvr) {
'avia' => 'доставкой самолётом',
default => 'автоматической доставкой'
};
} else {
return match($dlvr) {
return match ($dlvr) {
'avia' => 'Самолёт',
default => 'Автоматическая'
};

View File

@ -6,7 +6,6 @@ namespace app\models;
use app\models\traits\Xml2Array;
use carono\exchange1c\interfaces\OfferInterface;
use Zenwalker\CommerceML\Model\Offer;
class SupplyEdgeProduct extends Edge implements OfferInterface
{

View File

@ -196,7 +196,7 @@ class Dellin extends Model
}
// Инициализация часового пояса
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone);
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone);
$timezone = $timezone[1][0];
// Инициализация
@ -354,7 +354,7 @@ class Dellin extends Model
// Запрос прошел успешно
// Инициализация часового пояса
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone);
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone);
$timezone = $timezone[1][0];
// Инициализация параметров

View File

@ -86,7 +86,7 @@ use app\models\Settings;
<?php
// Инициализация часового пояса
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone);
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone);
$timezone = $timezone[1][0];
?>
<b>Счет на оплату <?= $order['id'] ?> от <?= (new DateTime())->setTimestamp($order['date'])->setTimezone(new DateTimeZone($timezone))->format('d.m.Y') ?></b>

View File

@ -95,14 +95,17 @@ AppAsset::register($this);
<h5 class="row mb-2 unselectable"><b>Контакты</b></h5>
<small class="row mb-1"><b>Адрес:&nbsp;</b>Хабаровск, Промышленная 3, 105</small>
<small class="row mb-1"><b>Время работы:&nbsp;</b>пн-пт 09:00-18:00</small>
<small class="row mb-1"><b>Телефон:&nbsp;</b>+7 (4212) 35-85-34</small>
<small class="row mb-1"><b>Почта:&nbsp;</b>info@skillparts.ru</small>
<small class="row mb-1"><b>Телефон:&nbsp;</b><a href="tel:+74212358534">+7 (4212) 35-85-34</a></small>
<small class="row"><b>Почта:&nbsp;</b><a href="mailto:info@skillparts.ru">info@skillparts.ru</a></small>
</div>
<div class="col-md-auto mr-md-5 partnership unselectable">
<h5 class="row mb-2"><b>Партнёрство</b></h5>
<small class="row mb-1"><a href="/buyers">Покупателям</a></small>
<small class="row mb-1"><a href="/suppliers">Поставщикам</a></small>
<small class="row mb-1"><a href="/partners">Сеть филиалов</a></small>
<small class="row"><a href="/partners">Сеть филиалов</a></small>
</div>
<div class="mt-auto ml-auto col-auto unselectable">
<small class="row"><a href="mailto:info@skillparts.ru?subject=Ошибка на сайте">Сообщить об ошибке</a></small>
</div>
</div>
</footer>

View File

@ -14,7 +14,7 @@ foreach ($notification->jrnl as $jrnl) {
// Найдена дата создания
// Инициализация часового пояса
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone);
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone);
$timezone = $timezone[1][0];
// Инициализация данных для генерации HTML

View File

@ -1,13 +1,25 @@
<?php
if($amount > 0) {
if ($created > 0 && $updated > 0) {
// Записаны новые и обновлены существующие документы
echo <<<HTML
<p>Импортировано $amount товаров из excel-документа <span>($date)</span></p>
<p>Записано $created новых товаров и $updated товара обновлено</p>
HTML;
} else if ($created > 0) {
// Записаны новые документы
echo <<<HTML
<p>Записано $created новых товаров</p>
HTML;
} else if ($updated > 0) {
// Записаны новые документы
echo <<<HTML
<p>Обновлено $updated товаров</p>
HTML;
} else {
echo <<<HTML
<p>Неудачная попытка импорта товаров из excel-документа <span>($date)</span></p>
<p>Неудачная попытка импорта товаров из excel-документа</p>
HTML;
}
?>

View File

@ -71,7 +71,7 @@ if (empty($window)) {
}
}
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone);
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone);
$timezone = $timezone[1][0];
// Конвертация данных из буфера
@ -300,7 +300,7 @@ if (empty($window)) {
// Найден принятый заказ
// Инициализация часового пояса
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone);
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone);
$timezone = $timezone[1][0];
// Запись данных о дате заказа
@ -516,7 +516,7 @@ if (empty($window)) {
orders_calendar_ready = false;
<?php
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone);
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone);
$timezone = $timezone[1][0];
?>

View File

@ -18,7 +18,7 @@ if (isset($history) && $history) {
)) {
// История поиска существует
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone);
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone);
$timezone = $timezone[1][0];
foreach ($rows as $row) {

View File

@ -71,7 +71,7 @@ use app\models\Product;
// Перебор изображений для генерации полных версий
// Инициализация
$name = $image['name'] ?? 'Без названия';
$prod = $image['prod'] ?? 'Неизвестный';
$orig = $image['orig'] ?? '/img/covers/product.png';
if (($image['covr'] ?? false) || ($covr_not_found && $key === 0)) {
@ -135,9 +135,9 @@ use app\models\Product;
&& (yii::$app->user->identity->type === 'administrator'
|| yii::$app->user->identity->type === 'moderator')
) : ?>
<h3 id="title_<?= $model['catn'] ?>" class="my-auto pointer-event product_title" role="button" onclick="return product_panel_title_edit('<?= $model['catn'] ?>', this);"><?= $model['name'] ?? 'Без названия' ?></h3>
<h3 id="title_<?= $model['catn'] ?>" class="my-auto pointer-event product_title" role="button" onclick="return product_panel_title_edit('<?= $model['catn'] ?>', this);"><?= $model['prod'] ?? 'Без названия' ?></h3>
<?php else : ?>
<h3 id="title_<?= $model['catn'] ?>" class="my-auto"><?= $model['name'] ?? 'Без названия' ?></h3>
<h3 id="title_<?= $model['catn'] ?>" class="my-auto"><?= $model['prod'] ?? 'Без названия' ?></h3>
<?php endif ?>
</div>
@ -207,7 +207,7 @@ use app\models\Product;
) : ?>
<p id="description_<?= $model['catn'] ?>" class="mt-0 ml-0 text-break pointer-event product_description" role="button" onclick="return product_panel_description_edit('<?= $model['catn'] ?>', this);"><?= $model['dscr'] ?? 'Без описания' ?></p>
<?php else : ?>
<p id="description_<?= $model['catn'] ?>" class="mt-0 ml-0 text-break product_description"><?= $model['name'] ?? 'Без описания' ?></p>
<p id="description_<?= $model['catn'] ?>" class="mt-0 ml-0 text-break product_description"><?= $model['prod'] ?? 'Без описания' ?></p>
<?php endif ?>
<p class="mt-0">
<?php

View File

@ -41,7 +41,7 @@ $panel ?? $panel = 'profile_panel_monitoring_input_search_history';
$time = $row->jrnl;
// Инициализация часового пояса
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone);
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone);
$timezone = $timezone[1][0];
$date = empty($row->jrnl) ? '' : (new DateTime())->setTimestamp(end($time)['date'])->setTimezone(new DateTimeZone($timezone))->format('H:i d.m.Y');

View File

@ -9,7 +9,7 @@ use app\models\Search;
<link href="/css/pages/search.css" rel="stylesheet">
<div id="page_search" class="container flex-grow-1 d-flex">
<div id="page_search" class="px-0 py-4 container flex-grow-1 d-flex flex-column">
<?php
if (isset($timer) && $timer > 0) : ?>
@ -28,90 +28,78 @@ use app\models\Search;
<?php else : ?>
<?php if (isset($response) && is_array($response) && $response) : ?>
<div class="row py-4 w-100 flex-column">
<section class="col-auto mb-4">
<h4 class="ml-4 mb-3">Товары по запросу: "<?= $query ?? 'ошибка чтения запроса' ?>"</h4>
<section class="mb-4 col-auto">
<h4 class="ml-4 mb-3">Товары по запросу: "<?= $query ?? 'ошибка чтения запроса' ?>"</h4>
<?php foreach ($response as $row) : ?>
<?php
// Инициализация данных товара
$cpny = $covr = $catg = $catn = null;
<?php foreach ($response as $row) : ?>
<?php
// Инициализация данных товара
$covr = null;
$prod = $row['prod'] ?? 'Неизвестно';
$catn = $row['catn'] ?? 'Неизвестно';
// Инициализация реестра пустышек (товаров без поставок или с ошибками)
$empties = [];
// Инициализация реестра пустышек (товаров без поставок или с ошибками)
$empties = [];
// Генерация списка товаров
$supplies_html = Search::generate($row, $cpny, $covr, $catg, $catn, $empties);
extract($row);
?>
<div class="col mb-2">
<div class="row p-2 rounded">
<img class="ml-0 h-100 img-fluid rounded" src="<?= $covr ?>" />
<div class="col-3 ml-3 p-0 d-flex flex-column row_fixed_height">
<a class="my-auto text-dark" href="/product/<?= $catn ?>">
<h5 class="m-0"><?= $cpny ?></h5>
<h6 class="m-0"><small><?= $catn ?></small></h6>
</a>
</div>
<!-- <div class="col-1 ml-2 p-0 d-flex flex-column row_fixed_height">
<a class="my-auto text-dark" href="/product/<?= $catn ?>">
<small><?= $catg ?></small>
</a>
</div> -->
<div class="col ml-3 p-0 d-flex flex-column">
<?= $supplies_html ?>
</div>
// Генерация списка товаров
$supplies_html = Search::generate($row, $covr, $empties);
?>
<div class="col mb-2">
<div class="row p-2 rounded">
<img class="ml-0 rounded" src="<?= $covr ?>" />
<div class="col-3 ml-3 p-0 d-flex flex-column row_fixed_height">
<a class="my-auto text-dark" href="/product/<?= $catn ?>">
<h5 class="m-0"><?= $catn ?></h5>
<h6 class="m-0"><small><?= $prod ?></small></h6>
</a>
</div>
<div class="col ml-3 p-0 d-flex flex-column">
<?= $supplies_html ?>
</div>
</div>
<?php endforeach ?>
</section>
</div>
<?php endforeach ?>
</section>
<?php if (!empty($empties)) : ?>
<section class="col">
<?php foreach ($empties as $catn) : ?>
<?php if (!empty($empties)) : ?>
<section class="col">
<?php foreach ($empties as $catn) : ?>
<?php if ($products = Search::content(products: Product::searchAnalogs($catn))) : ?>
<?php if ($products = Search::content(products: Product::searchAnalogs($catn))) : ?>
<h4 class="ml-4 mb-3">Аналогичные товары</h4>
<h4 class="ml-4 mb-3">Аналогичные товары</h4>
<?php foreach ($products as $product) : ?>
<?php
// Инициализация данных товара
$cpny = $covr = $catg = $catn = null;
<?php foreach ($products as $product) : ?>
<?php
// Инициализация данных товара
$covr = null;
$prod = $product['prod'] ?? 'Неизвестно';
$catn = $product['catn'] ?? 'Неизвестно';
// Генерация списка товаров
$supplies_html = Search::generate($product, $cpny, $covr, $catg, $catn);
extract($product);
?>
<div class="col mb-2">
<div class="row p-2 rounded">
<img class="ml-0 h-100 img-fluid rounded" src="<?= $covr ?>" />
<div class="col-3 ml-3 p-0 d-flex flex-column row_fixed_height">
<a class="my-auto text-dark" href="/product/<?= $catn ?>">
<h5 class="m-0"><?= $cpny ?></h5>
<h6 class="m-0"><small><?= $catn ?></small></h6>
</a>
</div>
<!-- <div class="col-1 ml-2 p-0 d-flex flex-column row_fixed_height">
// Генерация списка товаров
$supplies_html = Search::generate($product, $covr);
?>
<div class="col mb-2">
<div class="row p-2 rounded">
<img class="ml-0 rounded" src="<?= $covr ?>" />
<div class="col-3 ml-3 p-0 d-flex flex-column row_fixed_height">
<a class="my-auto text-dark" href="/product/<?= $catn ?>">
<small><?= $catg ?></small>
<h5 class="m-0"><?= $catn ?></h5>
<h6 class="m-0"><small><?= $prod ?></small></h6>
</a>
</div> -->
<div class="col ml-3 p-0 d-flex flex-column">
<?= $supplies_html ?>
</div>
</div>
<div class="col ml-3 p-0 d-flex flex-column">
<?= $supplies_html ?>
</div>
</div>
<?php endforeach ?>
</div>
<?php endforeach ?>
<?php endif ?>
<?php endif ?>
<?php endforeach ?>
</section>
<?php endif ?>
</div>
<?php endforeach ?>
</section>
<?php endif ?>
<?php else : ?>
<?php if ($advanced ?? false) : ?>

View File

@ -24,7 +24,7 @@ if (isset($history) && $history) {
)) {
// История поиска существует
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone);
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone);
$timezone = $timezone[1][0];
foreach ($rows as $row) {

View File

@ -12,6 +12,7 @@
#page_search section>div>div>img {
object-fit: cover;
width: calc(65px - 1rem);
height: calc(65px - 1rem);
}
/* #page_search nav > div, #page_search section > div:hover > div {

View File

@ -328,7 +328,7 @@ function product_panel_disconnect(catn) {
dataType: 'json',
data: {
'_csrf': yii.getCsrfToken(),
'catn': prompt('Отключить аналог')
'catn': prompt('Отсоединить аналог (пустое поле - все аналоги)')
},
success: product_response_success,
error: product_response_error