удаление складов + доставка

This commit is contained in:
Arsen Mirzaev Tatyano-Muradovich 2022-03-01 11:53:28 +10:00
parent 4683cf51db
commit 2f4f38b2aa
7 changed files with 400 additions and 110 deletions

View File

@ -56,7 +56,9 @@ class ProfileController extends Controller
'imports-delete',
'warehouses-write',
'warehouses-rename',
'warehouses-delete'
'warehouses-delete',
'warehouses-close',
'warehouses-open'
]
],
[
@ -1319,4 +1321,152 @@ class ProfileController extends Controller
return $return;
}
}
/**
* Открыть склад
*
* @return array|string|null
*/
public function actionWarehousesOpen(): array|string|null
{
// Инициализация аккаунта
$account = Account::initAccount();
// Инициализация остальных входных параметров
$supply = new Supply(yii::$app->request->post('Supply') ?? yii::$app->request->get('Supply'));
$panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
$sidebar = $this->renderPartial('sidebar');
$groups = self::readGroups();
if (yii::$app->request->isPost) {
// POST-запрос
// Запись заголовка с типом ответа
yii::$app->response->format = Response::FORMAT_JSON;
// Инициализация буфера вывода
$return = [
'_csrf' => yii::$app->request->getCsrfToken()
];
// Инициализация идентификатора
$_key = yii::$app->request->post('_key');
if (empty($_key)) {
// Не передан идентификатор
// Запись кода ошибки
yii::$app->response->statusCode = 500;
return $return;
}
if ($warehouse = Warehouse::searchById(Warehouse::collectionName() . "/$_key")) {
// Найден склад
// Запись статуса
$warehouse->open = true;
if ($warehouse->update() > 0) {
// Открыт склад
// Отправка уведомления
Notification::_write("Склад $_key был открыт", account: $account->_key);
// Запись в буфер вывода реинициализированного элемента
$return['opened'] = true;
}
} else {
// Не найден склад
// Отправка уведомления
Notification::_write("Не найден склад $_key", account: $account->_key);
}
// Запись в буфер вывода реинициализированного элемента
$return['main'] = $this->renderPartial('supplies', compact(
'supply',
'groups',
'sidebar',
'panel'
));
return $return;
}
}
/**
* Закрыть склад
*
* @return array|string|null
*/
public function actionWarehousesClose(): array|string|null
{
// Инициализация аккаунта
$account = Account::initAccount();
// Инициализация остальных входных параметров
$supply = new Supply(yii::$app->request->post('Supply') ?? yii::$app->request->get('Supply'));
$panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
$sidebar = $this->renderPartial('sidebar');
$groups = self::readGroups();
if (yii::$app->request->isPost) {
// POST-запрос
// Запись заголовка с типом ответа
yii::$app->response->format = Response::FORMAT_JSON;
// Инициализация буфера вывода
$return = [
'_csrf' => yii::$app->request->getCsrfToken()
];
// Инициализация идентификатора
$_key = yii::$app->request->post('_key');
if (empty($_key)) {
// Не передан идентификатор
// Запись кода ошибки
yii::$app->response->statusCode = 500;
return $return;
}
if ($warehouse = Warehouse::searchById(Warehouse::collectionName() . "/$_key")) {
// Найден склад
// Запись статуса
$warehouse->open = false;
if ($warehouse->update() > 0) {
// Закрыт склад
// Отправка уведомления
Notification::_write("Склад $_key был закрыт", account: $account->_key);
// Запись в буфер вывода реинициализированного элемента
$return['closed'] = true;
}
} else {
// Не найден склад
// Отправка уведомления
Notification::_write("Не найден склад $_key", account: $account->_key);
}
// Запись в буфер вывода реинициализированного элемента
$return['main'] = $this->renderPartial('supplies', compact(
'supply',
'groups',
'sidebar',
'panel'
));
return $return;
}
}
}

View File

@ -96,4 +96,28 @@ class Import extends Document
limit: $limit
);
}
/**
* Поиск по поставке
*
* @param Supply $supply Поставка
* @param int $limit Ограничение по максимальному количеству
*
* @return array Инстанции испортов
*/
public static function searchBySupply(Supply $supply, int $limit = 10): array
{
return self::searchByEdge(
from: 'supply',
to: 'import',
edge: 'import_edge_supply',
direction: 'OUTBOUND',
subquery_where: [
['import_edge_supply._to' => $supply->readId()],
['import_edge_supply.type' => 'imported']
],
where: 'import_edge_supply[0] != null',
limit: $limit
);
}
}

