This commit is contained in:
Arsen Mirzaev Tatyano-Muradovich 2021-12-14 14:29:38 +10:00
parent 9fb2e4dc90
commit 7a4f12aa94
11 changed files with 437 additions and 163 deletions

View File

@ -99,7 +99,7 @@ $config = [
'<_key:[0-9]+>/files/<file:[^/]+>' => 'account/file', '<_key:[0-9]+>/files/<file:[^/]+>' => 'account/file',
'<_key:[0-9]+>/<action:(accept|decline)>' => 'account/<action>', '<_key:[0-9]+>/<action:(accept|decline)>' => 'account/<action>',
'product/<catn:[^/]+>' => 'product/index', 'product/<catn:[^/]+>' => 'product/index',
'product/<catn:[^/]+>/<action:(connect|disconnect|delete)>' => 'product/<action>', 'product/<catn:[^/]+>/<action:(write|delete|connect|disconnect)>' => 'product/<action>',
'<section:(product|cart)>/<catn:[^/]+>/<action:(read|write|edit|delete)>/<target:(title|catn|dscr|dmns|wght|image|cover|comm)>' => '<section>/<action>-<target>', '<section:(product|cart)>/<catn:[^/]+>/<action:(read|write|edit|delete)>/<target:(title|catn|dscr|dmns|wght|image|cover|comm)>' => '<section>/<action>-<target>',
'profile/geolocation/<action:(init|write)>' => 'profile/geolocation-<action>', 'profile/geolocation/<action:(init|write)>' => 'profile/geolocation-<action>',
'profile/panel/<panel:(suppliers)>/<block:(requests)>/<action:(search)>' => 'profile/panel-<panel>-<block>-<action>', 'profile/panel/<panel:(suppliers)>/<block:(requests)>/<action:(search)>' => 'profile/panel-<panel>-<block>-<action>',

View File

@ -12,32 +12,11 @@ use yii\web\HttpException;
use yii\web\UploadedFile; use yii\web\UploadedFile;
use app\models\Product; use app\models\Product;
use app\models\ProductEdgeProduct; use app\models\SupplyEdgeProduct;
use app\models\Supply;
class ProductController extends Controller class ProductController extends Controller
{ {
public function actionIndex(string $catn): array|string|null public function actionIndex(string $catn): array|string|null
{ {
if ($model = Product::searchByCatn($catn)) { if ($model = Product::searchByCatn($catn)) {
@ -61,6 +40,206 @@ class ProductController extends Controller
} }
} }
/**
* Запись товара
*
* @param string $catn Артикул
*/
public function actionWrite(string $catn): array|string|null
{
// Инициализация буфера ответа
$return = [
'_csrf' => yii::$app->request->getCsrfToken()
];
if (empty($catn)) {
// Не получен артикул
// Запись кода ответа
yii::$app->response->statusCode = 500;
// Переход в конец алгоритма
goto end;
}
if ($product = Product::searchByCatn($catn)) {
// Найден товар
if (SupplyEdgeProduct::searchByVertex(Supply::searchByCatn($catn)->readId(), $product->readId(), filter: ['type' => 'connect'])) {
// Удалось найти ребро: ПОСТАВКА -> ТОВАР
// Запись кода ответа
yii::$app->response->statusCode = 500;
// Запись в буфер возврата
$return['alert'] = "Товар и связь с поставкой уже существует: $catn";
// Переход в конец алгоритма
goto end;
} else {
// Не удалось найти ребро: ПОСТАВКА -> ТОВАР
if (SupplyEdgeProduct::write(Supply::searchByCatn($catn)->readId(), $product->readId(), data: ['type' => 'connect'])) {
// Удалось создать ребро: ПОСТАВКА -> ТОВАР
$return['alert'] = "Товар уже существовал, связь с поставкой записана: $catn";
$return['catn'] = $catn;
} else {
// Не удалось создать ребро: ПОСТАВКА -> ТОВАР
// Запись кода ответа
yii::$app->response->statusCode = 500;
// Запись в буфер возврата
$return['alert'] = "Товар уже существует, попытка связать с поставкой не удалась: $catn";
}
}
} else {
// Не найден товар
if ($product = Product::writeEmpty($catn)) {
// Удалось записать товар
if (SupplyEdgeProduct::write(Supply::collectionName() . "/$catn", $product->readId(), data: ['type' => 'connect'])) {
// Удалось создать ребро: ПОСТАВКА -> ТОВАР
$return['alert'] = "Товар и связь с поставкой записаны: $catn";
$return['catn'] = $catn;
} else {
// Не удалось создать ребро: ПОСТАВКА -> ТОВАР
// Запись кода ответа
yii::$app->response->statusCode = 500;
// Запись в буфер возврата
$return['alert'] = "Удалось создать товар, но не удалось связать с поставкой: $catn";
}
} else {
// Не удалось записать товар
// Запись кода ответа
yii::$app->response->statusCode = 500;
// Запись в буфер возврата
$return['alert'] = "Не удалось записать товар: $catn";
}
}
/**
* Конец алгоритма
*/
end:
if (yii::$app->request->isPost) {
// POST-запрос
// Запись типа тела ответа
yii::$app->response->format = Response::FORMAT_JSON;
return $return;
}
// Переадресация на главную страницу
return $this->redirect("/");
}
/**
* Удаление товара
*
* @param string $catn Артикул
*/
public function actionDelete(string $catn): array|string|null
{
// Инициализация буфера ответа
$return = [
'_csrf' => yii::$app->request->getCsrfToken()
];
if (empty($catn)) {
// Не получен артикул
// Запись кода ответа
yii::$app->response->statusCode = 500;
// Переход в конец алгоритма
goto end;
}
if ($product = Product::searchByCatn($catn)) {
// Товар найден
if ($product->disconnect()) {
// Отсоединён от аналогов
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";
// Переход в конец алгоритма
goto end;
}
} else {
// Не найден товар
// Запись кода ответа
yii::$app->response->statusCode = 500;
// Запись в буфер возврата
$return['alert'] = "Не удалось найти товар: $catn";
// Переход в конец алгоритма
goto end;
}
/**
* Конец алгоритма
*/
end:
if (yii::$app->request->isPost) {
// POST-запрос
yii::$app->response->format = Response::FORMAT_JSON;
return $return;
}
if (Product::searchByCatn($catn)) {
// Обрабатываемый товар ещё существует (подразумевается, что произошла ошибка)
// Возврат на страницу товара
return $this->redirect("/product/$catn");
} else {
// Обрабатываемый товар не существует (подразумевается, что он успешно удалён)
// Переадресация на главную страницу
return $this->redirect("/");
}
}
/** /**
* Подключение аналога * Подключение аналога
* *
@ -238,101 +417,6 @@ class ProductController extends Controller
} }
} }
/**
* Отключение аналога
*
* @param string $catn Артикул
*/
public function actionDelete(string $catn): array|string|null
{
// Инициализация буфера ответа
$return = [
'_csrf' => yii::$app->request->getCsrfToken()
];
if (empty($catn)) {
// Не получен артикул
// Запись кода ответа
yii::$app->response->statusCode = 500;
// Переход в конец алгоритма
goto end;
}
if ($product = Product::searchByCatn($catn)) {
// Товар найден
if ($product->disconnect()) {
// Отсоединён от аналогов
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";
// Переход в конец алгоритма
goto end;
}
} else {
// Запись кода ответа
yii::$app->response->statusCode = 500;
// Запись в буфер возврата
$return['alert'] = "Не удалось найти товар: $catn";
// Переход в конец алгоритма
goto end;
}
/**
* Конец алгоритма
*/
end:
if (yii::$app->request->isPost) {
// POST-запрос
yii::$app->response->format = Response::FORMAT_JSON;
return $return;
}
if (Product::searchByCatn($catn)) {
// Обрабатываемый товар ещё существует (подразумевается, что произошла ошибка)
// Возврат на страницу товара
return $this->redirect("/product/$catn");
} else {
// Обрабатываемый товар не существует (подразумевается, что он успешно удалён)
// Переадресация на главную страницу
return $this->redirect("/");
}
}
public function actionEditTitle(string $catn): array|string|null public function actionEditTitle(string $catn): array|string|null
{ {
// Инициализация // Инициализация

View File

@ -450,33 +450,90 @@ class ProfileController extends Controller
$supply = new Supply(yii::$app->request->post('Supply') ?? yii::$app->request->get('Supply')); $supply = new Supply(yii::$app->request->post('Supply') ?? yii::$app->request->get('Supply'));
$supply->scenario = $supply::SCENARIO_IMPORT_EXCEL; $supply->scenario = $supply::SCENARIO_IMPORT_EXCEL;
$panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel'); $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
$help = (bool) (yii::$app->request->post('help') ?? yii::$app->request->get('help'));
$target = yii::$app->request->post('account') ?? yii::$app->request->get('account');
$number = yii::$app->request->post('number') ?? yii::$app->request->get('number');
$sidebar = $this->renderPartial('sidebar'); $sidebar = $this->renderPartial('sidebar');
$groups = self::readGroups(); $groups = self::readGroups();
if (yii::$app->request->isPost) { if (yii::$app->request->isPost) {
// AJAX-POST-запрос // AJAX-POST-запрос
// Настройка ответа // Запись типа тела ответа
yii::$app->response->format = Response::FORMAT_JSON; yii::$app->response->format = Response::FORMAT_JSON;
// Инициализация файлов if ($help) {
$supply->file_excel_1 = UploadedFile::getInstance($supply, 'file_excel_1'); // Запрошена отправка прайса модератору
$supply->file_excel_2 = UploadedFile::getInstance($supply, 'file_excel_2');
$supply->file_excel_3 = UploadedFile::getInstance($supply, 'file_excel_3'); // Отправка письма модераторам
$mail = Supply::sendMailForImport('ЗАГРУЗИТЬ ФАЙЛ НА СЕРВЕР НАДО');
if ($supply->importExcel()) {
return [ return [
'main' => $this->renderPartial('supplies', compact( '_csrf' => yii::$app->request->getCsrfToken(),
'supply', 'alert' => $mail ? 'Письмо с запросом отправлено' : 'Не удалось отправить письмо, свяжитесь с модерацией напрямую через контактные данные в нижней части сайта'
'groups',
'sidebar',
'panel'
)),
'_csrf' => yii::$app->request->getCsrfToken()
]; ];
} }
yii::$app->response->statusCode = 409; if (!empty($target)) {
// Получен аккаунт для которого необходимо загрузить каталог
if (empty($number)) {
// Не получен номер раздела в который надо загружать каталог
return [
'_csrf' => yii::$app->request->getCsrfToken(),
'alert' => 'Не получен номер раздела в который надо загружать каталог'
];
}
if (Account::isMinimalAuthorized()) {
// Авторизован доступ к выполнению этого действия
$supply->{"file_excel_$number"} = UploadedFile::getInstance($supply, 'file_excel');
if ($supply->importExcel($target)) {
return [
'main' => $this->renderPartial('supplies', compact(
'supply',
'groups',
'sidebar',
'panel'
)),
'_csrf' => yii::$app->request->getCsrfToken()
];
}
yii::$app->response->statusCode = 409;
} else {
// Не авторизован доступ к выполнению этого действия
return [
'_csrf' => yii::$app->request->getCsrfToken(),
'alert' => 'Вы не имеете разрешения на выполнение этого действия'
];
}
} else {
// Не получен аккаунт для которого необходимо загрузить каталог
// Инициализация файлов
$supply->file_excel_1 = UploadedFile::getInstance($supply, 'file_excel_1');
$supply->file_excel_2 = UploadedFile::getInstance($supply, 'file_excel_2');
$supply->file_excel_3 = UploadedFile::getInstance($supply, 'file_excel_3');
if ($supply->importExcel()) {
return [
'main' => $this->renderPartial('supplies', compact(
'supply',
'groups',
'sidebar',
'panel'
)),
'_csrf' => yii::$app->request->getCsrfToken()
];
}
yii::$app->response->statusCode = 409;
}
} }
return $this->render('supplies', compact( return $this->render('supplies', compact(

View File

@ -106,7 +106,7 @@ abstract class Edge extends Document
* *
* @param string $_from Идентификатор отправителя (_id) * @param string $_from Идентификатор отправителя (_id)
* @param string $_from Идентификатор получетеля (_id) * @param string $_from Идентификатор получетеля (_id)
* @param string $type Дополнительное поле - тип взаимосвязи * @param string $type Дополнительное поле - тип взаимосвязи @deprecated
* @param string $data Дополнительные данные * @param string $data Дополнительные данные
* *
* @todo * @todo

View File

@ -49,16 +49,31 @@ class Product extends Document
/** /**
* Файл .excel для импорта товаров * Файл .excel для импорта товаров
*
* Универсальный, когда неизвестно на какую позицию загружать каталог
*
* @todo Избавиться от свойств и сделать бесконечное количество места под новые каталоги
*/
public Excel|UploadedFile|string|null $file_excel = null;
/**
* Файл .excel для импорта товаров
*
* @todo Избавиться от свойств и сделать бесконечное количество места под новые каталоги
*/ */
public Excel|UploadedFile|string|null $file_excel_1 = null; public Excel|UploadedFile|string|null $file_excel_1 = null;
/** /**
* Файл .excel для импорта товаров * Файл .excel для импорта товаров
*
* @todo Избавиться от свойств и сделать бесконечное количество места под новые каталоги
*/ */
public Excel|UploadedFile|string|null $file_excel_2 = null; public Excel|UploadedFile|string|null $file_excel_2 = null;
/** /**
* Файл .excel для импорта товаров * Файл .excel для импорта товаров
*
* @todo Избавиться от свойств и сделать бесконечное количество места под новые каталоги
*/ */
public Excel|UploadedFile|string|null $file_excel_3 = null; public Excel|UploadedFile|string|null $file_excel_3 = null;

View File

@ -514,6 +514,15 @@ class Supply extends Product implements ProductInterface, OfferInterface
$imported[] = $supply; $imported[] = $supply;
}; };
} }
if (Product::searchByCatn($supply->catn)) {
// Найден товар подходящий для привязки с только что созданной поставкой
} else {
// Не найден товар подходящий для привязки с только что созданной поставкой
// Отправка уведомления
Notification::_write("Не найден товар подходящий для связи с поставкой: $supply->catn", account: '@authorized');
}
} else { } else {
// Проверка не пройдена // Проверка не пройдена
@ -901,4 +910,27 @@ class Supply extends Product implements ProductInterface, OfferInterface
return $limit === 1 ? $edge[0] ?? null : $edge; return $limit === 1 ? $edge[0] ?? null : $edge;
} }
} }
/**
* Отправить письмо модератору с просьбой обработать и загрузить прайс
*
* @param string $file Ссылка на скачивание файла с каталогом
* @param Account|int|null $account Аккаунт на который загружать каталог
*
* @return bool
*/
public static function sendMailForImport(string $file, Account|int|null $account = null): bool
{
return false;
// Отправка письма
yii::$app->mail_system->compose()
->setFrom(yii::$app->params['mail']['system'])
->setTo(yii::$app->params['mail']['info'])
->setSubject('Запрос на обработку каталога')
->setHtmlBody(yii::$app->controller->renderPartial('/mails/import', ['file' => $file, 'account' => Account::initAccount($account)]))
->send();
return false;
}
} }

