Merge branch 'stable' of https://git.mirzaev.sexy/mirzaev/skillparts into stable
|
@ -13,7 +13,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.0.0",
|
"php": "^8.1.0",
|
||||||
"ext-intl": "~8.0",
|
"ext-intl": "~8.0",
|
||||||
"twbs/bootstrap": "4.6.0",
|
"twbs/bootstrap": "4.6.0",
|
||||||
"yiisoft/yii2": "2.*",
|
"yiisoft/yii2": "2.*",
|
||||||
|
|
|
@ -24,9 +24,9 @@ class DellinController extends Controller
|
||||||
/**
|
/**
|
||||||
* Импортировать терминалы из ДеловыеЛинии
|
* Импортировать терминалы из ДеловыеЛинии
|
||||||
*/
|
*/
|
||||||
public function actionImportTerminals()
|
public function actionImportTerminals(?int $account = null)
|
||||||
{
|
{
|
||||||
if (Dellin::importTerminals()) {
|
if (Dellin::importTerminals($account)) {
|
||||||
return ExitCode::OK;
|
return ExitCode::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\commands;
|
||||||
|
|
||||||
|
use yii\console\Controller;
|
||||||
|
use yii\console\ExitCode;
|
||||||
|
|
||||||
|
use moonland\phpexcel\Excel;
|
||||||
|
|
||||||
|
use app\models\Supply;
|
||||||
|
use app\models\File;
|
||||||
|
|
||||||
|
class ImportController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Импортировать города из ДеловыеЛинии
|
||||||
|
*/
|
||||||
|
public function actionCities()
|
||||||
|
{
|
||||||
|
if (Dellin::importCities()) {
|
||||||
|
return ExitCode::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExitCode::UNSPECIFIED_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Импортировать терминалы из ДеловыеЛинии
|
||||||
|
*/
|
||||||
|
public function actionTerminals()
|
||||||
|
{
|
||||||
|
if (Dellin::importTerminals()) {
|
||||||
|
return ExitCode::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExitCode::UNSPECIFIED_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Импортировать поставки из файлов
|
||||||
|
*/
|
||||||
|
public function actionSupplies(int $amount = 3)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$files = File::searchSuppliesNeededToLoad($amount);
|
||||||
|
|
||||||
|
if ($files > 0) {
|
||||||
|
// Найдены файлы
|
||||||
|
|
||||||
|
foreach ($files as $file) {
|
||||||
|
// Перебор файлов для загрузки
|
||||||
|
|
||||||
|
// Загрузка в базу данных
|
||||||
|
Supply::loadExcel($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (exception $e) {
|
||||||
|
return ExitCode::UNSPECIFIED_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExitCode::OK;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\commands;
|
||||||
|
|
||||||
|
use yii\console\Controller;
|
||||||
|
use yii\console\ExitCode;
|
||||||
|
|
||||||
|
use app\models\Supply;
|
||||||
|
use app\models\File;
|
||||||
|
|
||||||
|
class SuppliesController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Импортировать города из ДеловыеЛинии
|
||||||
|
*/
|
||||||
|
public function actionImport(int $amount = 3)
|
||||||
|
{
|
||||||
|
if (Dellin::importCities($amount)) {
|
||||||
|
return ExitCode::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExitCode::UNSPECIFIED_ERROR;
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ use yii\web\Cookie;
|
||||||
use yii\filters\AccessControl;
|
use yii\filters\AccessControl;
|
||||||
|
|
||||||
use app\models\Account;
|
use app\models\Account;
|
||||||
|
use app\models\AccountForm;
|
||||||
|
|
||||||
class AccountController extends Controller
|
class AccountController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -24,7 +25,9 @@ class AccountController extends Controller
|
||||||
'allow' => true,
|
'allow' => true,
|
||||||
'actions' => [
|
'actions' => [
|
||||||
'file',
|
'file',
|
||||||
'data'
|
'data',
|
||||||
|
'restore',
|
||||||
|
'generate-password'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
@ -38,7 +41,10 @@ class AccountController extends Controller
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'allow' => true,
|
'allow' => true,
|
||||||
'actions' => ['accept', 'decline'],
|
'actions' => [
|
||||||
|
'read',
|
||||||
|
'accept',
|
||||||
|
'decline'],
|
||||||
'matchCallback' => function ($rule, $action): bool {
|
'matchCallback' => function ($rule, $action): bool {
|
||||||
if (
|
if (
|
||||||
!yii::$app->user->isGuest
|
!yii::$app->user->isGuest
|
||||||
|
@ -352,4 +358,127 @@ class AccountController extends Controller
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Восстановление пароля
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function actionRestore()
|
||||||
|
{
|
||||||
|
// Инициализация
|
||||||
|
$model = new AccountForm(yii::$app->request->post('AccountForm'));
|
||||||
|
$type = yii::$app->request->post('type') ?? yii::$app->request->get('type');
|
||||||
|
$target = yii::$app->request->post('target') ?? yii::$app->request->get('target');
|
||||||
|
|
||||||
|
// Фильтрация
|
||||||
|
$target = match ($target) {
|
||||||
|
'panel' => 'panel',
|
||||||
|
'main' => 'main',
|
||||||
|
default => 'main'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Рендер для всплывающей панели
|
||||||
|
$panel = $target === 'panel';
|
||||||
|
|
||||||
|
if (yii::$app->request->isPost) {
|
||||||
|
// AJAX-POST-запрос
|
||||||
|
|
||||||
|
// Настройка кода ответа
|
||||||
|
yii::$app->response->format = Response::FORMAT_JSON;
|
||||||
|
|
||||||
|
if (yii::$app->user->isGuest || $model->validate()) {
|
||||||
|
// Аккаунт не аутентифицирован и проверка пройдена
|
||||||
|
|
||||||
|
// Отправка запроса на генерацию пароля и запись ответа
|
||||||
|
$return = [
|
||||||
|
'status' => Account::restoreSend($model->mail),
|
||||||
|
'_csrf' => yii::$app->request->getCsrfToken()
|
||||||
|
];
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
} else {
|
||||||
|
// Аккаунт аутентифицирован
|
||||||
|
|
||||||
|
// Настройка кода ответа
|
||||||
|
yii::$app->response->statusCode = 400;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'redirect' => '/',
|
||||||
|
'_csrf' => yii::$app->request->getCsrfToken()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Генерация нового пароля
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function actionGeneratePassword(string $id, string $key)
|
||||||
|
{
|
||||||
|
if ($account = Account::searchById(Account::collectionName() . "/$id")) {
|
||||||
|
// Найден аккаунт
|
||||||
|
|
||||||
|
if ($account->chpk === $key) {
|
||||||
|
// Ключи совпадают
|
||||||
|
|
||||||
|
// Инициализация буфера пароля
|
||||||
|
$old = $account->pswd;
|
||||||
|
|
||||||
|
// Генерация пароля
|
||||||
|
$account->restoreGenerate();
|
||||||
|
|
||||||
|
if ($account->pswd !== $old) {
|
||||||
|
// Успешно сгенерирован новый пароль
|
||||||
|
|
||||||
|
// Инициализация формы аутентификации
|
||||||
|
$form = new AccountForm;
|
||||||
|
|
||||||
|
// Запись параметров
|
||||||
|
$form->mail = $account->mail;
|
||||||
|
$form->pswd = $account->pswd;
|
||||||
|
|
||||||
|
// Аутентификация
|
||||||
|
$form->authentication();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Перенаправление на главную страницу
|
||||||
|
$this->redirect('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Генерация нового пароля
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function actionRead(int $page = 1): string|array|null
|
||||||
|
{
|
||||||
|
if (yii::$app->request->isPost) {
|
||||||
|
// POST-запрос
|
||||||
|
|
||||||
|
// Инициализация входных параметров
|
||||||
|
$amount = yii::$app->request->post('amount') ?? yii::$app->request->get('amount') ?? 20;
|
||||||
|
$order = yii::$app->request->post('order') ?? yii::$app->request->get('order') ?? ['DESC'];
|
||||||
|
|
||||||
|
// Инициализация cookie
|
||||||
|
$cookies = yii::$app->response->cookies;
|
||||||
|
|
||||||
|
// Чтение аккаунтов
|
||||||
|
$accounts = Account::read(limit: $amount, page: $page, order: $order);
|
||||||
|
|
||||||
|
// Запись формата ответа
|
||||||
|
yii::$app->response->format = Response::FORMAT_JSON;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'accounts' => $this->renderPartial('/account/list', compact('accounts', 'amount', 'page')),
|
||||||
|
'_csrf' => yii::$app->request->getCsrfToken()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace app\controllers;
|
||||||
|
|
||||||
use app\models\AccountForm;
|
use app\models\AccountForm;
|
||||||
use app\models\Order;
|
use app\models\Order;
|
||||||
|
use app\models\Notification;
|
||||||
use yii;
|
use yii;
|
||||||
use yii\web\Controller;
|
use yii\web\Controller;
|
||||||
use yii\web\Response;
|
use yii\web\Response;
|
||||||
|
@ -61,6 +62,9 @@ class AuthenticationController extends Controller
|
||||||
if (!yii::$app->user->isGuest || $model->authentication()) {
|
if (!yii::$app->user->isGuest || $model->authentication()) {
|
||||||
// Аккаунт аутентифицирован
|
// Аккаунт аутентифицирован
|
||||||
|
|
||||||
|
// Отправка уведомления
|
||||||
|
Notification::_write('Вы аутентифицированы с устройства ' . $_SERVER['HTTP_USER_AGENT'] . ' ' . $_SERVER['REMOTE_ADDR'], true, yii::$app->user->identity->_key, Notification::TYPE_NOTICE);
|
||||||
|
|
||||||
// Инициализация
|
// Инициализация
|
||||||
$notifications_button = $this->renderPartial('/notification/button');
|
$notifications_button = $this->renderPartial('/notification/button');
|
||||||
$notifications_panel = $this->renderPartial('/notification/panel', ['notifications_panel_full' => true]);
|
$notifications_panel = $this->renderPartial('/notification/panel', ['notifications_panel_full' => true]);
|
||||||
|
|
|
@ -88,7 +88,6 @@ class CartController extends Controller
|
||||||
// Поиск корзины (текущего заказа)
|
// Поиск корзины (текущего заказа)
|
||||||
$data = Order::searchSmart()[0] ?? null;
|
$data = Order::searchSmart()[0] ?? null;
|
||||||
|
|
||||||
|
|
||||||
if (empty($data['order'])) {
|
if (empty($data['order'])) {
|
||||||
// Корзина не инициализирована
|
// Корзина не инициализирована
|
||||||
|
|
||||||
|
|
|
@ -18,10 +18,14 @@ class OfferController extends Controller
|
||||||
'access' => [
|
'access' => [
|
||||||
'class' => AccessControl::class,
|
'class' => AccessControl::class,
|
||||||
'rules' => [
|
'rules' => [
|
||||||
|
[
|
||||||
|
'allow' => true,
|
||||||
|
'actions' => ['index', 'suppliers'],
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'allow' => true,
|
'allow' => true,
|
||||||
'roles' => ['@'],
|
'roles' => ['@'],
|
||||||
'actions' => ['index', 'suppliers', 'accept', 'accept-suppliers']
|
'actions' => ['accept', 'accept-suppliers']
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'allow' => false,
|
'allow' => false,
|
||||||
|
|
|
@ -56,6 +56,21 @@ class OrderController extends Controller
|
||||||
'supply-edit-comm'
|
'supply-edit-comm'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'allow' => true,
|
||||||
|
'actions' => [
|
||||||
|
'list'
|
||||||
|
],
|
||||||
|
'matchCallback' => function ($rule, $action): bool {
|
||||||
|
if (
|
||||||
|
!yii::$app->user->isGuest
|
||||||
|
&& (yii::$app->user->identity->type === 'administrator'
|
||||||
|
|| yii::$app->user->identity->type === 'moderator')
|
||||||
|
) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'allow' => false,
|
'allow' => false,
|
||||||
'roles' => ['?'],
|
'roles' => ['?'],
|
||||||
|
@ -283,51 +298,20 @@ class OrderController extends Controller
|
||||||
to: $to,
|
to: $to,
|
||||||
search: $search
|
search: $search
|
||||||
);
|
);
|
||||||
|
|
||||||
// Инициализация панели модератора заказов
|
|
||||||
if (!yii::$app->user->isGuest && Account::isMinimalAuthorized($account)) {
|
|
||||||
// Имеет доступ пользователь
|
|
||||||
|
|
||||||
// Инициализация заказов для модератора
|
|
||||||
$moderator_data = Order::searchSmart(account: '@all', stts: '@all', limit: 10, page: 1, supplies: true);
|
|
||||||
} else {
|
|
||||||
// Не имеет доступ пользователь
|
|
||||||
|
|
||||||
// Инициализация заглушки
|
|
||||||
$moderator_data = null;
|
|
||||||
}
|
|
||||||
} else if ($window === 'orders_panel_moderation') {
|
} else if ($window === 'orders_panel_moderation') {
|
||||||
// Обработка панели модерации заказов
|
// Обработка панели модерации заказов
|
||||||
|
|
||||||
// Инициализация заказов
|
// Инициализация заказов
|
||||||
$data = Order::searchSmart(
|
$data = Order::searchSmart(
|
||||||
stts: '@all',
|
stts: $stts,
|
||||||
limit: 10,
|
limit: 10,
|
||||||
page: 1,
|
page: 1,
|
||||||
supplies: true
|
supplies: true,
|
||||||
|
from: $from,
|
||||||
|
to: $to,
|
||||||
|
search: $search
|
||||||
);
|
);
|
||||||
|
|
||||||
// Инициализация панели модератора заказов
|
|
||||||
if (!yii::$app->user->isGuest && Account::isMinimalAuthorized($account)) {
|
|
||||||
// Имеет доступ пользователь
|
|
||||||
|
|
||||||
// Инициализация заказов для модератора
|
|
||||||
$moderator_data = Order::searchSmart(
|
|
||||||
account: '@all',
|
|
||||||
stts: $stts,
|
|
||||||
limit: 10,
|
|
||||||
page: 1,
|
|
||||||
supplies: true,
|
|
||||||
from: $from,
|
|
||||||
to: $to,
|
|
||||||
search: $search
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Не имеет доступ пользователь
|
|
||||||
|
|
||||||
// Инициализация заглушки
|
|
||||||
$moderator_data = null;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Запрошено неизвестное окно
|
// Запрошено неизвестное окно
|
||||||
}
|
}
|
||||||
|
@ -343,7 +327,7 @@ class OrderController extends Controller
|
||||||
yii::$app->response->format = Response::FORMAT_JSON;
|
yii::$app->response->format = Response::FORMAT_JSON;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'main' => $this->renderPartial('/orders/index', compact('data', 'moderator_data', 'account', 'search', 'from', 'to', 'window')
|
'main' => $this->renderPartial('/orders/index', compact('data', 'account', 'search', 'from', 'to', 'window')
|
||||||
+ ['panel' => $this->renderPartial('/orders/search/panel', compact('account') + ['data' => $data] ?? null)]),
|
+ ['panel' => $this->renderPartial('/orders/search/panel', compact('account') + ['data' => $data] ?? null)]),
|
||||||
'title' => 'Заказы',
|
'title' => 'Заказы',
|
||||||
'redirect' => '/orders',
|
'redirect' => '/orders',
|
||||||
|
@ -351,7 +335,7 @@ class OrderController extends Controller
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('/orders/index', compact('data', 'moderator_data', 'account'));
|
return $this->render('/orders/index', compact('data', 'account'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -822,6 +806,60 @@ class OrderController extends Controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Список заказов для модерации
|
||||||
|
*
|
||||||
|
* @param string $catn Артикул
|
||||||
|
*/
|
||||||
|
public function actionList(int $page): array|string|null
|
||||||
|
{
|
||||||
|
if (!yii::$app->user->isGuest && Account::isMinimalAuthorized()) {
|
||||||
|
// Авторизован пользователь
|
||||||
|
|
||||||
|
// Инициализация буфера ответа
|
||||||
|
$return = [
|
||||||
|
'_csrf' => yii::$app->request->getCsrfToken()
|
||||||
|
];
|
||||||
|
|
||||||
|
// Инициализация количества
|
||||||
|
$amount = yii::$app->request->post('amount') ?? yii::$app->request->get('amount') ?? 8;
|
||||||
|
|
||||||
|
if ($moderator_data = Order::searchSmart(
|
||||||
|
account: '@all',
|
||||||
|
stts: '@all',
|
||||||
|
limit: (int) $amount,
|
||||||
|
page: $page,
|
||||||
|
supplies: true
|
||||||
|
)) {
|
||||||
|
// Найдены заказы
|
||||||
|
|
||||||
|
// Генерация списка
|
||||||
|
$list = trim($this->renderPartial('/orders/moderation', compact('moderator_data')));
|
||||||
|
|
||||||
|
if (!empty($list)) $return['list'] = $list;
|
||||||
|
} else {
|
||||||
|
// Не найдены заказы
|
||||||
|
|
||||||
|
// Запись кода ответа
|
||||||
|
yii::$app->response->statusCode = 500;
|
||||||
|
|
||||||
|
// Запись в буфер возврата
|
||||||
|
// $return['alert'] = "Не удалось найти заказы для генерации списка";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (yii::$app->request->isPost) {
|
||||||
|
// POST-запрос
|
||||||
|
|
||||||
|
yii::$app->response->format = Response::FORMAT_JSON;
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Переадресация на главную страницу
|
||||||
|
return $this->redirect("/");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Чтение инстанции поставки в заказе (order_edge_supply)
|
* Чтение инстанции поставки в заказе (order_edge_supply)
|
||||||
*
|
*
|
||||||
|
|
|
@ -33,6 +33,7 @@ class ProductController extends Controller
|
||||||
'allow' => true,
|
'allow' => true,
|
||||||
'actions' => [
|
'actions' => [
|
||||||
'index',
|
'index',
|
||||||
|
'analogs'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
@ -81,6 +82,36 @@ class ProductController extends Controller
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function accessDenied()
|
||||||
|
{
|
||||||
|
// Инициализация
|
||||||
|
$cookies = yii::$app->response->cookies;
|
||||||
|
|
||||||
|
// Запись cookie с редиректом, который выполнится после авторизации
|
||||||
|
$cookies->add(new Cookie([
|
||||||
|
'name' => 'redirect',
|
||||||
|
'value' => yii::$app->request->pathInfo
|
||||||
|
]));
|
||||||
|
|
||||||
|
if (Yii::$app->request->isPost) {
|
||||||
|
// POST-запрос
|
||||||
|
|
||||||
|
// Настройка
|
||||||
|
Yii::$app->response->format = Response::FORMAT_JSON;
|
||||||
|
|
||||||
|
// Генерация ответа
|
||||||
|
Yii::$app->response->content = json_encode([
|
||||||
|
'main' => $this->renderPartial('/account/index'),
|
||||||
|
'redirect' => yii::$app->request->pathInfo,
|
||||||
|
'_csrf' => Yii::$app->request->getCsrfToken()
|
||||||
|
]);
|
||||||
|
} else if (Yii::$app->request->isGet) {
|
||||||
|
// GET-запрос
|
||||||
|
|
||||||
|
$this->redirect('/authentication');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function actionIndex(string $prod, string $catn): array|string|null
|
public function actionIndex(string $prod, string $catn): array|string|null
|
||||||
{
|
{
|
||||||
if ($model = Product::searchByCatnAndProd($catn, $prod)) {
|
if ($model = Product::searchByCatnAndProd($catn, $prod)) {
|
||||||
|
@ -210,34 +241,34 @@ class ProductController extends Controller
|
||||||
/**
|
/**
|
||||||
* Чтение товаров
|
* Чтение товаров
|
||||||
*
|
*
|
||||||
* @param string $stts Статус
|
* @param string $type Тип
|
||||||
|
* @param int $page Страница
|
||||||
*
|
*
|
||||||
* @return string|array|null
|
* @return string|array|null
|
||||||
*/
|
*/
|
||||||
public function actionRead(string $stts = 'all'): string|array|null
|
public function actionRead(string $type = 'all', int $page = 1): string|array|null
|
||||||
{
|
{
|
||||||
if (yii::$app->request->isPost) {
|
if (yii::$app->request->isPost) {
|
||||||
// POST-запрос
|
// POST-запрос
|
||||||
|
|
||||||
// Инициализация входных параметров
|
// Инициализация входных параметров
|
||||||
$amount = yii::$app->request->post('amount') ?? yii::$app->request->get('amount') ?? 50;
|
$amount = yii::$app->request->post('amount') ?? yii::$app->request->get('amount') ?? 20;
|
||||||
$order = yii::$app->request->post('order') ?? yii::$app->request->get('order') ?? ['DESC'];
|
$order = yii::$app->request->post('order') ?? yii::$app->request->get('order') ?? ['DESC'];
|
||||||
|
|
||||||
// Инициализация cookie
|
// Инициализация cookie
|
||||||
$cookies = yii::$app->response->cookies;
|
$cookies = yii::$app->response->cookies;
|
||||||
|
|
||||||
|
|
||||||
// Инициализация аккаунта
|
// Инициализация аккаунта
|
||||||
$account ?? $account = Account::initAccount();
|
$account ?? $account = Account::initAccount();
|
||||||
|
|
||||||
// Чтение товаров
|
// Чтение товаров
|
||||||
$products = Product::read(where: $stts === 'all' || $stts === 'inactive' ? [] : ['stts' => $stts], limit: $amount, order: $order);
|
$products = Product::read(where: $type === 'all' || $type === 'inactive' ? [] : ['stts' => $type], limit: $amount, page: $page, order: $order);
|
||||||
|
|
||||||
// Запись формата ответа
|
// Запись формата ответа
|
||||||
yii::$app->response->format = Response::FORMAT_JSON;
|
yii::$app->response->format = Response::FORMAT_JSON;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'products' => $this->renderPartial('/product/list', compact('account', 'products')),
|
'products' => $this->renderPartial('/product/list', compact('account', 'products', 'amount', 'page')),
|
||||||
'_csrf' => yii::$app->request->getCsrfToken()
|
'_csrf' => yii::$app->request->getCsrfToken()
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -250,15 +281,15 @@ class ProductController extends Controller
|
||||||
*
|
*
|
||||||
* @param string $catn Артикул
|
* @param string $catn Артикул
|
||||||
*/
|
*/
|
||||||
public function actionDelete(string $catn, string $prod): array|string|null
|
public function actionDelete(string $prod, string $catn): array|string|null
|
||||||
{
|
{
|
||||||
// Инициализация буфера ответа
|
// Инициализация буфера ответа
|
||||||
$return = [
|
$return = [
|
||||||
'_csrf' => yii::$app->request->getCsrfToken()
|
'_csrf' => yii::$app->request->getCsrfToken()
|
||||||
];
|
];
|
||||||
|
|
||||||
if (empty($catn)) {
|
if (empty($catn) || empty($prod)) {
|
||||||
// Не получен артикул
|
// Не получен артикул или производитель
|
||||||
|
|
||||||
// Запись кода ответа
|
// Запись кода ответа
|
||||||
yii::$app->response->statusCode = 500;
|
yii::$app->response->statusCode = 500;
|
||||||
|
@ -355,8 +386,8 @@ class ProductController extends Controller
|
||||||
'_csrf' => yii::$app->request->getCsrfToken()
|
'_csrf' => yii::$app->request->getCsrfToken()
|
||||||
];
|
];
|
||||||
|
|
||||||
if (empty($catn)) {
|
if (empty($catn) || empty($prod)) {
|
||||||
// Не получен артикул
|
// Не получен артикул или производитель
|
||||||
|
|
||||||
// Запись кода ответа
|
// Запись кода ответа
|
||||||
yii::$app->response->statusCode = 500;
|
yii::$app->response->statusCode = 500;
|
||||||
|
@ -368,49 +399,52 @@ class ProductController extends Controller
|
||||||
if ($from = Product::searchByCatnAndProd($catn, $prod)) {
|
if ($from = Product::searchByCatnAndProd($catn, $prod)) {
|
||||||
// Найден товар
|
// Найден товар
|
||||||
|
|
||||||
if ($target = yii::$app->request->post('catn') ?? yii::$app->request->get('catn')) {
|
if (($target_catn = yii::$app->request->post('catn') ?? yii::$app->request->get('catn')) &&
|
||||||
// Инициализирован артикул товара для связи
|
$target_prod = yii::$app->request->post('prod') ?? yii::$app->request->get('prod')) {
|
||||||
|
// Инициализирован артикул и производитель товара для связи
|
||||||
|
|
||||||
if ($to = Product::searchByCatn($target)) {
|
foreach (explode(',', $target_catn, 50) as $analog) {
|
||||||
// Существуют товары к которым планируется соединение
|
// Перебор аналогов
|
||||||
} else {
|
|
||||||
// Не существуют товары к которым планируется соединение
|
|
||||||
|
|
||||||
// Инициализация товара
|
foreach (explode('/', $analog, 50) as $value) {
|
||||||
if ($to = [Product::writeEmpty((string) $target, $from->prod)]) {
|
// Перебор аналогов (дополнительная фильтрация)
|
||||||
// Удалось записать товар
|
|
||||||
|
|
||||||
// Запись в буфер возврата
|
if ($to = Product::searchByCatnAndProd($value, $target_prod)) {
|
||||||
$return['alert'] = "Записан новый товар: $target ($from->prod)";
|
// Существуют товары к которым планируется соединение
|
||||||
} else {
|
} else {
|
||||||
// Не удалось записать товар
|
// Не существуют товары к которым планируется соединение
|
||||||
|
|
||||||
// Запись кода ответа
|
// Инициализация товара
|
||||||
yii::$app->response->statusCode = 500;
|
if ($to = [Product::writeEmpty($value, $target_prod, true)]) {
|
||||||
|
// Удалось записать товар
|
||||||
|
} else {
|
||||||
|
// Не удалось записать товар
|
||||||
|
|
||||||
// Запись в буфер возврата
|
// Запись кода ответа
|
||||||
$return['alert'] = "Не удалось записать новый товар: $target ($from->prod)";
|
yii::$app->response->statusCode = 500;
|
||||||
|
|
||||||
// Переход в конец алгоритма
|
// Запись в буфер возврата
|
||||||
goto end;
|
$return['alert'] = "Не удалось записать новый товар: $value ($target_prod)";
|
||||||
|
|
||||||
|
// Переход в конец алгоритма
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Инициализация количества созданных рёбер
|
||||||
|
$writed = 0;
|
||||||
|
|
||||||
|
foreach (is_array($to) ? $to : [$to] as $product) {
|
||||||
|
// Перебор товаров для записи связи: ТОВАР -> ТОВАР
|
||||||
|
|
||||||
|
// Универсализация данных (приведение к объекту)
|
||||||
|
if (is_array($product) && !$product = Product::searchByCatnAndProd($product['catn'], $product['prod'])) continue;
|
||||||
|
|
||||||
|
// Запись в группу
|
||||||
|
if ($from->connect($product)) $writed++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Инициализация количества созданных рёбер
|
|
||||||
$writed = 0;
|
|
||||||
|
|
||||||
foreach ($to as $product) {
|
|
||||||
// Перебор товаров для записи связи: ТОВАР -> ТОВАР
|
|
||||||
|
|
||||||
// Универсализация данных (приведение к объекту)
|
|
||||||
if (is_array($product) && !$product = Product::searchByCatnAndProd($product['catn'], $product['prod'])) continue;
|
|
||||||
|
|
||||||
// Запись ребра и синхронизация (добавление в группу к остальным аналогам)
|
|
||||||
if (count($from->synchronization($product)) > 0) $writed++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Запись в буфер возврата
|
|
||||||
$return['alert'] = "Создано $writed связей";
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Не найден товар
|
// Не найден товар
|
||||||
|
@ -433,6 +467,13 @@ class ProductController extends Controller
|
||||||
|
|
||||||
yii::$app->response->format = Response::FORMAT_JSON;
|
yii::$app->response->format = Response::FORMAT_JSON;
|
||||||
|
|
||||||
|
// Запись в буфер возврата
|
||||||
|
$return['list'] = $this->renderPartial('analogs', [
|
||||||
|
'page' => 1,
|
||||||
|
'amount' => yii::$app->request->post('amount') ?? yii::$app->request->get('amount') ?? 30,
|
||||||
|
'model' => $from
|
||||||
|
]);
|
||||||
|
|
||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,7 +503,7 @@ class ProductController extends Controller
|
||||||
];
|
];
|
||||||
|
|
||||||
if (empty($catn) || empty($prod)) {
|
if (empty($catn) || empty($prod)) {
|
||||||
// Не получен артикул
|
// Не получен артикул или производитель
|
||||||
|
|
||||||
// Запись кода ответа
|
// Запись кода ответа
|
||||||
yii::$app->response->statusCode = 500;
|
yii::$app->response->statusCode = 500;
|
||||||
|
@ -471,35 +512,32 @@ class ProductController extends Controller
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($from = Product::searchByCatnAndProd($catn, $prod)) {
|
if ($target = Product::searchByCatnAndProd($catn, $prod)) {
|
||||||
// Товар найден
|
// Товар найден
|
||||||
|
|
||||||
// Инициализация цели
|
if ($target->disconnect()) {
|
||||||
$target = yii::$app->request->post('catn') ?? yii::$app->request->get('catn');
|
// Удалено ребро (связь)
|
||||||
|
|
||||||
if ($from->disconnect($target)) {
|
// Запись в буфер возврата
|
||||||
// Удалено ребро (связь)
|
$return['disconnected'] = 1;
|
||||||
|
} else {
|
||||||
|
// Не удалено ребро (связь)
|
||||||
|
|
||||||
// Запись в буфер возврата
|
// Запись кода ответа
|
||||||
$return['alert'] = "Продукты успешно отсоединены";
|
yii::$app->response->statusCode = 500;
|
||||||
} else {
|
|
||||||
// Не удалено ребро (связь)
|
|
||||||
|
|
||||||
// Запись кода ответа
|
// Запись в буфер возврата
|
||||||
yii::$app->response->statusCode = 500;
|
$return['alert'] = "Не удалось удалить $catn ($prod) из группы";
|
||||||
|
|
||||||
// Запись в буфер возврата
|
// Переход в конец алгоритма
|
||||||
$return['alert'] = "Не удалось отсоединить $target от $catn";
|
goto end;
|
||||||
|
}
|
||||||
// Переход в конец алгоритма
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Запись кода ответа
|
// Запись кода ответа
|
||||||
yii::$app->response->statusCode = 500;
|
yii::$app->response->statusCode = 500;
|
||||||
|
|
||||||
// Запись в буфер возврата
|
// Запись в буфер возврата
|
||||||
$return['alert'] = "Не удалось найти товар от когорого требуется отсоединение: $catn";
|
$return['alert'] = "Не удалось найти товар $catn ($prod)";
|
||||||
|
|
||||||
// Переход в конец алгоритма
|
// Переход в конец алгоритма
|
||||||
goto end;
|
goto end;
|
||||||
|
@ -529,6 +567,64 @@ class ProductController extends Controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Отключение аналога
|
||||||
|
*
|
||||||
|
* @param string $catn Артикул
|
||||||
|
*/
|
||||||
|
public function actionAnalogs(string $catn, string $prod, int $page): array|string|null
|
||||||
|
{
|
||||||
|
// Инициализация буфера ответа
|
||||||
|
$return = [
|
||||||
|
'_csrf' => yii::$app->request->getCsrfToken()
|
||||||
|
];
|
||||||
|
|
||||||
|
if (empty($catn) || empty($prod)) {
|
||||||
|
// Не получен артикул или производитель
|
||||||
|
|
||||||
|
// Запись кода ответа
|
||||||
|
yii::$app->response->statusCode = 500;
|
||||||
|
|
||||||
|
// Переход в конец алгоритма
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Инициализация количества
|
||||||
|
$amount = yii::$app->request->post('amount') ?? yii::$app->request->get('amount') ?? 30;
|
||||||
|
|
||||||
|
if ($model = Product::searchByCatnAndProd($catn, $prod)) {
|
||||||
|
// Товар найден
|
||||||
|
|
||||||
|
// Генерация списка
|
||||||
|
$list = trim($this->renderPartial('analogs', compact('model', 'page', 'amount')));
|
||||||
|
|
||||||
|
if (!empty($list)) $return['list'] = $list;
|
||||||
|
} else {
|
||||||
|
// Запись кода ответа
|
||||||
|
yii::$app->response->statusCode = 500;
|
||||||
|
|
||||||
|
// Запись в буфер возврата
|
||||||
|
$return['alert'] = "Не удалось найти товар $catn ($prod) для инициализации аналогов";
|
||||||
|
|
||||||
|
// Переход в конец алгоритма
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Конец алгоритма
|
||||||
|
end:
|
||||||
|
|
||||||
|
if (yii::$app->request->isPost) {
|
||||||
|
// POST-запрос
|
||||||
|
|
||||||
|
yii::$app->response->format = Response::FORMAT_JSON;
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Переадресация на главную страницу
|
||||||
|
return $this->redirect("/");
|
||||||
|
}
|
||||||
|
|
||||||
public function actionEditTitle(string $catn, string $prod): array|string|null
|
public function actionEditTitle(string $catn, string $prod): array|string|null
|
||||||
{
|
{
|
||||||
// Инициализация
|
// Инициализация
|
||||||
|
|
|
@ -50,7 +50,6 @@ class ProfileController extends Controller
|
||||||
'supplies',
|
'supplies',
|
||||||
'import',
|
'import',
|
||||||
'monitoring',
|
'monitoring',
|
||||||
'readGroups',
|
|
||||||
'geolocation-write',
|
'geolocation-write',
|
||||||
'panel-suppliers-requests-search',
|
'panel-suppliers-requests-search',
|
||||||
'imports-delete',
|
'imports-delete',
|
||||||
|
@ -428,7 +427,6 @@ 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'));
|
||||||
$panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
|
$panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
|
||||||
$sidebar = $this->renderPartial('sidebar');
|
$sidebar = $this->renderPartial('sidebar');
|
||||||
$groups = self::readGroups();
|
|
||||||
|
|
||||||
// Обработка настроек аккаунта
|
// Обработка настроек аккаунта
|
||||||
if ($vars = yii::$app->request->post('Warehouse') ?? yii::$app->request->get('Warehouse') and $warehouse = yii::$app->request->post('_key') ?? yii::$app->request->get('_key')) {
|
if ($vars = yii::$app->request->post('Warehouse') ?? yii::$app->request->get('Warehouse') and $warehouse = yii::$app->request->post('_key') ?? yii::$app->request->get('_key')) {
|
||||||
|
@ -461,7 +459,6 @@ class ProfileController extends Controller
|
||||||
return [
|
return [
|
||||||
'main' => $this->renderPartial('supplies', compact(
|
'main' => $this->renderPartial('supplies', compact(
|
||||||
'supply',
|
'supply',
|
||||||
'groups',
|
|
||||||
'sidebar',
|
'sidebar',
|
||||||
'panel'
|
'panel'
|
||||||
)),
|
)),
|
||||||
|
@ -472,7 +469,6 @@ class ProfileController extends Controller
|
||||||
|
|
||||||
return $this->render('supplies', compact(
|
return $this->render('supplies', compact(
|
||||||
'supply',
|
'supply',
|
||||||
'groups',
|
|
||||||
'sidebar',
|
'sidebar',
|
||||||
'panel'
|
'panel'
|
||||||
));
|
));
|
||||||
|
@ -495,7 +491,6 @@ class ProfileController extends Controller
|
||||||
$number = yii::$app->request->post('number') ?? yii::$app->request->get('number');
|
$number = yii::$app->request->post('number') ?? yii::$app->request->get('number');
|
||||||
$warehouse = yii::$app->request->post('warehouse') ?? yii::$app->request->get('warehouse');
|
$warehouse = yii::$app->request->post('warehouse') ?? yii::$app->request->get('warehouse');
|
||||||
$sidebar = $this->renderPartial('sidebar');
|
$sidebar = $this->renderPartial('sidebar');
|
||||||
$groups = self::readGroups();
|
|
||||||
|
|
||||||
if (yii::$app->request->isPost) {
|
if (yii::$app->request->isPost) {
|
||||||
// AJAX-POST-запрос
|
// AJAX-POST-запрос
|
||||||
|
@ -540,7 +535,6 @@ class ProfileController extends Controller
|
||||||
return [
|
return [
|
||||||
'main' => $this->renderPartial('supplies', compact(
|
'main' => $this->renderPartial('supplies', compact(
|
||||||
'supply',
|
'supply',
|
||||||
'groups',
|
|
||||||
'sidebar',
|
'sidebar',
|
||||||
'panel'
|
'panel'
|
||||||
)),
|
)),
|
||||||
|
@ -566,7 +560,6 @@ class ProfileController extends Controller
|
||||||
return [
|
return [
|
||||||
'main' => $this->renderPartial('supplies', compact(
|
'main' => $this->renderPartial('supplies', compact(
|
||||||
'supply',
|
'supply',
|
||||||
'groups',
|
|
||||||
'sidebar',
|
'sidebar',
|
||||||
'panel'
|
'panel'
|
||||||
)),
|
)),
|
||||||
|
@ -581,7 +574,6 @@ class ProfileController extends Controller
|
||||||
return [
|
return [
|
||||||
'main' => $this->renderPartial('supplies', compact(
|
'main' => $this->renderPartial('supplies', compact(
|
||||||
'supply',
|
'supply',
|
||||||
'groups',
|
|
||||||
'sidebar',
|
'sidebar',
|
||||||
'panel'
|
'panel'
|
||||||
)),
|
)),
|
||||||
|
@ -589,21 +581,6 @@ class ProfileController extends Controller
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function readGroups()
|
|
||||||
{
|
|
||||||
// Инициализация
|
|
||||||
$groups = [];
|
|
||||||
|
|
||||||
foreach (SupplyGroup::read() as $group) {
|
|
||||||
// Перебор всех групп
|
|
||||||
|
|
||||||
// Генерация [КЛЮЧ => ИМЯ]
|
|
||||||
$groups[$group->_key] = $group->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $groups;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Инициализация данных о геолокации
|
* Инициализация данных о геолокации
|
||||||
*
|
*
|
||||||
|
@ -887,7 +864,7 @@ class ProfileController extends Controller
|
||||||
/**
|
/**
|
||||||
* Поиск заявок на регистрацию
|
* Поиск заявок на регистрацию
|
||||||
*/
|
*/
|
||||||
public function actionPanelSuppliersRequestsSearch()
|
public function actionPanelSuppliersRequestsSearch(int $page = 1)
|
||||||
{
|
{
|
||||||
if (Yii::$app->request->isPost) {
|
if (Yii::$app->request->isPost) {
|
||||||
// POST-запрос
|
// POST-запрос
|
||||||
|
@ -895,11 +872,15 @@ class ProfileController extends Controller
|
||||||
if (Account::isAdmin() || Account::isModer()) {
|
if (Account::isAdmin() || Account::isModer()) {
|
||||||
// Доступ разрешен
|
// Доступ разрешен
|
||||||
|
|
||||||
|
// Инициализация входных параметров
|
||||||
|
$amount = yii::$app->request->post('amount') ?? yii::$app->request->get('amount') ?? 3;
|
||||||
|
$order = yii::$app->request->post('order') ?? yii::$app->request->get('order') ?? ['DESC'];
|
||||||
|
|
||||||
// Инициализация буфера ответа
|
// Инициализация буфера ответа
|
||||||
$response = [];
|
$response = [];
|
||||||
|
|
||||||
// Поиск заявок на регистрацию
|
// Поиск заявок на регистрацию
|
||||||
$suppliers = Account::searchSuppliersRequests();
|
$suppliers = Account::searchSuppliersRequests($amount, $page, $order);
|
||||||
|
|
||||||
foreach ($suppliers as $account) {
|
foreach ($suppliers as $account) {
|
||||||
// Перебор заявок
|
// Перебор заявок
|
||||||
|
@ -1025,7 +1006,6 @@ 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'));
|
||||||
$panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
|
$panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
|
||||||
$sidebar = $this->renderPartial('sidebar');
|
$sidebar = $this->renderPartial('sidebar');
|
||||||
$groups = self::readGroups();
|
|
||||||
|
|
||||||
if (yii::$app->request->isPost) {
|
if (yii::$app->request->isPost) {
|
||||||
// POST-запрос
|
// POST-запрос
|
||||||
|
@ -1062,6 +1042,8 @@ class ProfileController extends Controller
|
||||||
foreach (Supply::searchByImport($import->readId(), limit: 9999) as $supply) {
|
foreach (Supply::searchByImport($import->readId(), limit: 9999) as $supply) {
|
||||||
// Перебор найденных поставок
|
// Перебор найденных поставок
|
||||||
|
|
||||||
|
if (empty($supply)) continue;
|
||||||
|
|
||||||
if (ImportEdgeSupply::searchBySupply($supply)?->delete()) {
|
if (ImportEdgeSupply::searchBySupply($supply)?->delete()) {
|
||||||
// Удалено ребро: ИНСТАНЦИЯ ПОСТАВКИ -> ПОСТАВКА
|
// Удалено ребро: ИНСТАНЦИЯ ПОСТАВКИ -> ПОСТАВКА
|
||||||
|
|
||||||
|
@ -1071,7 +1053,7 @@ class ProfileController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
// Отправка уведомления
|
// Отправка уведомления
|
||||||
Notification::_write("Удалено $deleted поставок из инстанции поставки $_key", account: $account->_key);
|
Notification::_write("Удалено $deleted поставок из инстанции поставки $_key", account: $account->readId());
|
||||||
|
|
||||||
if ($edge->delete()) {
|
if ($edge->delete()) {
|
||||||
// Удалено ребро: СКЛАД -> ИНСТАНЦИЯ ПОСТАВКИ
|
// Удалено ребро: СКЛАД -> ИНСТАНЦИЯ ПОСТАВКИ
|
||||||
|
@ -1080,7 +1062,7 @@ class ProfileController extends Controller
|
||||||
// Удалена инстанция поставки
|
// Удалена инстанция поставки
|
||||||
|
|
||||||
// Отправка уведомления
|
// Отправка уведомления
|
||||||
Notification::_write("Инстанция поставки $_key была удалена", account: $account->_key);
|
Notification::_write("Инстанция поставки $_key была удалена", account: $account->readId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1088,13 +1070,12 @@ class ProfileController extends Controller
|
||||||
// Не найдена инстанция поставки
|
// Не найдена инстанция поставки
|
||||||
|
|
||||||
// Отправка уведомления
|
// Отправка уведомления
|
||||||
Notification::_write("Не найдена инстанция поставки $_key", account: $account->_key);
|
Notification::_write("Не найдена инстанция поставки $_key", account: $account->readId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Запись в буфер вывода реинициализированного элемента
|
// Запись в буфер вывода реинициализированного элемента
|
||||||
$return['main'] = $this->renderPartial('supplies', compact(
|
$return['main'] = $this->renderPartial('supplies', compact(
|
||||||
'supply',
|
'supply',
|
||||||
'groups',
|
|
||||||
'sidebar',
|
'sidebar',
|
||||||
'panel'
|
'panel'
|
||||||
));
|
));
|
||||||
|
@ -1117,7 +1098,6 @@ 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'));
|
||||||
$panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
|
$panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
|
||||||
$sidebar = $this->renderPartial('sidebar');
|
$sidebar = $this->renderPartial('sidebar');
|
||||||
$groups = self::readGroups();
|
|
||||||
|
|
||||||
if (yii::$app->request->isPost) {
|
if (yii::$app->request->isPost) {
|
||||||
// POST-запрос
|
// POST-запрос
|
||||||
|
@ -1137,7 +1117,6 @@ class ProfileController extends Controller
|
||||||
// Запись в буфер вывода реинициализированного элемента
|
// Запись в буфер вывода реинициализированного элемента
|
||||||
$return['main'] = $this->renderPartial('supplies', compact(
|
$return['main'] = $this->renderPartial('supplies', compact(
|
||||||
'supply',
|
'supply',
|
||||||
'groups',
|
|
||||||
'sidebar',
|
'sidebar',
|
||||||
'panel'
|
'panel'
|
||||||
));
|
));
|
||||||
|
@ -1161,7 +1140,6 @@ 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'));
|
||||||
$panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
|
$panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
|
||||||
$sidebar = $this->renderPartial('sidebar');
|
$sidebar = $this->renderPartial('sidebar');
|
||||||
$groups = self::readGroups();
|
|
||||||
|
|
||||||
if (yii::$app->request->isPost) {
|
if (yii::$app->request->isPost) {
|
||||||
// POST-запрос
|
// POST-запрос
|
||||||
|
@ -1219,7 +1197,6 @@ class ProfileController extends Controller
|
||||||
// Запись в буфер вывода реинициализированного элемента
|
// Запись в буфер вывода реинициализированного элемента
|
||||||
$return['main'] = $this->renderPartial('supplies', compact(
|
$return['main'] = $this->renderPartial('supplies', compact(
|
||||||
'supply',
|
'supply',
|
||||||
'groups',
|
|
||||||
'sidebar',
|
'sidebar',
|
||||||
'panel'
|
'panel'
|
||||||
));
|
));
|
||||||
|
@ -1245,7 +1222,6 @@ 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'));
|
||||||
$panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
|
$panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
|
||||||
$sidebar = $this->renderPartial('sidebar');
|
$sidebar = $this->renderPartial('sidebar');
|
||||||
$groups = self::readGroups();
|
|
||||||
|
|
||||||
if (yii::$app->request->isPost) {
|
if (yii::$app->request->isPost) {
|
||||||
// POST-запрос
|
// POST-запрос
|
||||||
|
@ -1337,7 +1313,6 @@ class ProfileController extends Controller
|
||||||
// Запись в буфер вывода реинициализированного элемента
|
// Запись в буфер вывода реинициализированного элемента
|
||||||
$return['main'] = $this->renderPartial('supplies', compact(
|
$return['main'] = $this->renderPartial('supplies', compact(
|
||||||
'supply',
|
'supply',
|
||||||
'groups',
|
|
||||||
'sidebar',
|
'sidebar',
|
||||||
'panel'
|
'panel'
|
||||||
));
|
));
|
||||||
|
@ -1360,7 +1335,6 @@ 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'));
|
||||||
$panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
|
$panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
|
||||||
$sidebar = $this->renderPartial('sidebar');
|
$sidebar = $this->renderPartial('sidebar');
|
||||||
$groups = self::readGroups();
|
|
||||||
|
|
||||||
if (yii::$app->request->isPost) {
|
if (yii::$app->request->isPost) {
|
||||||
// POST-запрос
|
// POST-запрос
|
||||||
|
@ -1411,7 +1385,6 @@ class ProfileController extends Controller
|
||||||
// Запись в буфер вывода реинициализированного элемента
|
// Запись в буфер вывода реинициализированного элемента
|
||||||
$return['main'] = $this->renderPartial('supplies', compact(
|
$return['main'] = $this->renderPartial('supplies', compact(
|
||||||
'supply',
|
'supply',
|
||||||
'groups',
|
|
||||||
'sidebar',
|
'sidebar',
|
||||||
'panel'
|
'panel'
|
||||||
));
|
));
|
||||||
|
@ -1434,7 +1407,6 @@ 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'));
|
||||||
$panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
|
$panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
|
||||||
$sidebar = $this->renderPartial('sidebar');
|
$sidebar = $this->renderPartial('sidebar');
|
||||||
$groups = self::readGroups();
|
|
||||||
|
|
||||||
if (yii::$app->request->isPost) {
|
if (yii::$app->request->isPost) {
|
||||||
// POST-запрос
|
// POST-запрос
|
||||||
|
@ -1485,7 +1457,6 @@ class ProfileController extends Controller
|
||||||
// Запись в буфер вывода реинициализированного элемента
|
// Запись в буфер вывода реинициализированного элемента
|
||||||
$return['main'] = $this->renderPartial('supplies', compact(
|
$return['main'] = $this->renderPartial('supplies', compact(
|
||||||
'supply',
|
'supply',
|
||||||
'groups',
|
|
||||||
'sidebar',
|
'sidebar',
|
||||||
'panel'
|
'panel'
|
||||||
));
|
));
|
||||||
|
|
|
@ -106,7 +106,7 @@ class SearchController extends Controller
|
||||||
|
|
||||||
$return = [
|
$return = [
|
||||||
'timer' => $timer,
|
'timer' => $timer,
|
||||||
'panel' => $this->renderPartial('/search/loading'),
|
'search_line_window_show' => 1,
|
||||||
'_csrf' => yii::$app->request->getCsrfToken()
|
'_csrf' => yii::$app->request->getCsrfToken()
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
|
@ -159,6 +159,7 @@ class SearchController extends Controller
|
||||||
// Запись ответа
|
// Запись ответа
|
||||||
$return = [
|
$return = [
|
||||||
'panel' => $this->renderPartial('/search/panel', compact('response', 'query')),
|
'panel' => $this->renderPartial('/search/panel', compact('response', 'query')),
|
||||||
|
'search_line_window_show' => 1,
|
||||||
'_csrf' => yii::$app->request->getCsrfToken()
|
'_csrf' => yii::$app->request->getCsrfToken()
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -167,7 +168,7 @@ class SearchController extends Controller
|
||||||
|
|
||||||
// Запись ответа
|
// Запись ответа
|
||||||
$return['main'] = $this->renderPartial('/search/index', compact('response', 'query'));
|
$return['main'] = $this->renderPartial('/search/index', compact('response', 'query'));
|
||||||
$return['hide'] = 1;
|
$return['search_line_window_show'] = 1;
|
||||||
$return['redirect'] = '/search?type=product&q=' . $query;
|
$return['redirect'] = '/search?type=product&q=' . $query;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,6 +190,7 @@ class SearchController extends Controller
|
||||||
|
|
||||||
return $return ?? [
|
return $return ?? [
|
||||||
'panel' => $this->renderPartial('/search/panel'),
|
'panel' => $this->renderPartial('/search/panel'),
|
||||||
|
'search_line_window_show' => 1,
|
||||||
'_csrf' => yii::$app->request->getCsrfToken()
|
'_csrf' => yii::$app->request->getCsrfToken()
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\controllers;
|
||||||
|
|
||||||
|
use yii;
|
||||||
|
use yii\web\Controller;
|
||||||
|
use yii\web\Response;
|
||||||
|
use yii\web\HttpException;
|
||||||
|
use yii\web\UploadedFile;
|
||||||
|
use yii\filters\AccessControl;
|
||||||
|
|
||||||
|
use app\models\Product;
|
||||||
|
use app\models\Settings;
|
||||||
|
use app\models\SupplyEdgeProduct;
|
||||||
|
use app\models\Supply;
|
||||||
|
use app\models\Account;
|
||||||
|
use app\models\Notification;
|
||||||
|
use app\models\OrderEdgeSupply;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class SupplyController extends Controller
|
||||||
|
{
|
||||||
|
public function behaviors()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'access' => [
|
||||||
|
'class' => AccessControl::class,
|
||||||
|
'rules' => [
|
||||||
|
[
|
||||||
|
'allow' => true,
|
||||||
|
'actions' => [
|
||||||
|
'index',
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'allow' => true,
|
||||||
|
'roles' => ['@'],
|
||||||
|
'actions' => []
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'allow' => true,
|
||||||
|
'actions' => [
|
||||||
|
'read'
|
||||||
|
],
|
||||||
|
'matchCallback' => function ($rule, $action): bool {
|
||||||
|
if (
|
||||||
|
!yii::$app->user->isGuest
|
||||||
|
&& (yii::$app->user->identity->type === 'administrator'
|
||||||
|
|| yii::$app->user->identity->type === 'moderator')
|
||||||
|
) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'allow' => false,
|
||||||
|
'roles' => ['?'],
|
||||||
|
'denyCallback' => [$this, 'accessDenied']
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Чтение поставок
|
||||||
|
*
|
||||||
|
* @param int $page Страница
|
||||||
|
*
|
||||||
|
* @return string|array|null
|
||||||
|
*/
|
||||||
|
public function actionRead(int $page = 1): string|array|null
|
||||||
|
{
|
||||||
|
if (yii::$app->request->isPost) {
|
||||||
|
// POST-запрос
|
||||||
|
|
||||||
|
// Инициализация входных параметров
|
||||||
|
$amount = yii::$app->request->post('amount') ?? yii::$app->request->get('amount') ?? 20;
|
||||||
|
$order = yii::$app->request->post('order') ?? yii::$app->request->get('order') ?? ['DESC'];
|
||||||
|
|
||||||
|
// Инициализация cookie
|
||||||
|
$cookies = yii::$app->response->cookies;
|
||||||
|
|
||||||
|
// Чтение поставок
|
||||||
|
$supplies = Supply::read(limit: $amount, page: $page, order: $order);
|
||||||
|
|
||||||
|
// Запись формата ответа
|
||||||
|
yii::$app->response->format = Response::FORMAT_JSON;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'supplies' => $this->renderPartial('/supply/list', compact('supplies', 'amount', 'page')),
|
||||||
|
'_csrf' => yii::$app->request->getCsrfToken()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use mirzaev\yii2\arangodb\Migration;
|
||||||
|
|
||||||
|
class m220808_185553_create_file_collection extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param string Название коллекции
|
||||||
|
* @param array Тип коллекции (2 - документ, 3 - ребро)
|
||||||
|
*/
|
||||||
|
$this->createCollection('file', ['type' => 2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
$this->dropCollection('file');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use mirzaev\yii2\arangodb\Migration;
|
||||||
|
|
||||||
|
class m220817_210350_create_import_edge_file_collection extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param string Название коллекции
|
||||||
|
* @param array Тип коллекции (2 - документ, 3 - ребро)
|
||||||
|
*/
|
||||||
|
$this->createCollection('import_edge_file', ['type' => 3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
$this->dropCollection('import_edge_file');
|
||||||
|
}
|
||||||
|
}
|
|
@ -62,7 +62,8 @@ class Account extends Document implements IdentityInterface, PartnerInterface
|
||||||
'vrfy',
|
'vrfy',
|
||||||
'geol',
|
'geol',
|
||||||
'auth',
|
'auth',
|
||||||
'acpt'
|
'acpt',
|
||||||
|
'chpk'
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -98,7 +99,8 @@ class Account extends Document implements IdentityInterface, PartnerInterface
|
||||||
'vrfy' => 'Статус подтверждения владением почты',
|
'vrfy' => 'Статус подтверждения владением почты',
|
||||||
'geol' => 'Геолокация',
|
'geol' => 'Геолокация',
|
||||||
'auth' => 'Аутентификационный хеш',
|
'auth' => 'Аутентификационный хеш',
|
||||||
'acpt' => 'Согласие с офертой'
|
'acpt' => 'Согласие с офертой',
|
||||||
|
'chpk' => 'Ключ для смены пароля'
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -212,6 +214,59 @@ class Account extends Document implements IdentityInterface, PartnerInterface
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Отправка сообщения для генерации нового пароля
|
||||||
|
*/
|
||||||
|
public static function restoreSend(string $mail): bool
|
||||||
|
{
|
||||||
|
if (($account = self::findByMail($mail)) instanceof self) {
|
||||||
|
// Найден аккаунт
|
||||||
|
|
||||||
|
// Запись ключа для аутентификации
|
||||||
|
$account->chpk = yii::$app->security->generateRandomString();
|
||||||
|
|
||||||
|
if ($account->update()) {
|
||||||
|
// Удалось обновить аккаунт
|
||||||
|
|
||||||
|
// Отправка письма
|
||||||
|
yii::$app->mail_system->compose()
|
||||||
|
->setFrom(yii::$app->params['mail']['system'])
|
||||||
|
->setTo($account->mail)
|
||||||
|
->setSubject('Подтвердите сброс пароля')
|
||||||
|
->setHtmlBody(yii::$app->controller->renderPartial('/mails/restore', ['id' => $account->_key, 'chpk' => $account->chpk]))
|
||||||
|
->send();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Генерация нового пароля
|
||||||
|
*/
|
||||||
|
public function restoreGenerate(): void
|
||||||
|
{
|
||||||
|
// Удаление ключа
|
||||||
|
$this->chpk = null;
|
||||||
|
|
||||||
|
// Генерация пароля
|
||||||
|
$this->pswd = self::passwordGenerate();
|
||||||
|
|
||||||
|
if ($this->update()) {
|
||||||
|
// Удалось обновить аккаунт
|
||||||
|
|
||||||
|
// Отправка письма
|
||||||
|
yii::$app->mail_system->compose()
|
||||||
|
->setFrom(yii::$app->params['mail']['system'])
|
||||||
|
->setTo($this->mail)
|
||||||
|
->setSubject('Генерация пароля')
|
||||||
|
->setHtmlBody(yii::$app->controller->renderPartial('/mails/password', ['pswd' => $this->pswd]))
|
||||||
|
->send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Чтение полей для экспорта из 1С
|
* Чтение полей для экспорта из 1С
|
||||||
*/
|
*/
|
||||||
|
@ -669,18 +724,15 @@ class Account extends Document implements IdentityInterface, PartnerInterface
|
||||||
edge: 'account_edge_supply',
|
edge: 'account_edge_supply',
|
||||||
direction: 'OUTBOUND',
|
direction: 'OUTBOUND',
|
||||||
subquery_where: [
|
subquery_where: [
|
||||||
[
|
|
||||||
'account_edge_supply._from == account._id'
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
'account_edge_supply._to == "' . $_id . '"'
|
'account_edge_supply._to == "' . $_id . '"'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
subquery_select: 'account',
|
subquery_select: 'account',
|
||||||
where: 'account_edge_supply[0]._id != null',
|
where: 'account_edge_supply[0]._id != null',
|
||||||
limit: 1,
|
select: 'account_edge_supply[0]',
|
||||||
select: 'account_edge_supply[0]'
|
limit: 1
|
||||||
)[0];
|
)[0] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -918,9 +970,9 @@ class Account extends Document implements IdentityInterface, PartnerInterface
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function searchSuppliersRequests(): array
|
public static function searchSuppliersRequests(int $amount = 3, int $page, array $order = ['DESC']): array
|
||||||
{
|
{
|
||||||
return self::find()->where(['agnt' => true, 'type' => 'requested'])->orderBy(['DESC'])->all();
|
return self::find()->where(['agnt' => true, 'type' => 'requested'])->limit($amount)->offset($amount * ($page - 1))->orderBy($order)->all();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -928,12 +980,12 @@ class Account extends Document implements IdentityInterface, PartnerInterface
|
||||||
*
|
*
|
||||||
* @param static|null $account Аккаунт
|
* @param static|null $account Аккаунт
|
||||||
*/
|
*/
|
||||||
public static function initAccount(Account|int $account = null): ?static
|
public static function initAccount(Account|string|int $account = null): ?static
|
||||||
{
|
{
|
||||||
if (is_null($account)) {
|
if (is_null($account)) {
|
||||||
// Данные аккаунта не переданы
|
// Данные аккаунта не переданы
|
||||||
|
|
||||||
if (yii::$app->user->isGuest) {
|
if (empty(yii::$app->user) || yii::$app->user->isGuest) {
|
||||||
// Аккаунт не аутентифицирован
|
// Аккаунт не аутентифицирован
|
||||||
} else {
|
} else {
|
||||||
// Аккаунт аутентифицирован
|
// Аккаунт аутентифицирован
|
||||||
|
@ -955,6 +1007,15 @@ class Account extends Document implements IdentityInterface, PartnerInterface
|
||||||
if ($account = Account::searchById(Account::collectionName() . "/$account")) {
|
if ($account = Account::searchById(Account::collectionName() . "/$account")) {
|
||||||
// Удалось инициализировать аккаунт
|
// Удалось инициализировать аккаунт
|
||||||
|
|
||||||
|
return $account;
|
||||||
|
}
|
||||||
|
} else if (is_string($account)) {
|
||||||
|
// Передан идентификатор документа (_id) (подразумевается)
|
||||||
|
|
||||||
|
// Инициализация (поиск в базе данных)
|
||||||
|
if ($account = Account::searchById($account)) {
|
||||||
|
// Удалось инициализировать аккаунт
|
||||||
|
|
||||||
return $account;
|
return $account;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,9 +168,9 @@ abstract class Document extends ActiveRecord
|
||||||
/**
|
/**
|
||||||
* Чтение записей по максимальному ограничению
|
* Чтение записей по максимальному ограничению
|
||||||
*/
|
*/
|
||||||
public static function read(?array $where = [], int $limit = 100, ?array $order = null): array
|
public static function read(?array $where = [], int $limit = 100, int $page = 1, ?array $order = null): array
|
||||||
{
|
{
|
||||||
return static::find()->where($where)->orderby($order)->limit($limit)->all();
|
return static::find()->where($where)->orderby($order)->limit($limit)->offset(($page - 1) * $limit)->all();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -167,7 +167,7 @@ abstract class Edge extends Document
|
||||||
/**
|
/**
|
||||||
* Поиск рёбер по направлению
|
* Поиск рёбер по направлению
|
||||||
*/
|
*/
|
||||||
public static function searchByDirection(string $_from, string $direction = 'OUTBOUND', string $type = '', array $where = [], int $limit = 1): static|array|null
|
public static function searchByDirection(string $_from, string $direction = 'OUTBOUND', string $type = '', array $where = [], int $limit = 1, int $page = 1): static|array|null
|
||||||
{
|
{
|
||||||
if (str_contains($direction, 'OUTBOUND')) {
|
if (str_contains($direction, 'OUTBOUND')) {
|
||||||
// Исходящие рёбра
|
// Исходящие рёбра
|
||||||
|
@ -204,7 +204,7 @@ abstract class Edge extends Document
|
||||||
} else if (str_contains($direction, 'ANY')) {
|
} else if (str_contains($direction, 'ANY')) {
|
||||||
// Исходящие и входящие рёбра
|
// Исходящие и входящие рёбра
|
||||||
|
|
||||||
return static::searchByDirection(_from: $_from, direction: 'OUTBOUND', type: $type, where: $where, limit: $limit) + static::searchByDirection(_from: $_from, direction: 'INBOUND', type: $type, where: $where, limit: $limit);
|
return static::searchByDirection(_from: $_from, direction: 'OUTBOUND', type: $type, where: $where, limit: $limit, page: $page) + static::searchByDirection(_from: $_from, direction: 'INBOUND', type: $type, where: $where, limit: $limit, page: $page);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($limit < 2) {
|
if ($limit < 2) {
|
||||||
|
@ -214,7 +214,7 @@ abstract class Edge extends Document
|
||||||
} else {
|
} else {
|
||||||
// Несколько рёбер
|
// Несколько рёбер
|
||||||
|
|
||||||
return $query->limit($limit)->all();
|
return $query->limit($limit)->offset($limit * ($page - 1))->all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\models;
|
||||||
|
|
||||||
|
use ArangoDBClient\Document as ArangoDBDocument;
|
||||||
|
|
||||||
|
use app\models\traits\SearchByEdge;
|
||||||
|
use app\models\ImportEdgeFile;
|
||||||
|
|
||||||
|
class File extends Document
|
||||||
|
{
|
||||||
|
use SearchByEdge;
|
||||||
|
|
||||||
|
public static function collectionName(): string
|
||||||
|
{
|
||||||
|
return 'file';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attributes(): array
|
||||||
|
{
|
||||||
|
return array_merge(
|
||||||
|
parent::attributes(),
|
||||||
|
[
|
||||||
|
'type',
|
||||||
|
'path',
|
||||||
|
'name',
|
||||||
|
'user',
|
||||||
|
'stts',
|
||||||
|
'meta'
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attributeLabels(): array
|
||||||
|
{
|
||||||
|
return array_merge(
|
||||||
|
parent::attributeLabels(),
|
||||||
|
[
|
||||||
|
'type' => 'Тип файла',
|
||||||
|
'path' => 'Относительный от хранилища путь до файла',
|
||||||
|
'name' => 'Название файла',
|
||||||
|
'user' => 'Пользователь управляющий файлом',
|
||||||
|
'stts' => 'Статус',
|
||||||
|
'meta' => 'Метаданные'
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Перед сохранением
|
||||||
|
*
|
||||||
|
* @todo Подождать обновление от ебаного Yii2 и добавить
|
||||||
|
* проверку типов передаваемых параметров
|
||||||
|
*/
|
||||||
|
public function beforeSave($data): bool
|
||||||
|
{
|
||||||
|
if (parent::beforeSave($data)) {
|
||||||
|
if ($this->isNewRecord) {
|
||||||
|
if ($this->type = 'supplies excel') {
|
||||||
|
// Список поставок
|
||||||
|
|
||||||
|
$this->stts = 'needed to load';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function searchSuppliesNeededToLoad(int $amount = 3): array
|
||||||
|
{
|
||||||
|
return static::find()->where(['stts' => 'needed to load'])->limit($amount)->all();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Поиск по инстанции импорта
|
||||||
|
*
|
||||||
|
* @param Import $import Инстанция импорта
|
||||||
|
*/
|
||||||
|
public static function searchByImport(Import $import): ?File
|
||||||
|
{
|
||||||
|
return new File(self::searchByEdge(
|
||||||
|
from: 'import',
|
||||||
|
to: 'file',
|
||||||
|
subquery_where: [
|
||||||
|
[
|
||||||
|
'import._id' => $import->readId()
|
||||||
|
]
|
||||||
|
],
|
||||||
|
where: 'import_edge_file[0]._id != null',
|
||||||
|
select: 'file',
|
||||||
|
limit: 1
|
||||||
|
)[0]) ?? null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -79,9 +79,9 @@ class Import extends Document
|
||||||
* @param Warehouse $warehouse Инстанция склада
|
* @param Warehouse $warehouse Инстанция склада
|
||||||
* @param int $limit Ограничение по максимальному количеству
|
* @param int $limit Ограничение по максимальному количеству
|
||||||
*
|
*
|
||||||
* @return array Инстанции испортов
|
* @return array Инстанции импортов
|
||||||
*/
|
*/
|
||||||
public static function searchByWarehouse(Warehouse $warehouse, int $limit = 10): array
|
public static function searchByWarehouse(Warehouse $warehouse, int $limit = 10): ?array
|
||||||
{
|
{
|
||||||
return self::searchByEdge(
|
return self::searchByEdge(
|
||||||
from: 'warehouse',
|
from: 'warehouse',
|
||||||
|
@ -103,9 +103,9 @@ class Import extends Document
|
||||||
* @param Supply $supply Поставка
|
* @param Supply $supply Поставка
|
||||||
* @param int $limit Ограничение по максимальному количеству
|
* @param int $limit Ограничение по максимальному количеству
|
||||||
*
|
*
|
||||||
* @return array Инстанции испортов
|
* @return array Инстанции импортов
|
||||||
*/
|
*/
|
||||||
public static function searchBySupply(Supply $supply, int $limit = 10): array
|
public static function searchBySupply(Supply $supply, int $limit = 10): ?array
|
||||||
{
|
{
|
||||||
return self::searchByEdge(
|
return self::searchByEdge(
|
||||||
from: 'supply',
|
from: 'supply',
|
||||||
|
@ -120,4 +120,27 @@ class Import extends Document
|
||||||
limit: $limit
|
limit: $limit
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Поиск по файлу
|
||||||
|
*
|
||||||
|
* @param File $file Файл
|
||||||
|
*
|
||||||
|
* @return Import|null Инстанция импорта
|
||||||
|
*/
|
||||||
|
public static function searchByFile(File $file): ?Import
|
||||||
|
{
|
||||||
|
return self::searchByEdge(
|
||||||
|
from: 'file',
|
||||||
|
to: 'import',
|
||||||
|
edge: 'import_edge_file',
|
||||||
|
direction: 'OUTBOUND',
|
||||||
|
subquery_where: [
|
||||||
|
['import_edge_file._to' => $file->readId()],
|
||||||
|
['import_edge_supply.type' => 'connected']
|
||||||
|
],
|
||||||
|
where: 'import_edge_supply[0] != null',
|
||||||
|
limit: 1
|
||||||
|
)[0] ?? null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\models;
|
||||||
|
|
||||||
|
use app\models\File;
|
||||||
|
use app\models\Import;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Связь инстанций импорта с поставками
|
||||||
|
*/
|
||||||
|
class ImportEdgeFile extends Edge
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Имя коллекции
|
||||||
|
*/
|
||||||
|
public static function collectionName(): string
|
||||||
|
{
|
||||||
|
return 'import_edge_file';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Свойства
|
||||||
|
*/
|
||||||
|
public function attributes(): array
|
||||||
|
{
|
||||||
|
return array_merge(
|
||||||
|
parent::attributes(),
|
||||||
|
[
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Метки свойств
|
||||||
|
*/
|
||||||
|
public function attributeLabels(): array
|
||||||
|
{
|
||||||
|
return array_merge(
|
||||||
|
parent::attributeLabels(),
|
||||||
|
[
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Правила
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return array_merge(
|
||||||
|
parent::rules(),
|
||||||
|
[
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Поиск по файлу
|
||||||
|
*
|
||||||
|
* @param File $file Файл
|
||||||
|
* @param int $limit Ограничение по максимальному количеству
|
||||||
|
*/
|
||||||
|
public static function searchByFile(File $file, int $limit = 1): array
|
||||||
|
{
|
||||||
|
return static::find()->where(['_to' => $file->readId(), 'type' => 'connected'])->limit($limit)->all();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Поиск по инстанции импорта
|
||||||
|
*
|
||||||
|
* @param Import $import Инстанция импорта
|
||||||
|
* @param int $limit Ограничение по максимальному количеству
|
||||||
|
*/
|
||||||
|
public static function searchByImport(Import $import, int $limit = 1): array
|
||||||
|
{
|
||||||
|
return static::find()->where(['_from' => $import->readId(), 'type' => 'connected'])->limit($limit)->all();
|
||||||
|
}
|
||||||
|
}
|
|
@ -110,6 +110,6 @@ class ImportEdgeSupply extends Edge
|
||||||
*/
|
*/
|
||||||
public static function searchBySupply(Supply $supply): ?static
|
public static function searchBySupply(Supply $supply): ?static
|
||||||
{
|
{
|
||||||
return static::find()->where(['_to' => $supply->readId()])->one()[0] ?? null;
|
return static::find()->where(['_to' => $supply->readId()])->one() ?? null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,16 +147,16 @@ class Notification extends Document
|
||||||
*
|
*
|
||||||
* @param string $html Содержимое уведомления (HTML или текст)
|
* @param string $html Содержимое уведомления (HTML или текст)
|
||||||
* @param bool|string|null $html Содержимое уведомления (HTML или текст)
|
* @param bool|string|null $html Содержимое уведомления (HTML или текст)
|
||||||
* @param string $account Получатель уведомления (_key)
|
* @param string $account Получатель уведомления (_key или "@...")
|
||||||
* @param string $type Тип уведомления
|
* @param string $type Тип уведомления
|
||||||
*
|
*
|
||||||
* @todo Намного удобнее будет заменить _key на _id, чтобы из рёбер сразу получать аккаунт без лишних операций
|
* @todo Намного удобнее будет заменить _key на _id, чтобы из рёбер сразу получать аккаунт без лишних операций
|
||||||
*/
|
*/
|
||||||
public static function _write(string $text, bool|string|null $html = false, string $account = null, string $type = self::TYPE_NOTICE): self|array|null
|
public static function _write(string $text, bool|string|null $html = false, string $account = '', string $type = self::TYPE_NOTICE): self|array|null
|
||||||
{
|
{
|
||||||
// Инициализация
|
// Инициализация
|
||||||
$model = new self;
|
$model = new self;
|
||||||
$account ?? $account = yii::$app->user->identity->_key ?? throw new Exception('Не удалось инициализировать получателя');
|
$receiver = Account::initAccount($account)->_key ?? $account ?? throw new Exception('Не удалось инициализировать получателя');
|
||||||
|
|
||||||
if ((bool) (int) $html) {
|
if ((bool) (int) $html) {
|
||||||
// Получен текст в формете HTML-кода
|
// Получен текст в формете HTML-кода
|
||||||
|
@ -176,7 +176,7 @@ class Notification extends Document
|
||||||
// Уведомление записано
|
// Уведомление записано
|
||||||
|
|
||||||
// Инициализация получателей и создание ребра
|
// Инициализация получателей и создание ребра
|
||||||
self::searchReceiverAndConnect($model, $account, $type);
|
self::searchReceiverAndConnect($model, $receiver, $type);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -273,7 +273,8 @@ class Order extends Document implements DocumentInterface
|
||||||
bool $supplies = false,
|
bool $supplies = false,
|
||||||
int|null $from = null,
|
int|null $from = null,
|
||||||
int|null $to = null,
|
int|null $to = null,
|
||||||
bool $count = false
|
bool $count = false,
|
||||||
|
bool $debug = false
|
||||||
): int|array|null {
|
): int|array|null {
|
||||||
// Инициализация аккаунта
|
// Инициализация аккаунта
|
||||||
if (empty($account)) {
|
if (empty($account)) {
|
||||||
|
@ -350,9 +351,15 @@ class Order extends Document implements DocumentInterface
|
||||||
sort: ['DESC'],
|
sort: ['DESC'],
|
||||||
select: $select,
|
select: $select,
|
||||||
direction: 'INBOUND',
|
direction: 'INBOUND',
|
||||||
count: !$supplies && $count
|
count: !$supplies && $count,
|
||||||
|
debug: $debug
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if ($debug) {
|
||||||
|
var_dump($orders);
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
if (!$supplies && $count) {
|
if (!$supplies && $count) {
|
||||||
// Запрошен подсчет заказов
|
// Запрошен подсчет заказов
|
||||||
|
|
||||||
|
@ -363,7 +370,7 @@ class Order extends Document implements DocumentInterface
|
||||||
$return = [];
|
$return = [];
|
||||||
|
|
||||||
// Инициализация архитектуры буфера вывода
|
// Инициализация архитектуры буфера вывода
|
||||||
foreach ($orders as $key => $order) {
|
foreach ($orders ?? [null] as $key => $order) {
|
||||||
// Перебор заказов
|
// Перебор заказов
|
||||||
|
|
||||||
// Запись в буфер возврата
|
// Запись в буфер возврата
|
||||||
|
@ -526,6 +533,7 @@ class Order extends Document implements DocumentInterface
|
||||||
$buffer['delivery'] = $buffer_connection['data'];
|
$buffer['delivery'] = $buffer_connection['data'];
|
||||||
} else {
|
} else {
|
||||||
// Инициализация инстанции продукта в базе данных (реинициализация под ActiveRecord)
|
// Инициализация инстанции продукта в базе данных (реинициализация под ActiveRecord)
|
||||||
|
|
||||||
$product = Product::searchByCatnAndProd($buffer['product']['catn'], $buffer['product']['prod']);
|
$product = Product::searchByCatnAndProd($buffer['product']['catn'], $buffer['product']['prod']);
|
||||||
|
|
||||||
// Инициализация доставки Dellin (автоматическая)
|
// Инициализация доставки Dellin (автоматическая)
|
||||||
|
@ -548,6 +556,7 @@ class Order extends Document implements DocumentInterface
|
||||||
$product->update();
|
$product->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Запись цены (цена поставки + цена доставки + наша наценка)
|
// Запись цены (цена поставки + цена доставки + наша наценка)
|
||||||
$buffer['cost'] = ($supply->cost ?? $supply->onec['Цены']['Цена']['ЦенаЗаЕдиницу'] ?? throw new exception('Не найдена цена товара')) + ($buffer['delivery']['price']['all'] ?? $buffer['delivery']['price']['one'] ?? 0) + ($settings['increase'] ?? 0) ?? 0;
|
$buffer['cost'] = ($supply->cost ?? $supply->onec['Цены']['Цена']['ЦенаЗаЕдиницу'] ?? throw new exception('Не найдена цена товара')) + ($buffer['delivery']['price']['all'] ?? $buffer['delivery']['price']['one'] ?? 0) + ($settings['increase'] ?? 0) ?? 0;
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
|
|
@ -457,7 +457,7 @@ class Product extends Document
|
||||||
where: 'supply_edge_product[0]._id != null',
|
where: 'supply_edge_product[0]._id != null',
|
||||||
limit: 1,
|
limit: 1,
|
||||||
select: 'supply_edge_product[0]'
|
select: 'supply_edge_product[0]'
|
||||||
)[0];
|
)[0] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -606,20 +606,6 @@ class Product extends Document
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Деактивация
|
|
||||||
*
|
|
||||||
* @return bool Статус выполнения
|
|
||||||
*/
|
|
||||||
public function deactivate(): bool
|
|
||||||
{
|
|
||||||
$this->stts = 'inactive';
|
|
||||||
|
|
||||||
if ($this->update() > 0) return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Найти товары по группе
|
* Найти товары по группе
|
||||||
*
|
*
|
||||||
|
@ -645,4 +631,31 @@ class Product extends Document
|
||||||
select: 'product_edge_product_group[0]'
|
select: 'product_edge_product_group[0]'
|
||||||
)[0];
|
)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Инициализация обложки для товара
|
||||||
|
*
|
||||||
|
* Ищет логотип в нужной категории (размере) для выбранного производителя
|
||||||
|
*
|
||||||
|
* @param string $prod Производитель
|
||||||
|
* @param int $size Размерная группа
|
||||||
|
*
|
||||||
|
* @return string Относительный путь до изображения от публичной корневой папки
|
||||||
|
*/
|
||||||
|
public static function cover(string $prod, int $size = 150): string
|
||||||
|
{
|
||||||
|
if ($size === 0) $size = '';
|
||||||
|
else $size = "h$size/";
|
||||||
|
|
||||||
|
// Инициализация пути
|
||||||
|
$path = "/img/covers/$size" . strtolower($prod);
|
||||||
|
|
||||||
|
// Поиск файла и возврат
|
||||||
|
if (file_exists(YII_PATH_PUBLIC . DIRECTORY_SEPARATOR . $path . '.jpg')) return $path . '.jpg';
|
||||||
|
else if (file_exists(YII_PATH_PUBLIC . DIRECTORY_SEPARATOR . $path . '.jpeg')) return $path . '.jpeg';
|
||||||
|
else if (file_exists(YII_PATH_PUBLIC . DIRECTORY_SEPARATOR . $path . '.png')) return $path . '.png';
|
||||||
|
|
||||||
|
// Возврат изображения по умолчанию
|
||||||
|
return "/img/covers/$size" . 'product.png';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,7 +125,7 @@ class ProductGroup extends Document implements GroupInterface
|
||||||
public function deleteProduct(Product $product): void
|
public function deleteProduct(Product $product): void
|
||||||
{
|
{
|
||||||
// Удаление товара из группы (подразумевается, что будет только одно)
|
// Удаление товара из группы (подразумевается, что будет только одно)
|
||||||
foreach (ProductEdgeProductGroup::searchByVertex($product->readId(), $this->readId(), filter: ['type' => 'member']) as $edge) $edge->delete;
|
foreach (ProductEdgeProductGroup::searchByVertex($product->readId(), $this->readId(), filter: ['type' => 'member']) as $edge) $edge->delete();
|
||||||
|
|
||||||
// Запись в журнал
|
// Запись в журнал
|
||||||
$this->journal('delete member', [
|
$this->journal('delete member', [
|
||||||
|
@ -138,9 +138,9 @@ class ProductGroup extends Document implements GroupInterface
|
||||||
*
|
*
|
||||||
* @param int $limit Ограничение по максимальному количеству
|
* @param int $limit Ограничение по максимальному количеству
|
||||||
*/
|
*/
|
||||||
public function searchEdges(int $limit = 999): ?array
|
public function searchEdges(int $limit = 100, int $page = 1): ?array
|
||||||
{
|
{
|
||||||
return ProductEdgeProductGroup::searchByDirection($this->readId(), 'INBOUND', where: ['type' => 'member'], limit: $limit);
|
return ProductEdgeProductGroup::searchByDirection($this->readId(), 'INBOUND', where: ['type' => 'member'], limit: $limit, page: $page);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -148,12 +148,12 @@ class ProductGroup extends Document implements GroupInterface
|
||||||
*
|
*
|
||||||
* @param int $limit Ограничение по максимальному количеству
|
* @param int $limit Ограничение по максимальному количеству
|
||||||
*/
|
*/
|
||||||
public function searchProducts(int $limit = 999): ?array
|
public function searchProducts(int $limit = 100, int $page = 1): ?array
|
||||||
{
|
{
|
||||||
// Инициализация буфера товаров
|
// Инициализация буфера товаров
|
||||||
$products = [];
|
$products = [];
|
||||||
|
|
||||||
foreach ($this->searchEdges($limit) as $edge) {
|
foreach ($this->searchEdges($limit, $page) as $edge) {
|
||||||
// Перебор рёбер
|
// Перебор рёбер
|
||||||
|
|
||||||
$products[] = Product::searchById($edge->_from);
|
$products[] = Product::searchById($edge->_from);
|
||||||
|
@ -191,6 +191,20 @@ class ProductGroup extends Document implements GroupInterface
|
||||||
return $transfered;
|
return $transfered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Деактивация
|
||||||
|
*
|
||||||
|
* @return bool Статус выполнения
|
||||||
|
*/
|
||||||
|
public function deactivate(): bool
|
||||||
|
{
|
||||||
|
$this->stts = 'inactive';
|
||||||
|
|
||||||
|
if ($this->update() > 0) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Запись рёбер групп
|
* Запись рёбер групп
|
||||||
*
|
*
|
||||||
|
|
|
@ -129,7 +129,7 @@ class Search extends Document
|
||||||
// Инициализация буфера вывода
|
// Инициализация буфера вывода
|
||||||
$response = $products;
|
$response = $products;
|
||||||
|
|
||||||
// Генерация сдвига по запрашиваемым данным (пагинация)
|
// Генерация сдвига по запрашиваемым данным (система страниц)
|
||||||
$offset = $limit * ($page - 1);
|
$offset = $limit * ($page - 1);
|
||||||
|
|
||||||
foreach ($response as &$row) {
|
foreach ($response as &$row) {
|
||||||
|
@ -167,7 +167,7 @@ class Search extends Document
|
||||||
// Инициализация буфера
|
// Инициализация буфера
|
||||||
$buffer_connections = [];
|
$buffer_connections = [];
|
||||||
|
|
||||||
if (count($connections) === 11) {
|
if (count($connections) === 100) {
|
||||||
// Если в базе данных хранится много поставок
|
// Если в базе данных хранится много поставок
|
||||||
|
|
||||||
// Инициализация
|
// Инициализация
|
||||||
|
@ -418,7 +418,7 @@ class Search extends Document
|
||||||
// Не удалось использовать первое изображение как обложку
|
// Не удалось использовать первое изображение как обложку
|
||||||
|
|
||||||
// Запись обложки по умолчанию
|
// Запись обложки по умолчанию
|
||||||
$cover = '/img/covers/h150/product.png';
|
$cover = Product::cover($row['prod'], 150);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,10 @@ use app\models\Product;
|
||||||
use app\models\SupplyEdgeProduct;
|
use app\models\SupplyEdgeProduct;
|
||||||
use app\models\Settings;
|
use app\models\Settings;
|
||||||
use app\models\Import;
|
use app\models\Import;
|
||||||
|
use app\models\File;
|
||||||
use app\models\ImportEdgeSupply;
|
use app\models\ImportEdgeSupply;
|
||||||
use app\models\WarehouseEdgeImport;
|
use app\models\WarehouseEdgeImport;
|
||||||
|
use app\models\ImportEdgeFile;
|
||||||
|
|
||||||
use carono\exchange1c\interfaces\OfferInterface;
|
use carono\exchange1c\interfaces\OfferInterface;
|
||||||
use carono\exchange1c\interfaces\ProductInterface;
|
use carono\exchange1c\interfaces\ProductInterface;
|
||||||
|
@ -23,6 +25,8 @@ use moonland\phpexcel\Excel;
|
||||||
|
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use DateTimeZone;
|
use DateTimeZone;
|
||||||
|
use DatePeriod;
|
||||||
|
use DateInterval;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
|
@ -38,13 +42,6 @@ class Supply extends Product implements ProductInterface, OfferInterface
|
||||||
{
|
{
|
||||||
use Xml2Array;
|
use Xml2Array;
|
||||||
|
|
||||||
/**
|
|
||||||
* Количество
|
|
||||||
*
|
|
||||||
* Используется при выводе в корзине
|
|
||||||
*/
|
|
||||||
public int $amnt = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Имя коллекции
|
* Имя коллекции
|
||||||
*/
|
*/
|
||||||
|
@ -101,14 +98,21 @@ class Supply extends Product implements ProductInterface, OfferInterface
|
||||||
*/
|
*/
|
||||||
public function afterSave($data, $vars): void
|
public function afterSave($data, $vars): void
|
||||||
{
|
{
|
||||||
if (AccountEdgeSupply::searchByVertex(yii::$app->user->id, $this->readId())) {
|
// Инициализация
|
||||||
// Ребро: "АККАУНТ -> ПОСТАВКА" уже существует
|
$account = Account::initAccount();
|
||||||
|
|
||||||
} else {
|
if (isset($account)) {
|
||||||
// Ребра не существует
|
// Инициализирован аккаунт
|
||||||
|
|
||||||
// Запись ребра: АККАУНТ -> ПОСТАВКА
|
if (AccountEdgeSupply::searchByVertex($account->readId(), $this->readId())) {
|
||||||
(new AccountEdgeSupply)->write(yii::$app->user->id, $this->readId(), 'import');
|
// Ребро: "АККАУНТ -> ПОСТАВКА" уже существует
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Ребра не существует
|
||||||
|
|
||||||
|
// Запись ребра: АККАУНТ -> ПОСТАВКА
|
||||||
|
(new AccountEdgeSupply)->write($account->readId(), $this->readId(), 'import');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,8 +175,13 @@ class Supply extends Product implements ProductInterface, OfferInterface
|
||||||
foreach (ImportEdgeSupply::find()->where(['_from' => $id])->limit($limit)->all() as $edge) {
|
foreach (ImportEdgeSupply::find()->where(['_from' => $id])->limit($limit)->all() as $edge) {
|
||||||
// Перебор найденных рёбер
|
// Перебор найденных рёбер
|
||||||
|
|
||||||
// Поиск поставки и запись в буфер вывода
|
// Поиск поставки
|
||||||
$supplies[] = static::searchById($edge->_to);
|
$supply = static::searchById($edge->_to);
|
||||||
|
|
||||||
|
if (empty($supply)) continue;
|
||||||
|
|
||||||
|
// Запись поставки в буфер вывода
|
||||||
|
$supplies[] = $supply;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $supplies;
|
return $supplies;
|
||||||
|
@ -387,20 +396,15 @@ class Supply extends Product implements ProductInterface, OfferInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Запись поставок из excel
|
* Импорт Excel-файла
|
||||||
*
|
|
||||||
* На данный момент обрабатывает только импорт из
|
|
||||||
* файлов с расширением .excel
|
|
||||||
*
|
*
|
||||||
* @param int $warehouse Идентификатор склада (_key)
|
* @param int $warehouse Идентификатор склада (_key)
|
||||||
* @param Account|int|null $account Аккаунт
|
* @param Account|int|null $account Аккаунт управляющий файлом и его данными
|
||||||
|
* @param bool $load Загрузить в базу данных
|
||||||
*/
|
*/
|
||||||
public function importExcel(int $warehouse, Account|int|null $account = null): bool
|
public function importExcel(int $warehouse, Account|int|null $account = null): bool
|
||||||
{
|
{
|
||||||
// Инициализация
|
// Инициализация
|
||||||
$data = [];
|
|
||||||
$created = 0;
|
|
||||||
$updated = 0;
|
|
||||||
$account = Account::initAccount($account);
|
$account = Account::initAccount($account);
|
||||||
|
|
||||||
if ($this->validate()) {
|
if ($this->validate()) {
|
||||||
|
@ -424,10 +428,85 @@ class Supply extends Product implements ProductInterface, OfferInterface
|
||||||
if (!file_exists($path))
|
if (!file_exists($path))
|
||||||
if (!mkdir($path, 0775, true))
|
if (!mkdir($path, 0775, true))
|
||||||
throw new Exception('Не удалось создать директорию', 500);
|
throw new Exception('Не удалось создать директорию', 500);
|
||||||
|
$this->file_excel->saveAs($path = "$path/" . $this->file_excel->baseName . '.' . $this->file_excel->extension);
|
||||||
|
|
||||||
$this->file_excel->saveAs($path = "$path/" . $filename = $this->file_excel->baseName . '.' . $this->file_excel->extension);
|
// Инициализация инстанции файла
|
||||||
|
$file = new File();
|
||||||
|
|
||||||
$data[] = Excel::import($path, [
|
// Запись настроек файла
|
||||||
|
$file->type = 'supplies excel';
|
||||||
|
$file->path = $path;
|
||||||
|
$file->name = $this->file_excel->baseName . '.' . $this->file_excel->extension;
|
||||||
|
$file->user = (int) $account->_key;
|
||||||
|
$file->meta = [
|
||||||
|
'warehouse' => $warehouse
|
||||||
|
];
|
||||||
|
|
||||||
|
// Запись в базу данных
|
||||||
|
$file->save();
|
||||||
|
|
||||||
|
// Инициализация инстанции импорта
|
||||||
|
$import = new Import;
|
||||||
|
|
||||||
|
if ($import->save()) {
|
||||||
|
// Записано в базу данных
|
||||||
|
|
||||||
|
if (ImportEdgeFile::write($import->readId(), $file->readId(), data: ['type' => 'connected'])) {
|
||||||
|
// Записано ребро: "ИНСТАНЦИЯ ИМПОРТА" -> ФАЙЛ
|
||||||
|
|
||||||
|
// Запись в журнал инстанции импорта
|
||||||
|
$import->journal('connect_with_file', [
|
||||||
|
'target' => $file->readId()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WarehouseEdgeImport::write(Warehouse::collectionName() . '/' . $file->meta['warehouse'], $import->readId(), data: ['type' => 'loaded'])) {
|
||||||
|
// Записано ребро: СКЛАД -> ИНСТАНЦИЯ ПОСТАВОК
|
||||||
|
|
||||||
|
// Запись в журнал инстанции импорта
|
||||||
|
$import->journal('connect_with_warehouse', [
|
||||||
|
'target' => Warehouse::collectionName() . '/' . $file->meta['warehouse']
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Макрос действий после импорта
|
||||||
|
static::afterImportExcel($account, $warehouse);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Запись ошибки
|
||||||
|
$this->addError('errors', 'Не пройдена проверка параметров');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Запись поставок из excel
|
||||||
|
*
|
||||||
|
* На данный момент обрабатывает только импорт из
|
||||||
|
* файлов с расширением .excel
|
||||||
|
*
|
||||||
|
* @param File $file Инстанция файла
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function loadExcel(File $file): bool {
|
||||||
|
// Инициализация
|
||||||
|
$created = 0;
|
||||||
|
$updated = 0;
|
||||||
|
$account = Account::initAccount((int) $file->user);
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
$supply = new Supply();
|
||||||
|
$supply->scenario = $supply::SCENARIO_IMPORT_EXCEL;
|
||||||
|
$supply->file_excel = $file->path;
|
||||||
|
|
||||||
|
if ($supply->validate()) {
|
||||||
|
// Пройдена проверка
|
||||||
|
|
||||||
|
$data[] = Excel::import($supply->file_excel, [
|
||||||
'setFirstRecordAsKeys' => true,
|
'setFirstRecordAsKeys' => true,
|
||||||
'setIndexSheetByName' => true,
|
'setIndexSheetByName' => true,
|
||||||
]);
|
]);
|
||||||
|
@ -441,7 +520,7 @@ class Supply extends Product implements ProductInterface, OfferInterface
|
||||||
if (count($data) < 1) {
|
if (count($data) < 1) {
|
||||||
// Не найдены строки с товарами
|
// Не найдены строки с товарами
|
||||||
|
|
||||||
$this->addError('errors', 'Не удалось найти данные товаров');
|
$supply->addError('errors', 'Не удалось найти данные товаров');
|
||||||
} else {
|
} else {
|
||||||
// Найдены строки с товарами
|
// Найдены строки с товарами
|
||||||
|
|
||||||
|
@ -489,10 +568,11 @@ class Supply extends Product implements ProductInterface, OfferInterface
|
||||||
if (!$product = Product::searchByCatnAndProd($article, $prod)) $product = Product::writeEmpty($article, $prod, Account::isMinimalAuthorized($account));
|
if (!$product = Product::searchByCatnAndProd($article, $prod)) $product = Product::writeEmpty($article, $prod, Account::isMinimalAuthorized($account));
|
||||||
|
|
||||||
// Инициализация группы товаров
|
// Инициализация группы товаров
|
||||||
if (!$group = ProductGroup::searchByProduct($product)) $group = ProductGroup::writeEmpty(active: true);
|
// if (!$group = ProductGroup::searchByProduct($product)) $group = ProductGroup::writeEmpty(active: true);
|
||||||
|
|
||||||
// Инициализация функции создания поставки
|
// Инициализация функции создания поставки
|
||||||
$create = function (string $_supply, int|null $amount = null) use ($group, $row, $prod, $analogs, &$created, &$updated, &$imported, $account): bool {
|
// $create = function (string $_supply, int|null $amount = null) use ($group, $row, $prod, $analogs, &$created, &$updated, &$imported, $account): bool {
|
||||||
|
$create = function (string $_supply, int|null $amount = null) use ($row, $prod, $analogs, &$created, &$updated, &$imported, $account): bool {
|
||||||
// Очистка
|
// Очистка
|
||||||
$_supply = trim($_supply);
|
$_supply = trim($_supply);
|
||||||
|
|
||||||
|
@ -504,8 +584,272 @@ class Supply extends Product implements ProductInterface, OfferInterface
|
||||||
|
|
||||||
// Запись артикула (каталожного номера) в буфер
|
// Запись артикула (каталожного номера) в буфер
|
||||||
$_row['catn'] = $_supply;
|
$_row['catn'] = $_supply;
|
||||||
|
|
||||||
|
// Запись цены в буфер
|
||||||
$_row['cost'] = (float) preg_replace('/[^\d\.]+/', '', preg_replace('/\,+/', ' ', (string) ($row['Стоимость'] ?? $row['стоимость'] ?? $row['Цена'] ?? $row['цена'] ?? $row['Cost'] ?? $row['cost'] ?? $row['Price'] ?? $row['price']))) ?? 0;
|
$_row['cost'] = (float) preg_replace('/[^\d\.]+/', '', preg_replace('/\,+/', ' ', (string) ($row['Стоимость'] ?? $row['стоимость'] ?? $row['Цена'] ?? $row['цена'] ?? $row['Cost'] ?? $row['cost'] ?? $row['Price'] ?? $row['price']))) ?? 0;
|
||||||
$_row['prod'] = $prod;
|
|
||||||
|
// Запись производителя в буфер
|
||||||
|
$_row['prod'] = match($prod = ucwords(strtolower(preg_replace('/[^A-zА-я\s]/', ' ', $prod, 300)))) {
|
||||||
|
'Akebono' => 'AKEBONO',
|
||||||
|
'Bosch' => 'BOSCH',
|
||||||
|
'Brembo' => 'BREMBO',
|
||||||
|
'Ctr' => 'CTR',
|
||||||
|
'Delphi' => 'DELPHI',
|
||||||
|
'Gates' => 'GATES',
|
||||||
|
'Hella' => 'HELLA',
|
||||||
|
'Kyb' => 'KYB',
|
||||||
|
'Mando' => 'MANDO',
|
||||||
|
'Mk Kachiyama', 'Mk-kachiyama', 'Mk-Kachiyama' => 'MK KACHIYAMA',
|
||||||
|
'Narva' => 'NARVA',
|
||||||
|
'Ngk' => 'NGK',
|
||||||
|
'Nk' => 'NK',
|
||||||
|
'Osram' => 'OSRAM',
|
||||||
|
'Philips' => 'PHILIPS',
|
||||||
|
'Rancho' => 'RANCHO',
|
||||||
|
'Sangsin' => 'SANGSIN',
|
||||||
|
'Swag' => 'SWAG',
|
||||||
|
'Trw' => 'TRW',
|
||||||
|
'Filtron' => 'FILTRON',
|
||||||
|
'Ajusa' => 'AJUSA',
|
||||||
|
'Denso' => 'DENSO',
|
||||||
|
'Dolz' => 'DOLZ',
|
||||||
|
'Era' => 'ERA',
|
||||||
|
'Febest' => 'FEBEST',
|
||||||
|
'Freccia' => 'FRECCIA',
|
||||||
|
'Gmb' => 'GMB',
|
||||||
|
'Gsp' => 'GSP',
|
||||||
|
'Honda' => 'HONDA',
|
||||||
|
'Hyundai/kia', 'Hyundai/Kia', 'Hyundai-kia', 'Hyundai-Kia' => 'HYUNDAI/KIA',
|
||||||
|
'Knecht/mahle', 'Knecht/Mahle', 'Knecht-mahle', 'Knecht-Mahle' => 'KNECHT/MAHLE',
|
||||||
|
'Lynx' => 'LYNX',
|
||||||
|
'Mann' => 'MANN',
|
||||||
|
'Mitsubishi' => 'MITSUBISHI',
|
||||||
|
'Nipparts' => 'NIPPARTS',
|
||||||
|
'Nissan' => 'NISSAN',
|
||||||
|
'Sasic' => 'SASIC',
|
||||||
|
'Snr' => 'SNR',
|
||||||
|
'Subaru' => 'SUBARU',
|
||||||
|
'Toyota' => 'TOYOTA',
|
||||||
|
'Trw_moto', 'Trw_Moto', 'Trw-moto', 'Trw-Moto' => 'TRW_MOTO',
|
||||||
|
'Vag' => 'VAG',
|
||||||
|
'Wynns' => 'WYNNS',
|
||||||
|
'Ert' => 'ERT',
|
||||||
|
'Dongil' => 'DONGIL',
|
||||||
|
'Febi' => 'FEBI',
|
||||||
|
'Ford' => 'FORD',
|
||||||
|
'Injin' => 'INJIN',
|
||||||
|
'Land Rover' => 'LAND ROVER',
|
||||||
|
'Lpr' => 'LPR',
|
||||||
|
'Luzar' => 'LUZAR',
|
||||||
|
'MercedesBenz', 'Mercedesbenz', 'Mercedes Benz' => 'MERCEDES BENZ',
|
||||||
|
'Suzuki' => 'SUZUKI',
|
||||||
|
'Teikin' => 'TEIKIN',
|
||||||
|
'Blue print' => 'BLUE PRINT',
|
||||||
|
'Daihatsu' => 'DAIHATSU',
|
||||||
|
'Goodwill' => 'GOODWILL',
|
||||||
|
'Ina' => 'INA',
|
||||||
|
'Iveco' => 'IVECO',
|
||||||
|
'Jp Group' => 'JP GROUP',
|
||||||
|
'Mfilter' => 'MFILTER',
|
||||||
|
'Moog' => 'MOOG',
|
||||||
|
'Nibk' => 'NIBK',
|
||||||
|
'Asakashi', 'Js Asakashi' => 'JS Asakashi',
|
||||||
|
'Lemforder' => 'LEMFORDER',
|
||||||
|
'Man' => 'MAN',
|
||||||
|
'Volvo' => 'VOLVO',
|
||||||
|
'Ctp', 'Costex Tractor Parts', => 'CTP',
|
||||||
|
'Czd' => 'CZD',
|
||||||
|
'Lavr' => 'LAVR',
|
||||||
|
'Wai' => 'WAI',
|
||||||
|
'Asam' => 'ASAM',
|
||||||
|
'Bmw' => 'BMW',
|
||||||
|
'Brisk' => 'BRISK',
|
||||||
|
'Fenox' => 'FENOX',
|
||||||
|
'Gm', 'General Motors' => 'GENERAL MOTORS',
|
||||||
|
'Idemitsu' => 'IDEMITSU',
|
||||||
|
'Krauf' => 'KRAUF',
|
||||||
|
'Liqui Moly', 'Lm' => 'LIQUI MOLY',
|
||||||
|
'Mazda' => 'MAZDA',
|
||||||
|
'Musashi' => 'MUSASHI',
|
||||||
|
'Seiken' => 'SEIKEN',
|
||||||
|
'Totachi' => 'TOTACHI',
|
||||||
|
'Trialli' => 'TRIALLI',
|
||||||
|
'Dong Feng', 'Dongfeng', 'Dongfeng Motors', 'Dfm' => 'DONGFENG',
|
||||||
|
'Miles' => 'MILES',
|
||||||
|
'Sidem' => 'SIDEM',
|
||||||
|
'Stellox' => 'STELLOX',
|
||||||
|
'Tokico' => 'TOKICO',
|
||||||
|
'Phc Valeo', 'Valeo Phc' => 'Valeo PHC',
|
||||||
|
'Точка Опоры' => 'ТОЧКА ОПОРЫ',
|
||||||
|
'Jikiu' => 'JIKIU',
|
||||||
|
'Lada' => 'LADA',
|
||||||
|
'Mitasu' => 'MITASU',
|
||||||
|
'Neolux' => 'NEOLUX',
|
||||||
|
'Pilenga' => 'PILENGA',
|
||||||
|
'Renault' => 'RENAULT',
|
||||||
|
'Startvolt' => 'STARTVOLT',
|
||||||
|
'Zic' => 'ZIC',
|
||||||
|
'Автодело' => 'АВТОДЕЛО',
|
||||||
|
'Berkut' => 'BERKUT',
|
||||||
|
'Fiat' => 'FIAT',
|
||||||
|
'Profix' => 'PROFIX',
|
||||||
|
'Sampa' => 'SAMPA',
|
||||||
|
'Topfils' => 'TOPFILS',
|
||||||
|
'Uaz', 'Уаз' => 'UAZ',
|
||||||
|
'Тольятти-тза', 'Тольятти-Тза', 'Тольятти Тза', 'Тольяттитза' => 'Тольятти-ТЗА',
|
||||||
|
'Aywiparts' => 'AYWIPARTS',
|
||||||
|
'Сatterpillar', 'Cat', 'Catterpillar Inc' => 'CAT',
|
||||||
|
'Difa', 'Дифа' => 'DIFA',
|
||||||
|
'Nisshimbo' => 'NISSHINBO',
|
||||||
|
'Ruei' => 'RUEI',
|
||||||
|
'Vic' => 'VIC',
|
||||||
|
'Auto-gur', 'Auto-Gur', 'Auto Gur' => 'AUTO-GUR',
|
||||||
|
'Daejin' => 'DAEJIN',
|
||||||
|
'Gbrake' => 'G-brake',
|
||||||
|
'Img' => 'IMG',
|
||||||
|
'Kortex' => 'KORTEX',
|
||||||
|
'Koyo' => 'KOYO',
|
||||||
|
'Peugeot/citroen', 'Peugeot/Citroen', 'Peugeot-citroen', 'Peugeot-Citroen' => 'PEUGEOT-CITROEN',
|
||||||
|
'Tangde' => 'TANGDE',
|
||||||
|
'Double-force', 'Double-Force', 'Doubleforce', 'Double Force' => 'DOUBLE FORCE',
|
||||||
|
'Just-drive', 'Just-Drive', 'Just Drive' => 'JUST DRIVE',
|
||||||
|
'Quattro-freni', 'Quattro-Freni', 'Quattro Freni' => 'QUATTRO FRENI',
|
||||||
|
'Roers Parts', 'Roers-parts', 'Roers-Parts' => 'ROTERS-PARTS',
|
||||||
|
'Tixona' => 'TIXONA',
|
||||||
|
'Zekkert' => 'ZEKKERT',
|
||||||
|
'Horex' => 'HOREX',
|
||||||
|
'Zevs', 'Зевс' => 'ZEVS',
|
||||||
|
'Aiko' => 'AIKO',
|
||||||
|
'Castrol' => 'CASTROL',
|
||||||
|
'Deko' => 'DEKO',
|
||||||
|
'Hyundai Xteer' => 'HYUNDAI XTEER',
|
||||||
|
'Dyg' => 'DYG',
|
||||||
|
'Nty' => 'NTY',
|
||||||
|
'Skf' => 'SKF',
|
||||||
|
'Alfi Parts' => 'ALFI PARTS',
|
||||||
|
'Fiestroco' => 'FIESTROCO',
|
||||||
|
'Golden Snail' => 'GOLDEN SNAIL',
|
||||||
|
'Ti-guar', 'Ti-Guar' => 'Ti-Guar',
|
||||||
|
'Cautex' => 'CAUTEX',
|
||||||
|
'Bm-motorsport', 'Bm-Motorsport' => 'BM-Motorsport',
|
||||||
|
'Маз', 'Maz' => 'MAZ',
|
||||||
|
'Брт' => 'БРТ',
|
||||||
|
'Гпз' => 'ГПЗ',
|
||||||
|
'Rm Terex' => 'Terex',
|
||||||
|
'Agm' => 'Agama',
|
||||||
|
'Tsn' => 'TSN',
|
||||||
|
'Igp', 'Isuzu Genuine Parts' => 'Isuzu',
|
||||||
|
'Etp', 'Europe Tractor Parts' => 'ETP',
|
||||||
|
'Cum' => 'Cummins',
|
||||||
|
'Xcmg' => 'XCMG',
|
||||||
|
'Sdlg' => 'SDLG',
|
||||||
|
'Xcmg-sdlg', 'Xcmg-Sdlg' => 'XCMG-SDLG',
|
||||||
|
'Vilitan' => 'ViliTan',
|
||||||
|
'Kato' => 'KATO',
|
||||||
|
'Bw' => 'Baldwin',
|
||||||
|
'Itr' => 'ITR',
|
||||||
|
'Ofm' => 'OFM',
|
||||||
|
'Kz' => 'Kezhang Mechanic',
|
||||||
|
'Dongfeng Cummins Engine Company', 'Dongfeng Cummins' => 'DCEC',
|
||||||
|
'Bomag' => 'BOMAG',
|
||||||
|
'Shehwa' => 'SHEHWA',
|
||||||
|
'Kmp Brand', 'Kmp' => 'KMP',
|
||||||
|
'Jd' => 'John Deere',
|
||||||
|
'World Gasket', 'Wg', 'World-gasket', 'World-Gasket' => 'WG',
|
||||||
|
'Original Equipment Manufacturer', 'Oem' => 'OEM',
|
||||||
|
'Case' => 'CASE',
|
||||||
|
'Jf Filtration', 'Jf' => 'JF Filtration',
|
||||||
|
'Hp' => 'HP',
|
||||||
|
'Ярославский Завод Дизельной Аппаратуры', 'Язда' => 'ЯЗДА',
|
||||||
|
'Prc' => 'PRC',
|
||||||
|
'Sf', 'Sf Filter' => 'SF Filter',
|
||||||
|
'Ga' => 'GA',
|
||||||
|
'Kentek' => 'KENTEK',
|
||||||
|
'Cgr Ghinassi', 'Gb Group' => 'Ghinassi',
|
||||||
|
'Doosan' => 'DOOSAN',
|
||||||
|
'Dressta' => 'DRESSTA',
|
||||||
|
'Ammann' => 'AMMANN',
|
||||||
|
'Blumaq' => 'BLUMAQ',
|
||||||
|
'Deutz' => 'DEUTZ',
|
||||||
|
'Daewoo' => 'DAEWOO',
|
||||||
|
'Furukawa' => 'FURUKAWA',
|
||||||
|
'Niipon' => 'NIIPON',
|
||||||
|
'Cargo' => 'CARGO',
|
||||||
|
'Wps' => 'WPS',
|
||||||
|
'Zaufer' => 'ZAUFER',
|
||||||
|
'Handok' => 'HANDOK',
|
||||||
|
'Fg Wilson', 'F.G.Wilson', 'F.g.wilson' => 'F.G.WILSON',
|
||||||
|
'Racor' => 'RACOR',
|
||||||
|
'Jcb' => 'JCB',
|
||||||
|
'Auger' => 'AUGER',
|
||||||
|
'Ekka' => 'EKKA',
|
||||||
|
'Berco' => 'BERCO',
|
||||||
|
'Bosch Rexroth' => 'BOSCH REXROTH',
|
||||||
|
'Byg' => 'BYG',
|
||||||
|
'Cgr' => 'CGR',
|
||||||
|
'Dayco' => 'DAYCO',
|
||||||
|
'Dcf' => 'DCF',
|
||||||
|
'Dunlop' => 'DUNLOP',
|
||||||
|
'Febi' => 'FeBi',
|
||||||
|
'Fleetguard' => 'FLEETGUARD',
|
||||||
|
'Foton' => 'FOTON',
|
||||||
|
'Getlf' => 'GETLF',
|
||||||
|
'Hidromek' => 'HIDROMEK',
|
||||||
|
'Mann&Hummel', 'Mann&hummel' => 'MANN&HUMMEL',
|
||||||
|
'Niitsu' => 'NIITSU',
|
||||||
|
'Nok' => 'NOK',
|
||||||
|
'Nsk' => 'NSK',
|
||||||
|
'Ntn' => 'NTN',
|
||||||
|
'Orme' => 'ORME',
|
||||||
|
'Parker-racor', 'Parker-Racor' => 'PARKER-RACOR',
|
||||||
|
'Sanz' => 'SANZ',
|
||||||
|
'Sem' => 'SEM',
|
||||||
|
'Separ' => 'SEPAR',
|
||||||
|
'Shaanxi' => 'SHAANXI',
|
||||||
|
'Shell' => 'SHELL',
|
||||||
|
'Skf' => 'SKF',
|
||||||
|
'Ssp' => 'SSP',
|
||||||
|
'Sst' => 'SST',
|
||||||
|
'Stal' => 'STAL',
|
||||||
|
'Steyr' => 'STEYR',
|
||||||
|
'Toyota' => 'TOYOTA',
|
||||||
|
'Tt' => 'Tesla Technics',
|
||||||
|
'Vag' => 'VAG',
|
||||||
|
'Wix', 'Wix Filters' => 'WIX',
|
||||||
|
'Yuchai' => 'Yuchai',
|
||||||
|
'Zexel' => 'ZEXEL',
|
||||||
|
'Dongil' => 'DONGIL',
|
||||||
|
'Sanlux' => 'SANLUX',
|
||||||
|
'Amt' => 'AMT',
|
||||||
|
'Dt' => 'DT',
|
||||||
|
'Pramo' => 'PRAMO',
|
||||||
|
'Haffen' => 'HAFFEN',
|
||||||
|
'Mfilter' => 'MFILTER',
|
||||||
|
'Hengst' => 'HENGST',
|
||||||
|
'Sofima' => 'SOFIMA',
|
||||||
|
'Dolz' => 'DOLZ',
|
||||||
|
'Element' => 'ELEMENT',
|
||||||
|
'Sardes' => 'SARDES',
|
||||||
|
'Seintex' => 'SEINTEX',
|
||||||
|
'Patron' => 'PATRON',
|
||||||
|
'Lpr' => 'LPR',
|
||||||
|
'Kaichin' => 'KAICHIN',
|
||||||
|
'Union' => 'UNION',
|
||||||
|
'Rb-exide', 'Rb-Exide' => 'RB-EXIDE',
|
||||||
|
'Kurin' => 'KURIN',
|
||||||
|
'Topfils' => 'TOPFILS',
|
||||||
|
'Knor' => 'KNOR',
|
||||||
|
'Megapower' => 'MEGAPOWER',
|
||||||
|
'Red Filter', 'Redfilter' => 'REDFilter',
|
||||||
|
'Skania' => 'SKANIA',
|
||||||
|
'Sct' => 'SCT',
|
||||||
|
'Kolbenschmidt' => 'KOLBENSCHMIDT',
|
||||||
|
'Big Filter' => 'BIG Filter',
|
||||||
|
'Alco Filter' => 'ALCO Filter',
|
||||||
|
default => $prod
|
||||||
|
};
|
||||||
|
|
||||||
|
// Запись аналогов в буфер
|
||||||
$_row['oemn'] = array_walk($analogs, 'trim');
|
$_row['oemn'] = array_walk($analogs, 'trim');
|
||||||
|
|
||||||
// Инициализация буфера поставки
|
// Инициализация буфера поставки
|
||||||
|
@ -660,6 +1004,9 @@ class Supply extends Product implements ProductInterface, OfferInterface
|
||||||
// Перенос данных в буфер (существующий в базе данных дубликат)
|
// Перенос данных в буфер (существующий в базе данных дубликат)
|
||||||
$supply->setAttributes($vars, false);
|
$supply->setAttributes($vars, false);
|
||||||
|
|
||||||
|
// Запись ребра: АККАУНТ -> ПОСТАВКА
|
||||||
|
(new AccountEdgeSupply)->write($account->readId(), $supply->readId(), 'import');
|
||||||
|
|
||||||
// Перезапись существующего документа
|
// Перезапись существующего документа
|
||||||
$supply->update();
|
$supply->update();
|
||||||
|
|
||||||
|
@ -672,7 +1019,7 @@ class Supply extends Product implements ProductInterface, OfferInterface
|
||||||
// Проверка не пройдена
|
// Проверка не пройдена
|
||||||
|
|
||||||
// Добавление ошибок
|
// Добавление ошибок
|
||||||
foreach ($supply->errors as $attribute => $error) $this->addError($attribute, $error);
|
foreach ($supply->errors as $attribute => $error) $supply->addError($attribute, $error);
|
||||||
|
|
||||||
// Запись статуса об ошибке
|
// Запись статуса об ошибке
|
||||||
$error = true;
|
$error = true;
|
||||||
|
@ -689,7 +1036,7 @@ class Supply extends Product implements ProductInterface, OfferInterface
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// Добавление в группу аналогов
|
// Добавление в группу аналогов
|
||||||
$group->writeProduct($product);
|
// $group->writeProduct($product);
|
||||||
}
|
}
|
||||||
|
|
||||||
return !$error;
|
return !$error;
|
||||||
|
@ -698,12 +1045,12 @@ class Supply extends Product implements ProductInterface, OfferInterface
|
||||||
// Запись поставки
|
// Запись поставки
|
||||||
$create($article, (int) $amount);
|
$create($article, (int) $amount);
|
||||||
|
|
||||||
foreach ($analogs as $_supply) {
|
// foreach ($analogs as $_supply) {
|
||||||
// Перебор аналогов (если найдены)
|
// // Перебор аналогов (если найдены)
|
||||||
|
|
||||||
// Запись поставки
|
// // Запись поставки
|
||||||
$create((string) $_supply);
|
// $create((string) $_supply);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -712,26 +1059,14 @@ class Supply extends Product implements ProductInterface, OfferInterface
|
||||||
if (count($imported) > 0) {
|
if (count($imported) > 0) {
|
||||||
// Успешно записана минимум 1 поставка
|
// Успешно записана минимум 1 поставка
|
||||||
|
|
||||||
// Инициализация инстанции импорта
|
foreach ($imported as $supply) {
|
||||||
$import = new Import;
|
// Перебор импортированных поставок
|
||||||
|
|
||||||
$import->file = $path;
|
// Инициализация инстанции импорта
|
||||||
$import->name = $filename;
|
$import = Import::searchByFile($file);
|
||||||
|
|
||||||
if ($import->save()) {
|
if (isset($import)) {
|
||||||
// Инстанция импорта успешно загружена
|
// Найдена интанция импорта
|
||||||
|
|
||||||
if (WarehouseEdgeImport::write(Warehouse::collectionName() . "/$warehouse", $import->readId(), data: ['type' => 'loaded'])) {
|
|
||||||
// Записано ребро: СКЛАД -> ИНСТАНЦИЯ ПОСТАВОК
|
|
||||||
|
|
||||||
// Запись в журнал инстанции импорта
|
|
||||||
$import->journal('connect_with_warehouse', [
|
|
||||||
'target' => Warehouse::collectionName() . "/$warehouse"
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($imported as $supply) {
|
|
||||||
// Перебор импортированных поставок
|
|
||||||
|
|
||||||
if (ImportEdgeSupply::write($import->readId(), $supply->readId(), data: ['type' => 'imported', 'vrsn' => ImportEdgeSupply::searchMaxVersion($supply) + 1])) {
|
if (ImportEdgeSupply::write($import->readId(), $supply->readId(), data: ['type' => 'imported', 'vrsn' => ImportEdgeSupply::searchMaxVersion($supply) + 1])) {
|
||||||
// Записано ребро: ИНСТАНЦИЯ ПОСТАВОК -> ПОСТАВКА
|
// Записано ребро: ИНСТАНЦИЯ ПОСТАВОК -> ПОСТАВКА
|
||||||
|
@ -745,23 +1080,25 @@ class Supply extends Product implements ProductInterface, OfferInterface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Макрос действий после импорта
|
// Запись статуса
|
||||||
static::afterImportExcel($created, $updated);
|
$file->stts = 'loaded';
|
||||||
|
|
||||||
|
if ($file->update() > 0) {
|
||||||
|
// Удалось записать в базу данных
|
||||||
|
|
||||||
|
// Запись в журнал
|
||||||
|
$file->journal('loaded');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Макрос действий после загрузки
|
||||||
|
static::afterLoadExcel($account, $created, $updated);
|
||||||
|
|
||||||
// Удаление (важно именно задать null для формы в представлении)
|
// Удаление (важно именно задать null для формы в представлении)
|
||||||
$this->file_excel = null;
|
$supply->file_excel = null;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Запись ошибки
|
// Запись ошибки
|
||||||
$this->addError('errors', 'Не пройдена проверка параметров');
|
$supply->addError('errors', 'Не пройдена проверка параметров');
|
||||||
|
|
||||||
// Макрос действий после импорта
|
|
||||||
static::afterImportExcel($created, $updated);
|
|
||||||
|
|
||||||
// Удаление (важно именно задать null для формы в представлении)
|
|
||||||
$this->file_excel = null;
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -974,16 +1311,59 @@ class Supply extends Product implements ProductInterface, OfferInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Вызывается после загрузки поставок из excel-документа
|
* Вызывается после загрузки excel-документа на сервер
|
||||||
*
|
*
|
||||||
|
* @param static|null $account Аккаунт
|
||||||
|
* @param string|int $warehouse Склад
|
||||||
|
*
|
||||||
|
* @return bool Статус выполнения
|
||||||
|
*/
|
||||||
|
public static function afterImportExcel(Account|int $account = null, string|int $warehouse = 'неизвестен'): bool
|
||||||
|
{
|
||||||
|
// Инициализация аккаунта
|
||||||
|
$account = Account::initAccount($account);
|
||||||
|
|
||||||
|
// Отправка уведомления о загрузке
|
||||||
|
$save = Notification::_write("Загружены товары для склада \"$warehouse\"", account: $account->_key);
|
||||||
|
|
||||||
|
// Инициализация периода
|
||||||
|
$period = new DatePeriod(new DateTime('@' . strtotime("00:00:00")), new DateInterval('PT5M'), new DateTime('@' . strtotime("next day 00:00:00")));
|
||||||
|
|
||||||
|
foreach($period as $date){
|
||||||
|
// Перебор периодов
|
||||||
|
|
||||||
|
if (($converted = $date->format('U')) > $time = time()) {
|
||||||
|
// Найден интервал из будущего времени (предполагается, что ближайший по причине остановки выполнения далее)
|
||||||
|
|
||||||
|
// Запись даты
|
||||||
|
$date = (new DateTime('@' . ($converted - $time)))->format('H:i:s');
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($date instanceof DateTime) $date = '5:00';
|
||||||
|
|
||||||
|
// Отправка уведомления об обработке
|
||||||
|
$handle = Notification::_write("Следующее обновление товаров начнётся через $date", account: $account->_key);
|
||||||
|
|
||||||
|
return $save && $handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Вызывается после загрузки поставок из excel-документа в базу данных
|
||||||
|
*
|
||||||
|
* @param static|null $account Аккаунт
|
||||||
* @param int $created Количество созданных документов
|
* @param int $created Количество созданных документов
|
||||||
* @param int $updated Количество обновлённых документов
|
* @param int $updated Количество обновлённых документов
|
||||||
|
*
|
||||||
|
* @return bool Статус выполнения
|
||||||
*/
|
*/
|
||||||
public static function afterImportExcel(int $created = 0, int $updated = 0): bool
|
public static function afterLoadExcel(Account|int $account = null, int $created = 0, int $updated = 0): bool
|
||||||
{
|
{
|
||||||
// Инициализация параметров
|
// Инициализация параметров
|
||||||
$model = new Notification;
|
$model = new Notification;
|
||||||
$account = yii::$app->user->identity;
|
$account = Account::initAccount($account);
|
||||||
|
|
||||||
// Инициализация часового пояса
|
// Инициализация часового пояса
|
||||||
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone);
|
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone);
|
||||||
|
@ -993,8 +1373,9 @@ class Supply extends Product implements ProductInterface, OfferInterface
|
||||||
$date = (new DateTime('now', new DateTimeZone($timezone)))->format('H:i d.m.Y');
|
$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('created', 'updated', 'date'));
|
$model->text = yii::$app->controller->renderPartial('@app/views/notification/system/afterLoadExcel', compact('created', 'updated', 'date'));
|
||||||
$model->type = $model::TYPE_NOTICE;
|
$model->type = $model::TYPE_NOTICE;
|
||||||
|
$model->account = $account->readId();
|
||||||
|
|
||||||
// Отправка
|
// Отправка
|
||||||
return (bool) $model->write();
|
return (bool) $model->write();
|
||||||
|
|
|
@ -67,7 +67,7 @@ class Dellin extends Model
|
||||||
*
|
*
|
||||||
* @param int $from Идентификатор терминала Dellin
|
* @param int $from Идентификатор терминала Dellin
|
||||||
* @param int $to Идентификатор терминала Dellin
|
* @param int $to Идентификатор терминала Dellin
|
||||||
* @param int $weight Вес (г)
|
* @param int $weight Вес (кг)
|
||||||
* @param int $x Ширина (cм)
|
* @param int $x Ширина (cм)
|
||||||
* @param int $y Высота (cм)
|
* @param int $y Высота (cм)
|
||||||
* @param int $z Длинна (cм)
|
* @param int $z Длинна (cм)
|
||||||
|
@ -101,9 +101,6 @@ class Dellin extends Model
|
||||||
$y /= 100;
|
$y /= 100;
|
||||||
$z /= 100;
|
$z /= 100;
|
||||||
|
|
||||||
// Конвертация из граммов в килограммы
|
|
||||||
$weight /= 1000;
|
|
||||||
|
|
||||||
// Вычисление самой крупной стороны, так как ДеловыеЛинии имеют ограничения на все три поля и у длинны оно больше всех
|
// Вычисление самой крупной стороны, так как ДеловыеЛинии имеют ограничения на все три поля и у длинны оно больше всех
|
||||||
if ($x > $z && $x > $y) {
|
if ($x > $z && $x > $y) {
|
||||||
// "X" больше всех
|
// "X" больше всех
|
||||||
|
@ -295,15 +292,19 @@ class Dellin extends Model
|
||||||
if (is_null($account)) {
|
if (is_null($account)) {
|
||||||
// Данные аккаунта не переданы
|
// Данные аккаунта не переданы
|
||||||
|
|
||||||
if (yii::$app->user->isGuest) {
|
if (isset(yii::$app->user)) {
|
||||||
// Аккаунт не аутентифицирован
|
if (yii::$app->user->isGuest) {
|
||||||
|
// Аккаунт не аутентифицирован
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
} else {
|
||||||
|
// Аккаунт аутентифицирован
|
||||||
|
|
||||||
|
// Инициализация
|
||||||
|
$account = yii::$app->user->identity;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Аккаунт аутентифицирован
|
return 0;
|
||||||
|
|
||||||
// Инициализация
|
|
||||||
$account = yii::$app->user->identity;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (is_int($account)) {
|
if (is_int($account)) {
|
||||||
|
|
|
@ -70,7 +70,7 @@ use app\models\AccountForm;
|
||||||
<?= $form->field($model, 'mail', ['enableLabel' => false, 'options' => ['class' => 'mb-2'], 'inputOptions' => ['class' => 'form-control button_clean'], 'errorOptions' => ['class' => 'help-block help-block-error px-2 small']])->textInput(['autofocus' => true, 'placeholder' => $model->getAttributeLabel('mail')]) ?>
|
<?= $form->field($model, 'mail', ['enableLabel' => false, 'options' => ['class' => 'mb-2'], 'inputOptions' => ['class' => 'form-control button_clean'], 'errorOptions' => ['class' => 'help-block help-block-error px-2 small']])->textInput(['autofocus' => true, 'placeholder' => $model->getAttributeLabel('mail')]) ?>
|
||||||
<?= $form->field($model, 'pswd', ['enableLabel' => false, 'inputOptions' => ['class' => 'form-control button_clean'], 'errorOptions' => ['class' => 'help-block help-block-error px-2 small']])->passwordInput(['placeholder' => $model->getAttributeLabel('pswd')]) ?>
|
<?= $form->field($model, 'pswd', ['enableLabel' => false, 'inputOptions' => ['class' => 'form-control button_clean'], 'errorOptions' => ['class' => 'help-block help-block-error px-2 small']])->passwordInput(['placeholder' => $model->getAttributeLabel('pswd')]) ?>
|
||||||
|
|
||||||
<div class="d-flex mb-2 mt-4">
|
<div class="d-flex mb-2 mt-3">
|
||||||
<?= Html::submitButton('Войти', ['name' => 'submitAuthentication', 'onclick' => 'authentication(this.parentElement.parentElement, \'' . $target . '\');', 'class' => 'flex-grow-1 mr-2 btn btn-primary button_clean']) ?>
|
<?= Html::submitButton('Войти', ['name' => 'submitAuthentication', 'onclick' => 'authentication(this.parentElement.parentElement, \'' . $target . '\');', 'class' => 'flex-grow-1 mr-2 btn btn-primary button_clean']) ?>
|
||||||
<?= $form->field($model, 'auto', ['checkboxTemplate' => '<div class="checkbox button_clean">{beginLabel}' .
|
<?= $form->field($model, 'auto', ['checkboxTemplate' => '<div class="checkbox button_clean">{beginLabel}' .
|
||||||
Html::submitButton('{labelTitle}', ['name' => 'submit', 'data-toggle' => 'button', 'class' => 'w-100 btn btn-primary button_clean', 'aria-pressed' => 'false', 'onclick' => 'return authentication_auto_button_status_switch(this);']) .
|
Html::submitButton('{labelTitle}', ['name' => 'submit', 'data-toggle' => 'button', 'class' => 'w-100 btn btn-primary button_clean', 'aria-pressed' => 'false', 'onclick' => 'return authentication_auto_button_status_switch(this);']) .
|
||||||
|
@ -78,6 +78,7 @@ use app\models\AccountForm;
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?= Html::submitButton('Регистрация', ['name' => 'submitRegistration', 'onclick' => 'return registration_start(this.parentElement, \'' . $target . '\');', 'class' => 'col-12 ml-auto btn btn-success btn-sm button_clean']) ?>
|
<?= Html::submitButton('Регистрация', ['name' => 'submitRegistration', 'onclick' => 'return registration_start(this.parentElement, \'' . $target . '\');', 'class' => 'col-12 ml-auto btn btn-success btn-sm button_clean']) ?>
|
||||||
|
<small class="d-flex mt-2"><a class="mx-auto text-dark" type="button" onclick="restore(this.parentElement.parentElement)">Восстановить пароль</a></small>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use app\models\Product;
|
||||||
|
use app\models\Account;
|
||||||
|
use app\models\Settings;
|
||||||
|
|
||||||
|
// Инициализация счетчика аккаунтов
|
||||||
|
$i = $amount * ($page - 1);
|
||||||
|
|
||||||
|
// Инициализация часового пояса
|
||||||
|
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone);
|
||||||
|
$timezone = $timezone[1][0];
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php if ($page > 1) : ?>
|
||||||
|
<div class="dropdown-divider mb-3"></div>
|
||||||
|
<?php endif ?>
|
||||||
|
|
||||||
|
<?php foreach ($accounts ?? [] as $account) : ?>
|
||||||
|
<?php
|
||||||
|
foreach ($account->jrnl ?? [] as $jrnl) {
|
||||||
|
// Перебор записей в журнале
|
||||||
|
|
||||||
|
if ($jrnl['action'] === 'create') {
|
||||||
|
// Найдена дата создания
|
||||||
|
|
||||||
|
// Инициализация даты
|
||||||
|
$create = (new DateTime())->setTimestamp($jrnl['date'])->setTimezone(new DateTimeZone($timezone))->format('d.m.Y') ?? 'Неизвестно';
|
||||||
|
|
||||||
|
// Выход из цикла
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="mb-3 row">
|
||||||
|
<div class="pr-0 col-auto"><?= ++$i ?>.</div>
|
||||||
|
<div class="pr-0 col overflow-hidden" title="ФИО">
|
||||||
|
<?= $account->name ?? 'Неизвестно' ?>
|
||||||
|
</div>
|
||||||
|
<div class="my-auto pr-0 col-auto" title="Псевдоним">
|
||||||
|
<?= $account->indx ?? '' ?>
|
||||||
|
</div>
|
||||||
|
<div class="my-auto pr-0 col-auto" title="Тип аккаунта">
|
||||||
|
<?= $account->agnt ? 'Поставщик' : 'Покупатель' ?>
|
||||||
|
</div>
|
||||||
|
<div class="mr-3 my-auto pr-0 col-2" title="Уровень авторизации">
|
||||||
|
<?= $account->type() ?>
|
||||||
|
</div>
|
||||||
|
<div class="my-auto pr-0 col-auto text-right" title="Дата регистрации">
|
||||||
|
<?= $create ?? 'Неизвестно' ?>
|
||||||
|
</div>
|
||||||
|
<a class="my-auto col-auto fas fa-trash-alt text-dark" type="button" onclick="page_profile_supplies_delete()"></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if ($i < count($accounts) + $amount * ($page - 1)) : ?>
|
||||||
|
<div class="dropdown-divider mb-3"></div>
|
||||||
|
<?php endif ?>
|
||||||
|
<?php endforeach ?>
|
|
@ -122,7 +122,7 @@ use DateTime;
|
||||||
<p title="Ориентировочно"><i class="mr-1 fas $icon"></i> <b>~</b>$days дн</p>
|
<p title="Ориентировочно"><i class="mr-1 fas $icon"></i> <b>~</b>$days дн</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-2 my-auto mr-3 text-right">
|
<div class="col-2 my-auto mr-3 text-right">
|
||||||
{$supply['cost']} {$supply['currency']}
|
{$supply['supply']->cost} {$supply['currency']}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
|
@ -223,20 +223,12 @@ use DateTime;
|
||||||
<script src="/js/textarea.js" defer></script>
|
<script src="/js/textarea.js" defer></script>
|
||||||
<script src="/js/cart.js" defer></script>
|
<script src="/js/cart.js" defer></script>
|
||||||
<script src="/js/profile.js" defer></script>
|
<script src="/js/profile.js" defer></script>
|
||||||
<script defer>
|
<script>
|
||||||
if (document.readyState === "complete") {
|
document.addEventListener('cart.loaded', function(e) {
|
||||||
cart_cost_calculate();
|
cart_cost_calculate();
|
||||||
|
|
||||||
cart_registration_entity_init(<?= $account['_key'] ?>);
|
cart_registration_entity_init(<?= $account['_key'] ?>);
|
||||||
|
|
||||||
cart_registration_choose('cart_registration_entity', <?= $account['_key'] ?>);
|
cart_registration_choose('cart_registration_entity', <?= $account['_key'] ?>);
|
||||||
} else {
|
});
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
cart_cost_calculate();
|
|
||||||
|
|
||||||
cart_registration_entity_init(<?= $account['_key'] ?>);
|
|
||||||
|
|
||||||
cart_registration_choose('cart_registration_entity', <?= $account['_key'] ?>);
|
|
||||||
}, false);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -5,10 +5,10 @@ declare(strict_types=1);
|
||||||
$this->title = 'SkillParts';
|
$this->title = 'SkillParts';
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<link href="/css/ticker.css" rel="stylesheet">
|
<link href="/css/hotline.css" rel="stylesheet">
|
||||||
|
|
||||||
<div id="page_index" class="mb-auto">
|
<div id="page_index" class="mb-auto">
|
||||||
<section class="info_panel mb-4 unselectable">
|
<section class="info_panel unselectable">
|
||||||
<div class="container h-100 d-flex flex-column justify-content-center">
|
<div class="container h-100 d-flex flex-column justify-content-center">
|
||||||
<h1 class="mb-4 ml-0 gilroy">Проблема с подбором запчастей?</h1>
|
<h1 class="mb-4 ml-0 gilroy">Проблема с подбором запчастей?</h1>
|
||||||
<p class="ml-0 d-flex">
|
<p class="ml-0 d-flex">
|
||||||
|
@ -21,22 +21,22 @@ $this->title = 'SkillParts';
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="h-100 d-flex ticker unselectable">
|
<section id="hotline" class="py-4 hotline unselectable" data-hotline="true" data-hotline-step="1">
|
||||||
<img class="w-auto h-100 mr-3 my-auto" src="/img/logos/h32px/compressed/cummins.png" alt="Cummins">
|
<article><img src="/img/logos/h32px/compressed/cummins.png" alt="Cummins"></article>
|
||||||
<img class="w-auto h-100 mr-3 my-auto" src="/img/logos/h32px/compressed/iveco.png" alt="Iveco">
|
<article><img src="/img/logos/h32px/compressed/iveco.png" alt="Iveco"></article>
|
||||||
<img class="w-auto h-100 mr-3 my-auto" src="/img/logos/h32px/compressed/komatsu.png" alt="Komatsu">
|
<article><img src="/img/logos/h32px/compressed/komatsu.png" alt="Komatsu"></article>
|
||||||
<img class="w-auto h-100 mr-3 my-auto" src="/img/logos/h32px/compressed/case.png" alt="Case">
|
<article><img src="/img/logos/h32px/compressed/case.png" alt="Case"></article>
|
||||||
<img class="w-auto h-100 mr-3 my-auto" src="/img/logos/h32px/compressed/isuzu.png" alt="Isuzu">
|
<article><img src="/img/logos/h32px/compressed/isuzu.png" alt="Isuzu"></article>
|
||||||
<img class="w-auto h-100 mr-3 my-auto" src="/img/logos/h32px/compressed/new_holland.png" alt="New Holland">
|
<article><img src="/img/logos/h32px/compressed/new_holland.png" alt="New Holland"></article>
|
||||||
<img class="w-auto h-100 mr-3 my-auto" src="/img/logos/h32px/compressed/perkins.png" alt="Perkins">
|
<article><img src="/img/logos/h32px/compressed/perkins.png" alt="Perkins"></article>
|
||||||
<img class="w-auto h-100 mr-3 my-auto" src="/img/logos/h32px/compressed/john_deere.png" alt="John Deere">
|
<article><img src="/img/logos/h32px/compressed/john_deere.png" alt="John Deere"></article>
|
||||||
<img class="w-auto h-100 mr-3 my-auto" src="/img/logos/h32px/compressed/caterpillar.png" alt="Caterpillar">
|
<article><img src="/img/logos/h32px/compressed/caterpillar.png" alt="Caterpillar"></article>
|
||||||
<img class="w-auto h-100 mr-3 my-auto" src="/img/logos/h32px/compressed/shantui.png" alt="Shantui">
|
<article><img src="/img/logos/h32px/compressed/shantui.png" alt="Shantui"></article>
|
||||||
<img class="w-auto h-100 mr-3 my-auto" src="/img/logos/h32px/compressed/xcmg.png" alt="XCMG">
|
<article><img src="/img/logos/h32px/compressed/xcmg.png" alt="XCMG"></article>
|
||||||
<img class="w-auto h-100 mr-3 my-auto" src="/img/logos/h32px/compressed/kobelco.png" alt="Kobelco">
|
<article><img src="/img/logos/h32px/compressed/kobelco.png" alt="Kobelco"></article>
|
||||||
<img class="w-auto h-100 mr-3 my-auto" src="/img/logos/h32px/compressed/shehwa.png" alt="SHEHWA">
|
<article><img src="/img/logos/h32px/compressed/shehwa.png" alt="SHEHWA"></article>
|
||||||
<img class="w-auto h-100 mr-3 my-auto" src="/img/logos/h32px/compressed/bomag.png" alt="BOMAG">
|
<article><img src="/img/logos/h32px/compressed/bomag.png" alt="BOMAG"></article>
|
||||||
<img class="w-auto h-100 mr-3 my-auto" src="/img/logos/h32px/compressed/hitachi.png" alt="Hitachi">
|
<article><img src="/img/logos/h32px/compressed/hitachi.png" alt="Hitachi"></article>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="container mb-4">
|
<section class="container mb-4">
|
||||||
|
@ -80,5 +80,13 @@ $this->title = 'SkillParts';
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/ticker.js" defer></script>
|
<script src="/js/hotline.js" defer></script>
|
||||||
<script src="/js/text.js" defer></script>
|
<script src="/js/text.js" defer></script>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('hotline.loaded', function(e) {
|
||||||
|
// Загружена программа: "бегущая строка"
|
||||||
|
|
||||||
|
// Обработка HTML-документа и генерация бегущих строк
|
||||||
|
e.detail.hotline.preprocessing();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use app\models\Settings;
|
use app\models\Settings;
|
||||||
|
use app\models\Product;
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
@ -133,9 +134,7 @@ use app\models\Settings;
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td style="text-align: center; border: solid; border-top: thick; border-left: thick;" colspan="1" rowspan="2" valign="center"><b>№</b></td>
|
<td style="text-align: center; border: solid; border-top: thick; border-left: thick;" colspan="1" rowspan="2" valign="center"><b>№</b></td>
|
||||||
<td style="text-align: center; border: solid; border-top: thick;" colspan="3" rowspan="2" valign="center"><b>Производитель</b></td>
|
<td style="text-align: center; border: solid; border-top: thick;" colspan="6" rowspan="2" valign="center"><b>Товар</b></td>
|
||||||
<td style="text-align: center; border: solid; border-top: thick;" colspan="3" rowspan="2" valign="center"><b>Товар</b></td>
|
|
||||||
<td style="text-align: center; border: solid; border-top: thick;" colspan="2" rowspan="2" valign="center"><b>Поставщик</b></td>
|
|
||||||
<td style="text-align: center; border: solid; border-top: thick;" colspan="2" rowspan="2" valign="center"><b>Количество</b></td>
|
<td style="text-align: center; border: solid; border-top: thick;" colspan="2" rowspan="2" valign="center"><b>Количество</b></td>
|
||||||
<td style="text-align: center; border: solid; border-top: thick;" colspan="2" rowspan="2" valign="center"><b>Цена</b></td>
|
<td style="text-align: center; border: solid; border-top: thick;" colspan="2" rowspan="2" valign="center"><b>Цена</b></td>
|
||||||
<td style="text-align: center; border: solid; border-top: thick; border-right: thick;" colspan="2" rowspan="2" valign="center"><b>Сумма</b></td>
|
<td style="text-align: center; border: solid; border-top: thick; border-right: thick;" colspan="2" rowspan="2" valign="center"><b>Сумма</b></td>
|
||||||
|
@ -156,11 +155,13 @@ use app\models\Settings;
|
||||||
<?php foreach ($data['supplies'] as $prod => $supplies) : ?>
|
<?php foreach ($data['supplies'] as $prod => $supplies) : ?>
|
||||||
<?php foreach ($supplies as $catn => $deliveries) : ?>
|
<?php foreach ($supplies as $catn => $deliveries) : ?>
|
||||||
<?php foreach ($deliveries as $delivery => $supply) : ?>
|
<?php foreach ($deliveries as $delivery => $supply) : ?>
|
||||||
|
<?php
|
||||||
|
// Инициализация названия
|
||||||
|
$name = Product::searchByCatn($catn)->name ?? 'Без названия';
|
||||||
|
?>
|
||||||
<tr>
|
<tr>
|
||||||
<td style="text-align: center; border: solid; border-left: thick;" colspan="1" valign="center"><?= $row++ ?></td>
|
<td style="text-align: center; border: solid; border-left: thick;" colspan="1" valign="center"><?= $row++ ?></td>
|
||||||
<td style="text-align: left; border: solid;" colspan="3" valign="center"><?= $prod ?></td>
|
<td style="text-align: left; border: solid;" colspan="6" valign="center"><?= $prod ?> <?= $catn ?> <?= $name ?></td>
|
||||||
<td style="text-align: left; border: solid;" colspan="3" valign="center"><?= $catn ?></td>
|
|
||||||
<td style="text-align: left; border: solid;" colspan="2" valign="center"><?= $supply['account']['indx'] ?></td>
|
|
||||||
<td style="text-align: center; border: solid;" colspan="2" valign="center"><?= $supply['amount'] ?></td>
|
<td style="text-align: center; border: solid;" colspan="2" valign="center"><?= $supply['amount'] ?></td>
|
||||||
<td style="text-align: center; border: solid;" valign="center"><?= $supply['cost'] * $supply['amount'] ?></td>
|
<td style="text-align: center; border: solid;" valign="center"><?= $supply['cost'] * $supply['amount'] ?></td>
|
||||||
<td style="text-align: center; border: solid;" valign="center"><?= $supply['currency'] ?></td>
|
<td style="text-align: center; border: solid;" valign="center"><?= $supply['currency'] ?></td>
|
||||||
|
|
|
@ -50,6 +50,7 @@ AppAsset::register($this);
|
||||||
<menu class="col-auto col-lg-4 mb-0 d-flex justify-content-end"></menu>
|
<menu class="col-auto col-lg-4 mb-0 d-flex justify-content-end"></menu>
|
||||||
</div>
|
</div>
|
||||||
<div class="h-divider"></div>
|
<div class="h-divider"></div>
|
||||||
|
<script src="/js/js.cookie.min.js" defer></script>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<aside class="container mb-4">
|
<aside class="container mb-4">
|
||||||
|
@ -110,6 +111,7 @@ AppAsset::register($this);
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<script src="/js/loading.js" defer></script>
|
||||||
<?php $this->endBody() ?>
|
<?php $this->endBody() ?>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
<div style="padding: 0 14%;">
|
||||||
|
<div style="background: #fff;">
|
||||||
|
<a title="SkillParts" href="https://skillparts.ru">
|
||||||
|
<img style="width: 150px;" src="https://skillparts.ru/img/logos/skillparts.png" alt="SkillParts">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div style="background: #f0eefb; padding: 40px; margin: 30px 0;">
|
||||||
|
<h3 style="text-align: center; margin-bottom: 30px;"><b>Новый пароль</b></h3>
|
||||||
|
<p style="margin: 0 40px; margin-bottom: 8px;">По вашему запросу сгенерирован новый пароль: <b><?= $pswd ?? 'ОШИБКА' ?></b></p>
|
||||||
|
</div>
|
||||||
|
<div style="background: #fff;">
|
||||||
|
<small>Если это были не вы свяжитесь с администрацией</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,15 @@
|
||||||
|
<div style="padding: 0 14%;">
|
||||||
|
<div style="background: #fff;">
|
||||||
|
<a title="SkillParts" href="https://skillparts.ru">
|
||||||
|
<img style="width: 150px;" src="https://skillparts.ru/img/logos/skillparts.png" alt="SkillParts">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div style="background: #f0eefb; padding: 40px; margin: 30px 0;">
|
||||||
|
<h3 style="text-align: center; margin-bottom: 30px;"><b>Генерация нового пароля</b></h3>
|
||||||
|
<p style="margin: 0 40px; margin-bottom: 8px;">Только что был получен запрос на генерацию нового пароля для вашего аккаунта</p>
|
||||||
|
<a style="display: block; text-align: center;" href="https://skillparts.ru/restore/<?= $id ?? '' ?>/<?= $chpk ?? '' ?>">Подтвердить</a>
|
||||||
|
</div>
|
||||||
|
<div style="background: #fff;">
|
||||||
|
<small>Если это были не вы, проигнорируйте это письмо</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -10,8 +10,6 @@
|
||||||
<a style="display: block; text-align: center;" href="https://skillparts.loc/suppliers/request">Повторная заявка</a>
|
<a style="display: block; text-align: center;" href="https://skillparts.loc/suppliers/request">Повторная заявка</a>
|
||||||
</div>
|
</div>
|
||||||
<div style="background: #fff;">
|
<div style="background: #fff;">
|
||||||
<small>Вы получили это сообщение потому, что на ваш почтовый адрес была совершена регистрация</small>
|
<small>Если это были не вы свяжитесь с администрацией</small>
|
||||||
</br>
|
|
||||||
<small>Если это были не вы, проверьте безопасность ваших аккаунтов и свяжитесь с администрацией</small>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -13,6 +13,6 @@
|
||||||
<div style="background: #fff;">
|
<div style="background: #fff;">
|
||||||
<small>Вы получили это сообщение потому, что на ваш почтовый адрес была совершена регистрация</small>
|
<small>Вы получили это сообщение потому, что на ваш почтовый адрес была совершена регистрация</small>
|
||||||
</br>
|
</br>
|
||||||
<small>Если это были не вы, проверьте безопасность ваших аккаунтов и свяжитесь с администрацией</small>
|
<small>Если это были не вы свяжитесь с администрацией</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use yii;
|
||||||
|
?>
|
||||||
|
|
||||||
<link href="/css/pages/offer.css" rel="stylesheet">
|
<link href="/css/pages/offer.css" rel="stylesheet">
|
||||||
|
|
||||||
<div id="page_offer" class="container mb-auto py-3">
|
<div id="page_offer" class="container mb-auto py-3">
|
||||||
|
@ -42,8 +49,10 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<?php if (!yii::$app->user->isGuest): ?>
|
||||||
<div class="row mb-0 justify-content-center">
|
<div class="row mb-0 justify-content-center">
|
||||||
<a class="col-auto text-center text-white btn button_blue button_clean" href="/offer/accept">Принять</a>
|
<a class="col-auto text-center text-white btn button_blue button_clean" href="/offer/accept">Принять</a>
|
||||||
</div>
|
</div>
|
||||||
|
<?php endif ?>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use yii;
|
||||||
|
?>
|
||||||
|
|
||||||
<link href="/css/pages/offer.css" rel="stylesheet">
|
<link href="/css/pages/offer.css" rel="stylesheet">
|
||||||
|
|
||||||
<div id="page_offer" class="container mb-auto py-3">
|
<div id="page_offer" class="container mb-auto py-3">
|
||||||
|
@ -54,8 +61,10 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<?php if (!yii::$app->user->isGuest): ?>
|
||||||
<div class="row mb-0 justify-content-center">
|
<div class="row mb-0 justify-content-center">
|
||||||
<a class="col-auto text-center text-white btn button_blue button_clean" href="/offer/accept-suppliers">Принять</a>
|
<a class="col-auto text-center text-white btn button_blue button_clean" href="/offer/accept-suppliers">Принять</a>
|
||||||
</div>
|
</div>
|
||||||
|
<?php endif ?>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -40,170 +40,13 @@ if (empty($window)) {
|
||||||
<label class="btn button_white mb-0" for="orders_panel_orders">Мои заказы</label>
|
<label class="btn button_white mb-0" for="orders_panel_orders">Мои заказы</label>
|
||||||
</div>
|
</div>
|
||||||
<input type="radio" id="orders_panel_moderation" name="main_panel" <?= $window === 'orders_panel_moderation' ? 'checked' : null ?> />
|
<input type="radio" id="orders_panel_moderation" name="main_panel" <?= $window === 'orders_panel_moderation' ? 'checked' : null ?> />
|
||||||
<article>
|
<article id="orders_panel_moderation_list">
|
||||||
<div class="orders_panel_moderation_menu mb-3">
|
<div class="orders_panel_moderation_menu mb-3">
|
||||||
<label class="btn btn-sm button_white mb-0" onclick="return orders_read('@last', '@all', null, null, 'orders_panel_moderation');">Все</label>
|
<label class="btn btn-sm button_white mb-0" onclick="return orders_read('@last', '@all', null, null, 'orders_panel_moderation');">Все</label>
|
||||||
<?php foreach(Order::statusListInRussian() as $id => $label) : ?>
|
<?php foreach(Order::statusListInRussian() as $id => $label) : ?>
|
||||||
<label class="btn btn-sm button_white mb-0 ml-2" onclick="return orders_read('@last', '<?= $id ?>', null, null, 'orders_panel_moderation');"><?= $label ?></label>
|
<label class="btn btn-sm button_white mb-0 ml-2" onclick="return orders_read('@last', '<?= $id ?>', null, null, 'orders_panel_moderation');"><?= $label ?></label>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</div>
|
</div>
|
||||||
<?php if (!empty($moderator_data)) : ?>
|
|
||||||
<?php foreach ($moderator_data as $moderator_data) : ?>
|
|
||||||
<div id="<?= $moderator_data['order']->_key ?>_panel" class="page_order_panel mb-2 py-3 px-4 rounded">
|
|
||||||
<h5 class="row mt-1 mb-3">
|
|
||||||
<?php
|
|
||||||
// Инициализация времени отправки заказа
|
|
||||||
$date = time();
|
|
||||||
|
|
||||||
foreach ($moderator_data['order']->jrnl as $entry) {
|
|
||||||
// Перебор записей в журнале
|
|
||||||
|
|
||||||
if ($entry['action'] === 'requested') {
|
|
||||||
// Найдена запись со временем запроса заказа
|
|
||||||
|
|
||||||
if (empty($date) || $date <= $entry['date']) {
|
|
||||||
// Буфер не инициализирован или в него записано более старое событие
|
|
||||||
|
|
||||||
// Запись в буфер
|
|
||||||
$date = $entry['date'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone);
|
|
||||||
$timezone = $timezone[1][0];
|
|
||||||
|
|
||||||
// Конвертация данных из буфера
|
|
||||||
$date = [
|
|
||||||
'H:i' => (new DateTime())->setTimestamp($date)->setTimezone(new DateTimeZone($timezone))->format('H:i'),
|
|
||||||
'm.d.Y' => (new DateTime())->setTimestamp($date)->setTimezone(new DateTimeZone($timezone))->format('d.m.Y')
|
|
||||||
];
|
|
||||||
|
|
||||||
?>
|
|
||||||
<p class="col-auto ml-1 font-weight-bold">#<?= $moderator_data['order']->_key ?></p>
|
|
||||||
<p class="col-auto mr-1 font-weight-bold">
|
|
||||||
<span><small><small><?= $date['H:i'] ?? 'Неизвестно' ?></small></small></span>
|
|
||||||
<span><?= $date['m.d.Y'] ?? 'Неизвестно' ?></span>
|
|
||||||
</p>
|
|
||||||
</h5>
|
|
||||||
<div class="dropdown-divider mb-3"></div>
|
|
||||||
<div class="row px-3">
|
|
||||||
<div id="orders_panel_supplies_<?= $moderator_data['order']->_key ?>" class="col-3 unselectable">
|
|
||||||
<?php if (!empty($moderator_data['supplies'])) : ?>
|
|
||||||
<?php
|
|
||||||
// Инициализация счетчика поставок для отрисовки горизонтального разделителя
|
|
||||||
$count = 1;
|
|
||||||
?>
|
|
||||||
|
|
||||||
<?php foreach ($moderator_data['supplies'] as $prod => $list) : ?>
|
|
||||||
<?php foreach ($list as $catn => $deliveries) : ?>
|
|
||||||
<?php foreach ($deliveries as $delivery => $supply) : ?>
|
|
||||||
<?php
|
|
||||||
// Инициализация обложки
|
|
||||||
$covr = null;
|
|
||||||
|
|
||||||
foreach ($supply['product']->imgs ?? [] as $img) {
|
|
||||||
// Перебор изображений для обложки
|
|
||||||
|
|
||||||
if ($img['covr'] ?? false) {
|
|
||||||
// Обложка найдена
|
|
||||||
|
|
||||||
$covr = $img['h150'];
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_null($covr)) {
|
|
||||||
// Обложка не инициализирована
|
|
||||||
|
|
||||||
if (!$covr = $supply['product']->imgs[0]['h150'] ?? false) {
|
|
||||||
// Не удалось использовать первое изображение как обложку
|
|
||||||
|
|
||||||
// Запись обложки по умолчанию
|
|
||||||
$covr = '/img/covers/h150/product.png';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($supply['amount'] > 0) {
|
|
||||||
// Пройдена проверка на количество поставок в заказе
|
|
||||||
|
|
||||||
if (Order::checkSuppliesStts($supply['edge'])) $status = "<span id=\"{$moderator_data['order']->_key}_{$prod}_{$catn}_{$delivery}_supply_stts_indicator_icon\" class=\"ml-auto my-auto fas fa-check\"></span>";
|
|
||||||
else $status = '';
|
|
||||||
|
|
||||||
// Инициализация иконки
|
|
||||||
$icon = $delivery === 'avia' ? 'fa-plane' : 'fa-truck';
|
|
||||||
|
|
||||||
// Генерация HTML
|
|
||||||
echo <<<HTML
|
|
||||||
<a id="{$moderator_data['order']->_key}_{$prod}_{$catn}_{$delivery}_supply" class="row mb-2 p-2 px-0 rounded row_supply" type="button" onclick="return orders_supply_edit('{$moderator_data['order']->_key}', '$prod', '$catn', '$delivery');">
|
|
||||||
<img class="col-auto px-0 h-100 img-fluid rounded" src="$covr" />
|
|
||||||
<p id="{$moderator_data['order']->_key}_{$prod}_{$catn}_{$delivery}_supply_stts_indicator" class="col d-flex text-dark">
|
|
||||||
{$catn}
|
|
||||||
<small class="ml-2 my-auto fas $icon"></small>
|
|
||||||
$status
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
HTML;
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<?php if ($count++ < count($moderator_data['supplies'])) : ?>
|
|
||||||
<div class="dropdown-divider mb-2"></div>
|
|
||||||
<?php endif ?>
|
|
||||||
<?php endforeach ?>
|
|
||||||
<?php endforeach ?>
|
|
||||||
<?php endforeach ?>
|
|
||||||
<?php else : ?>
|
|
||||||
<div class="row">
|
|
||||||
<p>Поставки не найдены</p>
|
|
||||||
</div>
|
|
||||||
<?php endif ?>
|
|
||||||
</div>
|
|
||||||
<div id="orders_panel_edit_<?= $moderator_data['order']->_key ?>" class="px-4 col-6 d-flex flex-column">
|
|
||||||
<p class="my-auto">Выберите поставку</p>
|
|
||||||
</div>
|
|
||||||
<div id="orders_panel_info_<?= $moderator_data['order']->_key ?>" class="col-3 d-flex flex-column">
|
|
||||||
<?php $form = ActiveForm::begin([
|
|
||||||
'id' => 'form_profile_settings',
|
|
||||||
'action' => false,
|
|
||||||
'fieldConfig' => [
|
|
||||||
'template' => '{label}{input}',
|
|
||||||
],
|
|
||||||
'options' => [
|
|
||||||
'onsubmit' => 'return false;',
|
|
||||||
'class' => 'row'
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Инициализация ребра до заказа
|
|
||||||
$account_edge_order = AccountEdgeOrder::searchByOrder($moderator_data['order']->readId())[0];
|
|
||||||
?>
|
|
||||||
|
|
||||||
<?= $form->field($account_edge_order, 'stts', ['options' => ['class' => "mb-1 w-100"]])
|
|
||||||
->dropDownList(Order::statusListInRussian($account_edge_order->stts), [
|
|
||||||
'onChange' => "return orders_status_edit('{$moderator_data['order']->_key}', this);",
|
|
||||||
'data-old-value' => $account_edge_order->stts
|
|
||||||
])->label(false); ?>
|
|
||||||
<small class="d-block mb-1 w-100 text-center"><b>Покупатель будет уведомлён</b></small>
|
|
||||||
<?php ActiveForm::end(); ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script defer>
|
|
||||||
document.addEventListener(
|
|
||||||
'DOMContentLoaded',
|
|
||||||
function() {
|
|
||||||
order_init('<?= $moderator_data['order']->_key ?>');
|
|
||||||
},
|
|
||||||
false
|
|
||||||
);
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
<?php endforeach ?>
|
|
||||||
<?php else : ?>
|
|
||||||
<div class="page_order_panel py-3 px-4 rounded">
|
|
||||||
<p class="text-center">Заказов нет</p>
|
|
||||||
</div>
|
|
||||||
<?php endif ?>
|
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<input type="radio" id="orders_panel_orders" name="main_panel" <?= $window === 'orders_panel_orders' ? 'checked' : null ?> />
|
<input type="radio" id="orders_panel_orders" name="main_panel" <?= $window === 'orders_panel_orders' ? 'checked' : null ?> />
|
||||||
|
@ -332,6 +175,41 @@ if (empty($window)) {
|
||||||
if (empty($time = $order_edge_supply[0]->time)) {
|
if (empty($time = $order_edge_supply[0]->time)) {
|
||||||
// Не найден срок доставки (в днях)
|
// Не найден срок доставки (в днях)
|
||||||
|
|
||||||
|
// if (empty($order_edge_supply[0]->dlvr['data'])) {
|
||||||
|
// // Не удалось рассчитать доставку
|
||||||
|
|
||||||
|
// // Инициализация времени
|
||||||
|
// $time = 0;
|
||||||
|
// } else {
|
||||||
|
// // Удалось рассчитать доставку
|
||||||
|
|
||||||
|
// // Инициализация даты отправки
|
||||||
|
// try {
|
||||||
|
// // Взять данные из "arrivalToOspSender" (Дата прибытия на терминал-отправитель)
|
||||||
|
|
||||||
|
// $delivery_send_date = DateTime::createFromFormat('Y-m-d', $order_edge_supply[0]->dlvr['data']['orderDates']['arrivalToOspSender'])->getTimestamp();
|
||||||
|
// } catch (Throwable $e) {
|
||||||
|
// // Взять данные из "pickup" (Дата передачи груза на адресе отправителя)
|
||||||
|
|
||||||
|
// $delivery_send_date = DateTime::createFromFormat('Y-m-d', $order_edge_supply[0]->dlvr['data']['orderDates']['pickup'])->getTimestamp();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Инициализация времени доставки
|
||||||
|
// try {
|
||||||
|
// // Доставка по воздуху (подразумевается), данные из "giveoutFromOspReceiver" (Дата и время, с которого груз готов к выдаче на терминале)
|
||||||
|
|
||||||
|
// // Оставлено на всякий случай для дальнейших разбирательств
|
||||||
|
|
||||||
|
// $delivery_converted = DateTime::createFromFormat('Y-m-d H:i:s', $order_edge_supply[0]->dlvr['data']['orderDates']['giveoutFromOspReceiver'])->getTimestamp();
|
||||||
|
// } catch (Throwable $e) {
|
||||||
|
// // Инициализация даты отправки
|
||||||
|
|
||||||
|
// // Автоматическая доставка (подразумевается), данные из "arrivalToOspReceiver" (Дата прибытия натерминал-получатель)
|
||||||
|
// $delivery_converted = DateTime::createFromFormat('Y-m-d', $order_edge_supply[0]->dlvr['data']['orderDates']['arrivalToOspReceiver'])->getTimestamp();
|
||||||
|
// }
|
||||||
|
// $time = ceil(($delivery_converted - ($delivery_send_date ?? 0)) / 60 / 60 / 24);
|
||||||
|
// }
|
||||||
|
|
||||||
if (empty($order_edge_supply[0]->dlvr['data'])) {
|
if (empty($order_edge_supply[0]->dlvr['data'])) {
|
||||||
// Не удалось рассчитать доставку
|
// Не удалось рассчитать доставку
|
||||||
|
|
||||||
|
@ -340,16 +218,8 @@ if (empty($window)) {
|
||||||
} else {
|
} else {
|
||||||
// Удалось рассчитать доставку
|
// Удалось рассчитать доставку
|
||||||
|
|
||||||
// Инициализация даты отправки
|
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone);
|
||||||
try {
|
$timezone = $timezone[1][0];
|
||||||
// Взять данные из "arrivalToOspSender" (Дата прибытия на терминал-отправитель)
|
|
||||||
|
|
||||||
$delivery_send_date = DateTime::createFromFormat('Y-m-d', $order_edge_supply[0]->dlvr['data']['orderDates']['arrivalToOspSender'])->getTimestamp();
|
|
||||||
} catch (Throwable $e) {
|
|
||||||
// Взять данные из "pickup" (Дата передачи груза на адресе отправителя)
|
|
||||||
|
|
||||||
$delivery_send_date = DateTime::createFromFormat('Y-m-d', $order_edge_supply[0]->dlvr['data']['orderDates']['pickup'])->getTimestamp();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Инициализация времени доставки
|
// Инициализация времени доставки
|
||||||
try {
|
try {
|
||||||
|
@ -357,14 +227,13 @@ if (empty($window)) {
|
||||||
|
|
||||||
// Оставлено на всякий случай для дальнейших разбирательств
|
// Оставлено на всякий случай для дальнейших разбирательств
|
||||||
|
|
||||||
$delivery_converted = DateTime::createFromFormat('Y-m-d H:i:s', $order_edge_supply[0]->dlvr['data']['orderDates']['giveoutFromOspReceiver'])->getTimestamp();
|
$delivery_converted = DateTime::createFromFormat('Y-m-d H:i:s', $order_edge_supply[0]->dlvr['data']['orderDates']['giveoutFromOspReceiver'])->setTimezone(new DateTimeZone($timezone))->format('d.m.Y');
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
// Инициализация даты отправки
|
// Инициализация даты отправки
|
||||||
|
|
||||||
// Автоматическая доставка (подразумевается), данные из "arrivalToOspReceiver" (Дата прибытия натерминал-получатель)
|
$delivery_converted = DateTime::createFromFormat('Y-m-d', $order_edge_supply[0]->dlvr['data']['orderDates']['arrivalToOspReceiver'])->setTimezone(new DateTimeZone($timezone))->format('d.m.Y');
|
||||||
$delivery_converted = DateTime::createFromFormat('Y-m-d', $order_edge_supply[0]->dlvr['data']['orderDates']['arrivalToOspReceiver'])->getTimestamp();
|
|
||||||
}
|
}
|
||||||
$time = ceil(($delivery_converted - ($delivery_send_date ?? 0)) / 60 / 60 / 24);
|
$time = $delivery_converted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,4 +369,12 @@ if (empty($window)) {
|
||||||
|| yii::$app->user->identity->type === 'moderator')
|
|| yii::$app->user->identity->type === 'moderator')
|
||||||
) : ?>
|
) : ?>
|
||||||
<script src="/js/orders_panel.js" defer></script>
|
<script src="/js/orders_panel.js" defer></script>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('orders_panel.loaded', function(e) {
|
||||||
|
// Загружена программа для работы с заказами
|
||||||
|
|
||||||
|
// Инициализация списка аналогов
|
||||||
|
order_init_list(8, 1);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
|
@ -0,0 +1,169 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use yii;
|
||||||
|
use yii\bootstrap\ActiveForm;
|
||||||
|
|
||||||
|
use app\models\AccountEdgeOrder;
|
||||||
|
use app\models\Order;
|
||||||
|
use app\models\Settings;
|
||||||
|
|
||||||
|
?>
|
||||||
|
<?php if (!empty($moderator_data)) : ?>
|
||||||
|
<?php foreach ($moderator_data as $moderator_data) : ?>
|
||||||
|
<div id="<?= $moderator_data['order']->_key ?>_panel" class="page_order_panel mb-2 py-3 px-4 rounded">
|
||||||
|
<h5 class="row mt-1 mb-3">
|
||||||
|
<?php
|
||||||
|
// Инициализация времени отправки заказа
|
||||||
|
$date = time();
|
||||||
|
|
||||||
|
foreach ($moderator_data['order']->jrnl as $entry) {
|
||||||
|
// Перебор записей в журнале
|
||||||
|
|
||||||
|
if ($entry['action'] === 'requested') {
|
||||||
|
// Найдена запись со временем запроса заказа
|
||||||
|
|
||||||
|
if (empty($date) || $date <= $entry['date']) {
|
||||||
|
// Буфер не инициализирован или в него записано более старое событие
|
||||||
|
|
||||||
|
// Запись в буфер
|
||||||
|
$date = $entry['date'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone);
|
||||||
|
$timezone = $timezone[1][0];
|
||||||
|
|
||||||
|
// Конвертация данных из буфера
|
||||||
|
$date = [
|
||||||
|
'H:i' => (new DateTime())->setTimestamp($date)->setTimezone(new DateTimeZone($timezone))->format('H:i'),
|
||||||
|
'd.m.Y' => (new DateTime())->setTimestamp($date)->setTimezone(new DateTimeZone($timezone))->format('d.m.Y')
|
||||||
|
];
|
||||||
|
|
||||||
|
?>
|
||||||
|
<p class="col-auto ml-1 font-weight-bold">#<?= $moderator_data['order']->_key ?></p>
|
||||||
|
<p class="col-auto mr-1 font-weight-bold">
|
||||||
|
<span><small><small><?= $date['H:i'] ?? 'Неизвестно' ?></small></small></span>
|
||||||
|
<span><?= $date['d.m.Y'] ?? 'Неизвестно' ?></span>
|
||||||
|
</p>
|
||||||
|
</h5>
|
||||||
|
<div class="dropdown-divider mb-3"></div>
|
||||||
|
<div class="row px-3">
|
||||||
|
<div id="orders_panel_supplies_<?= $moderator_data['order']->_key ?>" class="col-3 unselectable">
|
||||||
|
<?php if (!empty($moderator_data['supplies'])) : ?>
|
||||||
|
<?php
|
||||||
|
// Инициализация счетчика поставок для отрисовки горизонтального разделителя
|
||||||
|
$count = 1;
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php foreach ($moderator_data['supplies'] as $prod => $list) : ?>
|
||||||
|
<?php foreach ($list as $catn => $deliveries) : ?>
|
||||||
|
<?php foreach ($deliveries as $delivery => $supply) : ?>
|
||||||
|
<?php
|
||||||
|
// Инициализация обложки
|
||||||
|
$covr = null;
|
||||||
|
|
||||||
|
foreach ($supply['product']->imgs ?? [] as $img) {
|
||||||
|
// Перебор изображений для обложки
|
||||||
|
|
||||||
|
if ($img['covr'] ?? false) {
|
||||||
|
// Обложка найдена
|
||||||
|
|
||||||
|
$covr = $img['h150'];
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_null($covr)) {
|
||||||
|
// Обложка не инициализирована
|
||||||
|
|
||||||
|
if (!$covr = $supply['product']->imgs[0]['h150'] ?? false) {
|
||||||
|
// Не удалось использовать первое изображение как обложку
|
||||||
|
|
||||||
|
// Запись обложки по умолчанию
|
||||||
|
$covr = '/img/covers/h150/product.png';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($supply['amount'] > 0) {
|
||||||
|
// Пройдена проверка на количество поставок в заказе
|
||||||
|
|
||||||
|
if (Order::checkSuppliesStts($supply['edge'])) $status = "<span id=\"{$moderator_data['order']->_key}_{$prod}_{$catn}_{$delivery}_supply_stts_indicator_icon\" class=\"ml-auto my-auto fas fa-check\"></span>";
|
||||||
|
else $status = '';
|
||||||
|
|
||||||
|
// Инициализация иконки
|
||||||
|
$icon = $delivery === 'avia' ? 'fa-plane' : 'fa-truck';
|
||||||
|
|
||||||
|
// Генерация HTML
|
||||||
|
echo <<<HTML
|
||||||
|
<a id="{$moderator_data['order']->_key}_{$prod}_{$catn}_{$delivery}_supply" class="row mb-2 p-2 px-0 rounded row_supply" type="button" onclick="return orders_supply_edit('{$moderator_data['order']->_key}', '$prod', '$catn', '$delivery');">
|
||||||
|
<img class="col-auto px-0 h-100 img-fluid rounded" src="$covr" />
|
||||||
|
<p id="{$moderator_data['order']->_key}_{$prod}_{$catn}_{$delivery}_supply_stts_indicator" class="col d-flex text-dark">
|
||||||
|
{$catn}
|
||||||
|
<small class="ml-2 my-auto fas $icon"></small>
|
||||||
|
$status
|
||||||
|
</p>
|
||||||
|
</a>
|
||||||
|
HTML;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<?php if ($count++ < count($moderator_data['supplies'])) : ?>
|
||||||
|
<div class="dropdown-divider mb-2"></div>
|
||||||
|
<?php endif ?>
|
||||||
|
<?php endforeach ?>
|
||||||
|
<?php endforeach ?>
|
||||||
|
<?php endforeach ?>
|
||||||
|
<?php else : ?>
|
||||||
|
<div class="row">
|
||||||
|
<p>Поставки не найдены</p>
|
||||||
|
</div>
|
||||||
|
<?php endif ?>
|
||||||
|
</div>
|
||||||
|
<div id="orders_panel_edit_<?= $moderator_data['order']->_key ?>" class="px-4 col-6 d-flex flex-column">
|
||||||
|
<p class="my-auto">Выберите поставку</p>
|
||||||
|
</div>
|
||||||
|
<div id="orders_panel_info_<?= $moderator_data['order']->_key ?>" class="col-3 d-flex flex-column">
|
||||||
|
<?php $form = ActiveForm::begin([
|
||||||
|
'id' => 'form_profile_settings',
|
||||||
|
'action' => false,
|
||||||
|
'fieldConfig' => [
|
||||||
|
'template' => '{label}{input}',
|
||||||
|
],
|
||||||
|
'options' => [
|
||||||
|
'onsubmit' => 'return false;',
|
||||||
|
'class' => 'row'
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Инициализация ребра до заказа
|
||||||
|
$account_edge_order = AccountEdgeOrder::searchByOrder($moderator_data['order']->readId())[0];
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?= $form->field($account_edge_order, 'stts', ['options' => ['class' => "mb-1 w-100"]])
|
||||||
|
->dropDownList(Order::statusListInRussian($account_edge_order->stts), [
|
||||||
|
'onChange' => "return orders_status_edit('{$moderator_data['order']->_key}', this);",
|
||||||
|
'data-old-value' => $account_edge_order->stts
|
||||||
|
])->label(false); ?>
|
||||||
|
<small class="d-block mb-1 w-100 text-center"><b>Покупатель будет уведомлён</b></small>
|
||||||
|
<?php ActiveForm::end(); ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script defer>
|
||||||
|
document.addEventListener(
|
||||||
|
'DOMContentLoaded',
|
||||||
|
function() {
|
||||||
|
order_init('<?= $moderator_data['order']->_key ?>');
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
<?php endforeach ?>
|
||||||
|
<?php else : ?>
|
||||||
|
<div class="page_order_panel py-3 px-4 rounded">
|
||||||
|
<p class="text-center">Заказов нет</p>
|
||||||
|
</div>
|
||||||
|
<?php endif ?>
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use app\models\Search;
|
||||||
|
use app\models\ProductGroup;
|
||||||
|
|
||||||
|
// Инициализация аналогов
|
||||||
|
$analogs = Search::content(ProductGroup::searchByProduct($model)?->searchProducts((int) $amount, (int) $page) ?? []);
|
||||||
|
|
||||||
|
// Удаление товара из списка его аналогов
|
||||||
|
foreach($analogs as $key => $analog) if ($analog['_key'] === $model->_key) unset($analogs[$key]);
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php foreach($analogs as $analog) : ?>
|
||||||
|
<?php
|
||||||
|
// Инициализация данных товара
|
||||||
|
$covr = null;
|
||||||
|
$prod = $analog['prod'] ?? 'Неизвестно';
|
||||||
|
$catn = $analog['catn'] ?? 'Неизвестно';
|
||||||
|
$name = $analog['name'] ?? 'Без названия';
|
||||||
|
|
||||||
|
// Генерация списка товаров
|
||||||
|
$supplies_html = Search::generate($analog, $covr, analogs: true);
|
||||||
|
?>
|
||||||
|
<div class="col mb-2 rounded">
|
||||||
|
<div class="row p-2 rounded row_analog">
|
||||||
|
<img class="ml-0 rounded" src="<?= $covr ?>" />
|
||||||
|
<div class="col ml-3 p-0 d-flex flex-column row_fixed_height">
|
||||||
|
<a class="my-auto text-dark" href="/product/<?= urlencode($prod) ?>/<?= urlencode($catn) ?>">
|
||||||
|
<h5 class="m-0"><b><?= $prod ?></b> <?= $catn ?></h5>
|
||||||
|
<h6 class="m-0"><small><?= $name ?></small></h6>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="col ml-3 p-0 d-flex flex-column">
|
||||||
|
<?= $supplies_html ?>
|
||||||
|
</div>
|
||||||
|
<?php if (!yii::$app->user->isGuest
|
||||||
|
&& (yii::$app->user->identity->type === 'administrator'
|
||||||
|
|| yii::$app->user->identity->type === 'moderator')) : ?>
|
||||||
|
<button class="ml-3 col-2 btn btn-small button_red button_clean" onclick="return product_panel_disconnect('<?= $catn ?>', '<?= $prod ?>', this.parentElement.parentElement);">Отключить</button>
|
||||||
|
<?php endif ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach ?>
|
|
@ -5,6 +5,8 @@ declare(strict_types=1);
|
||||||
use yii\bootstrap\ActiveForm;
|
use yii\bootstrap\ActiveForm;
|
||||||
|
|
||||||
use app\models\Product;
|
use app\models\Product;
|
||||||
|
use app\models\ProductGroup;
|
||||||
|
use app\models\Search;
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
|
@ -31,7 +33,7 @@ use app\models\Product;
|
||||||
// Перебор изображений для генерации обложек
|
// Перебор изображений для генерации обложек
|
||||||
|
|
||||||
// Инициализация
|
// Инициализация
|
||||||
$h150 = $image['h150'] ?? '/img/covers/h150/product.png';
|
$h150 = $image['h150'] ?? Product::cover($prod, 150);
|
||||||
|
|
||||||
if (($image['covr'] ?? false) || ($covr_not_found && $key === 0)) {
|
if (($image['covr'] ?? false) || ($covr_not_found && $key === 0)) {
|
||||||
echo <<<HTML
|
echo <<<HTML
|
||||||
|
@ -71,8 +73,7 @@ use app\models\Product;
|
||||||
// Перебор изображений для генерации полных версий
|
// Перебор изображений для генерации полных версий
|
||||||
|
|
||||||
// Инициализация
|
// Инициализация
|
||||||
$prod = $image['prod'] ?? 'Неизвестный';
|
$orig = $image['orig'] ?? Product::cover($model['prod'], 0);
|
||||||
$orig = $image['orig'] ?? '/img/covers/product.png';
|
|
||||||
|
|
||||||
if (($image['covr'] ?? false) || ($covr_not_found && $key === 0)) {
|
if (($image['covr'] ?? false) || ($covr_not_found && $key === 0)) {
|
||||||
// Если это изображение является обложкой или обложка не найдена
|
// Если это изображение является обложкой или обложка не найдена
|
||||||
|
@ -116,22 +117,6 @@ use app\models\Product;
|
||||||
?>
|
?>
|
||||||
</div>
|
</div>
|
||||||
<div class="ml-4 px-3 d-flex flex-column w-50">
|
<div class="ml-4 px-3 d-flex flex-column w-50">
|
||||||
<?php if (!yii::$app->user->isGuest
|
|
||||||
&& (yii::$app->user->identity->type === 'administrator'
|
|
||||||
|| yii::$app->user->identity->type === 'moderator')) : ?>
|
|
||||||
<nav class="row my-2 py-2 px-3 rounded product_admin_menu">
|
|
||||||
<a id="product_info_admin_connect" class="mr-2 h-100 text-dark d-flex" title="Подсоединить аналог" role="button" onclick="return product_panel_connect('<?= $model['catn'] ?>', '<?= $model['prod'] ?>');">
|
|
||||||
<i class="fas fa-plus-square my-auto"></i>
|
|
||||||
</a>
|
|
||||||
<a id="product_info_admin_connect" class="mr-2 h-100 text-dark d-flex" title="Отсоединить аналог" role="button" onclick="return product_panel_disconnect('<?= $model['catn'] ?>', '<?= $model['prod'] ?>');">
|
|
||||||
<i class="fas fa-minus-square my-auto"></i>
|
|
||||||
</a>
|
|
||||||
<a id="product_info_admin_connect" class="ml-auto h-100 text-dark d-flex" title="Удалить" role="button" onclick="return product_panel_delete('<?= $model['catn'] ?>', '<?= $model['prod'] ?>');">
|
|
||||||
<i class="fas fa-trash-alt my-auto"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
||||||
<div class="row mb-2">
|
<div class="row mb-2">
|
||||||
<?php if (
|
<?php if (
|
||||||
!yii::$app->user->isGuest
|
!yii::$app->user->isGuest
|
||||||
|
@ -148,12 +133,15 @@ use app\models\Product;
|
||||||
<?= $model['prod'] ?? 'Неизвестно' ?>
|
<?= $model['prod'] ?? 'Неизвестно' ?>
|
||||||
</h3>
|
</h3>
|
||||||
<?php else : ?>
|
<?php else : ?>
|
||||||
<h1 id="catn_<?= $model['catn'] ?>" class="mr-auto my-auto product_catn">
|
<h2 id="name_<?= $model['catn'] ?>" class="mt-auto my-0 w-100 mb-1 product_name">
|
||||||
<?= $model['catn'] ?>
|
<?= $model['name'] ?? 'Неизвестно' ?>
|
||||||
</h1>
|
|
||||||
<h2 id="prod_<?= $model['catn'] ?>" class="mt-auto my-0 product_prod">
|
|
||||||
<?= $model['prod'] ?? 'Неизвестно' ?>
|
|
||||||
</h2>
|
</h2>
|
||||||
|
<h1 id="catn_<?= $model['catn'] ?>" class="mr-auto my-auto pointer-event product_catn">
|
||||||
|
<?= $model['catn'] ?? '' ?>
|
||||||
|
</h1>
|
||||||
|
<h3 id="prod_<?= $model['catn'] ?>" class="mt-auto my-0 product_prod">
|
||||||
|
<?= $model['prod'] ?? 'Неизвестно' ?>
|
||||||
|
</h3>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -173,7 +161,7 @@ use app\models\Product;
|
||||||
</p>
|
</p>
|
||||||
<!-- Вес -->
|
<!-- Вес -->
|
||||||
<p class="form-control-sm p-0 h-auto">
|
<p class="form-control-sm p-0 h-auto">
|
||||||
<b>Вес:</b><span id="prod_<?= $model['catn'] ?>_dmns_x" class="ml-1 pointer-event" role="button" onclick="return product_panel_weight_edit('<?= $model['catn'] ?>', '<?= $model['prod'] ?>', this);"><?= empty($model['wght']) ? '0' : $model['wght'] ?></span><span class="mr-1">г</span>
|
<b>Вес:</b><span id="prod_<?= $model['catn'] ?>_dmns_x" class="ml-1 pointer-event" role="button" onclick="return product_panel_weight_edit('<?= $model['catn'] ?>', '<?= $model['prod'] ?>', this);"><?= empty($model['wght']) ? '0' : $model['wght'] ?></span><span class="mr-1">кг</span>
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<?php else : ?>
|
<?php else : ?>
|
||||||
|
@ -184,7 +172,7 @@ use app\models\Product;
|
||||||
</p>
|
</p>
|
||||||
<!-- Вес -->
|
<!-- Вес -->
|
||||||
<p class="form-control-sm p-0 h-auto">
|
<p class="form-control-sm p-0 h-auto">
|
||||||
<b>Вес:</b><span id="prod_<?= $model['catn'] ?>_dmns_x" class="ml-1"><?= empty($model['wght']) ? '0' : $model['wght'] ?></span>г
|
<b>Вес:</b><span id="prod_<?= $model['catn'] ?>_dmns_x" class="ml-1"><?= empty($model['wght']) ? '0' : $model['wght'] ?>кг</span>
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
@ -201,7 +189,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'] ?>', '<?= $model['prod'] ?>', this);"><?= $model['dscr'] ?? 'Без описания' ?></p>
|
<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'] ?>', '<?= $model['prod'] ?>', this);"><?= $model['dscr'] ?? 'Без описания' ?></p>
|
||||||
<?php else : ?>
|
<?php else : ?>
|
||||||
<p id="description_<?= $model['catn'] ?>" class="mt-0 ml-0 text-break product_description"><?= $model['prod'] ?? 'Без описания' ?></p>
|
<p id="description_<?= $model['catn'] ?>" class="mt-0 ml-0 text-break pointer-event product_description"><?= $model['dscr'] ?? 'Без описания' ?></p>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -211,6 +199,8 @@ use app\models\Product;
|
||||||
&& (yii::$app->user->identity->type === 'administrator'
|
&& (yii::$app->user->identity->type === 'administrator'
|
||||||
|| yii::$app->user->identity->type === 'moderator')
|
|| yii::$app->user->identity->type === 'moderator')
|
||||||
) {
|
) {
|
||||||
|
echo '<div class="row">';
|
||||||
|
|
||||||
// Инициализация артикула
|
// Инициализация артикула
|
||||||
$catn = $model['catn'];
|
$catn = $model['catn'];
|
||||||
$prod = $model['prod'];
|
$prod = $model['prod'];
|
||||||
|
@ -219,15 +209,21 @@ use app\models\Product;
|
||||||
// Товар активен
|
// Товар активен
|
||||||
|
|
||||||
echo <<<HTML
|
echo <<<HTML
|
||||||
<button class="row btn button_red button_clean" onclick="return product_panel_product_stts('$catn', '$prod', 'inactive');">Деактивировать</button>
|
<button class="col btn button_red button_clean" onclick="return product_panel_product_stts('$catn', '$prod', 'inactive');">Деактивировать</button>
|
||||||
HTML;
|
HTML;
|
||||||
} else {
|
} else {
|
||||||
// Товар неактивен, либо что-то с ним ещё
|
// Товар неактивен, либо что-то с ним ещё
|
||||||
|
|
||||||
echo <<<HTML
|
echo <<<HTML
|
||||||
<button class="row btn button_green button_clean" onclick="return product_panel_product_stts('$catn', '$prod', 'active');">Активировать</button>
|
<button class="col btn button_green button_clean" onclick="return product_panel_product_stts('$catn', '$prod', 'active');">Активировать</button>
|
||||||
HTML;
|
HTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
echo <<<HTML
|
||||||
|
<button class="ml-3 col-3 btn button_red button_clean" onclick="return product_panel_delete('{$model['catn']}', '{$model['prod']}');">Удалить</button>
|
||||||
|
HTML;
|
||||||
|
|
||||||
|
echo '</div>';
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
</div>
|
</div>
|
||||||
|
@ -238,6 +234,18 @@ use app\models\Product;
|
||||||
<time class="ml-auto"></time>
|
<time class="ml-auto"></time>
|
||||||
</div> -->
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<?php if (!yii::$app->user->isGuest
|
||||||
|
&& (yii::$app->user->identity->type === 'administrator'
|
||||||
|
|| yii::$app->user->identity->type === 'moderator')) : ?>
|
||||||
|
<div class="my-3 p-3 d-flex rounded">
|
||||||
|
<input type="text" class="mr-2 col-2 form-control button_clean" title="Производитель" placeholder="Производитель" value="<?= $model['prod'] ?>">
|
||||||
|
<input type="text" class="mr-2 col form-control button_clean" title="Артикулы (через запятую)" placeholder="Артикулы (через запятую)">
|
||||||
|
<button class="col-3 btn button_green button_clean" onclick="return product_panel_connect('<?= $model['catn'] ?>', '<?= $model['prod'] ?>', this.parentElement.children[1].value, this.parentElement.children[0].value, 'products_list');">Подключить аналог</button>
|
||||||
|
</div>
|
||||||
|
<?php endif ?>
|
||||||
|
|
||||||
|
<div id="products_list" class="mt-2 rounded"></div>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -250,3 +258,21 @@ use app\models\Product;
|
||||||
) : ?>
|
) : ?>
|
||||||
<script src="/js/product_panel.js" defer></script>
|
<script src="/js/product_panel.js" defer></script>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
<script>
|
||||||
|
if (document.readyState === "complete") {
|
||||||
|
// Документ загружен
|
||||||
|
|
||||||
|
// Инициализация списка аналогов
|
||||||
|
panel_analogs_initializing('<?= $model['prod'] ?>', '<?= $model['catn'] ?>', 10, 1);
|
||||||
|
} else {
|
||||||
|
// Документ не загружен
|
||||||
|
|
||||||
|
// Обработчик события загрузки документа
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Обработчик события инициализации
|
||||||
|
|
||||||
|
// Инициализация списка аналогов
|
||||||
|
panel_analogs_initializing('<?= $model['prod'] ?>', '<?= $model['catn'] ?>', 10, 1);
|
||||||
|
}, false);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
|
@ -7,14 +7,18 @@ use app\models\Settings;
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use DateTimeZone;
|
use DateTimeZone;
|
||||||
|
|
||||||
// Инициализация счетчика аккаунтов
|
// Инициализация счетчика товаров
|
||||||
$amount = 0;
|
$i = $amount * ($page - 1);
|
||||||
|
|
||||||
// Инициализация часового пояса
|
// Инициализация часового пояса
|
||||||
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone);
|
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone);
|
||||||
$timezone = $timezone[1][0];
|
$timezone = $timezone[1][0];
|
||||||
?>
|
?>
|
||||||
|
|
||||||
|
<?php if ($page > 1 && count($products) > 0) : ?>
|
||||||
|
<div class="dropdown-divider mb-3"></div>
|
||||||
|
<?php endif ?>
|
||||||
|
|
||||||
<?php foreach ($products as $product) : ?>
|
<?php foreach ($products as $product) : ?>
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
@ -34,8 +38,8 @@ $timezone = $timezone[1][0];
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="mb-3 row">
|
<div class="mb-3 row">
|
||||||
<div class="pr-0 col-auto"><?= ++$amount ?>.</div>
|
<div class="pr-0 col-auto"><?= ++$i ?>.</div>
|
||||||
<a class="pr-0 col overflow-hidden" title="<?= $product->name ?? 'Артикул' ?>" href="/product/<?= $product->prod ?? 'Неизвестно' ?>/<?= $product->catn ?? 'Неизвестно' ?>">
|
<a class="pr-0 col overflow-hidden" title="<?= $product->name ?? 'Артикул' ?>" href="/product/<?= urlencode($product->prod ?? 'Неизвестно') ?>/<?= $product->catn ?? 'Неизвестно' ?>">
|
||||||
<?= $product->catn ?? 'Неизвестно' ?>
|
<?= $product->catn ?? 'Неизвестно' ?>
|
||||||
<span class="text-dark" title="Производитель"> (<?= $product->prod ?? 'Неизвестно' ?>)</span>
|
<span class="text-dark" title="Производитель"> (<?= $product->prod ?? 'Неизвестно' ?>)</span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -45,7 +49,7 @@ $timezone = $timezone[1][0];
|
||||||
<a class="my-auto col-auto fas fa-trash-alt text-dark" type="button" onclick="page_profile_supplies_delete()"></a>
|
<a class="my-auto col-auto fas fa-trash-alt text-dark" type="button" onclick="page_profile_supplies_delete()"></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if ($amount < count($products)) : ?>
|
<?php if ($i < count($products) + $amount * ($page - 1)) : ?>
|
||||||
<div class="dropdown-divider mb-3"></div>
|
<div class="dropdown-divider mb-3"></div>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
|
|
|
@ -39,7 +39,7 @@ $timezone = $timezone[1][0];
|
||||||
<label class="btn button_white mb-0 mr-2" for="profile_panel_input_notifications" onclick="return page_profile_panel_choose('profile_panel_input_notifications');">Уведомления</label>
|
<label class="btn button_white mb-0 mr-2" for="profile_panel_input_notifications" onclick="return page_profile_panel_choose('profile_panel_input_notifications');">Уведомления</label>
|
||||||
<label class="btn button_white mb-0 mr-2" for="profile_panel_input_accounts" onclick="return page_profile_panel_choose('profile_panel_input_accounts');">Аккаунты</label>
|
<label class="btn button_white mb-0 mr-2" for="profile_panel_input_accounts" onclick="return page_profile_panel_choose('profile_panel_input_accounts');">Аккаунты</label>
|
||||||
<label class="btn button_white mb-0 mr-2" for="profile_panel_input_products" onclick="return page_profile_panel_choose('profile_panel_input_products');">Товары</label>
|
<label class="btn button_white mb-0 mr-2" for="profile_panel_input_products" onclick="return page_profile_panel_choose('profile_panel_input_products');">Товары</label>
|
||||||
<label class="btn button_white mb-0 mr-2" for="profile_panel_input_supplies" onclick="return page_profile_panel_choose('profile_panel_input_supplies');">Поставки</label>
|
<label class="btn button_white mb-0 mr-2" for="profile_panel_input_supplies" onclick="return page_profile_panel_choose('profile_panel_supplies_read');">Поставки</label>
|
||||||
<label class="btn button_white mb-0 mr-2" for="profile_panel_input_settings" onclick="return page_profile_panel_choose('profile_panel_input_settings');">Настройки</label>
|
<label class="btn button_white mb-0 mr-2" for="profile_panel_input_settings" onclick="return page_profile_panel_choose('profile_panel_input_settings');">Настройки</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="profile_panel_content">
|
<div class="profile_panel_content">
|
||||||
|
@ -90,63 +90,14 @@ $timezone = $timezone[1][0];
|
||||||
|
|
||||||
<input type="radio" id="profile_panel_input_accounts" name="main_panel" <?= $panel === 'profile_panel_input_accounts' ? 'checked' : null ?> />
|
<input type="radio" id="profile_panel_input_accounts" name="main_panel" <?= $panel === 'profile_panel_input_accounts' ? 'checked' : null ?> />
|
||||||
<div class="profile_panel_input_accounts_menu mb-4">
|
<div class="profile_panel_input_accounts_menu mb-4">
|
||||||
<label class="mb-0 mr-2 px-2 py-1 btn button_white_small" for="profile_panel_input_accounts_control" onclick="return page_profile_panel_accounts_choose('profile_panel_input_accounts_control');">Пользователи</label>
|
<label class="mb-0 mr-2 px-2 py-1 btn button_white_small" for="profile_panel_input_accounts_control" onclick="return page_profile_panel_choose('profile_panel_input_accounts_control');">Пользователи</label>
|
||||||
<label class="mb-0 mr-2 px-2 py-1 btn button_white_small" for="profile_panel_input_accounts_suppliers" onclick="return page_profile_panel_accounts_choose('profile_panel_input_accounts_suppliers');">Поставщики</label>
|
<label class="mb-0 mr-2 px-2 py-1 btn button_white_small" for="profile_panel_input_accounts_suppliers" onclick="return page_profile_panel_choose('profile_panel_input_accounts_suppliers');">Поставщики</label>
|
||||||
</div>
|
</div>
|
||||||
<input type="radio" id="profile_panel_input_accounts_control" name="main_panel_accounts" <?= $panel_accounts === 'profile_panel_input_accounts_control' ? 'checked' : null ?> />
|
<input type="radio" id="profile_panel_input_accounts_control" name="main_panel_accounts" <?= $panel_accounts === 'profile_panel_input_accounts_control' ? 'checked' : null ?> />
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h5>Список пользователей</h5>
|
<h5>Список пользователей</h5>
|
||||||
<div class="dropdown-divider mb-4"></div>
|
<div class="dropdown-divider mb-4"></div>
|
||||||
<div id="profile_panel_input_accounts_list" class="px-3">
|
<div id="profile_panel_input_accounts_list" class="px-3"></div>
|
||||||
<?php
|
|
||||||
// Инициализация счетчика аккаунтов
|
|
||||||
$amount = 0;
|
|
||||||
|
|
||||||
// Чтение аккаунтов
|
|
||||||
$accounts = Account::read(limit: 100, order: ['desc']);
|
|
||||||
?>
|
|
||||||
<?php foreach ($accounts ?? [] as $account) : ?>
|
|
||||||
<?php
|
|
||||||
foreach ($account->jrnl ?? [] as $jrnl) {
|
|
||||||
// Перебор записей в журнале
|
|
||||||
|
|
||||||
if ($jrnl['action'] === 'create') {
|
|
||||||
// Найдена дата создания
|
|
||||||
|
|
||||||
// Инициализация даты
|
|
||||||
$create = (new DateTime())->setTimestamp($jrnl['date'])->setTimezone(new DateTimeZone($timezone))->format('d.m.Y') ?? 'Неизвестно';
|
|
||||||
|
|
||||||
// Выход из цикла
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
||||||
<div class="mb-3 row">
|
|
||||||
<div class="pr-0 col-auto"><?= ++$amount ?>.</div>
|
|
||||||
<div class="pr-0 col overflow-hidden" title="ФИО">
|
|
||||||
<?= $account->name ?? 'Неизвестно' ?>
|
|
||||||
</div>
|
|
||||||
<div class="my-auto pr-0 col-auto" title="Псевдоним">
|
|
||||||
<?= $account->indx ?? '' ?>
|
|
||||||
</div>
|
|
||||||
<div class="my-auto pr-0 col-auto" title="Тип аккаунта">
|
|
||||||
<?= $account->agnt ? 'Поставщик' : 'Покупатель' ?>
|
|
||||||
</div>
|
|
||||||
<div class="mr-3 my-auto pr-0 col-2" title="Уровень авторизации">
|
|
||||||
<?= $account->type() ?>
|
|
||||||
</div>
|
|
||||||
<div class="my-auto pr-0 col-auto text-right" title="Дата регистрации">
|
|
||||||
<?= $create ?? 'Неизвестно' ?>
|
|
||||||
</div>
|
|
||||||
<a class="my-auto col-auto fas fa-trash-alt text-dark" type="button" onclick="page_profile_supplies_delete()"></a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php if ($amount < count($accounts)) : ?>
|
|
||||||
<div class="dropdown-divider mb-3"></div>
|
|
||||||
<?php endif ?>
|
|
||||||
<?php endforeach ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input type="radio" id="profile_panel_input_accounts_suppliers" name="main_panel_accounts" <?= $panel_accounts === 'profile_panel_input_accounts_suppliers' ? 'checked' : null ?> />
|
<input type="radio" id="profile_panel_input_accounts_suppliers" name="main_panel_accounts" <?= $panel_accounts === 'profile_panel_input_accounts_suppliers' ? 'checked' : null ?> />
|
||||||
|
@ -159,10 +110,10 @@ $timezone = $timezone[1][0];
|
||||||
<input type="radio" id="profile_panel_input_products" name="main_panel" <?= $panel === 'profile_panel_input_products' ? 'checked' : null ?> />
|
<input type="radio" id="profile_panel_input_products" name="main_panel" <?= $panel === 'profile_panel_input_products' ? 'checked' : null ?> />
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h5>Список товаров</h5>
|
<h5>Список товаров</h5>
|
||||||
<div class="col-auto orders_panel_menu ml-auto text-right">
|
<div class="orders_panel_menu ml-auto text-right">
|
||||||
<a class="btn btn-sm button_white button_clean font-weight-bold mb-0 mr-2" type="button" onclick="return profile_panel_products_read('@last', 'all');">Все</a>
|
<a class="btn btn-sm button_white button_clean font-weight-bold mb-0 mr-2" type="button" onclick="return profile_panel_products_read('@last', 'all', '@last', '@last', 1, true);">Все</a>
|
||||||
<a class="btn btn-sm button_white button_clean font-weight-bold mb-0 mr-2" type="button" onclick="return profile_panel_products_read('@last', 'active');">Активные</a>
|
<a class="btn btn-sm button_white button_clean font-weight-bold mb-0 mr-2" type="button" onclick="return profile_panel_products_read('@last', 'active', '@last', '@last', 1, true);">Активные</a>
|
||||||
<a class="btn btn-sm button_white button_clean font-weight-bold mb-0 mr-2" type="button" onclick="return profile_panel_products_read('@last', 'inactive');">Неактивные</a>
|
<a class="btn btn-sm button_white button_clean font-weight-bold mb-0" type="button" onclick="return profile_panel_products_read('@last', 'inactive', '@last', '@last', 1, true);">Неактивные</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="dropdown-divider mb-4"></div>
|
<div class="dropdown-divider mb-4"></div>
|
||||||
<div id="profile_panel_input_products_wrap"></div>
|
<div id="profile_panel_input_products_wrap"></div>
|
||||||
|
@ -172,76 +123,7 @@ $timezone = $timezone[1][0];
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h5>Список поставок</h5>
|
<h5>Список поставок</h5>
|
||||||
<div class="dropdown-divider mb-4"></div>
|
<div class="dropdown-divider mb-4"></div>
|
||||||
<?php
|
<div id="profile_panel_input_supplies_wrap"></div>
|
||||||
// Инициализация счетчика аккаунтов
|
|
||||||
$amount = 0;
|
|
||||||
|
|
||||||
// Чтение аккаунтов
|
|
||||||
$supplies = Supply::read(limit: 100, order: ['desc']);
|
|
||||||
?>
|
|
||||||
<?php foreach ($supplies ?? [] as $supply) : ?>
|
|
||||||
<?php
|
|
||||||
try {
|
|
||||||
// Поиск аккаунта владельца
|
|
||||||
$account = '/account/' . Account::searchBySupplyId($supply->readId())['_key'];
|
|
||||||
|
|
||||||
// Деинициализация товара
|
|
||||||
unset($product);
|
|
||||||
|
|
||||||
if ($connect = $supply->searchConnectWithProduct()) {
|
|
||||||
// Найдена привязка поставки к аккаунту
|
|
||||||
|
|
||||||
$product = Product::searchById($connect->_to);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($supply->jrnl ?? [] as $jrnl) {
|
|
||||||
// Перебор записей в журнале
|
|
||||||
|
|
||||||
if ($jrnl['action'] === 'create') {
|
|
||||||
// Найдена дата создания
|
|
||||||
|
|
||||||
// Инициализация даты
|
|
||||||
$create = (new DateTime())->setTimestamp($jrnl['date'])->setTimezone(new DateTimeZone($timezone))->format('H:i d.m.Y') ?? 'Неизвестно';
|
|
||||||
|
|
||||||
// Выход из цикла
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Throwable $t) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
||||||
<div class="mb-3 row">
|
|
||||||
<div class="pr-0 col-auto"><?= ++$amount ?>.</div>
|
|
||||||
<div class="pr-0 col-2 overflow-hidden" title="Артикул">
|
|
||||||
<?= $supply->catn ?? 'Неизвестно' ?>
|
|
||||||
<span class="text-dark" title="Производитель"> (<?= $product->prod ?? 'Неизвестно' ?>)</span>
|
|
||||||
</div>
|
|
||||||
<div class="my-auto pr-0 col">
|
|
||||||
</div>
|
|
||||||
<div class="my-auto pr-0 col-auto" title="Количество">
|
|
||||||
<?= $supply->amnt ?? '0' ?>шт
|
|
||||||
</div>
|
|
||||||
<div class="my-auto pr-0 col-auto" title="Стоимость">
|
|
||||||
<?= $supply->cost ?? '0' ?>р
|
|
||||||
</div>
|
|
||||||
<div class="my-auto pr-0 col-auto text-right" title="Дата создания">
|
|
||||||
<?= $create ?? 'Неизвестно' ?>
|
|
||||||
</div>
|
|
||||||
<?php if (empty($product)) : ?>
|
|
||||||
<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 ?>, <?= "'$supply->prod'" ?? null ?>);"></a>
|
|
||||||
<?php else : ?>
|
|
||||||
<a class="my-auto pr-0 col-auto fas fa-shopping-basket text-dark" title="Товар" href="<?= "/product/$product->prod/$product->catn" ?>"></a>
|
|
||||||
<?php endif ?>
|
|
||||||
<a class="my-auto pr-0 col-auto fas fa-user text-dark" title="Владелец" href="<?= $account ?? '/' ?>"></a>
|
|
||||||
<a class="my-auto col-auto fas fa-trash-alt text-dark" type="button" title="Удалить" onclick="page_profile_supplies_delete()"></a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php if ($amount < count($supplies)) : ?>
|
|
||||||
<div class="dropdown-divider mb-3"></div>
|
|
||||||
<?php endif ?>
|
|
||||||
<?php endforeach ?>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input type="radio" id="profile_panel_input_settings" name="main_panel" <?= $panel === 'profile_panel_input_settings' ? 'checked' : null ?> />
|
<input type="radio" id="profile_panel_input_settings" name="main_panel" <?= $panel === 'profile_panel_input_settings' ? 'checked' : null ?> />
|
||||||
|
@ -362,12 +244,20 @@ $timezone = $timezone[1][0];
|
||||||
<script src="/js/product_panel.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>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('profile.loaded', function(e) {
|
||||||
// Загружен документ
|
// Загружена программа для работы с профилем
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('profile_panel.loaded', function(e) {
|
||||||
|
// Загружена программа для работы с панелью управления
|
||||||
|
|
||||||
// Инициализация активной вкладки
|
// Инициализация активной вкладки
|
||||||
page_profile_panel_choose('<?= $panel ?? '' ?>');
|
page_profile_panel_choose('<?= $panel ?? '' ?>');
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('textarea.loaded', function(e) {
|
||||||
|
// Загружена программа для работы с блоками текста
|
||||||
|
|
||||||
// Инициализация панели для ввода текста (тест уведомлений для администратора)
|
// Инициализация панели для ввода текста (тест уведомлений для администратора)
|
||||||
initTextarea(
|
initTextarea(
|
||||||
|
@ -394,5 +284,5 @@ $timezone = $timezone[1][0];
|
||||||
send.disabled = false;
|
send.disabled = false;
|
||||||
send_html.disabled = false;
|
send_html.disabled = false;
|
||||||
});
|
});
|
||||||
}, false);
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -9,6 +9,7 @@ use app\models\Account;
|
||||||
use app\models\Import;
|
use app\models\Import;
|
||||||
use app\models\Settings;
|
use app\models\Settings;
|
||||||
use app\models\Warehouse;
|
use app\models\Warehouse;
|
||||||
|
use app\models\File;
|
||||||
|
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use DateTimeZone;
|
use DateTimeZone;
|
||||||
|
@ -103,9 +104,12 @@ $panel ?? $panel = 'profile_panel_supplies_input_import';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Инициализация файла
|
||||||
|
$file = File::searchByImport($import);
|
||||||
|
|
||||||
// Инициализация ссылки на скачивание
|
// Инициализация ссылки на скачивание
|
||||||
preg_match_all('/\/files\/.*$/', $import->file, $matches);
|
preg_match_all('/\/files\/.*$/', $file->path ?? '', $matches);
|
||||||
$download = $matches[0][0];
|
$download = $matches[0][0] ?? '';
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="mb-3 row">
|
<div class="mb-3 row">
|
||||||
|
@ -113,7 +117,7 @@ $panel ?? $panel = 'profile_panel_supplies_input_import';
|
||||||
<?= ++$amount ?>.
|
<?= ++$amount ?>.
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<?= $import->name ?? 'Без названия' ?>
|
<?= (isset($file->stts) && $file->stts === 'loaded') ? $file->name ?? 'Без названия' : ($file->name ?? 'Без названия') . ' (в очереди на загрузку)' ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-3 px-0 text-right">
|
<div class="col-3 px-0 text-right">
|
||||||
<?= $create ?? 'Неизвестно' ?>
|
<?= $create ?? 'Неизвестно' ?>
|
||||||
|
@ -172,16 +176,19 @@ $panel ?? $panel = 'profile_panel_supplies_input_import';
|
||||||
|
|
||||||
<?php foreach (Import::searchByWarehouse($warehouse) as $import) : ?>
|
<?php foreach (Import::searchByWarehouse($warehouse) as $import) : ?>
|
||||||
<?php
|
<?php
|
||||||
|
// Инициализация файла
|
||||||
|
$file = File::searchByImport($import);
|
||||||
|
|
||||||
// Инициализация ссылки на скачивание
|
// Инициализация ссылки на скачивание
|
||||||
preg_match_all('/\/files\/.*$/', $import->file, $matches);
|
preg_match_all('/\/files\/.*$/', $file->path ?? '', $matches);
|
||||||
$download = $matches[0][0];
|
$download = $matches[0][0] ?? '';
|
||||||
?>
|
?>
|
||||||
<div class="mx-2 mb-3 row">
|
<div class="mx-2 mb-3 row">
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<?= ++$amount_imports ?>.
|
<?= ++$amount_imports ?>.
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<?= $import->name ?? 'Без названия' ?>
|
<?= (isset($file->stts) && $file->stts === 'loaded') ? $file->name ?? 'Без названия' : ($file->name ?? 'Без названия') . ' (в очереди на загрузку)' ?>
|
||||||
</div>
|
</div>
|
||||||
<a class="pr-0 my-auto col-auto fas fa-file-download text-dark" title="Скачать" href="<?= $download ?? '/#' ?>" aria-hidden="true" download></a>
|
<a class="pr-0 my-auto col-auto fas fa-file-download text-dark" title="Скачать" href="<?= $download ?? '/#' ?>" aria-hidden="true" download></a>
|
||||||
<a class="my-auto col-auto fas fa-trash-alt text-dark" title="Удалить" type="button" aria-hidden="true" onclick="return page_profile_imports_delete(<?= $import->_key ?>);"></a>
|
<a class="my-auto col-auto fas fa-trash-alt text-dark" title="Удалить" type="button" aria-hidden="true" onclick="return page_profile_imports_delete(<?= $import->_key ?>);"></a>
|
||||||
|
|
|
@ -51,7 +51,7 @@ use app\models\Search;
|
||||||
<div class="row p-2 rounded">
|
<div class="row p-2 rounded">
|
||||||
<img class="ml-0 rounded" src="<?= $covr ?>" />
|
<img class="ml-0 rounded" src="<?= $covr ?>" />
|
||||||
<div class="col ml-3 p-0 d-flex flex-column row_fixed_height">
|
<div class="col ml-3 p-0 d-flex flex-column row_fixed_height">
|
||||||
<a class="my-auto text-dark" href="/product/<?= $prod ?>/<?= $catn ?>">
|
<a class="my-auto text-dark" href="/product/<?= urlencode($prod) ?>/<?= urlencode($catn) ?>">
|
||||||
<h5 class="m-0"><b><?= $prod ?></b> <?= $catn ?></h5>
|
<h5 class="m-0"><b><?= $prod ?></b> <?= $catn ?></h5>
|
||||||
<h6 class="m-0"><small><?= $name ?></small></h6>
|
<h6 class="m-0"><small><?= $name ?></small></h6>
|
||||||
</a>
|
</a>
|
||||||
|
@ -83,7 +83,7 @@ use app\models\Search;
|
||||||
// Перебор найденных товаров товаров производителя
|
// Перебор найденных товаров товаров производителя
|
||||||
|
|
||||||
// Чтение и запись аналогов
|
// Чтение и запись аналогов
|
||||||
$analogs[$prod][$catn] = Search::content(products: ProductGroup::searchByProduct(Product::searchByCatnAndProd($catn, $prod))->searchProducts());
|
$analogs[$prod][$catn] = Search::content(products: ProductGroup::searchByProduct(Product::searchByCatnAndProd($catn, $prod))?->searchProducts() ?? []);
|
||||||
|
|
||||||
// Исключение из вывода в списке аналогов (проверка на дубликат)
|
// Исключение из вывода в списке аналогов (проверка на дубликат)
|
||||||
$writed[$prod][$catn] = true;
|
$writed[$prod][$catn] = true;
|
||||||
|
@ -98,8 +98,9 @@ use app\models\Search;
|
||||||
<?php foreach ($catns as $catn => $products) : ?>
|
<?php foreach ($catns as $catn => $products) : ?>
|
||||||
<?php foreach ($products as $product) : ?>
|
<?php foreach ($products as $product) : ?>
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
// Проверка на дубликат
|
// Проверка на дубликат
|
||||||
if (array_key_exists($product['catn'], $writed[$prod])) continue;
|
if (isset($writed[$prod]) && array_key_exists($product['catn'], $writed[$prod])) continue;
|
||||||
|
|
||||||
// Инициализация данных товара
|
// Инициализация данных товара
|
||||||
$covr = null;
|
$covr = null;
|
||||||
|
@ -122,7 +123,7 @@ use app\models\Search;
|
||||||
<div class="row p-2 rounded">
|
<div class="row p-2 rounded">
|
||||||
<img class="ml-0 rounded" src="<?= $covr ?>" />
|
<img class="ml-0 rounded" src="<?= $covr ?>" />
|
||||||
<div class="col ml-3 p-0 d-flex flex-column row_fixed_height">
|
<div class="col ml-3 p-0 d-flex flex-column row_fixed_height">
|
||||||
<a class="my-auto text-dark" href="/product/<?= $prod ?>/<?= $catn ?>">
|
<a class="my-auto text-dark" href="/product/<?= urlencode($prod) ?>/<?= urlencode($catn) ?>">
|
||||||
<h5 class="m-0"><b><?= $prod ?></b> <?= $catn ?></h5>
|
<h5 class="m-0"><b><?= $prod ?></b> <?= $catn ?></h5>
|
||||||
<h6 class="m-0"><small><?= $name ?></small></h6>
|
<h6 class="m-0"><small><?= $name ?></small></h6>
|
||||||
</a>
|
</a>
|
||||||
|
@ -144,9 +145,7 @@ use app\models\Search;
|
||||||
|
|
||||||
<?php else : ?>
|
<?php else : ?>
|
||||||
<?php if ($advanced ?? false) : ?>
|
<?php if ($advanced ?? false) : ?>
|
||||||
|
|
||||||
<h1 class="m-auto gilroy text-center"><b>Ничего не найдено</b></h1>
|
<h1 class="m-auto gilroy text-center"><b>Ничего не найдено</b></h1>
|
||||||
|
|
||||||
<?php else : ?>
|
<?php else : ?>
|
||||||
|
|
||||||
<div class="row py-3 w-100">
|
<div class="row py-3 w-100">
|
||||||
|
|
|
@ -44,9 +44,12 @@ if (isset($history) && $history) {
|
||||||
// Перебор найденных данных
|
// Перебор найденных данных
|
||||||
|
|
||||||
$catn = $row['catn'];
|
$catn = $row['catn'];
|
||||||
|
$prod = $row['prod'];
|
||||||
|
$_catn = urlencode($row['catn']);
|
||||||
|
$_prod = urlencode($row['prod']);
|
||||||
|
|
||||||
echo <<<HTML
|
echo <<<HTML
|
||||||
<a class="dropdown-item button_white text-dark" href="/product/$catn">$catn</a>
|
<a class="d-flex dropdown-item button_white text-dark" href="/product/$_prod/$_catn"><span class="col-auto pl-0">$catn</span><b class="col-auto ml-auto px-0 text-right">$prod</b></a>
|
||||||
HTML;
|
HTML;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use app\models\Product;
|
||||||
|
use app\models\Account;
|
||||||
|
use app\models\Settings;
|
||||||
|
|
||||||
|
|
||||||
|
// Инициализация счетчика поставок
|
||||||
|
$i = $amount * ($page - 1);
|
||||||
|
|
||||||
|
// Инициализация часового пояса
|
||||||
|
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::searchActive()['timezone_default'] ?? 'UTC+3', $timezone);
|
||||||
|
$timezone = $timezone[1][0];
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php if ($page > 1) : ?>
|
||||||
|
<div class="dropdown-divider mb-3"></div>
|
||||||
|
<?php endif ?>
|
||||||
|
|
||||||
|
<?php foreach ($supplies ?? [] as $supply) : ?>
|
||||||
|
<?php
|
||||||
|
// Поиск аккаунта владельца
|
||||||
|
$account = '/account/' . Account::searchBySupplyId($supply->readId())['_key'];
|
||||||
|
|
||||||
|
if ($connect = $supply->searchConnectWithProduct()) {
|
||||||
|
// Найдена привязка поставки к аккаунту
|
||||||
|
|
||||||
|
$product = Product::searchById($connect->_to);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($supply->jrnl ?? [] as $jrnl) {
|
||||||
|
// Перебор записей в журнале
|
||||||
|
|
||||||
|
if ($jrnl['action'] === 'create') {
|
||||||
|
// Найдена дата создания
|
||||||
|
|
||||||
|
// Инициализация даты
|
||||||
|
$create = (new DateTime())->setTimestamp($jrnl['date'])->setTimezone(new DateTimeZone($timezone))->format('H:i d.m.Y') ?? 'Неизвестно';
|
||||||
|
|
||||||
|
// Выход из цикла
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="mb-3 row">
|
||||||
|
<div class="pr-0 col-auto"><?= ++$i ?>.</div>
|
||||||
|
<div class="pr-0 col-auto mr-auto overflow-hidden" title="Артикул">
|
||||||
|
<?= $supply->catn ?? 'Неизвестно' ?>
|
||||||
|
<span class="text-dark" title="Производитель"> (<?= $product->prod ?? 'Неизвестно' ?>)</span>
|
||||||
|
</div>
|
||||||
|
<div class="my-auto pr-0 col-auto" title="Стоимость">
|
||||||
|
<?= $supply->cost ?? '0' ?>р
|
||||||
|
</div>
|
||||||
|
<div class="my-auto pr-0 col-auto text-right" title="Дата создания">
|
||||||
|
<?= $create ?? 'Неизвестно' ?>
|
||||||
|
</div>
|
||||||
|
<?php if (empty($product)) : ?>
|
||||||
|
<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 ?>, <?= "'$supply->prod'" ?? null ?>);"></a>
|
||||||
|
<?php else : ?>
|
||||||
|
<a class="my-auto pr-0 col-auto fas fa-shopping-basket text-dark" title="Товар" href="<?= urlencode("/product/$product->prod/$product->catn") ?>"></a>
|
||||||
|
<?php endif ?>
|
||||||
|
<a class="my-auto pr-0 col-auto fas fa-user text-dark" title="Владелец" href="<?= urlencode($account ?? '/') ?>"></a>
|
||||||
|
<a class="my-auto col-auto fas fa-trash-alt text-dark" type="button" title="Удалить" onclick="page_profile_supplies_delete()"></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if ($i < count($supplies) + $amount * ($page - 1)) : ?>
|
||||||
|
<div class="dropdown-divider mb-3"></div>
|
||||||
|
<?php endif ?>
|
||||||
|
<?php endforeach ?>
|
|
@ -0,0 +1,48 @@
|
||||||
|
section.hotline {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.hotline.vertical {
|
||||||
|
margin-bottom: unset;
|
||||||
|
margin-right: 10px;
|
||||||
|
height: unset;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.hotline.vertical:last-child {
|
||||||
|
margin-right: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.hotline:last-child {
|
||||||
|
margin-bottom: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.hotline > article {
|
||||||
|
margin-right: 3vh;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.hotline.vertical > article {
|
||||||
|
margin-right: unset;
|
||||||
|
margin-bottom: 3vh;
|
||||||
|
width: 20vh;
|
||||||
|
height: 10vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.hotline:not(.vertical) > article:last-child {
|
||||||
|
margin-right: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.hotline.vertical > article:last-child {
|
||||||
|
margin-bottom: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.hotline > article > * {
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.hotline>article>img {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
|
@ -267,6 +267,10 @@ main {
|
||||||
border-top: 1px solid #CEDCFF !important;
|
border-top: 1px solid #CEDCFF !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.help-block-error {
|
||||||
|
color: #e60000;
|
||||||
|
}
|
||||||
|
|
||||||
/* @media (max-width: 400px) {} */
|
/* @media (max-width: 400px) {} */
|
||||||
|
|
||||||
/* Малые девайсы («ландшафтные телефоны», >= 576px) */
|
/* Малые девайсы («ландшафтные телефоны», >= 576px) */
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#page_product nav>div,
|
#page_product nav>div,
|
||||||
#page_product article>div {
|
#page_product article>div:not(#products_list) {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,3 +95,20 @@
|
||||||
#page_product article .product_admin_menu {
|
#page_product article .product_admin_menu {
|
||||||
background-color: #f4f4f6;
|
background-color: #f4f4f6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#page_product .row_analog {
|
||||||
|
/* height : 65px; */
|
||||||
|
background-color: #fff;
|
||||||
|
border-right: 0 solid #fff;
|
||||||
|
transition: 100ms ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
#page_product .row_fixed_height {
|
||||||
|
height: calc(65px - 1rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
#page_product .row_analog>img {
|
||||||
|
object-fit: cover;
|
||||||
|
width: calc(65px - 1rem);
|
||||||
|
height: calc(65px - 1rem);
|
||||||
|
}
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
.ticker img {
|
|
||||||
object-fit: contain;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bx-wrapper {
|
|
||||||
margin-bottom: 1.5rem !important;
|
|
||||||
width: 100vw;
|
|
||||||
-webkit-box-sizing: border-box;
|
|
||||||
-moz-box-sizing: border-box;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bx-wrapper .bx-viewport {
|
|
||||||
width: 100vw !important;
|
|
||||||
height: 2rem !important;
|
|
||||||
}
|
|
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 860 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 771 B |
After Width: | Height: | Size: 619 B |
After Width: | Height: | Size: 907 B |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 873 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 942 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 5.8 KiB |
After Width: | Height: | Size: 3.2 KiB |
|
@ -43,6 +43,120 @@ function authentication(form, target = 'main') {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function restore(form, target = 'main') {
|
||||||
|
|
||||||
|
if (form == undefined) {
|
||||||
|
form = {
|
||||||
|
'_csrf': yii.getCsrfToken()
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
form = $(form).serializeArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
form.push(
|
||||||
|
{
|
||||||
|
name: 'type',
|
||||||
|
value: 'restore'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'target',
|
||||||
|
value: target
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: '/restore',
|
||||||
|
type: 'post',
|
||||||
|
dataType: 'json',
|
||||||
|
data: form,
|
||||||
|
success: function (data, status, xhr) {
|
||||||
|
if (data !== undefined) {
|
||||||
|
// Получены данные с сервера
|
||||||
|
|
||||||
|
// Панель
|
||||||
|
if (typeof data.status === 'boolean') {
|
||||||
|
// Успешное выполнение
|
||||||
|
|
||||||
|
// Инициализация оболочки для уведомлений, оболочки для уведомлений и оболочки формы
|
||||||
|
let id, body, alert;
|
||||||
|
|
||||||
|
console.log(window.location.pathname);
|
||||||
|
console.log(window.location.pathname === '/authentication');
|
||||||
|
|
||||||
|
if (window.location.pathname === '/authentication') {
|
||||||
|
// Страница аутентификации
|
||||||
|
|
||||||
|
// Запись оболочки формы
|
||||||
|
body = document.getElementById('form_account');
|
||||||
|
|
||||||
|
// Запись оболочки для уведомлений
|
||||||
|
id = 'form_account_alert';
|
||||||
|
|
||||||
|
// Запись оболочки для уведомлений
|
||||||
|
alert = document.getElementById(id);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Панель аутентификации
|
||||||
|
|
||||||
|
// Запись оболочки формы
|
||||||
|
body = document.getElementById('form_account_panel');
|
||||||
|
|
||||||
|
// Запись идентификатора оболочки для уведомлений
|
||||||
|
id = 'form_account_panel_alert';
|
||||||
|
|
||||||
|
// Запись оболочки для уведомлений
|
||||||
|
alert = document.getElementById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(alert instanceof HTMLElement)) {
|
||||||
|
// Не найдена оболочка для уведомлений (подразумевается)
|
||||||
|
|
||||||
|
// Инициализация оболочки для уведомлений
|
||||||
|
const wrap = document.createElement('small');
|
||||||
|
wrap.classList.add('d-flex');
|
||||||
|
const element = document.createElement('small');
|
||||||
|
element.id = id;
|
||||||
|
element.classList.add('mx-auto');
|
||||||
|
|
||||||
|
// Запись в панель
|
||||||
|
wrap.appendChild(element);
|
||||||
|
body.appendChild(wrap);
|
||||||
|
|
||||||
|
// Реинициализация оболочки для уведомлений
|
||||||
|
alert = element;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.status) {
|
||||||
|
// Отправлено сообщение
|
||||||
|
|
||||||
|
// Запись уведомления
|
||||||
|
alert.innerText = 'Сообщение отправлено на почту';
|
||||||
|
} else if (document.getElementById('accountform-mail').value === '') {
|
||||||
|
// Пустое содержимое почты
|
||||||
|
|
||||||
|
// Запись уведомления
|
||||||
|
alert.innerText = 'Введите почту';
|
||||||
|
|
||||||
|
// Удаление ненужных полей
|
||||||
|
document.getElementById('accountform-pswd').parentElement.remove();
|
||||||
|
panel.querySelector('[name="submitAuthentication"]').parentElement.remove();
|
||||||
|
panel.querySelector('[name="submitRegistration"]').remove();
|
||||||
|
} else {
|
||||||
|
// Не удалось отправить сообщение
|
||||||
|
|
||||||
|
// Запись уведомления
|
||||||
|
alert.innerText = 'Ошибка при отправке сообщения';
|
||||||
|
}
|
||||||
|
|
||||||
|
alert.innerText = data.status ? 'Сообщение отправлено на почту' : 'Введите почту';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
account_response_success(data, status, xhr);
|
||||||
|
},
|
||||||
|
error: account_response_error
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
function deauthentication() {
|
function deauthentication() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/deauthentication',
|
url: '/deauthentication',
|
||||||
|
|
|
@ -653,3 +653,5 @@ function cart_response_error(data, status, xhr) {
|
||||||
|
|
||||||
cart_response(data, status, xhr);
|
cart_response(data, status, xhr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
document.dispatchEvent(new CustomEvent("cart.loaded"));
|
||||||
|
|
|
@ -0,0 +1,679 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Бегущая строка
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Простой, но мощный класс для создания бегущих строк. Поддерживает
|
||||||
|
* перемещение мышью и прокрутку колесом, полностью настраивается очень гибок
|
||||||
|
* для настроек в CSS и подразумевается, что отлично индексируется поисковыми роботами.
|
||||||
|
* Имеет свой препроцессор, благодаря которому можно создавать бегущие строки
|
||||||
|
* без программирования - с помощью HTML-аттрибутов, а так же возможность
|
||||||
|
* изменять параметры (data-hotline-* аттрибуты) на лету. Есть возможность вызывать
|
||||||
|
* события при выбранных действиях для того, чтобы пользователь имел возможность
|
||||||
|
* дорабатывать функционал без изучения и изменения моего кода
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* сonst hotline = new hotline();
|
||||||
|
* hotline.step = '-5';
|
||||||
|
* hotline.start();
|
||||||
|
*
|
||||||
|
* @todo
|
||||||
|
* 1. Бесконечный режим - элементы не удаляются если видны на экране (будут дубликаты)
|
||||||
|
*
|
||||||
|
* @copyright WTFPL
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
class hotline {
|
||||||
|
// Идентификатор
|
||||||
|
#id = 0;
|
||||||
|
|
||||||
|
// Оболочка (instanceof HTMLElement)
|
||||||
|
#shell = document.getElementById("hotline");
|
||||||
|
|
||||||
|
// Инстанция горячей строки
|
||||||
|
#instance = null;
|
||||||
|
|
||||||
|
// Перемещение
|
||||||
|
#transfer = true;
|
||||||
|
|
||||||
|
// Движение
|
||||||
|
#move = true;
|
||||||
|
|
||||||
|
// Наблюдатель
|
||||||
|
#observer = null;
|
||||||
|
|
||||||
|
// Наблюдатель
|
||||||
|
#block = new Set(["events"]);
|
||||||
|
|
||||||
|
// Настраиваемые параметры
|
||||||
|
transfer = null;
|
||||||
|
move = null;
|
||||||
|
delay = 10;
|
||||||
|
step = 1;
|
||||||
|
hover = true;
|
||||||
|
movable = true;
|
||||||
|
sticky = false;
|
||||||
|
wheel = false;
|
||||||
|
delta = null;
|
||||||
|
vertical = false;
|
||||||
|
observe = false;
|
||||||
|
events = new Map([
|
||||||
|
["start", false],
|
||||||
|
["stop", false],
|
||||||
|
["move", false],
|
||||||
|
["move.block", false],
|
||||||
|
["move.unblock", false],
|
||||||
|
["offset", false],
|
||||||
|
["transfer.start", true],
|
||||||
|
["transfer.end", true],
|
||||||
|
["onmousemove", false]
|
||||||
|
]);
|
||||||
|
|
||||||
|
constructor(id, shell) {
|
||||||
|
// Запись идентификатора
|
||||||
|
if (typeof id === "string" || typeof id === "number") this.#id = id;
|
||||||
|
|
||||||
|
// Запись оболочки
|
||||||
|
if (shell instanceof HTMLElement) this.#shell = shell;
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
if (this.#instance === null) {
|
||||||
|
// Нет запущенной инстанции бегущей строки
|
||||||
|
|
||||||
|
// Инициализация ссылки на ядро
|
||||||
|
const _this = this;
|
||||||
|
|
||||||
|
// Запуск движения
|
||||||
|
this.#instance = setInterval(function () {
|
||||||
|
if (_this.#shell.childElementCount > 1) {
|
||||||
|
// Найдено содержимое бегущей строки (2 и более)
|
||||||
|
|
||||||
|
// Инициализация буфера для временных данных
|
||||||
|
let buffer;
|
||||||
|
|
||||||
|
// Инициализация данных первого элемента в строке
|
||||||
|
const first = {
|
||||||
|
element: (buffer = _this.#shell.firstElementChild),
|
||||||
|
coords: buffer.getBoundingClientRect()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_this.vertical) {
|
||||||
|
// Вертикальная бегущая строка
|
||||||
|
|
||||||
|
// Инициализация сдвига у первого элемента (движение)
|
||||||
|
first.offset = isNaN(
|
||||||
|
(buffer = parseFloat(first.element.style.marginTop))
|
||||||
|
)
|
||||||
|
? 0
|
||||||
|
: buffer;
|
||||||
|
|
||||||
|
// Инициализация отступа до второго элемента у первого элемента (разделение)
|
||||||
|
first.separator = isNaN(
|
||||||
|
(buffer = parseFloat(
|
||||||
|
getComputedStyle(first.element).marginBottom
|
||||||
|
))
|
||||||
|
)
|
||||||
|
? 0
|
||||||
|
: buffer;
|
||||||
|
|
||||||
|
// Инициализация крайнего с конца ребра первого элемента в строке
|
||||||
|
first.end = first.coords.y + first.coords.height + first.separator;
|
||||||
|
} else {
|
||||||
|
// Горизонтальная бегущая строка
|
||||||
|
|
||||||
|
// Инициализация отступа у первого элемента (движение)
|
||||||
|
first.offset = isNaN(
|
||||||
|
(buffer = parseFloat(first.element.style.marginLeft))
|
||||||
|
)
|
||||||
|
? 0
|
||||||
|
: buffer;
|
||||||
|
|
||||||
|
// Инициализация отступа до второго элемента у первого элемента (разделение)
|
||||||
|
first.separator = isNaN(
|
||||||
|
(buffer = parseFloat(getComputedStyle(first.element).marginRight))
|
||||||
|
)
|
||||||
|
? 0
|
||||||
|
: buffer;
|
||||||
|
|
||||||
|
// Инициализация крайнего с конца ребра первого элемента в строке
|
||||||
|
first.end = first.coords.x + first.coords.width + first.separator;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(_this.vertical &&
|
||||||
|
Math.round(first.end) < _this.#shell.offsetTop) ||
|
||||||
|
(!_this.vertical && Math.round(first.end) < _this.#shell.offsetLeft)
|
||||||
|
) {
|
||||||
|
// Элемент (вместе с отступом до второго элемента) вышел из области видимости (строки)
|
||||||
|
|
||||||
|
if (
|
||||||
|
(_this.transfer === null && _this.#transfer) ||
|
||||||
|
_this.transfer === true
|
||||||
|
) {
|
||||||
|
// Перенос разрешен
|
||||||
|
|
||||||
|
if (_this.vertical) {
|
||||||
|
// Вертикальная бегущая строка
|
||||||
|
|
||||||
|
// Удаление отступов (движения)
|
||||||
|
first.element.style.marginTop = null;
|
||||||
|
} else {
|
||||||
|
// Горизонтальная бегущая строка
|
||||||
|
|
||||||
|
// Удаление отступов (движения)
|
||||||
|
first.element.style.marginLeft = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Копирование первого элемента в конец строки
|
||||||
|
_this.#shell.appendChild(first.element);
|
||||||
|
|
||||||
|
if (_this.events.get("transfer.end")) {
|
||||||
|
// Запрошен вызов события: "перемещение в конец"
|
||||||
|
|
||||||
|
// Вызов события: "перемещение в конец"
|
||||||
|
document.dispatchEvent(
|
||||||
|
new CustomEvent(`hotline.${_this.#id}.transfer.end`, {
|
||||||
|
detail: {
|
||||||
|
element: first.element,
|
||||||
|
offset: -(
|
||||||
|
(_this.vertical
|
||||||
|
? first.coords.height
|
||||||
|
: first.coords.width) + first.separator
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
(_this.vertical &&
|
||||||
|
Math.round(first.coords.y) > _this.#shell.offsetTop) ||
|
||||||
|
(!_this.vertical &&
|
||||||
|
Math.round(first.coords.x) > _this.#shell.offsetLeft)
|
||||||
|
) {
|
||||||
|
// Передняя (движущая) граница первого элемента вышла из области видимости
|
||||||
|
|
||||||
|
if (
|
||||||
|
(_this.transfer === null && _this.#transfer) ||
|
||||||
|
_this.transfer === true
|
||||||
|
) {
|
||||||
|
// Перенос разрешен
|
||||||
|
|
||||||
|
// Инициализация отступа у последнего элемента (разделение)
|
||||||
|
const separator =
|
||||||
|
(buffer = isNaN(
|
||||||
|
(buffer = parseFloat(
|
||||||
|
getComputedStyle(_this.#shell.lastElementChild)[
|
||||||
|
_this.vertical ? "marginBottom" : "marginRight"
|
||||||
|
]
|
||||||
|
))
|
||||||
|
)
|
||||||
|
? 0
|
||||||
|
: buffer) === 0
|
||||||
|
? first.separator
|
||||||
|
: buffer;
|
||||||
|
|
||||||
|
// Инициализация координат первого элемента в строке
|
||||||
|
const coords = _this.#shell.lastElementChild.getBoundingClientRect();
|
||||||
|
|
||||||
|
if (_this.vertical) {
|
||||||
|
// Вертикальная бегущая строка
|
||||||
|
|
||||||
|
// Удаление отступов (движения)
|
||||||
|
_this.#shell.lastElementChild.style.marginTop =
|
||||||
|
-coords.height - separator + "px";
|
||||||
|
} else {
|
||||||
|
// Горизонтальная бегущая строка
|
||||||
|
|
||||||
|
// Удаление отступов (движения)
|
||||||
|
_this.#shell.lastElementChild.style.marginLeft =
|
||||||
|
-coords.width - separator + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Копирование последнего элемента в начало строки
|
||||||
|
_this.#shell.insertBefore(
|
||||||
|
_this.#shell.lastElementChild,
|
||||||
|
first.element
|
||||||
|
);
|
||||||
|
|
||||||
|
// Удаление отступов у второго элемента в строке (движения)
|
||||||
|
_this.#shell.children[1].style[
|
||||||
|
_this.vertical ? "marginTop" : "marginLeft"
|
||||||
|
] = null;
|
||||||
|
|
||||||
|
if (_this.events.get("transfer.start")) {
|
||||||
|
// Запрошен вызов события: "перемещение в начало"
|
||||||
|
|
||||||
|
// Вызов события: "перемещение в начало"
|
||||||
|
document.dispatchEvent(
|
||||||
|
new CustomEvent(`hotline.${_this.#id}.transfer.start`, {
|
||||||
|
detail: {
|
||||||
|
element: _this.#shell.lastElementChild,
|
||||||
|
offset:
|
||||||
|
(_this.vertical ? coords.height : coords.width) +
|
||||||
|
separator
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Элемент в области видимости
|
||||||
|
|
||||||
|
if ((_this.move === null && _this.#move) || _this.move === true) {
|
||||||
|
// Движение разрешено
|
||||||
|
|
||||||
|
// Запись новых координат сдвига
|
||||||
|
const offset = first.offset + _this.step;
|
||||||
|
|
||||||
|
// Запись сдвига (движение)
|
||||||
|
_this.offset(offset);
|
||||||
|
|
||||||
|
if (_this.events.get("move")) {
|
||||||
|
// Запрошен вызов события: "движение"
|
||||||
|
|
||||||
|
// Вызов события: "движение"
|
||||||
|
document.dispatchEvent(
|
||||||
|
new CustomEvent(`hotline.${_this.#id}.move`, {
|
||||||
|
detail: {
|
||||||
|
from: first.offset,
|
||||||
|
to: offset
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, _this.delay);
|
||||||
|
|
||||||
|
if (this.hover) {
|
||||||
|
// Запрошена возможность останавливать бегущую строку
|
||||||
|
|
||||||
|
// Инициализация сдвига
|
||||||
|
let offset = 0;
|
||||||
|
|
||||||
|
// Инициализация слушателя события при перемещении элемента в бегущей строке
|
||||||
|
const listener = function (e) {
|
||||||
|
// Увеличение сдвига
|
||||||
|
offset += e.detail.offset ?? 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Инициализация обработчика наведения курсора (остановка движения)
|
||||||
|
this.#shell.onmouseover = function (e) {
|
||||||
|
// Курсор наведён на бегущую строку
|
||||||
|
|
||||||
|
// Блокировка движения
|
||||||
|
_this.#move = false;
|
||||||
|
|
||||||
|
if (_this.events.get("move.block")) {
|
||||||
|
// Запрошен вызов события: "блокировка движения"
|
||||||
|
|
||||||
|
// Вызов события: "блокировка движения"
|
||||||
|
document.dispatchEvent(
|
||||||
|
new CustomEvent(`hotline.${_this.#id}.move.block`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_this.movable) {
|
||||||
|
// Запрошена возможность двигать бегущую строку
|
||||||
|
|
||||||
|
_this.#shell.onmousedown = function (onmousedown) {
|
||||||
|
// Курсор активирован
|
||||||
|
|
||||||
|
// Инициализация слушателей события перемещения элемента в бегущей строке
|
||||||
|
document.addEventListener(
|
||||||
|
`hotline.${_this.#id}.transfer.start`,
|
||||||
|
listener
|
||||||
|
);
|
||||||
|
document.addEventListener(
|
||||||
|
`hotline.${_this.#id}.transfer.end`,
|
||||||
|
listener
|
||||||
|
);
|
||||||
|
|
||||||
|
// Инициализация буфера для временных данных
|
||||||
|
let buffer;
|
||||||
|
|
||||||
|
// Инициализация данных первого элемента в строке
|
||||||
|
const first = {
|
||||||
|
offset: isNaN(
|
||||||
|
(buffer = parseFloat(
|
||||||
|
_this.vertical
|
||||||
|
? _this.#shell.firstElementChild.style.marginTop
|
||||||
|
: _this.#shell.firstElementChild.style.marginLeft
|
||||||
|
))
|
||||||
|
)
|
||||||
|
? 0
|
||||||
|
: buffer
|
||||||
|
};
|
||||||
|
|
||||||
|
document.onmousemove = function (onmousemove) {
|
||||||
|
// Курсор движется
|
||||||
|
|
||||||
|
if (_this.vertical) {
|
||||||
|
// Вертикальная бегущая строка
|
||||||
|
|
||||||
|
// Инициализация буфера местоположения
|
||||||
|
const from = _this.#shell.firstElementChild.style.marginTop;
|
||||||
|
const to =
|
||||||
|
onmousemove.pageY -
|
||||||
|
(onmousedown.pageY + offset - first.offset);
|
||||||
|
|
||||||
|
// Движение
|
||||||
|
_this.#shell.firstElementChild.style.marginTop = to + "px";
|
||||||
|
|
||||||
|
if (_this.events.get("onmousemove")) {
|
||||||
|
// Запрошен вызов события: "перемещение мышью"
|
||||||
|
|
||||||
|
// Вызов события: "перемещение мышью"
|
||||||
|
document.dispatchEvent(
|
||||||
|
new CustomEvent(`hotline.${_this.#id}.onmousemove`, {
|
||||||
|
detail: { from, to }
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Горизонтальная бегущая строка
|
||||||
|
|
||||||
|
// Инициализация буфера местоположения
|
||||||
|
const from = _this.#shell.firstElementChild.style.marginLeft;
|
||||||
|
const to =
|
||||||
|
onmousemove.pageX -
|
||||||
|
(onmousedown.pageX + offset - first.offset);
|
||||||
|
|
||||||
|
// Движение
|
||||||
|
_this.#shell.firstElementChild.style.marginLeft = to + "px";
|
||||||
|
|
||||||
|
if (_this.events.get("onmousemove")) {
|
||||||
|
// Запрошен вызов события: "перемещение мышью"
|
||||||
|
|
||||||
|
// Вызов события: "перемещение мышью"
|
||||||
|
document.dispatchEvent(
|
||||||
|
new CustomEvent(`hotline.${_this.#id}.onmousemove`, {
|
||||||
|
detail: { from, to }
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Запись курсора
|
||||||
|
_this.#shell.style.cursor = "grabbing";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Перещапись событий браузера (чтобы не дёргалось)
|
||||||
|
_this.#shell.ondragstart = null;
|
||||||
|
|
||||||
|
_this.#shell.onmouseup = function () {
|
||||||
|
// Курсор деактивирован
|
||||||
|
|
||||||
|
// Остановка обработки движения
|
||||||
|
document.onmousemove = null;
|
||||||
|
|
||||||
|
// Сброс сдвига
|
||||||
|
offset = 0;
|
||||||
|
|
||||||
|
document.removeEventListener(
|
||||||
|
`hotline.${_this.#id}.transfer.start`,
|
||||||
|
listener
|
||||||
|
);
|
||||||
|
document.removeEventListener(
|
||||||
|
`hotline.${_this.#id}.transfer.end`,
|
||||||
|
listener
|
||||||
|
);
|
||||||
|
|
||||||
|
// Восстановление курсора
|
||||||
|
_this.#shell.style.cursor = null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Инициализация обработчика отведения курсора (остановка движения)
|
||||||
|
this.#shell.onmouseleave = function (onmouseleave) {
|
||||||
|
// Курсор отведён от бегущей строки
|
||||||
|
|
||||||
|
if (!_this.sticky) {
|
||||||
|
// Отключено прилипание
|
||||||
|
|
||||||
|
// Остановка обработки движения
|
||||||
|
document.onmousemove = null;
|
||||||
|
|
||||||
|
document.removeEventListener(
|
||||||
|
`hotline.${_this.#id}.transfer.start`,
|
||||||
|
listener
|
||||||
|
);
|
||||||
|
document.removeEventListener(
|
||||||
|
`hotline.${_this.#id}.transfer.end`,
|
||||||
|
listener
|
||||||
|
);
|
||||||
|
|
||||||
|
// Восстановление курсора
|
||||||
|
_this.#shell.style.cursor = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Сброс сдвига
|
||||||
|
offset = 0;
|
||||||
|
|
||||||
|
// Разблокировка движения
|
||||||
|
_this.#move = true;
|
||||||
|
|
||||||
|
if (_this.events.get("move.unblock")) {
|
||||||
|
// Запрошен вызов события: "разблокировка движения"
|
||||||
|
|
||||||
|
// Вызов события: "разблокировка движения"
|
||||||
|
document.dispatchEvent(
|
||||||
|
new CustomEvent(`hotline.${_this.#id}.move.unblock`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.wheel) {
|
||||||
|
// Запрошена возможность прокручивать колесом мыши
|
||||||
|
|
||||||
|
// Инициализация обработчика наведения курсора (остановка движения)
|
||||||
|
this.#shell.onwheel = function (e) {
|
||||||
|
// Курсор наведён на бегущую
|
||||||
|
|
||||||
|
// Инициализация буфера для временных данных
|
||||||
|
let buffer;
|
||||||
|
|
||||||
|
// Перемещение
|
||||||
|
_this.offset(
|
||||||
|
(isNaN(
|
||||||
|
(buffer = parseFloat(
|
||||||
|
_this.#shell.firstElementChild.style[
|
||||||
|
_this.vertical ? "marginTop" : "marginLeft"
|
||||||
|
]
|
||||||
|
))
|
||||||
|
)
|
||||||
|
? 0
|
||||||
|
: buffer) +
|
||||||
|
(_this.delta === null
|
||||||
|
? e.wheelDelta
|
||||||
|
: e.wheelDelta > 0
|
||||||
|
? _this.delta
|
||||||
|
: -_this.delta)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.observe) {
|
||||||
|
// Запрошено наблюдение за изменениями аттрибутов элемента бегущей строки
|
||||||
|
|
||||||
|
if (this.#observer === null) {
|
||||||
|
// Отсутствует наблюдатель
|
||||||
|
|
||||||
|
// Инициализация ссылки на ядро
|
||||||
|
const _this = this;
|
||||||
|
|
||||||
|
// Инициализация наблюдателя
|
||||||
|
this.#observer = new MutationObserver(function (mutations) {
|
||||||
|
for (const mutation of mutations) {
|
||||||
|
if (mutation.type === "attributes") {
|
||||||
|
// Запись параметра в инстанцию бегущей строки
|
||||||
|
_this.configure(mutation.attributeName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Перезапуск бегущей строки
|
||||||
|
_this.restart();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Активация наблюдения
|
||||||
|
this.#observer.observe(this.#shell, {
|
||||||
|
attributes: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (this.#observer instanceof MutationObserver) {
|
||||||
|
// Запрошено отключение наблюдения
|
||||||
|
|
||||||
|
// Деактивация наблюдения
|
||||||
|
this.#observer.disconnect();
|
||||||
|
|
||||||
|
// Удаление наблюдателя
|
||||||
|
this.#observer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.events.get("start")) {
|
||||||
|
// Запрошен вызов события: "запуск"
|
||||||
|
|
||||||
|
// Вызов события: "запуск"
|
||||||
|
document.dispatchEvent(new CustomEvent(`hotline.${this.#id}.start`));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
// Остановка бегущей строки
|
||||||
|
clearInterval(this.#instance);
|
||||||
|
|
||||||
|
// Удаление инстанции интервала
|
||||||
|
this.#instance = null;
|
||||||
|
|
||||||
|
if (this.events.get("stop")) {
|
||||||
|
// Запрошен вызов события: "остановка"
|
||||||
|
|
||||||
|
// Вызов события: "остановка"
|
||||||
|
document.dispatchEvent(new CustomEvent(`hotline.${this.#id}.stop`));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
restart() {
|
||||||
|
// Остановка бегущей строки
|
||||||
|
this.stop();
|
||||||
|
|
||||||
|
// Запуск бегущей строки
|
||||||
|
this.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
configure(attribute) {
|
||||||
|
// Инициализация названия параметра
|
||||||
|
const parameter = (/^data-hotline-(\w+)$/.exec(attribute) ?? [, null])[1];
|
||||||
|
|
||||||
|
if (typeof parameter === "string") {
|
||||||
|
// Параметр найден
|
||||||
|
|
||||||
|
// Проверка на разрешение изменения
|
||||||
|
if (this.#block.has(parameter)) return;
|
||||||
|
|
||||||
|
// Инициализация значения параметра
|
||||||
|
const value = this.#shell.getAttribute(attribute);
|
||||||
|
|
||||||
|
// Инициализация буфера для временных данных
|
||||||
|
let buffer;
|
||||||
|
|
||||||
|
// Запись параметра
|
||||||
|
this[parameter] = isNaN((buffer = parseFloat(value)))
|
||||||
|
? value === "true"
|
||||||
|
? true
|
||||||
|
: value === "false"
|
||||||
|
? false
|
||||||
|
: value
|
||||||
|
: buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset(value) {
|
||||||
|
// Запись отступа
|
||||||
|
this.#shell.firstElementChild.style[
|
||||||
|
this.vertical ? "marginTop" : "marginLeft"
|
||||||
|
] = value + "px";
|
||||||
|
|
||||||
|
if (this.events.get("offset")) {
|
||||||
|
// Запрошен вызов события: "сдвиг"
|
||||||
|
|
||||||
|
// Вызов события: "сдвиг"
|
||||||
|
document.dispatchEvent(
|
||||||
|
new CustomEvent(`hotline.${this.#id}.offset`, {
|
||||||
|
detail: {
|
||||||
|
to: value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
static preprocessing(event = false) {
|
||||||
|
// Инициализация счётчиков инстанций горячей строки
|
||||||
|
const success = new Set();
|
||||||
|
let error = 0;
|
||||||
|
|
||||||
|
for (const element of document.querySelectorAll('*[data-hotline="true"]')) {
|
||||||
|
// Перебор элементов для инициализации бегущих строк
|
||||||
|
|
||||||
|
if (typeof element.id === "string") {
|
||||||
|
// Найден идентификатор
|
||||||
|
|
||||||
|
// Инициализация инстанции бегущей строки
|
||||||
|
const hotline = new this(element.id, element);
|
||||||
|
|
||||||
|
for (const attribute of element.getAttributeNames()) {
|
||||||
|
// Перебор аттрибутов
|
||||||
|
|
||||||
|
// Запись параметра в инстанцию бегущей строки
|
||||||
|
hotline.configure(attribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Запуск бегущей строки
|
||||||
|
hotline.start();
|
||||||
|
|
||||||
|
// Запись инстанции бегущей строки в элемент
|
||||||
|
element.hotline = hotline;
|
||||||
|
|
||||||
|
// Запись в счётчик успешных инициализаций
|
||||||
|
success.add(hotline);
|
||||||
|
} else ++error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
// Запрошен вызов события: "предварительная подготовка"
|
||||||
|
|
||||||
|
// Вызов события: "предварительная подготовка"
|
||||||
|
document.dispatchEvent(
|
||||||
|
new CustomEvent(`hotline.preprocessed`, {
|
||||||
|
detail: {
|
||||||
|
success,
|
||||||
|
error
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.dispatchEvent(
|
||||||
|
new CustomEvent("hotline.loaded", {
|
||||||
|
detail: { hotline }
|
||||||
|
})
|
||||||
|
);
|
|
@ -0,0 +1,2 @@
|
||||||
|
/*! js-cookie v3.0.1 | MIT */
|
||||||
|
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self,function(){var n=e.Cookies,o=e.Cookies=t();o.noConflict=function(){return e.Cookies=n,o}}())}(this,(function(){"use strict";function e(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)e[o]=n[o]}return e}return function t(n,o){function r(t,r,i){if("undefined"!=typeof document){"number"==typeof(i=e({},o,i)).expires&&(i.expires=new Date(Date.now()+864e5*i.expires)),i.expires&&(i.expires=i.expires.toUTCString()),t=encodeURIComponent(t).replace(/%(2[346B]|5E|60|7C)/g,decodeURIComponent).replace(/[()]/g,escape);var c="";for(var u in i)i[u]&&(c+="; "+u,!0!==i[u]&&(c+="="+i[u].split(";")[0]));return document.cookie=t+"="+n.write(r,t)+c}}return Object.create({set:r,get:function(e){if("undefined"!=typeof document&&(!arguments.length||e)){for(var t=document.cookie?document.cookie.split("; "):[],o={},r=0;r<t.length;r++){var i=t[r].split("="),c=i.slice(1).join("=");try{var u=decodeURIComponent(i[0]);if(o[u]=n.read(c,u),e===u)break}catch(e){}}return e?o[e]:o}},remove:function(t,n){r(t,"",e({},n,{expires:-1}))},withAttributes:function(n){return t(this.converter,e({},this.attributes,n))},withConverter:function(n){return t(e({},this.converter,n),this.attributes)}},{attributes:{value:Object.freeze(o)},converter:{value:Object.freeze(n)}})}({read:function(e){return'"'===e[0]&&(e=e.slice(1,-1)),e.replace(/(%[\dA-F]{2})+/gi,decodeURIComponent)},write:function(e){return encodeURIComponent(e).replace(/%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g,decodeURIComponent)}},{path:"/"})}));
|
|
@ -0,0 +1,33 @@
|
||||||
|
function generate(id, text = 'Загрузка') {
|
||||||
|
// Поиск файла со стилем индикатора загрузки
|
||||||
|
const file = document.querySelector('[href="/css/loading.css"]');
|
||||||
|
|
||||||
|
if (file === null) {
|
||||||
|
// Не загружен файл
|
||||||
|
|
||||||
|
// Запись ссылки на файл
|
||||||
|
let link = document.createElement("link");
|
||||||
|
link.href = '/css/loading.css';
|
||||||
|
link.rel = "stylesheet";
|
||||||
|
document.getElementsByTagName("head")[0].appendChild(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof id === 'string', typeof text === 'string') {
|
||||||
|
// Получены необходимые параметры
|
||||||
|
|
||||||
|
// Инициализация оболочки
|
||||||
|
let wrap = document.createElement("p");
|
||||||
|
wrap.id = 'loading_' + id;
|
||||||
|
wrap.classList.add('my-2', 'd-flex', 'justify-content-center');
|
||||||
|
|
||||||
|
// Инициализация иконки
|
||||||
|
let icon = document.createElement('i');
|
||||||
|
icon.classList.add('loading', 'mr-2');
|
||||||
|
|
||||||
|
// Инициализация архитектуры
|
||||||
|
wrap.appendChild(icon);
|
||||||
|
wrap.append(text);
|
||||||
|
|
||||||
|
return wrap
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,11 +12,6 @@ function main_response(data, status, xhr) {
|
||||||
|
|
||||||
// Обновление документа
|
// Обновление документа
|
||||||
main.innerHTML = data.main;
|
main.innerHTML = data.main;
|
||||||
|
|
||||||
// alert('Основной блок на ' + data.main);
|
|
||||||
|
|
||||||
// Реинициализация
|
|
||||||
reinitialization(main);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Заголовок
|
// Заголовок
|
||||||
|
|
|
@ -25,6 +25,71 @@ function order_init(order) {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Инициализация списка
|
||||||
|
*
|
||||||
|
* @param {number} amount
|
||||||
|
* @param {number} page
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function order_init_list(amount, page, id = 'orders_panel_moderation_list') {
|
||||||
|
if (typeof amount === 'number' && typeof page === 'number' && typeof id === 'string') {
|
||||||
|
$.ajax({
|
||||||
|
url: `/orders/list/${page}`,
|
||||||
|
type: 'post',
|
||||||
|
dataType: 'json',
|
||||||
|
data: {
|
||||||
|
'_csrf': yii.getCsrfToken(),
|
||||||
|
amount
|
||||||
|
},
|
||||||
|
success: (data, status, xhr) => {
|
||||||
|
// Обработка ответа
|
||||||
|
|
||||||
|
if (data !== undefined) {
|
||||||
|
// Получены данные с сервера
|
||||||
|
|
||||||
|
if (data.list !== undefined && data.list !== null) {
|
||||||
|
// Найдены данные поставщиков
|
||||||
|
|
||||||
|
// Запись cookie с номером страницы
|
||||||
|
Cookies.set('order_init_list', parseInt(Cookies.get('order_init_list') ?? 1) + 1, { path: window.location.pathname });
|
||||||
|
|
||||||
|
// Инициализация оболочки
|
||||||
|
let wrap = document.getElementById(id);
|
||||||
|
|
||||||
|
// Запись в документ
|
||||||
|
wrap.innerHTML += data.list;
|
||||||
|
|
||||||
|
// Инициализация блокировщика
|
||||||
|
let block = false;
|
||||||
|
|
||||||
|
document.onscroll = function (e) {
|
||||||
|
// Обработчик события: "прокрутка экрана"
|
||||||
|
|
||||||
|
if (wrap.lastElementChild.getBoundingClientRect().y <= window.innerHeight) {
|
||||||
|
// Строка в области видимости окна
|
||||||
|
|
||||||
|
// Генерация и запись следующей страницы
|
||||||
|
if (!block) order_init_list(amount, parseInt(Cookies.get('order_init_list')), id);
|
||||||
|
|
||||||
|
// Блокировка
|
||||||
|
block = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Переход к остальным обработчикам
|
||||||
|
orders_response_success(data, status, xhr);
|
||||||
|
},
|
||||||
|
error: orders_response_error
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
function order_accept(order) {
|
function order_accept(order) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
@ -591,3 +656,9 @@ function orders_supply_status_edit(order, prod, catn, delivery, element) {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Запись (сброс) cookie с номером страницы
|
||||||
|
Cookies.set('order_init_list', 1, { path: window.location.pathname });
|
||||||
|
|
||||||
|
// Вызов события: "loaded"
|
||||||
|
document.dispatchEvent(new CustomEvent("orders_panel.loaded"));
|
||||||
|
|
|
@ -21,6 +21,72 @@ function product_image_choose(key, wrap) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Инициализация
|
||||||
|
*
|
||||||
|
* @param {number} amount
|
||||||
|
* @param {number} page
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function panel_analogs_initializing(prod, catn, amount, page, id = 'products_list') {
|
||||||
|
if (typeof prod === 'string' && typeof catn === 'string' && typeof amount === 'number' && typeof page === 'number'&& typeof id === 'string') {
|
||||||
|
$.ajax({
|
||||||
|
url: `/product/${prod}/${catn}/analogs/${page}`,
|
||||||
|
type: 'post',
|
||||||
|
dataType: 'json',
|
||||||
|
data: {
|
||||||
|
'_csrf': yii.getCsrfToken(),
|
||||||
|
amount
|
||||||
|
},
|
||||||
|
success: (data, status, xhr) => {
|
||||||
|
// Обработка ответа
|
||||||
|
|
||||||
|
if (data !== undefined) {
|
||||||
|
// Получены данные с сервера
|
||||||
|
|
||||||
|
if (data.list !== undefined && data.list !== null) {
|
||||||
|
// Найдены данные поставщиков
|
||||||
|
|
||||||
|
// Запись cookie с номером страницы
|
||||||
|
Cookies.set('product_analogs_page', parseInt(Cookies.get('product_analogs_page') ?? 1) + 1, { path: window.location.pathname });
|
||||||
|
|
||||||
|
// Инициализация оболочки
|
||||||
|
let wrap = document.getElementById(id);
|
||||||
|
|
||||||
|
// Запись в документ
|
||||||
|
wrap.innerHTML += data.list;
|
||||||
|
|
||||||
|
// Инициализация блокировщика
|
||||||
|
let block = false;
|
||||||
|
|
||||||
|
document.onscroll = function (e) {
|
||||||
|
// Обработчик события: "прокрутка экрана"
|
||||||
|
|
||||||
|
if (wrap.lastElementChild.getBoundingClientRect().y <= window.innerHeight) {
|
||||||
|
// Строка в области видимости окна
|
||||||
|
|
||||||
|
// Генерация и запись следующей страницы
|
||||||
|
if (!block) panel_analogs_initializing(prod, catn, amount, parseInt(Cookies.get('product_analogs_page')), id);
|
||||||
|
|
||||||
|
// Блокировка
|
||||||
|
block = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Переход к остальным обработчикам
|
||||||
|
product_response_success(data, status, xhr);
|
||||||
|
},
|
||||||
|
error: product_response_error
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
function product_response(data, status, xhr) {
|
function product_response(data, status, xhr) {
|
||||||
// Обработка ответов
|
// Обработка ответов
|
||||||
|
|
||||||
|
@ -41,3 +107,6 @@ function product_response_error(data, status, xhr) {
|
||||||
|
|
||||||
product_response(data, status, xhr);
|
product_response(data, status, xhr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Запись (сброс) cookie с номером страницы
|
||||||
|
Cookies.set('product_analogs_page', 1, { path: window.location.pathname });
|
||||||
|
|
|
@ -254,7 +254,7 @@ function product_panel_dimensions_save(catn, prod, element, dimension) {
|
||||||
|
|
||||||
|
|
||||||
function product_panel_weight_edit(catn, prod, element) {
|
function product_panel_weight_edit(catn, prod, element) {
|
||||||
if (catn !== null && catn !== undefined && prod !== null && prod !== undefined && element !== null && element !== undefined) {
|
if (catn !== null && catn !== undefined && prod !== null && prod !== undefined && element !== null && element !== undefined) {
|
||||||
|
|
||||||
let input = document.createElement('input');
|
let input = document.createElement('input');
|
||||||
|
|
||||||
|
@ -327,7 +327,7 @@ function product_panel_weight_save(catn, prod, element) {
|
||||||
};
|
};
|
||||||
|
|
||||||
function product_panel_description_edit(catn, prod, element) {
|
function product_panel_description_edit(catn, prod, element) {
|
||||||
if (catn !== null && catn !== undefined && prod !== null && prod !== undefined && element !== null && element !== undefined) {
|
if (catn !== null && catn !== undefined && prod !== null && prod !== undefined && element !== null && element !== undefined) {
|
||||||
element.innerHTML = '<textarea class="form-control" cols="50" rows="5" onchange = "return product_panel_description_save(\'' + catn + '\', \'' + prod + '\', this.parentElement)">' + element.innerText + '</textarea>';
|
element.innerHTML = '<textarea class="form-control" cols="50" rows="5" onchange = "return product_panel_description_save(\'' + catn + '\', \'' + prod + '\', this.parentElement)">' + element.innerText + '</textarea>';
|
||||||
|
|
||||||
element.removeAttribute('onclick');
|
element.removeAttribute('onclick');
|
||||||
|
@ -388,27 +388,46 @@ function product_panel_description_save(catn, prod, element) {
|
||||||
* @param {*} catn
|
* @param {*} catn
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function product_panel_connect(catn, prod, group) {
|
function product_panel_connect(catn, prod, target_catn, target_prod, list) {
|
||||||
if (group === null || group === '') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (group === undefined) {
|
|
||||||
// Не получены данные о группе
|
|
||||||
|
|
||||||
group = prompt('Подключить аналог');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (catn !== null && catn !== undefined && prod !== null && prod !== undefined) {
|
if (catn !== null && catn !== undefined && prod !== null && prod !== undefined) {
|
||||||
|
|
||||||
|
if (target_catn === undefined) {
|
||||||
|
// Не получены данные о группе
|
||||||
|
|
||||||
|
target_catn = prompt('Артикул');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target_prod === undefined) {
|
||||||
|
// Не получены данные о группе
|
||||||
|
|
||||||
|
target_prod = prompt('Производитель');
|
||||||
|
}
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/product/' + prod + '/' + catn + '/connect',
|
url: '/product/' + prod + '/' + catn + '/connect',
|
||||||
type: 'post',
|
type: 'post',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
data: {
|
data: {
|
||||||
'_csrf': yii.getCsrfToken(),
|
'_csrf': yii.getCsrfToken(),
|
||||||
'catn': group
|
'catn': target_catn,
|
||||||
|
'prod': target_prod
|
||||||
},
|
},
|
||||||
success: product_response_success,
|
success: (data, status, xhr) => {
|
||||||
|
if (data.list !== undefined && data.list !== null) {
|
||||||
|
// Найдены данные поставщиков
|
||||||
|
|
||||||
|
// Запись cookie с номером страницы
|
||||||
|
Cookies.set('product_analogs_page', 1, { path: window.location.pathname });
|
||||||
|
|
||||||
|
// Инициализация оболочки
|
||||||
|
let wrap = document.getElementById(list);
|
||||||
|
|
||||||
|
// Запись в документ
|
||||||
|
wrap.innerHTML = data.list;
|
||||||
|
|
||||||
|
// Переход к остальным обработчикам
|
||||||
|
product_response_success(data, status, xhr);
|
||||||
|
}},
|
||||||
error: product_response_error
|
error: product_response_error
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -418,24 +437,35 @@ function product_panel_connect(catn, prod, group) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Отключение от группы
|
* Отключение от группы
|
||||||
*
|
*
|
||||||
* @param {*} catn
|
* @param {*} catn
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function product_panel_disconnect(catn, prod) {
|
function product_panel_disconnect(catn, prod, element) {
|
||||||
if (catn !== null && catn !== undefined) {
|
if (typeof prod === 'string' && typeof catn === 'string' && typeof element === 'object') {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/product/' + prod + '/' + catn + '/disconnect',
|
url: '/product/' + prod + '/' + catn + '/disconnect',
|
||||||
type: 'post',
|
type: 'post',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
data: {
|
data: {
|
||||||
'_csrf': yii.getCsrfToken(),
|
'_csrf': yii.getCsrfToken()
|
||||||
'catn': prompt('Отсоединить аналог (пустое поле - все аналоги)')
|
},
|
||||||
|
success: function (data, status, xhr) {
|
||||||
|
if (data !== undefined) {
|
||||||
|
// Получены данные с сервера
|
||||||
|
|
||||||
|
if (data.disconnected === 1) {
|
||||||
|
// Статус об отключении
|
||||||
|
|
||||||
|
// Удаление элемента
|
||||||
|
element.remove();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
product_response_success(data, status, xhr);
|
||||||
},
|
},
|
||||||
success: product_response_success,
|
|
||||||
error: product_response_error
|
error: product_response_error
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -443,10 +473,10 @@ function product_panel_disconnect(catn, prod) {
|
||||||
};
|
};
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function product_panel_delete(catn, prod) {
|
function product_panel_delete(catn, prod) {
|
||||||
if (catn !== null && catn !== undefined && prod !== null && prod !== undefined) {
|
if (typeof prod === 'string' && typeof catn === 'string') {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/product/' + prod + '/' + catn + '/delete',
|
url: '/product/' + prod + '/' + catn + '/delete',
|
||||||
type: 'post',
|
type: 'post',
|
||||||
|
|