View File

@ -176,9 +176,6 @@ class Search extends Document
foreach ($connections as $key => &$connection) {
// Перебор поставок
// if (($cost = $connection['cost'] ?? $cost['ЦенаЗаЕдиницу'] ?? $connection['supply_edge_product'][0]['onec']['Цены']['Цена']['ЦенаЗаЕдиницу']) < 1
// || ($amount = $connection['supply']['amnt'] ?? $connection['supply_edge_product'][0]['onec']['Количество']) < 1
// ) {
if ($cost = $connection['supply']['cost'] < 1) {
// Цена меньше единицы (подразумевается как ошибка)
@ -198,7 +195,7 @@ class Search extends Document
// Инициализация данных геолокации
try {
$from = (int) $connection['account']['opts']['delivery_from_terminal'] ?? empty(Settings::searchActive()->delivery_from_default) ? 36 : (int) Settings::searchActive()->delivery_from_default;
$from = (int) (Warehouse::searchBySupply(Supply::searchByCatn($connection['supply']['catn']))[0]->trmn ?? Settings::searchActive()?->delivery_from_default ?? 36);
} catch (exception $e) {
$from = empty(Settings::searchActive()->delivery_from_default) ? 36 : (int) Settings::searchActive()->delivery_from_default;
}
@ -209,13 +206,20 @@ class Search extends Document
$to = 36;
}
if (
($buffer_connection = $connection['product']['bffr']["$from-$to"] ?? false)
&& time() < $buffer_connection['expires']
) {
// Инициализация буфера доставки
$buffer_connection = $connection['product']['bffr']["$from-$to"] ?? null;
if (isset($buffer_connection) && !empty($buffer_connection['data']) && time() < $buffer_connection['expires'] ?? 0) {
// Найдены данные доставки в буфере
// и срок хранения не превышен, информация актуальна
// var_dump($buffer_connection);
// var_dump(isset($buffer_connection['data']));
// var_dump(isset($buffer_connection));
// var_dump(time() < $buffer_connection['expires'] ?? 0);
// var_dump(isset($buffer_connection) && time() < $buffer_connection['expires'] ?? 0);
// die;
// Запись в буфер вывода
$connection['delivery'] = $buffer_connection['data'];
$connection['delivery']['type'] = 'auto';
@ -223,24 +227,30 @@ class Search extends Document
// Инициализация инстанции продукта в базе данных
$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';
if ($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)
)) {
// Получены данные доставки
// Отправка в базу данных
$product->update();
// Инициализация доставки Dellin (автоматическая)
$product->bffr = [
"$from-$to" => [
'data' => $connection['delivery'],
'expires' => time() + 86400
]
] + ($product->bffr ?? []);
// Отправка в базу данных
$product->update();
}
// Запись типа доставки
$connection['delivery']['type'] = 'auto';
}
} catch (Exception $e) {
$connection['delivery']['error'] = true;
@ -251,21 +261,20 @@ class Search extends Document
// var_dump(json_decode($e->getMessage(), true)['errors']);
// die;
} finally {
// echo $connection['delivery']['price']['all'];
// Инициализация цены (цена поставки + цена доставки + наша наценка)
$connection['cost'] = $cost + ($connection['delivery']['price']['all'] ?? $connection['delivery']['price']['one'] ?? 0) + ($settings['increase'] ?? 0);
}
// Инициализация цены (цена поставки + цена доставки + наша наценка)
$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
) {
// Цена меньше единицы (подразумевается как ошибка) или количество меньше единицы
if ($cost = $connection['supply']['cost'] < 1) {
// Цена меньше единицы (подразумевается как ошибка)
// Этот код не будет выполняться, так как цена одна на обе позиции и аналогичная проверка выше уже есть
// Однако я это оставлю для возможных доработок в будущем
@ -276,7 +285,7 @@ class Search extends Document
}
try {
$from = (int) $buffer_delivery_avia['account']['opts']['delivery_from_terminal'] ?? empty(Settings::searchActive()->delivery_from_default) ? 36 : (int) Settings::searchActive()->delivery_from_default;
$from = (int) (Warehouse::searchBySupply(Supply::searchByCatn($connection['supply']['catn']))[0]->trmn ?? Settings::searchActive()?->delivery_from_default ?? 36);
} catch (Exception $e) {
$from = empty(Settings::searchActive()->delivery_from_default) ? 36 : (int) Settings::searchActive()->delivery_from_default;
}
@ -287,10 +296,10 @@ class Search extends Document
$to = 36;
}
if (
($buffer_connection = $buffer_delivery_avia['product']['bffr']["$from-$to-avia"] ?? false)
&& time() < $buffer_connection['expires']
) {
// Инициализация буфера доставки
$buffer_connection = $connection['product']['bffr']["$from-$to-avia"] ?? null;
if (isset($buffer_connection) && !empty($buffer_connection['data']) && time() < $buffer_connection['expires'] ?? 0) {
// Найдены данные доставки в буфере
// и срок хранения не превышен, информация актуальна
@ -301,46 +310,53 @@ class Search extends Document
// Инициализация инстанции продукта в базе данных
$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';
if ($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
)) {
// Получены данные доставки
// Отправка в базу данных
$product->update();
// Инициализация доставки Dellin (автоматическая)
$product->bffr = [
"$from-$to-avia" => [
'data' => $buffer_delivery_avia['delivery'],
'expires' => time() + 86400
]
] + ($product->bffr ?? []);
// Отправка в базу данных
$product->update();
}
// Запись типа доставки
$buffer_delivery_avia['delivery']['type'] = 'avia';
}
} 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;
}
} finally {
if (!isset($buffer_delivery_avia['delivery']['error']) || $buffer_delivery_avia['delivery']['error'] !== true) {
// Если рассчиталась доставка самолётом
if (!isset($buffer_delivery_avia['delivery']['error']) || $buffer_delivery_avia['delivery']['error'] !== true) {
// Если рассчиталась доставка самолётом
// echo $buffer_delivery_avia['delivery']['price']['all']; die;
// Инициализация цены (цена поставки + цена доставки + наша наценка)
$buffer_delivery_avia['cost'] = $cost + ($buffer_delivery_avia['delivery']['price']['all'] ?? $buffer_delivery_avia['delivery']['price']['one'] ?? 0) + ($settings['increase'] ?? 0);
// Инициализация цены (цена поставки + цена доставки + наша наценка)
$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;
// Запись в буфер
$buffer_connections[] = $buffer_delivery_avia;
}
}
}
@ -426,7 +442,7 @@ class Search extends Document
}
// Инициализация цены
$price_raw = $supply['cost'];
$price_raw = ($supply['cost'] ?? 0) + ($cost ?? 0);
// $price = $price_raw . ' ' . $supply_edge_product[0]['onec']['Цены']['Цена']['Валюта'] ?? 'руб';
$price = $price_raw . ' руб';
@ -518,6 +534,7 @@ class Search extends Document
$delivery_converted = datetime::createFromFormat('Y-m-d', $delivery['orderDates']['arrivalToOspReceiver'])->getTimestamp();
}
$delivery = ceil(($delivery_converted - ($delivery_send_date ?? 0)) / 60 / 60 / 24) + 1;
}