View File

@ -262,7 +262,7 @@ $timezone = $timezone[1][0];
<?= $create ?? 'Неизвестно' ?> <?= $create ?? 'Неизвестно' ?>
</div> </div>
<?php if (empty($product)) : ?> <?php if (empty($product)) : ?>
<a class="my-auto pr-0 col-auto fas fa-shopping-basket icon_red" title="Товар отсутствует" type="button" onclick="create_product()"></a> <a class="my-auto pr-0 col-auto fas fa-shopping-basket icon_red" title="Товар отсутствует" type="button" onclick="return profile_panel_input_suppliers_accounts_create_product(this, <?= "'$supply->catn'" ?? null ?>);"></a>
<?php else : ?> <?php else : ?>
<a class="my-auto pr-0 col-auto fas fa-shopping-basket text-dark" title="Товар" href="<?= "/product/$product->catn" ?>"></a> <a class="my-auto pr-0 col-auto fas fa-shopping-basket text-dark" title="Товар" href="<?= "/product/$product->catn" ?>"></a>
<?php endif ?> <?php endif ?>
@ -350,6 +350,8 @@ $timezone = $timezone[1][0];
</div> </div>
<script src="/js/profile.js" defer></script> <script src="/js/profile.js" defer></script>
<script src="/js/product.js" defer></script>
<script src="/js/product_panel.js" defer></script>
<script src="/js/profile_panel.js" defer></script> <script src="/js/profile_panel.js" defer></script>
<script src="/js/textarea.js" defer></script> <script src="/js/textarea.js" defer></script>
<script defer> <script defer>

