Доработка блока "Аналогичные товары"
This commit is contained in:
parent
a235ed25ac
commit
53281ee422
|
@ -95,12 +95,7 @@ class ProductController extends Controller
|
|||
// Не существует товар к которому планируется соединение
|
||||
|
||||
// Инициализация товара
|
||||
$to = new Product();
|
||||
|
||||
// Запись артикула
|
||||
$to->catn = (string) $target;
|
||||
|
||||
if ($to->save()) {
|
||||
if ($to = Product::writeEmpty((string) $target)) {
|
||||
// Удалось записать товар
|
||||
} else {
|
||||
// Не удалось записать товар
|
||||
|
@ -116,19 +111,8 @@ class ProductController extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
// Запись ребра
|
||||
if ($edge = ProductEdgeProduct::writeSafe(Product::collectionName() . "/$from->_key", Product::collectionName() . "/$to->_key", data: ['type' => 'analogue'])) {
|
||||
// Ребро сохранено
|
||||
|
||||
// Запись в журнал о соединении
|
||||
$from->journal('connect', [
|
||||
'to' => Product::collectionName() . "/$to->_key"
|
||||
]);
|
||||
|
||||
// Запись в журнал о соединении
|
||||
$to->journal('connect', [
|
||||
'from' => Product::collectionName() . "/$from->_key"
|
||||
]);
|
||||
if (($edge = $from->synchronization($to)) instanceof ProductEdgeProduct) {
|
||||
// Ребро создано
|
||||
|
||||
// Запись в буфер возврата
|
||||
$return['alert'] = "Продукты успешно соединены ребром: $edge->_key";
|
||||
|
@ -202,37 +186,9 @@ class ProductController extends Controller
|
|||
if ($to = Product::searchByCatn($target)) {
|
||||
// Существует товар который нужно отсоединить
|
||||
|
||||
// Поиск ребра
|
||||
if ($edge = @ProductEdgeProduct::searchByVertex(Product::collectionName() . "/$from->_key", Product::collectionName() . "/$to->_key", type: 'analogue')[0]) {
|
||||
// Найдено ребро (from: $from, to: $to)
|
||||
} else if ($edge = @ProductEdgeProduct::searchByVertex(Product::collectionName() . "/$to->_key", Product::collectionName() . "/$from->_key", type: 'analogue')[0]) {
|
||||
// Найдено ребро (from: $to, to: $from)
|
||||
} else {
|
||||
// Не найдены ребра
|
||||
|
||||
// Запись кода ответа
|
||||
yii::$app->response->statusCode = 500;
|
||||
|
||||
// Запись в буфер возврата
|
||||
$return['alert'] = "Не удалось найти связь с этим товаром: $target";
|
||||
|
||||
// Переход в конец алгоритма
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ($edge->delete() > 0) {
|
||||
if ($from->disconnect($to)) {
|
||||
// Удалось удалить ребро (связь)
|
||||
|
||||
// Запись в журнал о разъединении
|
||||
$from->journal('disconnect', [
|
||||
'to' => Product::collectionName() . "/$to->_key"
|
||||
]);
|
||||
|
||||
// Запись в журнал о соединении
|
||||
$to->journal('disconnect', [
|
||||
'from' => Product::collectionName() . "/$from->_key"
|
||||
]);
|
||||
|
||||
// Запись в буфер возврата
|
||||
$return['alert'] = "Продукты успешно отсоединены";
|
||||
} else {
|
||||
|
@ -243,7 +199,7 @@ class ProductController extends Controller
|
|||
yii::$app->response->statusCode = 500;
|
||||
|
||||
// Запись в буфер возврата
|
||||
$return['alert'] = "Не удалось удалить ребро между $catn и $target";
|
||||
$return['alert'] = "Не удалось отсоединить $target от $catn";
|
||||
|
||||
// Переход в конец алгоритма
|
||||
goto end;
|
||||
|
|
|
@ -8,29 +8,15 @@ use yii;
|
|||
use yii\web\Controller;
|
||||
use yii\web\Response;
|
||||
|
||||
use app\models\Account;
|
||||
use app\models\Product;
|
||||
use app\models\Supply;
|
||||
use app\models\Search;
|
||||
|
||||
use app\models\connection\Dellin;
|
||||
use app\models\Settings;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* @todo
|
||||
* 1. Ограничение доступа
|
||||
*/
|
||||
class SearchController extends Controller
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @todo
|
||||
* 1. Сессию привязать к аккаунту и проверку по нему делать, иначе её можно просто сбрасывать
|
||||
|
@ -161,212 +147,15 @@ class SearchController extends Controller
|
|||
])) {
|
||||
// Данные найдены по поиску в полях Каталожного номера
|
||||
|
||||
foreach ($response as &$row) {
|
||||
// Перебор продуктов
|
||||
// Генерация данных для представления
|
||||
$response = Search::content(products: $response);
|
||||
|
||||
// Поиск поставок привязанных к продуктам
|
||||
$connections = Supply::searchByEdge(
|
||||
from: 'product',
|
||||
to: 'supply',
|
||||
edge: 'supply_edge_product',
|
||||
limit: 11,
|
||||
direction: 'OUTBOUND',
|
||||
subquery_where: [
|
||||
['product._key' => $row['_key']],
|
||||
['supply.catn == product.catn'],
|
||||
['supply_edge_product.type' => 'connect']
|
||||
],
|
||||
where: 'supply._id == supply_edge_product[0]._from',
|
||||
select: '{supply, supply_edge_product}'
|
||||
);
|
||||
|
||||
// Инициализация буфера
|
||||
$buffer_connections = [];
|
||||
|
||||
if (count($connections) === 11) {
|
||||
// Если в базе данных хранится много поставок
|
||||
|
||||
// Инициализация
|
||||
$row['overload'] = true;
|
||||
}
|
||||
|
||||
foreach ($connections as $key => &$connection) {
|
||||
// Перебор поставок
|
||||
|
||||
if (($cost = $cost['ЦенаЗаЕдиницу'] ?? $connection['supply_edge_product'][0]['onec']['Цены']['Цена']['ЦенаЗаЕдиницу']) < 1
|
||||
|| ($amount = $connection['supply']['amnt'] ?? $connection['supply_edge_product'][0]['onec']['Количество']) < 1
|
||||
) {
|
||||
// Цена меньше единицы (подразумевается как ошибка) или количество меньше единицы
|
||||
|
||||
// Скрыть из выдачи
|
||||
unset($connections[$key]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Инициализация аккаунта
|
||||
$connection['account'] = Account::searchBySupplyId($connection['supply_edge_product'][0]['_from']);
|
||||
|
||||
// Инициализация продукта
|
||||
$connection['product'] = Product::searchBySupplyId($connection['supply_edge_product'][0]['_from']);
|
||||
|
||||
try {
|
||||
// Инициализация данных геолокации
|
||||
|
||||
try {
|
||||
$from = (int) $connection['account']['opts']['delivery_from_terminal'] ?? empty(Settings::search()->delivery_from_default) ? 36 : (int) Settings::search()->delivery_from_default;
|
||||
} catch (Exception $e) {
|
||||
$from = empty(Settings::search()->delivery_from_default) ? 36 : (int) Settings::search()->delivery_from_default;
|
||||
}
|
||||
|
||||
try {
|
||||
$to = (int) yii::$app->user->identity->opts['delivery_to_terminal'] ?? 36;
|
||||
} catch (Exception $e) {
|
||||
$to = 36;
|
||||
}
|
||||
|
||||
if (
|
||||
($buffer_connection = $connection['product']['bffr']["$from-$to"] ?? false)
|
||||
&& time() < $buffer_connection['expires']
|
||||
) {
|
||||
// Найдены данные доставки в буфере
|
||||
// и срок хранения не превышен, информация актуальна
|
||||
|
||||
// Запись в буфер вывода
|
||||
$connection['delivery'] = $buffer_connection['data'];
|
||||
$connection['delivery']['type'] = 'auto';
|
||||
} else {
|
||||
// Инициализация инстанции продукта в базе данных
|
||||
$product = Product::searchByCatn($connection['product']['catn']);
|
||||
|
||||
// Инициализация доставки Dellin (автоматическая)
|
||||
$product->bffr = [
|
||||
"$from-$to" => [
|
||||
'data' => $connection['delivery'] = Dellin::calcDeliveryAdvanced(
|
||||
$from,
|
||||
$to,
|
||||
(int) ($connection['product']['wght'] ?? 0),
|
||||
(int) ($connection['product']['dmns']['x'] ?? 0),
|
||||
(int) ($connection['product']['dmns']['y'] ?? 0),
|
||||
(int) ($connection['product']['dmns']['z'] ?? 0)
|
||||
),
|
||||
'expires' => time() + 86400
|
||||
]
|
||||
] + ($product->bffr ?? []);
|
||||
$connection['delivery']['type'] = 'auto';
|
||||
|
||||
// Отправка в базу данных
|
||||
$product->update();
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$connection['delivery']['error'] = true;
|
||||
|
||||
// var_dump($e->getMessage());
|
||||
// var_dump($e->getTrace());
|
||||
// var_dump($e->getFile());
|
||||
|
||||
// var_dump(json_decode($e->getMessage(), true)['errors']);
|
||||
// die;
|
||||
}
|
||||
|
||||
// Инициализация цены (цена поставки + цена доставки + наша наценка)
|
||||
$connection['cost'] = $cost + ($connection['delivery']['price']['all'] ?? $connection['delivery']['price']['one'] ?? 0) + ($settings['increase'] ?? 0);
|
||||
|
||||
// Инициализация версии для рассчета доставки по воздуху
|
||||
$buffer_delivery_avia = $connection;
|
||||
|
||||
try {
|
||||
// Инициализация данных геолокации
|
||||
|
||||
if (($cost = $cost['ЦенаЗаЕдиницу'] ?? $buffer_delivery_avia['supply_edge_product'][0]['onec']['Цены']['Цена']['ЦенаЗаЕдиницу']) < 1
|
||||
|| ($amount = $connection['supply']['amnt'] ?? $connection['supply_edge_product'][0]['onec']['Количество']) < 1
|
||||
) {
|
||||
// Цена меньше единицы (подразумевается как ошибка) или количество меньше единицы
|
||||
// Этот код не будет выполняться, так как цена одна на обе позиции и аналогичная проверка выше уже есть
|
||||
// Однако я это оставлю для возможных доработок в будущем
|
||||
|
||||
// Скрыть из выдачи
|
||||
unset($connections[$key]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$from = (int) $buffer_delivery_avia['account']['opts']['delivery_from_terminal'] ?? empty(Settings::search()->delivery_from_default) ? 36 : (int) Settings::search()->delivery_from_default;
|
||||
} catch (Exception $e) {
|
||||
$from = empty(Settings::search()->delivery_from_default) ? 36 : (int) Settings::search()->delivery_from_default;
|
||||
}
|
||||
|
||||
try {
|
||||
$to = (int) yii::$app->user->identity->opts['delivery_to_terminal'] ?? 36;
|
||||
} catch (Exception $e) {
|
||||
$to = 36;
|
||||
}
|
||||
|
||||
if (
|
||||
($buffer_connection = $buffer_delivery_avia['product']['bffr']["$from-$to-avia"] ?? false)
|
||||
&& time() < $buffer_connection['expires']
|
||||
) {
|
||||
// Найдены данные доставки в буфере
|
||||
// и срок хранения не превышен, информация актуальна
|
||||
|
||||
// Запись в буфер вывода
|
||||
$buffer_delivery_avia['delivery'] = $buffer_connection['data'];
|
||||
$buffer_delivery_avia['delivery']['type'] = 'avia';
|
||||
} else {
|
||||
// Инициализация инстанции продукта в базе данных
|
||||
$product = Product::searchByCatn($buffer_delivery_avia['product']['catn']);
|
||||
|
||||
// Инициализация доставки Dellin (автоматическая)
|
||||
$product->bffr = [
|
||||
"$from-$to-avia" => [
|
||||
'data' => $buffer_delivery_avia['delivery'] = Dellin::calcDeliveryAdvanced(
|
||||
$from,
|
||||
$to,
|
||||
(int) ($buffer_delivery_avia['product']['wght'] ?? 0),
|
||||
(int) ($buffer_delivery_avia['product']['dmns']['x'] ?? 0),
|
||||
(int) ($buffer_delivery_avia['product']['dmns']['y'] ?? 0),
|
||||
(int) ($buffer_delivery_avia['product']['dmns']['z'] ?? 0),
|
||||
avia: true
|
||||
),
|
||||
'expires' => time() + 86400
|
||||
]
|
||||
] + ($product->bffr ?? []);
|
||||
$buffer_delivery_avia['delivery']['type'] = 'avia';
|
||||
|
||||
// Отправка в базу данных
|
||||
$product->update();
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$buffer_delivery_avia['delivery']['error'] = true;
|
||||
|
||||
// echo '<pre>';
|
||||
// var_dump($e->getMessage());
|
||||
// var_dump($e->getTrace());
|
||||
// var_dump($e->getFile());
|
||||
|
||||
// var_dump(json_decode($e->getMessage(), true)['errors']);
|
||||
// die;
|
||||
}
|
||||
|
||||
if (!isset($buffer_delivery_avia['delivery']['error']) || $buffer_delivery_avia['delivery']['error'] !== true) {
|
||||
// Если рассчиталась доставка самолётом
|
||||
|
||||
// Инициализация цены (цена поставки + цена доставки + наша наценка)
|
||||
$buffer_delivery_avia['cost'] = $cost + ($buffer_delivery_avia['delivery']['price']['all'] ?? $buffer_delivery_avia['delivery']['price']['one'] ?? 0) + ($settings['increase'] ?? 0);
|
||||
|
||||
// Запись в буфер
|
||||
$buffer_connections[] = $buffer_delivery_avia;
|
||||
}
|
||||
}
|
||||
|
||||
// Запись обработанных данных
|
||||
$row['supplies'] = array_merge($connections, $buffer_connections);
|
||||
}
|
||||
if (yii::$app->request->isPost) {
|
||||
// POST-запрос
|
||||
|
||||
// Запись ответа
|
||||
$return = [
|
||||
'panel' => $this->renderPartial('/search/panel', compact('response')),
|
||||
'panel' => $this->renderPartial('/search/panel', compact('response', 'query')),
|
||||
'_csrf' => yii::$app->request->getCsrfToken()
|
||||
];
|
||||
|
||||
|
@ -374,10 +163,11 @@ class SearchController extends Controller
|
|||
// Полноценный поиск
|
||||
|
||||
// Запись ответа
|
||||
$return['main'] = $this->renderPartial('/search/index', compact('response'));
|
||||
$return['main'] = $this->renderPartial('/search/index', compact('response', 'query'));
|
||||
$return['hide'] = 1;
|
||||
$return['redirect'] = '/search?type=product&q=' . $query;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Данные не найдены
|
||||
|
||||
|
@ -413,7 +203,7 @@ class SearchController extends Controller
|
|||
|
||||
$advanced = true;
|
||||
|
||||
return $this->render('/search/index', compact('response', 'timer', 'advanced'));
|
||||
return $this->render('/search/index', compact('response', 'timer', 'advanced', 'query'));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ abstract class Edge extends Document
|
|||
* @todo
|
||||
* 1. Удалить $type и оставить только $data
|
||||
*/
|
||||
public static function write(string $_from, string $_to, string $type, array $data = []): ?static
|
||||
public static function write(string $_from, string $_to, string $type = '', array $data = []): ?static
|
||||
{
|
||||
// Инициализация
|
||||
$edge = new static;
|
||||
|
@ -159,19 +159,31 @@ abstract class Edge extends Document
|
|||
}
|
||||
|
||||
/**
|
||||
* Поиск рёбер
|
||||
* Поиск рёбер по направлению
|
||||
*/
|
||||
public static function search(string $target, string $direction = 'OUTBOUND', string $type = '', int $limit = 1): static|array|null
|
||||
{
|
||||
if ($direction === 'OUTBOUND') {
|
||||
$query = self::find()->where(['_from' => $target, 'type' => $type]);
|
||||
} else if ($direction === 'INBOUND') {
|
||||
$query = self::find()->where(['_to' => $target, 'type' => $type]);
|
||||
if (str_contains($direction, 'OUTBOUND')) {
|
||||
// Исходящие рёбра
|
||||
|
||||
$query = static::find()->where(['_from' => $target, 'type' => $type]);
|
||||
} else if (str_contains($direction, 'INBOUND')) {
|
||||
// Входящие рёбра
|
||||
|
||||
$query = static::find()->where(['_to' => $target, 'type' => $type]);
|
||||
} 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);
|
||||
}
|
||||
|
||||
if ($limit < 2) {
|
||||
// Одно ребро или меньше
|
||||
|
||||
return $query->one();
|
||||
} else {
|
||||
// Несколько рёбер
|
||||
|
||||
return $query->limit($limit)->all();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ use DateTime;
|
|||
use DateTimeZone;
|
||||
|
||||
use Exception;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Var_;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Продукт (в ассортименте магазина)
|
||||
|
@ -596,10 +598,183 @@ class Product extends Document
|
|||
*/
|
||||
public static function searchAnalogs(string $catn, int $limit = 30): ?array
|
||||
{
|
||||
// Инициализация буфера возврата
|
||||
$return = [];
|
||||
|
||||
// Поиск ключей аналогов
|
||||
$analogs = ProductEdgeProduct::searchConnections(self::searchByCatn($catn)->_key, $limit);
|
||||
|
||||
foreach ($analogs as $analog) {
|
||||
// Перебор найденных ключей (_key) аналогов
|
||||
|
||||
return [];
|
||||
if ($analog = Product::searchById(self::collectionName() . "/$analog")) {
|
||||
// Найден товар
|
||||
|
||||
// Запись в буфер вывода
|
||||
$return[] = $analog;
|
||||
} else {
|
||||
// Не найден товар
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Синхронизация аналогов
|
||||
*
|
||||
* Связывает с товаром и связанными с ним товарами в одну группу
|
||||
*
|
||||
* @param self $to Цель
|
||||
*
|
||||
* @return array Созданные рёбра
|
||||
*/
|
||||
public function synchronization(self $to): array
|
||||
{
|
||||
// Инициализация буфера сохранённых рёбер
|
||||
$edges = [];
|
||||
|
||||
// Инициализация списка товаров в группе и буфера для связей "всех со всеми"
|
||||
$products = $_products = array_unique(array_merge($this->connections(), $to->connections(), [Product::collectionName() . "/$to->_key"]));
|
||||
|
||||
foreach ($products as $product) {
|
||||
// Перебор связей для создания связей во всех товарах
|
||||
|
||||
// Удаление обрабатываемого товара из буферного списка товаров
|
||||
unset($_products[array_search($product, $_products)]);
|
||||
|
||||
foreach ($_products as $_product) {
|
||||
// Перебор товаров из буфера
|
||||
|
||||
if ($from = self::searchById($product)) {
|
||||
// Товар найден
|
||||
} else {
|
||||
if ($from = Product::writeEmpty($product)) {
|
||||
// Удалось записать товар
|
||||
} else {
|
||||
// Не удалось записать товар
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($to = self::searchById($_product)) {
|
||||
// Товар найден
|
||||
} else {
|
||||
if ($to = Product::writeEmpty($_product)) {
|
||||
// Удалось записать товар
|
||||
} else {
|
||||
// Не удалось записать товар
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($edge = $from->connect($to)) {
|
||||
// Ребро создано
|
||||
|
||||
// Запись в буфер
|
||||
$edges[] = $edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $edges;
|
||||
}
|
||||
|
||||
/**
|
||||
* Подключение аналога
|
||||
*
|
||||
* СВЯЗЫВАЕТ ТОЛЬКО ДВА ТОВАРА, ГРУППА ОСТАНЕТСЯ НЕИЗМЕННОЙ
|
||||
*
|
||||
* @param self $to Цель
|
||||
*/
|
||||
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)) {
|
||||
// Дубликат найден (наоборот)
|
||||
|
||||
// Вероятно эта проверка здесь не нужна, так как мы знаем входные данные
|
||||
} else {
|
||||
// Дубликаты не найдены
|
||||
|
||||
if ($edge = ProductEdgeProduct::write(Product::collectionName() . "/$this->_key", Product::collectionName() . "/$to->_key", data: ['type' => 'analogue'])) {
|
||||
// Ребро сохранено
|
||||
|
||||
// Запись в журнал о соединении
|
||||
$this->journal('connect analogue', [
|
||||
'to' => Product::collectionName() . "/$to->_key"
|
||||
]);
|
||||
|
||||
// Запись в журнал о соединении
|
||||
$to->journal('connect analogue', [
|
||||
'from' => Product::collectionName() . "/$this->_key"
|
||||
]);
|
||||
|
||||
return $edge;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Отключение аналога
|
||||
*
|
||||
* @param self $to Цель
|
||||
*/
|
||||
public function disconnect(self $to): 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 {
|
||||
// Не найдены ребра
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($edge->delete() > 0) {
|
||||
// Удалось удалить ребро (связь)
|
||||
|
||||
// Запись в журнал о разъединении
|
||||
$this->journal('disconnect analogue', [
|
||||
'to' => Product::collectionName() . "/$to->_key"
|
||||
]);
|
||||
|
||||
// Запись в журнал о соединении
|
||||
$to->journal('disconnect analogue', [
|
||||
'from' => Product::collectionName() . "/$this->_key"
|
||||
]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Найти все связанные товары
|
||||
*
|
||||
* @param int $limit Ограничение по максимальному значению
|
||||
*/
|
||||
public function connections(int $limit = 100): array
|
||||
{
|
||||
// Инициализация буфера связанных товаров
|
||||
$products = [];
|
||||
|
||||
foreach (ProductEdgeProduct::search(self::collectionName() . "/$this->_key", direction: 'ANY', type: 'analogue', limit: $limit) as $edge) {
|
||||
// Перебор связей для создания списка товаров (вершин)
|
||||
|
||||
// Добавление товаров (вершин) в буфер (подразумевается, что без дубликатов)
|
||||
if (!in_array($edge->_from, $products, true)) $products[] = $edge->_from;
|
||||
if (!in_array($edge->_to, $products, true)) $products[] = $edge->_to;
|
||||
}
|
||||
|
||||
return $products;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ class ProductEdgeProduct extends Edge
|
|||
preg_match_all('/\w+\/([0-9]+)/', $edge->_to, $matches);
|
||||
|
||||
// Запись артикула в буфер вывода
|
||||
$return[] = $matches[1];
|
||||
$return[] = $matches[1][0];
|
||||
}
|
||||
|
||||
// Перерасчет ограничения по количеству
|
||||
|
@ -47,10 +47,10 @@ class ProductEdgeProduct extends Edge
|
|||
// Перебор найденных рёбер
|
||||
|
||||
// Извлечение ключа
|
||||
preg_match_all('/\w+\/([0-9]+)/', $edge->_to, $matches);
|
||||
preg_match_all('/\w+\/([0-9]+)/', $edge->_from, $matches);
|
||||
|
||||
// Запись артикула в буфер вывода
|
||||
$return[] = $matches[1];
|
||||
$return[] = $matches[1][0];
|
||||
}
|
||||
|
||||
return $return;
|
||||
|
|
|
@ -5,9 +5,14 @@ declare(strict_types=1);
|
|||
namespace app\models;
|
||||
|
||||
use yii;
|
||||
use yii\web\IdentityInterface;
|
||||
|
||||
use app\models\traits\SearchByEdge;
|
||||
use app\models\connection\Dellin;
|
||||
use app\models\Settings;
|
||||
|
||||
use datetime;
|
||||
use exception;
|
||||
use throwable;
|
||||
|
||||
/**
|
||||
* Поиск
|
||||
|
@ -110,4 +115,435 @@ class Search extends Document
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Поиск содержимого поиска
|
||||
*
|
||||
* @todo В будущем возможно заказ не только поставок реализовать
|
||||
* Переписать реестр и проверку на дубликаты, не понимаю как они работают
|
||||
*/
|
||||
public static function content(array $products, int $limit = 50, int $page = 1): Supply|int|array|null
|
||||
{
|
||||
// Инициализация буфера вывода
|
||||
$response = $products;
|
||||
|
||||
// Генерация сдвига по запрашиваемым данным (пагинация)
|
||||
$offset = $limit * ($page - 1);
|
||||
|
||||
foreach ($response as &$row) {
|
||||
// Перебор продуктов
|
||||
|
||||
if ($row instanceof Product) {
|
||||
// В массиве объект - инстанция товара
|
||||
|
||||
// Преобразование к массиву в буфер (унификация данных)
|
||||
$_row = $row->attributes;
|
||||
} else {
|
||||
// В массиве не товар (подразумевается, что это массив с параметрами)
|
||||
|
||||
// Запись в буфер (унификация данных)
|
||||
$_row = $row;
|
||||
}
|
||||
|
||||
// Поиск поставок привязанных к продуктам
|
||||
$connections = Supply::searchByEdge(
|
||||
from: 'product',
|
||||
to: 'supply',
|
||||
edge: 'supply_edge_product',
|
||||
limit: $limit,
|
||||
offset: $offset,
|
||||
direction: 'OUTBOUND',
|
||||
subquery_where: [
|
||||
['product._key' => $_row['_key']],
|
||||
['supply.catn == product.catn'],
|
||||
['supply_edge_product.type' => 'connect']
|
||||
],
|
||||
where: 'supply._id == supply_edge_product[0]._from',
|
||||
select: '{supply, supply_edge_product}'
|
||||
);
|
||||
|
||||
// Инициализация буфера
|
||||
$buffer_connections = [];
|
||||
|
||||
if (count($connections) === 11) {
|
||||
// Если в базе данных хранится много поставок
|
||||
|
||||
// Инициализация
|
||||
$_row['overload'] = true;
|
||||
}
|
||||
|
||||
foreach ($connections as $key => &$connection) {
|
||||
// Перебор поставок
|
||||
|
||||
if (($cost = $cost['ЦенаЗаЕдиницу'] ?? $connection['supply_edge_product'][0]['onec']['Цены']['Цена']['ЦенаЗаЕдиницу']) < 1
|
||||
|| ($amount = $connection['supply']['amnt'] ?? $connection['supply_edge_product'][0]['onec']['Количество']) < 1
|
||||
) {
|
||||
// Цена меньше единицы (подразумевается как ошибка) или количество меньше единицы
|
||||
|
||||
// Скрыть из выдачи
|
||||
unset($connections[$key]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Инициализация аккаунта
|
||||
$connection['account'] = Account::searchBySupplyId($connection['supply_edge_product'][0]['_from']);
|
||||
|
||||
// Инициализация продукта
|
||||
$connection['product'] = Product::searchBySupplyId($connection['supply_edge_product'][0]['_from']);
|
||||
|
||||
try {
|
||||
// Инициализация данных геолокации
|
||||
|
||||
try {
|
||||
$from = (int) $connection['account']['opts']['delivery_from_terminal'] ?? empty(Settings::search()->delivery_from_default) ? 36 : (int) Settings::search()->delivery_from_default;
|
||||
} catch (exception $e) {
|
||||
$from = empty(Settings::search()->delivery_from_default) ? 36 : (int) Settings::search()->delivery_from_default;
|
||||
}
|
||||
|
||||
try {
|
||||
$to = (int) yii::$app->user->identity->opts['delivery_to_terminal'] ?? 36;
|
||||
} catch (Exception $e) {
|
||||
$to = 36;
|
||||
}
|
||||
|
||||
if (
|
||||
($buffer_connection = $connection['product']['bffr']["$from-$to"] ?? false)
|
||||
&& time() < $buffer_connection['expires']
|
||||
) {
|
||||
// Найдены данные доставки в буфере
|
||||
// и срок хранения не превышен, информация актуальна
|
||||
|
||||
// Запись в буфер вывода
|
||||
$connection['delivery'] = $buffer_connection['data'];
|
||||
$connection['delivery']['type'] = 'auto';
|
||||
} else {
|
||||
// Инициализация инстанции продукта в базе данных
|
||||
$product = Product::searchByCatn($connection['product']['catn']);
|
||||
|
||||
// Инициализация доставки Dellin (автоматическая)
|
||||
$product->bffr = [
|
||||
"$from-$to" => [
|
||||
'data' => $connection['delivery'] = Dellin::calcDeliveryAdvanced(
|
||||
$from,
|
||||
$to,
|
||||
(int) ($connection['product']['wght'] ?? 0),
|
||||
(int) ($connection['product']['dmns']['x'] ?? 0),
|
||||
(int) ($connection['product']['dmns']['y'] ?? 0),
|
||||
(int) ($connection['product']['dmns']['z'] ?? 0)
|
||||
),
|
||||
'expires' => time() + 86400
|
||||
]
|
||||
] + ($product->bffr ?? []);
|
||||
$connection['delivery']['type'] = 'auto';
|
||||
|
||||
// Отправка в базу данных
|
||||
$product->update();
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$connection['delivery']['error'] = true;
|
||||
|
||||
// var_dump($e->getMessage());
|
||||
// var_dump($e->getTrace());
|
||||
// var_dump($e->getFile());
|
||||
|
||||
// var_dump(json_decode($e->getMessage(), true)['errors']);
|
||||
// die;
|
||||
}
|
||||
|
||||
// Инициализация цены (цена поставки + цена доставки + наша наценка)
|
||||
$connection['cost'] = $cost + ($connection['delivery']['price']['all'] ?? $connection['delivery']['price']['one'] ?? 0) + ($settings['increase'] ?? 0);
|
||||
|
||||
// Инициализация версии для рассчета доставки по воздуху
|
||||
$buffer_delivery_avia = $connection;
|
||||
|
||||
try {
|
||||
// Инициализация данных геолокации
|
||||
|
||||
if (($cost = $cost['ЦенаЗаЕдиницу'] ?? $buffer_delivery_avia['supply_edge_product'][0]['onec']['Цены']['Цена']['ЦенаЗаЕдиницу']) < 1
|
||||
|| ($amount = $connection['supply']['amnt'] ?? $connection['supply_edge_product'][0]['onec']['Количество']) < 1
|
||||
) {
|
||||
// Цена меньше единицы (подразумевается как ошибка) или количество меньше единицы
|
||||
// Этот код не будет выполняться, так как цена одна на обе позиции и аналогичная проверка выше уже есть
|
||||
// Однако я это оставлю для возможных доработок в будущем
|
||||
|
||||
// Скрыть из выдачи
|
||||
unset($connections[$key]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$from = (int) $buffer_delivery_avia['account']['opts']['delivery_from_terminal'] ?? empty(Settings::search()->delivery_from_default) ? 36 : (int) Settings::search()->delivery_from_default;
|
||||
} catch (Exception $e) {
|
||||
$from = empty(Settings::search()->delivery_from_default) ? 36 : (int) Settings::search()->delivery_from_default;
|
||||
}
|
||||
|
||||
try {
|
||||
$to = (int) yii::$app->user->identity->opts['delivery_to_terminal'] ?? 36;
|
||||
} catch (Exception $e) {
|
||||
$to = 36;
|
||||
}
|
||||
|
||||
if (
|
||||
($buffer_connection = $buffer_delivery_avia['product']['bffr']["$from-$to-avia"] ?? false)
|
||||
&& time() < $buffer_connection['expires']
|
||||
) {
|
||||
// Найдены данные доставки в буфере
|
||||
// и срок хранения не превышен, информация актуальна
|
||||
|
||||
// Запись в буфер вывода
|
||||
$buffer_delivery_avia['delivery'] = $buffer_connection['data'];
|
||||
$buffer_delivery_avia['delivery']['type'] = 'avia';
|
||||
} else {
|
||||
// Инициализация инстанции продукта в базе данных
|
||||
$product = Product::searchByCatn($buffer_delivery_avia['product']['catn']);
|
||||
|
||||
// Инициализация доставки Dellin (автоматическая)
|
||||
$product->bffr = [
|
||||
"$from-$to-avia" => [
|
||||
'data' => $buffer_delivery_avia['delivery'] = Dellin::calcDeliveryAdvanced(
|
||||
$from,
|
||||
$to,
|
||||
(int) ($buffer_delivery_avia['product']['wght'] ?? 0),
|
||||
(int) ($buffer_delivery_avia['product']['dmns']['x'] ?? 0),
|
||||
(int) ($buffer_delivery_avia['product']['dmns']['y'] ?? 0),
|
||||
(int) ($buffer_delivery_avia['product']['dmns']['z'] ?? 0),
|
||||
avia: true
|
||||
),
|
||||
'expires' => time() + 86400
|
||||
]
|
||||
] + ($product->bffr ?? []);
|
||||
$buffer_delivery_avia['delivery']['type'] = 'avia';
|
||||
|
||||
// Отправка в базу данных
|
||||
$product->update();
|
||||
}
|
||||
} catch (exception $e) {
|
||||
$buffer_delivery_avia['delivery']['error'] = true;
|
||||
|
||||
// echo '<pre>';
|
||||
// var_dump($e->getMessage());
|
||||
// var_dump($e->getTrace());
|
||||
// var_dump($e->getFile());
|
||||
|
||||
// var_dump(json_decode($e->getMessage(), true)['errors']);
|
||||
// die;
|
||||
}
|
||||
|
||||
if (!isset($buffer_delivery_avia['delivery']['error']) || $buffer_delivery_avia['delivery']['error'] !== true) {
|
||||
// Если рассчиталась доставка самолётом
|
||||
|
||||
// Инициализация цены (цена поставки + цена доставки + наша наценка)
|
||||
$buffer_delivery_avia['cost'] = $cost + ($buffer_delivery_avia['delivery']['price']['all'] ?? $buffer_delivery_avia['delivery']['price']['one'] ?? 0) + ($settings['increase'] ?? 0);
|
||||
|
||||
// Запись в буфер
|
||||
$buffer_connections[] = $buffer_delivery_avia;
|
||||
}
|
||||
}
|
||||
|
||||
// Запись обработанных данных
|
||||
$_row['supplies'] = array_merge($connections, $buffer_connections);
|
||||
|
||||
// Запись из буфера
|
||||
$row = $_row;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Генерация HTML-кода с найденным товаром
|
||||
*
|
||||
* @param array $row Товар сгенерированный через Search::content()
|
||||
* @param string|null $cpny Компания (сейчас пока что это $name - Название)
|
||||
* @param string|null $covr Обложка
|
||||
* @param string|null $catg Категория
|
||||
* @param string|null $catn Артикул
|
||||
* @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
|
||||
{
|
||||
// Инициализация
|
||||
extract($row);
|
||||
$cpny ?? $cpny = 'Без названия';
|
||||
// $dscr ?? $dscr = 'Описание';
|
||||
$catg ?? $catg = 'Категория';
|
||||
$catn ?? $catn = 'Неизвестно';
|
||||
foreach ($imgs ?? [] as $img) {
|
||||
// Перебор изображений для обложки
|
||||
|
||||
if ($img['covr'] ?? false) {
|
||||
// Обложка найдена
|
||||
|
||||
$covr = $img['h150'];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_null($covr)) {
|
||||
// Обложка не инициализирована
|
||||
|
||||
if (!$covr = $imgs[0]['h150'] ?? false) {
|
||||
// Не удалось использовать первое изображение как обложку
|
||||
|
||||
// Запись обложки по умолчанию
|
||||
$covr = '/img/covers/h150/product.png';
|
||||
}
|
||||
}
|
||||
|
||||
// Инициализация буфера с HTML поставок
|
||||
$supplies_html = '';
|
||||
|
||||
// Инициализация блокировщика для пустого блока (на случай, если нет поставок, чтобы не было дубликатов вывода)
|
||||
$empty_block = false;
|
||||
|
||||
// Инициализация счётчика поставок
|
||||
$supplies_amount = count($row['supplies']);
|
||||
|
||||
// Инициализация указателя номера цикла
|
||||
$supply_iterator = 1;
|
||||
|
||||
foreach (empty($row['supplies']) || count($row['supplies']) === 0 ? [null] : $row['supplies'] as $supply) {
|
||||
// Инициализация модификатора класса
|
||||
if ($supplies_amount > $supply_iterator) {
|
||||
// Это не последняя строка с товаром и его поставками
|
||||
|
||||
$supply_class_modifier = 'mb-1';
|
||||
} else {
|
||||
// Это последняя строка с товаром и его поставками
|
||||
|
||||
$supply_class_modifier = '';
|
||||
}
|
||||
|
||||
if (is_null($supply)) {
|
||||
// Поставки отсутствуют
|
||||
|
||||
// Генерация данных об отсутствии заказов
|
||||
goto no_supplies;
|
||||
} else {
|
||||
// Обычная обработка поставки
|
||||
|
||||
// Инициализация переменных
|
||||
extract($supply);
|
||||
}
|
||||
|
||||
// Инициализация цены
|
||||
$price_raw = $cost;
|
||||
$price = $price_raw . ' ' . $supply_edge_product[0]['onec']['Цены']['Цена']['Валюта'] ?? 'руб';
|
||||
|
||||
// Инициализация количества
|
||||
$amount_raw = $amount = $supply['amnt'] ?? $supply_edge_product[0]['onec']['Количество'];
|
||||
if (empty($amount_raw) || $amount_raw < 1) {
|
||||
// Уже не используется
|
||||
$amount = 'Под заказ';
|
||||
} else {
|
||||
$amount .= ' шт';
|
||||
}
|
||||
|
||||
if ($amount_raw < 1 || $price_raw < 1) {
|
||||
// Нет в наличии или цена 0 рублей
|
||||
|
||||
// Поставки отстутвуют
|
||||
no_supplies:
|
||||
|
||||
// Проверка на блокировку
|
||||
if ($empty_block) continue;
|
||||
|
||||
$supplies_html .= <<<HTML
|
||||
<div class="row $supply_class_modifier m-0 h-100 text-right">
|
||||
<a class="col-auto ml-auto my-auto text-dark" href="/order/new/custom" role="button" onclick="return false;">
|
||||
<small>
|
||||
Заказать поиск у оператора
|
||||
</small>
|
||||
</a>
|
||||
</div>
|
||||
HTML;
|
||||
|
||||
// Запись в список ненайденных
|
||||
$empties[] = $catn;
|
||||
|
||||
// Запись блокировщика
|
||||
$empty_block = true;
|
||||
|
||||
// Обновление счётчика
|
||||
++$supply_iterator;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Инициализация доставки
|
||||
if (isset($delivery['error']) || $delivery === '?') {
|
||||
// Не удалось рассчитать доставку
|
||||
|
||||
// Инициализация типа доставки
|
||||
$delivery_type = $delivery['type'] ?? 'auto';
|
||||
|
||||
// Инициализация индикатора
|
||||
$delivery_icon = '<i class="mr-1 fas fa-truck"></i>';
|
||||
|
||||
// Инициализация времени
|
||||
$delivery = '?';
|
||||
} else {
|
||||
// Удалось рассчитать доставку
|
||||
|
||||
// Инициализация типа доставки
|
||||
$delivery_type = $delivery['type'] ?? 'auto';
|
||||
|
||||
// Инициализация индикатора
|
||||
$delivery_icon = match ($delivery_type) {
|
||||
'avia' => '<i class="mr-1 fas fa-plane"></i>',
|
||||
default => '<i class="mr-1 fas fa-truck"></i>'
|
||||
};
|
||||
|
||||
// Инициализация даты отправки
|
||||
try {
|
||||
// Взять данные из "arrivalToOspSender" (Дата прибытия на терминал-отправитель)
|
||||
|
||||
$delivery_send_date = datetime::createFromFormat('Y-m-d', $delivery['orderDates']['arrivalToOspSender'])->getTimestamp();
|
||||
} catch (throwable $e) {
|
||||
// Взять данные из "pickup" (Дата передачи груза на адресе отправителя)
|
||||
|
||||
$delivery_send_date = datetime::createFromFormat('Y-m-d', $delivery['orderDates']['pickup'])->getTimestamp();
|
||||
}
|
||||
|
||||
// Инициализация времени доставки
|
||||
try {
|
||||
// Доставка по воздуху (подразумевается), данные из "giveoutFromOspReceiver" (Дата и время, с которого груз готов к выдаче на терминале)
|
||||
|
||||
$delivery_converted = datetime::createFromFormat('Y-m-d H:i:s', $delivery['orderDates']['giveoutFromOspReceiver'])->getTimestamp();
|
||||
} catch (Throwable $e) {
|
||||
// Автоматическая доставка (подразумевается), данные из "arrivalToOspReceiver" (Дата прибытия натерминал-получатель)
|
||||
|
||||
$delivery_converted = datetime::createFromFormat('Y-m-d', $delivery['orderDates']['arrivalToOspReceiver'])->getTimestamp();
|
||||
}
|
||||
$delivery = ceil(($delivery_converted - ($delivery_send_date ?? 0)) / 60 / 60 / 24) + 1;
|
||||
}
|
||||
|
||||
// Инициализация индекса аккаунта
|
||||
$index = $account['indx'] ?? 'Неизвестен';
|
||||
|
||||
// Генерация
|
||||
$supplies_html .= <<<HTML
|
||||
<div class="row $supply_class_modifier m-0 text-right">
|
||||
<small class="ml-auto col-1 ml-2 my-auto pl-2 pr-0">$index</small>
|
||||
<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');">
|
||||
<i class="fas fa-cart-arrow-down pr-1 m-auto"></i>
|
||||
</a>
|
||||
</div>
|
||||
HTML;
|
||||
|
||||
// Обновление счётчика
|
||||
++$supply_iterator;
|
||||
}
|
||||
|
||||
return $supplies_html;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
use app\models\Product;
|
||||
use app\models\Search;
|
||||
|
||||
?>
|
||||
|
||||
|
@ -27,218 +28,29 @@ use app\models\Product;
|
|||
<?php else : ?>
|
||||
<?php if (isset($response) && is_array($response) && $response) : ?>
|
||||
|
||||
<div class="row py-3 w-100">
|
||||
<section class="col">
|
||||
|
||||
<?php
|
||||
// Инициализация
|
||||
$covr_not_found = true;
|
||||
$i = 0;
|
||||
$amount = count($response);
|
||||
?>
|
||||
<div class="row py-3 w-100 flex-column">
|
||||
<section class="col-auto mb-4">
|
||||
<h4 class="ml-4 mb-3">Товары по запросу: "<?= $query ?? 'ошибка чтения запроса' ?>"</h4>
|
||||
|
||||
<?php foreach ($response as $row) : ?>
|
||||
|
||||
<?php
|
||||
// Инициализация
|
||||
extract($row);
|
||||
$name ?? $name = 'Без названия';
|
||||
// $dscr ?? $dscr = 'Описание';
|
||||
$catg ?? $catg = 'Категория';
|
||||
$catn ?? $catn = 'Неизвестно';
|
||||
|
||||
// Инициализация обложки
|
||||
$covr = null;
|
||||
foreach ($imgs ?? [] as $img) {
|
||||
// Перебор изображений для обложки
|
||||
|
||||
if ($img['covr'] ?? false) {
|
||||
// Обложка найдена
|
||||
|
||||
$covr = $img['h150'];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_null($covr)) {
|
||||
// Обложка не инициализирована
|
||||
|
||||
if (!$covr = $imgs[0]['h150'] ?? false) {
|
||||
// Не удалось использовать первое изображение как обложку
|
||||
|
||||
// Запись обложки по умолчанию
|
||||
$covr = '/img/covers/h150/product.png';
|
||||
}
|
||||
}
|
||||
|
||||
// Инициализация буфера с HTML поставок
|
||||
$supplies_html = '';
|
||||
|
||||
// Инициализация блокировщика для пустого блока (на случай, если нет поставок, чтобы не было дубликатов вывода)
|
||||
$empty_block = false;
|
||||
|
||||
// Инициализация счётчика поставок
|
||||
$supplies_amount = count($row['supplies']);
|
||||
|
||||
// Инициализация указателя номера цикла
|
||||
$supply_iterator = 1;
|
||||
// Инициализация данных товара
|
||||
$cpny = $covr = $catg = $catn = null;
|
||||
|
||||
// Инициализация реестра пустышек (товаров без поставок или с ошибками)
|
||||
$empties = [];
|
||||
|
||||
// Генерация списка товаров
|
||||
$supplies_html = Search::generate($row, $cpny, $covr, $catg, $catn, $empties);
|
||||
|
||||
extract($row);
|
||||
?>
|
||||
<?php foreach (empty($row['supplies']) || count($row['supplies']) === 0 ? [null] : $row['supplies'] as $supply) : ?>
|
||||
<?php
|
||||
|
||||
// Инициализация модификатора класса
|
||||
if ($supplies_amount > $supply_iterator) {
|
||||
// Это не последняя строка с товаром и его поставками
|
||||
|
||||
$supply_class_modifier = 'mb-1';
|
||||
} else {
|
||||
// Это последняя строка с товаром и его поставками
|
||||
|
||||
$supply_class_modifier = '';
|
||||
}
|
||||
|
||||
if (is_null($supply)) {
|
||||
// Поставки отсутствуют
|
||||
|
||||
// Генерация данных об отсутствии заказов
|
||||
goto no_supplies;
|
||||
} else {
|
||||
// Обычная обработка поставки
|
||||
|
||||
// Инициализация переменных
|
||||
extract($supply);
|
||||
}
|
||||
|
||||
// Инициализация цены
|
||||
$price_raw = $cost;
|
||||
$price = $price_raw . ' ' . $supply_edge_product[0]['onec']['Цены']['Цена']['Валюта'] ?? 'руб';
|
||||
|
||||
// Инициализация количества
|
||||
$amount_raw = $amount = $supply['amnt'] ?? $supply_edge_product[0]['onec']['Количество'];
|
||||
if (empty($amount_raw) || $amount_raw < 1) {
|
||||
// Уже не используется
|
||||
$amount = 'Под заказ';
|
||||
} else {
|
||||
$amount .= ' шт';
|
||||
}
|
||||
|
||||
if ($amount_raw < 1 || $price_raw < 1) {
|
||||
// Нет в наличии или цена 0 рублей
|
||||
|
||||
// Поставки отстутвуют
|
||||
no_supplies:
|
||||
|
||||
// Проверка на блокировку
|
||||
if ($empty_block) continue;
|
||||
|
||||
$supplies_html .= <<<HTML
|
||||
<div class="row $supply_class_modifier m-0 h-100 text-right">
|
||||
<a class="col-auto ml-auto my-auto text-dark" href="/order/new/custom" role="button" onclick="return false;">
|
||||
<small>
|
||||
Заказать поиск у оператора
|
||||
</small>
|
||||
</a>
|
||||
</div>
|
||||
HTML;
|
||||
|
||||
// Запись в список ненайденных
|
||||
$empties[] = $catn;
|
||||
|
||||
// Запись блокировщика
|
||||
$empty_block = true;
|
||||
|
||||
// Обновление счётчика
|
||||
++$supply_iterator;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Инициализация доставки
|
||||
if (isset($delivery['error']) || $delivery === '?') {
|
||||
// Не удалось рассчитать доставку
|
||||
|
||||
// Инициализация типа доставки
|
||||
$delivery_type = $delivery['type'] ?? 'auto';
|
||||
|
||||
// Инициализация индикатора
|
||||
$delivery_icon = '<i class="mr-1 fas fa-truck"></i>';
|
||||
|
||||
// Инициализация времени
|
||||
$delivery = '?';
|
||||
} else {
|
||||
// Удалось рассчитать доставку
|
||||
|
||||
// Инициализация типа доставки
|
||||
$delivery_type = $delivery['type'] ?? 'auto';
|
||||
|
||||
// Инициализация индикатора
|
||||
$delivery_icon = match ($delivery_type) {
|
||||
'avia' => '<i class="mr-1 fas fa-plane"></i>',
|
||||
default => '<i class="mr-1 fas fa-truck"></i>'
|
||||
};
|
||||
|
||||
// Инициализация даты отправки
|
||||
try {
|
||||
// Взять данные из "arrivalToOspSender" (Дата прибытия на терминал-отправитель)
|
||||
|
||||
$delivery_send_date = DateTime::createFromFormat('Y-m-d', $delivery['orderDates']['arrivalToOspSender'])->getTimestamp();
|
||||
} catch (Throwable $e) {
|
||||
// Взять данные из "pickup" (Дата передачи груза на адресе отправителя)
|
||||
|
||||
$delivery_send_date = DateTime::createFromFormat('Y-m-d', $delivery['orderDates']['pickup'])->getTimestamp();
|
||||
}
|
||||
|
||||
// Инициализация времени доставки
|
||||
try {
|
||||
// Доставка по воздуху (подразумевается), данные из "giveoutFromOspReceiver" (Дата и время, с которого груз готов к выдаче на терминале)
|
||||
|
||||
$delivery_converted = DateTime::createFromFormat('Y-m-d H:i:s', $delivery['orderDates']['giveoutFromOspReceiver'])->getTimestamp();
|
||||
} catch (Throwable $e) {
|
||||
// Автоматическая доставка (подразумевается), данные из "arrivalToOspReceiver" (Дата прибытия натерминал-получатель)
|
||||
|
||||
$delivery_converted = DateTime::createFromFormat('Y-m-d', $delivery['orderDates']['arrivalToOspReceiver'])->getTimestamp();
|
||||
}
|
||||
$delivery = ceil(($delivery_converted - ($delivery_send_date ?? 0)) / 60 / 60 / 24) + 1;
|
||||
}
|
||||
|
||||
// Инициализация индекса аккаунта
|
||||
$index = $account['indx'] ?? 'Неизвестен';
|
||||
|
||||
// Генерация
|
||||
$supplies_html .= <<<HTML
|
||||
<div class="row $supply_class_modifier m-0 text-right">
|
||||
<small class="ml-auto col-1 ml-2 my-auto pl-2 pr-0">$index</small>
|
||||
<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');">
|
||||
<i class="fas fa-cart-arrow-down pr-1 m-auto"></i>
|
||||
</a>
|
||||
</div>
|
||||
HTML;
|
||||
|
||||
// Обновление счётчика
|
||||
++$supply_iterator;
|
||||
?>
|
||||
|
||||
<?php endforeach ?>
|
||||
<?php foreach ($empties as $catn) : ?>
|
||||
<?php foreach (Product::searchAnalogs($catn) as $product) : ?>
|
||||
<?php
|
||||
var_dump($product);
|
||||
?>
|
||||
<?php endforeach ?>
|
||||
<?php endforeach ?>
|
||||
<div class="col pb-2">
|
||||
<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"><?= $name ?></h5>
|
||||
<h5 class="m-0"><?= $cpny ?></h5>
|
||||
<h6 class="m-0"><small><?= $catn ?></small></h6>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -249,14 +61,56 @@ use app\models\Product;
|
|||
</div> -->
|
||||
<div class="col ml-3 p-0 d-flex flex-column">
|
||||
<?= $supplies_html ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach ?>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php if (!empty($empties)) : ?>
|
||||
<section class="col">
|
||||
<?php foreach ($empties as $catn) : ?>
|
||||
|
||||
<?php if ($products = Search::content(products: Product::searchAnalogs($catn))) : ?>
|
||||
|
||||
<h4 class="ml-4 mb-3">Аналогичные товары</h4>
|
||||
|
||||
<?php foreach ($products as $product) : ?>
|
||||
<?php
|
||||
// Инициализация данных товара
|
||||
$cpny = $covr = $catg = $catn = null;
|
||||
|
||||
// Генерация списка товаров
|
||||
$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">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach ?>
|
||||
|
||||
<?php endif ?>
|
||||
|
||||
<?php endforeach ?>
|
||||
</section>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
||||
<?php else : ?>
|
||||
|
|
Reference in New Issue