View File

@ -34,7 +34,8 @@ class Warehouse extends Document
'name',
'addr',
'trmn',
'actv'
'actv',
'open'
]
);
}
@ -50,7 +51,8 @@ class Warehouse extends Document
'name' => 'Название',
'addr' => 'Адрес',
'trmn' => 'Терминал',
'actv' => 'Активность'
'actv' => 'Активность',
'open' => 'Доступность'
]
);
}
@ -115,6 +117,8 @@ class Warehouse extends Document
* @param int $limit Ограничение по максимальному количеству
*
* @return mixed Склады
*
* @deprecated
*/
public static function searchByAccount(Account|null $account = null, int $limit = 10): mixed
{
@ -142,6 +146,43 @@ class Warehouse extends Document
return null;
}
/**
* Найти по поставке
*
* @param Supply $supply Поставка
* @param int $limit Ограничение по максимальному количеству
*
* @return mixed Склады
*/
public static function searchBySupply(Supply $supply, int $limit = 10): mixed
{
return static::searchByImport(Import::searchBySupply($supply, limit: 1)[0], $limit);
}
/**
* Найти по инстанции поставки
*
* @param Import $import Инстанция поставки
* @param int $limit Ограничение по максимальному количеству
*
* @return mixed Склады
*/
public static function searchByImport(Import $import, int $limit = 10): mixed
{
return self::searchByEdge(
from: 'import',
to: 'warehouse',
edge: 'warehouse_edge_import',
direction: 'OUTBOUND',
subquery_where: [
['warehouse_edge_import._to' => $import->readId()],
['warehouse_edge_import.type' => 'loaded']
],
where: 'warehouse_edge_import[0] != null',
limit: $limit
);
}
/**
* Инициализация с записью
*
@ -196,7 +237,7 @@ class Warehouse extends Document
}
// Запись
$list[$termial['id']] = $city->data['name'];
$list[$termial['id']] = $city->data['name'] . ' (' . $termial['address'] . ')';
}
}

View File

@ -84,41 +84,17 @@ class Dellin extends Model
return self::handle(function () use ($from, $to, $weight, $x, $y, $z, $amount, $avia, $account) {
// Всё готово к работе
if (is_null($account)) {
// Данные аккаунта не переданы
if (yii::$app->user->isGuest) {
// Аккаунт не аутентифицирован
return [];
} else {
// Аккаунт аутентифицирован
// Инициализация
$account = yii::$app->user->identity;
}
} else {
if (is_int($account)) {
// Передан идентификатор (_key) аккаунта (подразумевается)
// Инициализация (поиск в базе данных)
if (!$account = Account::searchById(Account::collectionName() . "/$account")) {
// Не удалось инициализировать аккаунт
return [];
}
}
}
$account = Account::initAccount($account);
// Инициализация
$from = DellinModel::searchByTerminalId($from, terminal_data_only: true);
$to = DellinModel::searchByTerminalId($to, terminal_data_only: true);
// Значения по умолчанию, если указан 0
$x === 0 and $x = 25;
$y === 0 and $y = 40;
$z === 0 and $z = 25;
$weight === 0 and $weight = 300;
if (empty($x) || $x === 0) $x = 25;
if (empty($y) || $y === 0) $y = 40;
if (empty($z) || $z === 0) $z = 25;
if (empty($weight) || $weight === 0) $weight = 300;
// Конвертация из сантиметров в метры
$x /= 100;
@ -220,11 +196,10 @@ class Dellin extends Model
'width' => $width,
'height' => $height,
'length' => $length,
'weight' => $weight,
'totalVolume' => $x * $y * $z,
'totalVolume' => $width * $height * $length,
'totalWeight' => $weight,
'oversizedWeight' => $weight,
'oversizedVolume' => $x * $y * $z
'oversizedVolume' => $width * $height * $length
]
]
);

View File

@ -136,7 +136,7 @@ $panel ?? $panel = 'profile_panel_supplies_input_import';
$amount_warehouses = 0;
?>
<?php foreach ($warehouses as $warehouse) : ?>
<section class="col<?= ++$amount_warehouses < count($warehouses) ? ' mb-4' : '' ?>">
<section class="col mb-4">
<h4 class="mb-3 d-flex">
<span class="my-auto"><?= $warehouse->name ?? 'Без названия' ?></span>
<?php $form = ActiveForm::begin([
@ -147,7 +147,7 @@ $panel ?? $panel = 'profile_panel_supplies_input_import';
],
'options' => [
'onsubmit' => 'return false;',
'class' => 'ml-auto'
'class' => 'ml-auto px-0 col-5'
]
]);
@ -161,8 +161,9 @@ $panel ?? $panel = 'profile_panel_supplies_input_import';
])->label(false); ?>
<?php ActiveForm::end(); ?>
<small class="ml-4 my-auto h6"><a class="text-dark fas fa-pen" type="button" onclick="return page_profile_warehouses_rename(<?= $warehouse->_key ?>, prompt('Название склада', this.parentElement.parentElement.innerText));"></a></small>
<small class="ml-3 my-auto h6"><a class="text-dark fas fa-trash-alt" type="button" onclick="return page_profile_warehouses_delete(<?= $warehouse->_key ?>);"></a></small>
<small class="ml-4 my-auto h6"><a class="text-dark fas fa-pen" title="Переименовать" type="button" onclick="return page_profile_warehouses_rename(<?= $warehouse->_key ?>, prompt('Название склада', this.parentElement.parentElement.innerText));"></a></small>
<small class="ml-3 my-auto h6"><a class="text-dark fas fa-solid <?= ($warehouse->open ?? false) ? 'fa-lock-open' : 'fa-lock' ?>" title="<?= ($warehouse->open ?? false) ? 'Закрыть' : 'Открыть' ?>" type="button" onclick="return <?= ($warehouse->open ?? false) ? 'page_profile_warehouses_close' : 'page_profile_warehouses_open' ?>(this, <?= $warehouse->_key ?>, '<?= $warehouse->name ?? 'Без названия' ?>');"></a></small>
<small class="ml-3 my-auto h6"><a class="text-dark fas fa-trash-alt" title="Удалить" type="button" onclick="return page_profile_warehouses_delete(<?= $warehouse->_key ?>, '<?= $warehouse->name ?? 'Без названия' ?>');"></a></small>
</h4>
<?php
// Инициализация номера инстанции импорта
@ -215,7 +216,7 @@ $panel ?? $panel = 'profile_panel_supplies_input_import';
<!-- <div class="dropdown-divider mx-3 mb-3"></div> -->
<?php endif ?>
<?php endforeach ?>
<a class="mx-auto text-dark fas fa-plus" title="Добавить" type="button" onclick="return page_profile_warehouses_write();"></a>
<a class="mx-auto text-dark fas fa-plus" title="Добавить склад" type="button" onclick="return page_profile_warehouses_write();"></a>
<?php endif ?>
<div class="dropdown-divider mt-4 mb-3"></div>
<section class="mx-3 px-2">

View File

@ -118,8 +118,90 @@ function page_profile_warehouses_write() {
return false;
};
function page_profile_warehouses_delete(_key) {
if (confirm(`Удалить склад ${_key}?`)) {
function page_profile_warehouses_open(element, _key, name) {
if (confirm(`Открыть склад "${name}"?`)) {
$.ajax({
url: '/profile/warehouses/open',
type: 'post',
dataType: 'json',
data: {
'_csrf': yii.getCsrfToken(),
_key
},
success: function (data, status, xhr) {
if (data !== undefined) {
// Получены данные с сервера
if (data.opened !== undefined && data.opened == true) {
// Получена информации об успешном открытии склала
// Перезапись иконки
element.classList.remove('fa-lock');
element.classList.add('fa-lock-open');
// Перезапись вызываемой функции
element.removeAttribute('onclick');
element.setAttribute('onclick', 'return page_profile_warehouses_close(this, ' + _key + ', \'' + element.parentElement.parentElement.parentElement.children[0].children[0].textContent + '\');"');
// Перезапись всплывающей подсказки
element.title = 'Закрыть';
}
}
page_profile_response_success(data, status, xhr);
},
error: page_profile_response_error
});
return false;
}
return true;
};
function page_profile_warehouses_close(element, _key, name) {
if (confirm(`Закрыть склад "${name}"?`)) {
$.ajax({
url: '/profile/warehouses/close',
type: 'post',
dataType: 'json',
data: {
'_csrf': yii.getCsrfToken(),
_key
},
success: function (data, status, xhr) {
if (data !== undefined) {
// Получены данные с сервера
if (data.closed !== undefined && data.closed == true) {
// Получена информации об успешном открытии склала
// Перезапись иконки
element.classList.remove('fa-lock-open');
element.classList.add('fa-lock');
// Перезапись вызываемой функции
element.removeAttribute('onclick');
element.setAttribute('onclick', 'return page_profile_warehouses_open(this, ' + _key + ', \'' + element.parentElement.parentElement.parentElement.children[0].children[0].textContent + '\');"');
// Перезапись всплывающей подсказки
element.title = 'Открыть';
}
}
page_profile_response_success(data, status, xhr);
},
error: page_profile_response_error
});
return false;
}
return true;
};
function page_profile_warehouses_delete(_key, name) {
if (confirm(`Удалить склад "${name}"?`)) {
$.ajax({
url: '/profile/warehouses/delete',
type: 'post',
@ -262,9 +344,7 @@ function page_profile_monitoring(change = 1, panel) {
'search': search,
'panel': panel
},
success: function (data, status) {
page_profile_response_success(data, status);
success: function (data, status, xhr) {
// Ренициализация
let url = new URL(document.location);
@ -273,6 +353,8 @@ function page_profile_monitoring(change = 1, panel) {
// Запись в историю
history.pushState('', document.title, url.toString());
page_profile_response_success(data, status, xhr);
},
error: page_profile_response_error
});