View File

@ -55,12 +55,15 @@ $panel ?? $panel = 'profile_panel_supplies_input_import';
'options' => ['class' => ''] 'options' => ['class' => '']
], ],
'options' => [ 'options' => [
'class' => 'px-3 mb-3', 'class' => 'px-3 mb-3 d-flex',
'onsubmit' => 'return false;' 'onsubmit' => 'return false;'
] ]
]); ]);
?> ?>
<?= $form->field($supply, 'account', ['options' => ['class' => "mb-4 col-4"]])->input('text', ['placeholder' => yii::$app->user->identity->_key]); ?>
<?= $form->field($supply, 'account', ['options' => ['class' => "ml-auto mb-4 pr-0 col-4 d-flex"]])->input('text', ['placeholder' => yii::$app->user->identity->_key])->label(options: ['class' => 'mr-2 my-auto font-weight-bold']); ?>
<?= $form->field($supply, 'file_excel', ['enableLabel' => false, 'options' => ['class' => 'mr-auto mb-4 pr-0 col-5 d-flex flex-column']])->fileInput(['class' => 'my-auto', 'multiple' => true, 'onChange' => 'page_profile_supplies_import_excel_moderator(this.parentElement.parentElement, \'profile_panel_supplies_input_import\', this.parentElement.parentElement.getElementsByTagName(\'input\')[0].value)']) ?>
<?php ActiveForm::end(); ?> <?php ActiveForm::end(); ?>
<?php <?php
// Инициализация счетчика инстанций импорта // Инициализация счетчика инстанций импорта

View File

@ -300,7 +300,23 @@ function product_panel_description_save(catn, element) {
return true; return true;
}; };
function product_panel_connect(catn) { /**
* Подключение к группе
*
* @param {*} catn
* @returns
*/
function product_panel_connect(catn, group) {
if (group === null || group === '') {
return false;
}
if (group === undefined) {
// Не получены данные о группе
group = prompt('Подключить аналог');
}
if (catn !== null && catn !== undefined) { if (catn !== null && catn !== undefined) {
$.ajax({ $.ajax({
url: '/product/' + catn + '/connect', url: '/product/' + catn + '/connect',
@ -308,7 +324,7 @@ function product_panel_connect(catn) {
dataType: 'json', dataType: 'json',
data: { data: {
'_csrf': yii.getCsrfToken(), '_csrf': yii.getCsrfToken(),
'catn': prompt('Подключить аналог') 'catn': group
}, },
success: product_response_success, success: product_response_success,
error: product_response_error error: product_response_error
@ -320,6 +336,13 @@ function product_panel_connect(catn) {
return true; return true;
} }
/**
* Отключение от группы
*
* @param {*} catn
* @returns
*/
function product_panel_disconnect(catn) { function product_panel_disconnect(catn) {
if (catn !== null && catn !== undefined) { if (catn !== null && catn !== undefined) {
$.ajax({ $.ajax({

View File

@ -27,33 +27,52 @@ function page_profile_supplies(form, panel) {
return false; return false;
}; };
function page_profile_supplies_import_excel(form, panel) { function page_profile_supplies_import_excel(form, panel, account) {
if (form === undefined) { function send(help = false) {
form = { if (form === undefined) {
'_csrf': yii.getCsrfToken() form = {
'_csrf': yii.getCsrfToken()
};
if (panel !== undefined) {
form.panel = panel;
};
if (account !== undefined) {
form.number = prompt('Номер позиции в которую загружать каталог', 1);
form.account = account;
};
} else {
form = new FormData(form);
form.append('help', help);
if (panel !== undefined) {
form.append('panel', panel);
};
if (account !== undefined) {
form.append('number', prompt('Номер позиции в которую загружать каталог', 1));
form.append('account', account);
};
}; };
if (panel !== undefined) { $.ajax({
form.panel = panel; url: '/profile/import',
}; type: 'post',
} else { dataType: 'json',
form = new FormData(form); processData: false,
contentType: false,
data: form,
success: page_profile_response_success,
error: page_profile_response_error
});
}
if (panel !== undefined) { if (confirm('Отправить документ на сервер? (убедитесь, что настроили согласно инструкции)')) send();
form.append('panel', panel); else if (confirm('Отправить документ модераторам? (мы можем настроить его сами)')) send(true);
};
};
$.ajax({
url: '/profile/import',
type: 'post',
dataType: 'json',
processData: false,
contentType: false,
data: form,
success: page_profile_response_success,
error: page_profile_response_error
});
return false; return false;
}; };

View File

@ -687,6 +687,10 @@ function profile_panel_input_suppliers_requests_block_decline(_key, reason) {
reason = prompt('Причина отказа', 'Недостаточно данных'); reason = prompt('Причина отказа', 'Недостаточно данных');
} }
if (_key === undefined) {
return false;
}
$.ajax({ $.ajax({
url: `/${_key}/decline`, url: `/${_key}/decline`,
type: 'post', type: 'post',
@ -706,3 +710,38 @@ function profile_panel_input_suppliers_requests_block_decline(_key, reason) {
return false; return false;
} }
/**
* Создание товара
*/
function profile_panel_input_suppliers_accounts_create_product(button, _key) {
if (_key === undefined) {
return false;
}
$.ajax({
url: `/product/${_key}/write`,
type: 'post',
dataType: 'json',
data: {
'_csrf': yii.getCsrfToken(),
},
success: (data, status, xhr) => {
if (data.catn !== undefined) {
// Реинициализация кнопки создания товара
button.href = `/product/${_key}`;
button.onclick = null;
button.classList.remove('icon_red');
button.classList.add('text-dark');
button.title = 'Товар создан';
product_panel_connect(_key, prompt('Подключить аналог (пусто - не подключать)'));
}
return page_profile_response_success(data, status, xhr);
},
error: page_profile_response_error
});
return false;
}