diff --git a/mirzaev/skillparts/system/controllers/AuthenticationController.php b/mirzaev/skillparts/system/controllers/AuthenticationController.php
index 9ee8ed9..bd85bce 100644
--- a/mirzaev/skillparts/system/controllers/AuthenticationController.php
+++ b/mirzaev/skillparts/system/controllers/AuthenticationController.php
@@ -47,9 +47,18 @@ class AuthenticationController extends Controller
if (!Yii::$app->user->isGuest || $model->authentication()) {
// Аккаунт аутентифицирован
+ // Инициализация
+ $notifications_button = $this->renderPartial('/notification/button');
+ $notifications_panel_full = true;
+ $notifications_panel = $this->renderPartial('/notification/panel', compact('notifications_panel_full'));
+
// Запись ответа
$return = [
- 'menu' => $this->renderPartial('/account/deauthentication'),
+ 'menu' => $this->renderPartial('/account/panel/authenticated', compact(
+ 'notifications_button',
+ 'notifications_panel',
+ 'notifications_panel_full'
+ )),
'_csrf' => Yii::$app->request->getCsrfToken()
];
diff --git a/mirzaev/skillparts/system/controllers/CartController.php b/mirzaev/skillparts/system/controllers/CartController.php
index 9e86b7e..68d8b7c 100644
--- a/mirzaev/skillparts/system/controllers/CartController.php
+++ b/mirzaev/skillparts/system/controllers/CartController.php
@@ -15,22 +15,6 @@ use Exception;
class CartController extends Controller
{
- public function behaviors()
- {
- return [
- 'access' => [
- 'class' => AccessControl::class,
- 'only' => ['index'],
- 'rules' => [
- [
- 'allow' => true,
- 'roles' => ['@']
- ]
- ]
- ]
- ];
- }
-
/**
* Страница: "Корзина"
*
diff --git a/mirzaev/skillparts/system/controllers/DeauthenticationController.php b/mirzaev/skillparts/system/controllers/DeauthenticationController.php
index a96bb42..13f42d6 100644
--- a/mirzaev/skillparts/system/controllers/DeauthenticationController.php
+++ b/mirzaev/skillparts/system/controllers/DeauthenticationController.php
@@ -44,7 +44,7 @@ class DeauthenticationController extends Controller
// Ответа
return [
- 'menu' => $this->renderPartial('/account/authentication', compact('model')),
+ 'menu' => $this->renderPartial('/account/panel/deauthenticated', compact('model')),
'main' => $this->renderPartial('/index'),
'redirect' => '/',
'_csrf' => yii::$app->request->getCsrfToken()
diff --git a/mirzaev/skillparts/system/controllers/IdentificationController.php b/mirzaev/skillparts/system/controllers/IdentificationController.php
index 5da2f4a..fa27578 100644
--- a/mirzaev/skillparts/system/controllers/IdentificationController.php
+++ b/mirzaev/skillparts/system/controllers/IdentificationController.php
@@ -27,7 +27,7 @@ class IdentificationController extends Controller
// Запись ответа
$return = [
- 'menu' => $this->renderPartial('/account/authentication', compact('model')),
+ 'menu' => $this->renderPartial('/account/panel/deauthenticated', compact('model')),
'_csrf' => yii::$app->request->getCsrfToken()
];
} else {
@@ -36,9 +36,17 @@ class IdentificationController extends Controller
// Инициализация
$model = yii::$app->user;
+ // Инициализация
+ $notifications_button = $this->renderPartial('/notification/button');
+ $notifications_panel_full = true;
+ $notifications_panel = $this->renderPartial('/notification/panel', compact('notifications_panel_full'));
+
// Запись ответа
$return = [
- 'menu' => $this->renderPartial('/account/deauthentication'),
+ 'menu' => $this->renderPartial('/account/panel/authenticated', compact(
+ 'notifications_button',
+ 'notifications_panel'
+ )),
'_csrf' => yii::$app->request->getCsrfToken()
];
}
diff --git a/mirzaev/skillparts/system/controllers/NotificationController.php b/mirzaev/skillparts/system/controllers/NotificationController.php
index f12e68f..1a5d05e 100644
--- a/mirzaev/skillparts/system/controllers/NotificationController.php
+++ b/mirzaev/skillparts/system/controllers/NotificationController.php
@@ -40,6 +40,7 @@ class NotificationController extends Controller
// Инициализация
$model = new Notification(yii::$app->request->post('Notification'));
+ $preload = (bool) (int) yii::$app->request->post('preload');
yii::$app->response->format = Response::FORMAT_JSON;
@@ -50,11 +51,11 @@ class NotificationController extends Controller
if (yii::$app->request->post('last')) {
// Запрос последнего уведомлений (всплывающее окно)
+ // Инициализация
$limit = 1;
} else if (yii::$app->request->post('stream')) {
// Запрос последних уведомлений (панель)
-
- $limit = 5;
+ $limit = 10;
}
if (isset($limit)) {
@@ -87,13 +88,22 @@ class NotificationController extends Controller
/**
* Поиск рёбер: (УВЕДОМЛЕНИЕ)? -> ПОЛЬЗОВАТЕЛЬ
*
- * @param bool $check Активация проверки на то, что уведомление не получено
+ * @param bool $new Активация проверки на то, что уведомление не получено
+ * @param bool $count Посчитать
*/
- $search = function (bool $check = false) use ($model, $type, $let, $limit): array {
+ $search = function (bool $new = false, bool $count = false) use ($model, $type, $let, $limit): array|int {
+ if ($count) {
+ // Запрошен подсчёт непрочитанных уведомлений
+
+ // Реинициализация
+ $type = 'checked';
+ $limit = null;
+ }
+
return $model::searchByEdge(
from: 'account',
to: 'notification',
- params: $check ? $let->getBindVars() : [],
+ params: $new ? $let->getBindVars() : [],
subquery_where: [
[
'account._id' => yii::$app->user->id
@@ -112,20 +122,28 @@ class NotificationController extends Controller
'notification_edge_account',
'(' . (string) $let . ')'
],
- where: $check ? [
+ where: $new ? [
'account_edge_notification[0]._to' => null
] : [],
limit: $limit,
sort: ['DESC'],
- direction: 'INBOUND'
+ direction: 'INBOUND',
+ handle: $count ? function ($request) {
+ // Посчитать рёбра (информация о количестве непрочитанных уведомлений)
+ return $request->count();
+ }: null
);
};
- // Поиск непрочитанных уведомлений пользователя
+ // Поиск новых (непрочитанных) уведомлений пользователя
+ // Если заккоментировать, то вместо только новых отправит все последние уведомления
$notifications = $search(true);
+ // Подсчёт новых (непрочитанных) уведомлений
+ $return['button'] = $this->renderPartial('button', ['notifications_new_amount' => $search(new: true, count: true)]);
+
if (!yii::$app->request->post('last') && empty($notifications)) {
- // Уведомления не найдены и запрошены НЕ всплывающие уведомления
+ // Запрошены НЕ ВСПЛЫВАЮЩИЕ уведомления и новые уведомления не найдены
// Поиск уведомлений пользователя
$notifications = $search();
@@ -134,7 +152,10 @@ class NotificationController extends Controller
if (empty($notifications)) {
// Уведомления не найдены
- yii::$app->response->statusCode = 404;
+ /**
+ * @todo Определить какой код лучше использовать (404 не подходит)
+ */
+ yii::$app->response->statusCode = 200;
goto end;
}
@@ -142,6 +163,12 @@ class NotificationController extends Controller
foreach ($notifications as $notification) {
// Перебор найденных уведомлений
+ if ($preload) {
+ // Запрошены уведомления для предзагрузки (их ещё не увидели)
+
+ break;
+ }
+
// Запись ребра: ПОЛЬЗОВАТЕЛЬ -> УВЕДОМЛЕНИЕ (о том, что уведомление прочитано)
AccountEdgeNotification::write(yii::$app->user->id, $notification->readId(), $type);
}
@@ -168,7 +195,11 @@ class NotificationController extends Controller
$return['redirect'] = '/notification';
}
+ /**
+ * Конец алгоритма
+ */
end:
+
return $return;
}
diff --git a/mirzaev/skillparts/system/controllers/OrderController.php b/mirzaev/skillparts/system/controllers/OrderController.php
index 5ef5fdc..76616eb 100644
--- a/mirzaev/skillparts/system/controllers/OrderController.php
+++ b/mirzaev/skillparts/system/controllers/OrderController.php
@@ -4,16 +4,13 @@ declare(strict_types=1);
namespace app\controllers;
-use app\models\AccountEdgeNotification;
use yii;
use yii\filters\AccessControl;
use yii\web\Controller;
use yii\web\Response;
-use app\models\Supply;
use app\models\Order;
use app\models\AccountEdgeOrder;
-use app\models\OrderEdgeSupply;
use Exception;
class OrderController extends Controller
@@ -102,7 +99,7 @@ class OrderController extends Controller
}
// Если запись не удалась, то вернуть код: 500 Internal Server Error
- $model->write($supplies) or yii::$app->response->statusCode = 500;
+ $model->writeSupply($supplies) or yii::$app->response->statusCode = 500;
}
return $return;
@@ -115,6 +112,8 @@ class OrderController extends Controller
/**
* Удаление
+ *
+ * @todo Разделить логику (для удобства чтения)
*/
public function actionDelete(): string|array|null
{
@@ -122,36 +121,65 @@ class OrderController extends Controller
$targets = yii::$app->request->post('targets') ?? yii::$app->request->get('targets');
$page = yii::$app->request->get('page') ?? yii::$app->request->post('page') ?? 1;
$account = yii::$app->user;
+ $order = Order::search();
if ($targets) {
// Удаление выбранных целей (удаление из заказа)
- foreach ($targets as $target) {
+ foreach (isset($targets[0]) && is_array($targets[0]) ? $targets : [$targets] as $target) {
+ // Унификация входных параметров
- // Инициализация
- $model = Order::search();
+ foreach ($target as $catn => $amount) {
+ // Перебор целей
- // Удаление
- $model->deleteEdge($target);
+ // Удаление
+ $order->deleteSupply([$catn => (int) $amount]);
+ }
}
} else {
// Целью подразумевается сам заказ (удаление заказа)
- // Инициализация корзины (текущего заказа)
- $model = Order::search();
+ // Инициализация
+ $order->stts = 'reserved';
- // Поиск
- $edge = AccountEdgeOrder::searchByVertex($account->id, $model->readId(), 'current');
+ if ($order->update()) {
+ // Запись в журнал
+ $order->journal('reserved');
- // Запись
- $edge->type = 'reserved';
+ // Поиск
+ $edge = AccountEdgeOrder::searchByVertex($account->id, $order->readId(), 'current');
- // Отправка
- $edge->update();
+ if (count($edge) > 1) {
+ // Найден более чем 1 заказ
+
+ return null;
+ }
+
+ // Инициализация
+ $edge = $edge[0];
+ $edge->type = 'reserved';
+
+ // Запись
+ $edge->update();
+
+ // Реинициализация
+ $order = Order::search();
+
+ if (empty($order)) {
+ // Корзина не инициализирована
+
+ // Инициализация
+ $order = new Order();
+ $order->save() or throw new Exception('Не удалось инициализировать заказ');
+
+ // Подключение
+ $order->connect($account);
+ }
+ }
}
// Инициализация содержимого корзины
- $supplies = $model->content(10, $page);
+ $supplies = $order->content(10, $page);
if (yii::$app->request->isPost) {
// POST-запрос
@@ -159,14 +187,73 @@ class OrderController extends Controller
yii::$app->response->format = Response::FORMAT_JSON;
return [
- 'main' => $this->renderPartial('/cart/index', compact('model', 'supplies')),
+ 'main' => $this->renderPartial('/cart/index', compact('order', 'supplies')),
'title' => 'Корзина',
'redirect' => '/cart',
'_csrf' => yii::$app->request->getCsrfToken()
];
}
- return $this->render('/cart/index', compact('model', 'supplies'));
+ return $this->render('/cart/index', compact('order', 'supplies'));
+ }
+
+ /**
+ * Обновление количества товара
+ */
+ public function actionAmountUpdate(): string|array|null
+ {
+ // Инициализация
+ $targets = yii::$app->request->post('targets') ?? yii::$app->request->get('targets');
+ $page = yii::$app->request->get('page') ?? yii::$app->request->post('page') ?? 1;
+ $account = yii::$app->user;
+ $order = Order::search();
+ $supplies = $order->content(10, $page);
+
+ foreach (isset($targets[0]) && is_array($targets[0]) ? $targets : [$targets] as $target) {
+ // Унификация входных параметров
+
+ foreach ($target as $catn => $amount) {
+ // Перебор целей (переданных объектов в корзине)
+
+ foreach ($supplies as $supply) {
+ // Перебор объектов в корзине
+
+ if ($supply->catn === $catn) {
+ // Цель найдена
+
+ if ($supply->amnt > $amount) {
+ // Запрошено уменьшение количества
+
+ // Удаление
+ $order->deleteSupply([$catn => $supply->amnt - $amount]);
+ } else if ($supply->amnt < $amount) {
+ // Запрошено увеличение количества
+
+ // Запись
+ $order->writeSupply([$supply->catn => $amount - $supply->amnt]);
+ }
+ }
+ }
+ }
+ }
+
+ // Ренициализация
+ $supplies = $order->content(10, $page);
+
+ if (yii::$app->request->isPost) {
+ // POST-запрос
+
+ yii::$app->response->format = Response::FORMAT_JSON;
+
+ return [
+ 'main' => $this->renderPartial('/cart/index', compact('order', 'supplies')),
+ 'title' => 'Корзина',
+ 'redirect' => '/cart',
+ '_csrf' => yii::$app->request->getCsrfToken()
+ ];
+ }
+
+ return $this->render('/cart/index', compact('order', 'supplies'));
}
/**
@@ -180,6 +267,15 @@ class OrderController extends Controller
// Поиск ребра
$edge = AccountEdgeOrder::searchByVertex(yii::$app->user->id, $model->readId(), 'current');
+ if (count($edge) > 1) {
+ // Найден более чем 1 заказ
+
+ return null;
+ }
+
+ // Инициализация
+ $edge = $edge[0];
+
// Запись
$edge->type = 'accepted';
diff --git a/mirzaev/skillparts/system/controllers/ProfileController.php b/mirzaev/skillparts/system/controllers/ProfileController.php
index 5760303..ff6e6e1 100644
--- a/mirzaev/skillparts/system/controllers/ProfileController.php
+++ b/mirzaev/skillparts/system/controllers/ProfileController.php
@@ -85,8 +85,10 @@ class ProfileController extends Controller
{
// Инициализация
$model = yii::$app->user->identity;
- $supplies = Supply::searchByAccount(select: 'supply.onec["ЗначенияСвойств"]');
+ $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
+ $sidebar = $this->renderPartial('sidebar');
+ // Обработка настроек аккаунта
if ($vars = yii::$app->request->post('Account') ?? yii::$app->request->get('Account')) {
// Обнаружены входные параметры
@@ -107,8 +109,8 @@ class ProfileController extends Controller
}
}
- // Генерация
- $sidebar = $this->renderPartial('sidebar');
+ // Инициализация
+ $list = $model->genListOem(Supply::searchByAccount(select: 'supply.onec["ЗначенияСвойств"]', limit: null));
if (yii::$app->request->isPost) {
// POST-запрос
@@ -116,39 +118,23 @@ class ProfileController extends Controller
yii::$app->response->format = Response::FORMAT_JSON;
return [
- 'main' => $this->renderPartial('index', compact('model', 'sidebar', 'supplies')),
+ 'main' => $this->renderPartial('index', compact(
+ 'model',
+ 'sidebar',
+ 'list',
+ 'panel'
+ )),
'redirect' => '/profile',
'_csrf' => yii::$app->request->getCsrfToken()
];
}
- return $this->render('index', compact('model', 'sidebar', 'supplies'));
- }
-
- /**
- * Страница поставок
- */
- public function actionSupplies(): string|array
- {
- // Инициализация
- $model = new Supply(yii::$app->request->post('Supply') ?? yii::$app->request->get('Supply'));
-
- // Генерация
- $sidebar = $this->renderPartial('sidebar');
-
- if (yii::$app->request->isPost) {
- // POST-запрос
-
- yii::$app->response->format = Response::FORMAT_JSON;
-
- return [
- 'main' => $this->renderPartial('supplies', compact('model', 'sidebar')),
- 'redirect' => '/profile/supplies',
- '_csrf' => yii::$app->request->getCsrfToken()
- ];
- }
-
- return $this->render('supplies', compact('model', 'sidebar'));
+ return $this->render('index', compact(
+ 'model',
+ 'sidebar',
+ 'list',
+ 'panel'
+ ));
}
/**
@@ -159,6 +145,8 @@ class ProfileController extends Controller
// Инициализация
$model_notifications = null;
$model_settings = Settings::readLast();
+ $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
+ $sidebar = $this->renderPartial('sidebar');
if (!is_null($vars = yii::$app->request->post('Notification') ?? yii::$app->request->get('Notification'))) {
// Обнаружены входные параметры из раздела "Уведомления"
@@ -202,69 +190,53 @@ class ProfileController extends Controller
// Деинициализация
unset($vars);
- // Генерация
- $sidebar = $this->renderPartial('sidebar');
-
if (yii::$app->request->isPost) {
// AJAX-POST-запрос
yii::$app->response->format = Response::FORMAT_JSON;
return [
- 'main' => $this->renderPartial('trusted', compact('model_notifications', 'model_settings', 'sidebar')),
+ 'main' => $this->renderPartial('trusted', compact(
+ 'model_notifications',
+ 'model_settings',
+ 'sidebar',
+ 'panel'
+ )),
'redirect' => '/profile/trusted',
'_csrf' => yii::$app->request->getCsrfToken()
];
}
- return $this->render('trusted', compact('model_notifications', 'model_settings', 'sidebar'));
+ return $this->render('trusted', compact(
+ 'model_notifications',
+ 'model_settings',
+ 'sidebar',
+ 'panel'
+ ));
}
-
/**
- * Страницка панели управления для доверенных пользователей
- *
- * @todo Перенести в уведомления
- */
- // public function actionTrustedNotificationWrite(): string|array
- // {
- // // Инициализация
- // $model = new Notification(yii::$app->request->post('Notification') ?? yii::$app->request->get('Notification'));
-
- // $model->write();
-
- // if (yii::$app->request->isPost) {
- // // POST-запрос
-
- // yii::$app->response->format = Response::FORMAT_JSON;
-
- // return [
- // 'main' => $this->renderPartial('trusted', compact('model', 'sidebar')),
- // 'redirect' => '/profile/trusted',
- // '_csrf' => yii::$app->request->getCsrfToken()
- // ];
- // }
-
- // return $this->render('trusted', compact('model', 'sidebar'));
- // }
-
- /**
- * Страницка панели управления для доверенных пользователей
+ * Страница мониторинга
*/
public function actionMonitoring(): string|array
{
+ // Инициализация
+ $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
+ $sidebar = $this->renderPartial('sidebar');
// Инициализация номера страницы
$page_search_history = (yii::$app->request->post('search') ?? yii::$app->request->get('search')) - 1;
+
if ($page_search_history <= 0) {
+ // Вышли за границу поиска перед первой страницей
+
+ // Инициализация
$page_search_history = 0;
}
// Инициализация количества строк на одной странице
$rows_amount = 10;
- // Генерация
- $sidebar = $this->renderPartial('sidebar');
$search_history = Search::SearchByEdge(
from: 'account',
to: 'search',
@@ -279,6 +251,33 @@ class ProfileController extends Controller
offset: ((int) $page_search_history ?? 0) * $rows_amount
);
+ // Проверка результатов
+ monitoring_result_check:
+
+ if (count($search_history) === 0) {
+ // Вышли за границу поиска после последней страницы
+
+ // Реинициализация (вычитание для идентичного конечного результата)
+ --$page_search_history;
+
+ $search_history = Search::SearchByEdge(
+ from: 'account',
+ to: 'search',
+ subquery_where: [
+ [
+ 'account._id' => yii::$app->user->id
+ ]
+ ],
+ foreach: ['edge' => 'account_edge_search'],
+ where: 'edge._to == search._id',
+ limit: $rows_amount,
+ offset: ((int) $page_search_history ?? 0) * $rows_amount
+ );
+
+ // Повторная проверка
+ goto monitoring_result_check;
+ }
+
if (yii::$app->request->isPost) {
// AJAX-POST-запрос
@@ -288,7 +287,8 @@ class ProfileController extends Controller
'main' => $this->renderPartial('monitoring', compact(
'sidebar',
'search_history',
- 'page_search_history'
+ 'page_search_history',
+ 'panel'
)),
'search' => $page_search_history + 1,
'redirect' => '/profile/monitoring',
@@ -299,18 +299,61 @@ class ProfileController extends Controller
return $this->render('monitoring', compact(
'sidebar',
'search_history',
- 'page_search_history'
+ 'page_search_history',
+ 'panel'
));
}
+ /**
+ * Страница поставок
+ */
+ public function actionSupplies(): string|array
+ {
+ // Инициализация
+ $model = new Supply(yii::$app->request->post('Supply') ?? yii::$app->request->get('Supply'));
+ $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
+ $sidebar = $this->renderPartial('sidebar');
+ $groups = self::readGroups();
+
+
+ if (yii::$app->request->isPost) {
+ // POST-запрос
+
+ yii::$app->response->format = Response::FORMAT_JSON;
+
+ return [
+ 'main' => $this->renderPartial('supplies', compact(
+ 'model',
+ 'groups',
+ 'sidebar',
+ 'panel'
+ )),
+ 'redirect' => '/profile/supplies',
+ '_csrf' => yii::$app->request->getCsrfToken()
+ ];
+ }
+
+ return $this->render('supplies', compact(
+ 'model',
+ 'groups',
+ 'sidebar',
+ 'panel'
+ ));
+ }
+
+ /**
+ * Импорт поставок
+ *
+ * На данный момент только из Excel-таблицы
+ */
public function actionImport()
{
// Инициализация
$model = new Supply(yii::$app->request->post('Supply') ?? yii::$app->request->get('Supply'));
$model->scenario = $model::SCENARIO_IMPORT;
-
- // Генерация
+ $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
$sidebar = $this->renderPartial('sidebar');
+ $groups = self::readGroups();
if (yii::$app->request->isPost) {
// AJAX-POST-запрос
@@ -319,17 +362,27 @@ class ProfileController extends Controller
$model->file = UploadedFile::getInstances($model, 'file');
- if (!$test = $model->import()) {
- yii::$app->response->statusCode = 409;
+ if ($model->import()) {
+ return [
+ 'main' => $this->renderPartial('supplies', compact(
+ 'model',
+ 'groups',
+ 'sidebar',
+ 'panel'
+ )),
+ '_csrf' => yii::$app->request->getCsrfToken()
+ ];
}
- return [
- 'main' => $this->renderPartial('supplies', compact('model', 'sidebar')),
- '_csrf' => yii::$app->request->getCsrfToken()
- ];
+ yii::$app->response->statusCode = 409;
}
- return $this->render('supplies', compact('model', 'sidebar'));
+ return $this->render('supplies', compact(
+ 'model',
+ 'groups',
+ 'sidebar',
+ 'panel'
+ ));
}
public static function readGroups()
diff --git a/mirzaev/skillparts/system/controllers/RegistrationController.php b/mirzaev/skillparts/system/controllers/RegistrationController.php
index f37bea1..4997020 100644
--- a/mirzaev/skillparts/system/controllers/RegistrationController.php
+++ b/mirzaev/skillparts/system/controllers/RegistrationController.php
@@ -48,7 +48,7 @@ class RegistrationController extends Controller
// Запись ответа
$return = [
- 'menu' => $this->renderPartial('/account/deauthentication'),
+ 'menu' => $this->renderPartial('/account/panel/authenticated'),
'_csrf' => yii::$app->request->getCsrfToken()
];
diff --git a/mirzaev/skillparts/system/migrations/arangodb/m210314_133722_create_session_collection.php b/mirzaev/skillparts/system/migrations/arangodb/m210314_133722_create_session_collection.php
new file mode 100644
index 0000000..6e7461b
--- /dev/null
+++ b/mirzaev/skillparts/system/migrations/arangodb/m210314_133722_create_session_collection.php
@@ -0,0 +1,16 @@
+createCollection('session', []);
+ }
+
+ public function down()
+ {
+ $this->dropCollection('session');
+ }
+}
diff --git a/mirzaev/skillparts/system/migrations/arangodb/m210314_133926_create_account_edge_session_collection.php b/mirzaev/skillparts/system/migrations/arangodb/m210314_133926_create_account_edge_session_collection.php
new file mode 100644
index 0000000..cd8d6e1
--- /dev/null
+++ b/mirzaev/skillparts/system/migrations/arangodb/m210314_133926_create_account_edge_session_collection.php
@@ -0,0 +1,16 @@
+createCollection('account_edge_session', ['type' => 3]);
+ }
+
+ public function down()
+ {
+ $this->dropCollection('account_edge_session');
+ }
+}
diff --git a/mirzaev/skillparts/system/models/Account.php b/mirzaev/skillparts/system/models/Account.php
index 52e6287..cf9c98e 100644
--- a/mirzaev/skillparts/system/models/Account.php
+++ b/mirzaev/skillparts/system/models/Account.php
@@ -242,4 +242,62 @@ class Account extends Document implements IdentityInterface, PartnerInterface
// Отправка
return $this->save();
}
+
+ /**
+ * Генерация списка OEM-номеров
+ *
+ * Актуальное (выбранное, активное) значение записывается первым
+ *
+ * @param array $supplies Необработанный список поставок
+ */
+ public function genListOem(array $supplies): array
+ {
+ // Инициализация
+ $list = [];
+
+ // Перебор свойств поставок
+ foreach ($supplies as $supply) {
+ // Инициализация
+
+ $id = $supply['ЗначенияСвойства']['Ид'];
+
+ if (in_array($id, $list, true)) {
+ // Если встретился дубликат (исполняется очень часто)
+ continue;
+ }
+
+ // Генерация
+ !isset($supply['ЗначенияСвойства']['Наименование']) or $list[$id] = $supply['ЗначенияСвойства']['Наименование'];
+ }
+
+ // Инициализация текущего значения параметра в начале массива
+ if (isset($this->opts['import_sections_oem'])) {
+ // Параметр 'import_sections_oem' найден в настройках аккаунта
+
+ if (isset($list[$this->opts['import_sections_oem']])) {
+ // Найдено совпадение сохранённого параметра с полученным списком из поставок
+
+ // Буфер для сохранения параметра
+ $buffer = $list[$this->opts['import_sections_oem']];
+
+ // Удаление параметра
+ unset($list[$this->opts['import_sections_oem']]);
+
+ // Сохранение параметра в начале массива
+ $list = array_merge([$this->opts['import_sections_oem'] => $buffer], $list);
+ } else {
+ // Совпадение не найдено
+
+ // Сохранение параметра из данных аккаунта в начале массива
+ $list = array_merge([$this->opts['import_sections_oem'] => $this->opts['import_sections_oem']], $list);
+ }
+ } else {
+ // Параметр 'import_sections_oem' не найден в настройках аккаунта
+
+ // Сохранение параметра из данных аккаунта в начале массива
+ $list = array_merge(['Выберите'], $list);
+ }
+
+ return $list;
+ }
}
diff --git a/mirzaev/skillparts/system/models/Document.php b/mirzaev/skillparts/system/models/Document.php
index 435ffe1..8d0c1e1 100644
--- a/mirzaev/skillparts/system/models/Document.php
+++ b/mirzaev/skillparts/system/models/Document.php
@@ -20,7 +20,7 @@ abstract class Document extends ActiveRecord
*/
public static function collectionName(): string
{
- return throw new Exception('Не установлено название коллекции');
+ return throw new Exception('Не инициализировано название коллекции');
}
/**
@@ -30,8 +30,7 @@ abstract class Document extends ActiveRecord
{
return [
'_key',
- 'date',
- 'wrtr'
+ 'jrnl'
];
}
@@ -42,8 +41,7 @@ abstract class Document extends ActiveRecord
{
return [
'_key' => 'Ключ',
- 'date' => 'Дата',
- 'wrtr' => 'Аккаунт записавшего'
+ 'jrnl' => 'Журнал'
];
}
@@ -55,22 +53,62 @@ abstract class Document extends ActiveRecord
*/
public function rules(): array
{
- return [
- [
- 'wrtr',
- 'string'
- ],
- [
- 'wrtr',
- 'default',
- 'value' => yii::$app->user->id
- ],
- [
- 'date',
- 'default',
- 'value' => time()
- ]
- ];
+ return [];
+ }
+
+ /**
+ * Перед сохранением
+ *
+ * @todo Подождать обновление от ебаного Yii2 и добавить
+ * проверку типов передаваемых параметров
+ */
+ public function beforeSave($data): bool
+ {
+ if (parent::beforeSave($data)) {
+ if ($this->isNewRecord) {
+ // Запись в журнал
+ $this->jrnl = [[
+ 'date' => time(),
+ 'account' => yii::$app->user->id,
+ 'action' => 'create'
+ ]];
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Журнал
+ *
+ * Записывает данные в журнал
+ *
+ * @param string $action
+ *
+ * @return int|bool Время записанное в журнале или false, если не удалось записать
+ */
+ public function journal(string $action = 'update', array ...$data): int|bool
+ {
+ // Инициализация
+ is_array($this->jrnl) or $this->jrnl = [];
+
+ // Генерация
+ $this->jrnl = array_merge(
+ $this->jrnl,
+ [array_merge(
+ [
+ 'date' => $time = time(),
+ 'account' => yii::$app->user->id,
+ 'action' => $action
+ ],
+ ...$data
+ )]
+ );
+
+ // Запись и возврат
+ return $this->save() ? $time : false;
}
/**
diff --git a/mirzaev/skillparts/system/models/Edge.php b/mirzaev/skillparts/system/models/Edge.php
index eda7fe2..fa10d2a 100644
--- a/mirzaev/skillparts/system/models/Edge.php
+++ b/mirzaev/skillparts/system/models/Edge.php
@@ -32,9 +32,8 @@ abstract class Edge extends Document
return array_merge(
parent::attributeLabels(),
[
- 'date' => 'От кого',
- 'date' => 'К кому',
- 'type' => 'Тип'
+ '_from' => 'От кого',
+ '_to' => 'К кому',
]
);
}
@@ -72,8 +71,6 @@ abstract class Edge extends Document
if ($this->isNewRecord) {
}
- $this->type = $this->type ?? '';
-
return true;
}
@@ -99,7 +96,7 @@ abstract class Edge extends Document
/**
* Записать
*/
- public static function write(string $_from, string $_to, string $type = '', array $data = []): ?static
+ public static function write(string $_from, string $_to, string $type, array $data = []): ?static
{
// Инициализация
$edge = new static;
@@ -121,22 +118,33 @@ abstract class Edge extends Document
}
}
- // Запись
- return $edge->save() ? $edge : null;
+ if ($edge->save()) {
+ // Записано в базу данных
+
+ // Запись в журнал
+ $edge->journal('create');
+
+ return $edge;
+ }
+
+ return null;
}
/**
* Поиск ребра по его вершинам
*/
- public static function searchByVertex(string $_from, string $_to, string $type = '', int $limit = 1): static|array|null
+ public static function searchByVertex(string $_from, string $_to, string|null $type = null, int $limit = 1): array|null
{
- $query = self::find()->where(['_from' => $_from, '_to' => $_to, 'type' => $type]);
+ $query = self::find()->where([
+ '_from' => $_from,
+ '_to' => $_to
+ ]);
- if ($limit < 2) {
- return $query->one();
- } else {
- return $query->limit($limit)->all();
+ if (isset($type)) {
+ $query->where(['type' => $type]);
}
+
+ return $query->limit($limit)->all();
}
/**
diff --git a/mirzaev/skillparts/system/models/Notification.php b/mirzaev/skillparts/system/models/Notification.php
index d0e9380..fb9c7fd 100644
--- a/mirzaev/skillparts/system/models/Notification.php
+++ b/mirzaev/skillparts/system/models/Notification.php
@@ -5,10 +5,11 @@ declare(strict_types=1);
namespace app\models;
use yii;
-use yii\web\IdentityInterface;
use app\models\traits\SearchByEdge;
+use app\models\Account;
+
use Exception;
/**
@@ -25,6 +26,16 @@ class Notification extends Document
*/
const SCENARIO_TRUSTED_CREATE = 'create';
+ /**
+ * Тип уведомления: памятка
+ */
+ const TYPE_NOTICE = 'notice';
+
+ /**
+ * Тип уведомления: предупреждение
+ */
+ const TYPE_WARNING = 'warning';
+
/**
* Цель для отправки уведомления
*
@@ -32,7 +43,7 @@ class Notification extends Document
*
* @see SCENARIO_TRUSTED_CREATE
*/
- public IdentityInterface|string|array|null $trgt;
+ public Account|string|array|null $account;
/**
* Текст уведомления
@@ -109,108 +120,116 @@ class Notification extends Document
/**
* Запись
*
- * @param string $html HTML уведомления
- * @param IdentityInterface $trgt Получатель уведомления
- * @param string $type Тип уведомления
- *
- * @todo Создать параметр разделителя для администрации
+ * @param bool|string $html Содержимое уведомления (HTML или текст)
+ * @param Account|array|string|null $account Получатель уведомления
*/
- public function write(string $html = null, IdentityInterface|array|string $trgt = null, string $type = 'notice'): self|array|null
+ public function write(Account|array|string|null $account = null): self|array|null
+ {
+ return $this::_write($this->text, $this->html, $account, $this->type);
+ }
+
+ /**
+ * Запись
+ *
+ * @param string $html Содержимое уведомления (HTML или текст)
+ * @param bool|string|null $html Содержимое уведомления (HTML или текст)
+ * @param Account|array|string|null $account Получатель уведомления
+ * @param string $type Тип уведомления
+ */
+ public static function _write(string $text, bool|string|null $html = false, Account|array|string|null $account = null, string $type = self::TYPE_NOTICE): self|array|null
{
// Инициализация
- $html ?? $html = $this->html ?? throw new Exception('Не удалось инициализировать содержимое');
- $trgt ?? $trgt = yii::$app->user ?? throw new Exception('Не удалось инициализировать получателя');
- $type ?? $trgt = $this->type ?? throw new Exception('Не удалось инициализировать тип');
+ $model = new self;
+ $account ?? $account = yii::$app->user->identity ?? throw new Exception('Не удалось инициализировать получателя');
- // Инициализация уведомления
- if (isset($html) && (bool) (int) $html) {
+ if ((bool) (int) $html) {
// Получен текст в формете HTML-кода
- $this->html = $this->text ?? null;
+ $model->html = $text ?? null;
} else {
// Получен необработанный текст
- $text = htmlspecialchars(strip_tags($this->text ?? null));
+ $text = htmlspecialchars(strip_tags($text ?? null));
- $this->html = <<html = <<$text
HTML;
}
- if ($this->save()) {
+ if ($model->save()) {
// Уведомление записано
// Инициализация получателей и создание ребра
- if (empty($trgt)) {
+ if (empty($account)) {
// Получатель не передан
goto test;
- } else if (is_string($trgt)) {
+ } else if (is_string($account)) {
// Передана необработанная строка
// Инициализация
$delimiter = ',';
// Конвертация
- $trgt = array_map('trim', explode($delimiter, $trgt));
+ $account = array_map('trim', explode($delimiter, $account));
- if (in_array('@all', $trgt, true)) {
+ if (in_array('@all', $account, true)) {
// Найден флаг обозначающий отправку всем пользователям
// Инициализация
$return = [];
- foreach (Account::readAll() as $target) {
+ foreach (Account::readAll() as $account) {
// Перебор всех аккаунтов
// Запись ребра: УВЕДОМЛЕНИЕ -> АККАУНТ
- $return[] = AccountEdgeNotification::writeSafe($this->readId(), $target->readId(), $type) ? $this : null;
+ $return[] = AccountEdgeNotification::writeSafe($model->readId(), $account->readId(), $type) ? $model : null;
}
return $return ? $return : null;
}
- if (in_array('@test', $trgt, true)) {
+ if (in_array('@test', $account, true)) {
// Найден флаг обозначающий тестирование (отправка самому себе)
test:
- return AccountEdgeNotification::writeSafe($this->readId(), yii::$app->user->id, $type) ? $this : null;
+ return AccountEdgeNotification::writeSafe($model->readId(), yii::$app->user->id, $type) ? $model : null;
}
}
- if (is_array($trgt)) {
+ if (is_array($account)) {
// Несколько получателей
// Инициализация
$return = [];
- foreach ($trgt as $target) {
+ foreach ($account as $account) {
// Перебор получателей
- if ($target instanceof Account) {
+ if ($account instanceof Account) {
// Один получатель
// Запись ребра: УВЕДОМЛЕНИЕ -> АККАУНТ
- return AccountEdgeNotification::writeSafe($this->readId(), $target->readId(), $type) ? $this : null;
+ return AccountEdgeNotification::writeSafe($model->readId(), $account->readId(), $type) ? $model : null;
}
- if ($target = Account::searchById(Account::collectionName() . '/' . $target)) {
+ if ($account = Account::searchById(Account::collectionName() . '/' . $account)) {
// Аккаунт найден
- echo ($target->readId()) . "\n";
+ echo ($account->readId()) . "\n";
// Запись ребра: УВЕДОМЛЕНИЕ -> АККАУНТ
- $return[] = AccountEdgeNotification::writeSafe($this->readId(), $target->readId(), $type) ? $this : null;
+ $return[] = AccountEdgeNotification::writeSafe($model->readId(), $account->readId(), $type) ? $model : null;
}
}
return $return ? $return : null;
- } else if ($trgt instanceof Account) {
+ } else if ($account instanceof Account) {
// Один получатель
// Запись ребра: УВЕДОМЛЕНИЕ -> АККАУНТ
- return AccountEdgeNotification::writeSafe($this->readId(), $trgt->readId(), $type) ? $this : null;
+ return AccountEdgeNotification::writeSafe($model->readId(), $account->readId(), $type) ? $model : null;
}
}
diff --git a/mirzaev/skillparts/system/models/Order.php b/mirzaev/skillparts/system/models/Order.php
index 45f166e..30f20c6 100644
--- a/mirzaev/skillparts/system/models/Order.php
+++ b/mirzaev/skillparts/system/models/Order.php
@@ -41,7 +41,9 @@ class Order extends Document
{
return array_merge(
parent::attributes(),
- []
+ [
+ 'stts'
+ ]
);
}
@@ -52,7 +54,9 @@ class Order extends Document
{
return array_merge(
parent::attributeLabels(),
- []
+ [
+ 'stts' => 'Статус'
+ ]
);
}
@@ -63,21 +67,43 @@ class Order extends Document
{
return array_merge(
parent::rules(),
- []
+ [
+ [
+ 'stts',
+ 'string',
+ 'message' => '{attribute} должен быть строкой'
+ ],
+ [
+ 'stts',
+ 'default',
+ 'value' => 'preparing'
+ ]
+ ]
);
}
/**
- * Запись
+ * Подключение к аккаунту
+ */
+ public function connect(Account $account): ?AccountEdgeOrder
+ {
+ // Запись ребра: АККАУНТ -> ЗАКАЗ
+ return AccountEdgeOrder::write($account->id, $this->readId(), 'current') ?? throw new Exception('Не удалось инициализировать ребро: АККАУНТ -> ЗАКАЗ');
+ }
+
+ /**
+ * Запись товара
*
* $supply = [ Supply $supply, int $amount = 1 ]
*
* @param Supply|array $supply Поставка
* @param Account $trgt Заказчик
*
+ * @return int Количество записанных поставок
+ *
* @todo Создать параметр разделителя для администрации
*/
- public function write(Supply|array $supply, Account $trgt = null): self|null
+ public function writeSupply(Supply|string|array $supply, Account $trgt = null): int
{
// Инициализация
$trgt ?? $trgt = yii::$app->user ?? throw new Exception('Не удалось инициализировать заказчика');
@@ -86,7 +112,7 @@ class Order extends Document
// Передана инстанция класса поставки или второй элемент массива не является числом
// Унификация входных данных
- $supply = [$supply, 1];
+ $supply = [$supply->catn => 1];
}
if (is_null($this->_key)) {
@@ -107,40 +133,98 @@ class Order extends Document
}
}
- foreach (is_array($supply[0]) ? $supply : [$supply] as $supply_raw) {
+ // Инициализация
+ $amount = 0;
+
+ foreach (is_array($supply) ? $supply : [$supply => 1] as $supply_raw => $amount_raw) {
// Перебор поставок
- for ($i = 0; $i < $supply_raw[1]; $i++) {
+ for ($i = 0; $i < $amount_raw; $i++) {
// Создание рёбер соразмерно запросу (добавление нескольких продуктов в корзину)
// Запись ребра: ЗАКАЗ -> ПОСТАВКА
- if (!$supply = Supply::searchByCatn($supply_raw[0]) or !OrderEdgeSupply::write($this->readId(), $supply->readId(), 'write')) {
+ if (!$supply_model = Supply::searchByCatn($supply_raw) or !OrderEdgeSupply::write($this->readId(), $supply_model->readId(), 'write')) {
// Поставка не найдена или запись ребра не удалась
+ var_dump('ПИЗДА');
+
continue;
+ } else {
+ // Ребро создано (товар подключен к заказу)
+
+ // Постинкрементация счётчика добавленных товаров
+ $amount++;
+
+ // Запись в журнал
+ $this->journal('write', ['target' => $supply_model->readId()]);
}
}
}
- // Отправка на сервер базы данных
- return $this->save() ? $this : null;
+ if ($amount === 0) {
+ // Отправка уведомления
+ self::notification('Неудачная попытка добавить товар в корзину');
+ } else if ($amount === 1) {
+ // Отправка уведомления
+ self::notification('Товар ' . $supply_model->catn . ' добавлен в корзину');
+ } else {
+ // Отправка уведомления
+ self::notification('Добавлено ' . $amount . ' товаров в корзину');
+ }
+
+ return $amount;
}
/**
- * Подключение к аккаунту
+ * Удаление поставки
+ *
+ * @param Supply|string|array $supply Товары
+ *
+ * @return int Количество удалённых рёбер
*/
- public function connect(Account $account): ?AccountEdgeOrder {
- // Запись ребра: АККАУНТ -> ЗАКАЗ
- return AccountEdgeOrder::write($account->id, $this->readId(), 'current') ?? throw new Exception('Не удалось инициализировать ребро: АККАУНТ -> ЗАКАЗ');
- }
-
- /**
- * Удаление
- */
- public function deleteEdge(string|array $catn): ?OrderEdgeSupply
+ public function deleteSupply(Supply|string|array $supply): int
{
- // Запись ребра: ЗАКАЗ -> ПОСТАВКА
- return OrderEdgeSupply::write($this->readId(), Supply::searchByCatn($catn)->readId(), 'delete');
+ // Инициализация
+ $amount = 0;
+
+ if ($supply instanceof Supply) {
+ // Передана инстанция класса поставки или второй элемент массива не является числом
+
+ // Унификация входных данных
+ $supply = [$supply->catn => 1];
+ }
+
+ foreach (is_array($supply) ? $supply : [$supply => 1] as $catn => $amount_raw) {
+ // Перебор товаров
+
+ if ($supply = Supply::searchByCatn($catn)) {
+ foreach (OrderEdgeSupply::searchByVertex($this->readId(), $supply->readId(), limit: $amount_raw) as $edge) {
+ // Перебор рёбер до продукта (если товаров в заказе несколько)
+
+ // Удаление
+ $edge->delete();
+
+ // Запись в журнал
+ $this->journal('delete', ['target' => $supply->readId()]);
+
+ // Постинкрементация счётчика удалённых рёбер
+ $amount++;
+ }
+ }
+ }
+
+ if ($amount === 0) {
+ // Отправка уведомления
+ self::notification('Неудачная попытка удалить товар из корзины');
+ } else if ($amount === 1) {
+ // Отправка уведомления
+ self::notification('Товар ' . $supply->catn . ' удалён из корзины');
+ } else {
+ // Отправка уведомления
+ self::notification('Удалено ' . $amount . ' товаров из корзины');
+ }
+
+ return $amount;
}
/**
@@ -195,26 +279,6 @@ class Order extends Document
// Генерация сдвига по запрашиваемым данным (пагинация)
$offset = $limit * ($page - 1);
-
- // Подзапрос для проверки статуса уведомления относительно пользователя
- // Поиск рёбер: ПОЛЬЗОВАТЕЛЬ -> УВЕДОМЛЕНИЕ
- $let = Supply::find()
- ->for(['order', 'order_edge_supply_deleted'])
- ->traversal('supply', 'INBOUND')
- ->in('order_edge_supply')
- ->where([
- [
- 'order._id' => $this->readId()
- ],
- [
- 'order_edge_supply_deleted.type' => 'delete'
- ]
- ])
- ->select('order_edge_supply_deleted');
-
- // Генерация
- $let = $let->createCommand();
-
// Поиск рёбер: ЗАКАЗ -> ПОСТАВКА
$supplies = Supply::searchByEdge(
from: 'order',
@@ -223,18 +287,10 @@ class Order extends Document
subquery_where: [
[
'order._id' => $this->readId()
- ],
- [
- 'order_edge_supply.type' => 'write'
]
],
- params: $let->getBindVars(),
- let: [
- 'order_edge_supply_deleted',
- '(' . (string) $let . ')'
- ],
foreach: ['edge' => 'order_edge_supply'],
- where: 'edge._to == supply._id && edge._to != order_edge_supply_deleted[0]._to',
+ where: 'edge._to == supply._id',
limit: $limit,
offset: $offset,
direction: 'INBOUND'
@@ -257,6 +313,7 @@ class Order extends Document
continue;
}
+ // Инициализация
$amount = 0;
// Повторный перебор для поиска дубликатов
@@ -286,9 +343,10 @@ class Order extends Document
if ($cost < 1) {
// Если стоимость равна нулю (явная ошибка)
- $this->deleteEdge($supply->readId());
+ // Удаление из базы данных
+ $this->deleteSupply($supply->readId());
- // Удаление
+ // Удаление из списка
unset($supplies[$key]);
// Пропуск итерации
@@ -301,4 +359,13 @@ class Order extends Document
return $supplies;
}
+
+ /**
+ * Отправка уведомления
+ */
+ public static function notification(string $text, string|null $type = Notification::TYPE_NOTICE): Notification|array|null
+ {
+ // Отправка
+ return Notification::_write($text, type: $type);
+ }
}
diff --git a/mirzaev/skillparts/system/models/Product.php b/mirzaev/skillparts/system/models/Product.php
index 8ba8c43..7d52fa7 100644
--- a/mirzaev/skillparts/system/models/Product.php
+++ b/mirzaev/skillparts/system/models/Product.php
@@ -4,9 +4,12 @@ declare(strict_types=1);
namespace app\models;
-use moonland\phpexcel\Excel;
+use yii;
+
use app\models\traits\SearchByEdge;
+use moonland\phpexcel\Excel;
+
/**
* Продукт (в ассортименте магазина)
*
@@ -20,6 +23,8 @@ class Product extends Document
/**
* Сценарий импорта из .excel документа
+ *
+ * Использовать для обхода правил при загрузке файла
*/
const SCENARIO_IMPORT = 'import';
@@ -31,7 +36,7 @@ class Product extends Document
/**
* Файл .excel для импорта товаров
*/
- public Excel|null $file = null;
+ public Excel|string|array|null $file = null;
/**
* Группа в которой состоит товар
@@ -54,7 +59,6 @@ class Product extends Document
return array_merge(
parent::attributes(),
[
- 'name',
'desc',
'ocid',
'catn',
@@ -74,16 +78,15 @@ class Product extends Document
return array_merge(
parent::attributeLabels(),
[
- 'name' => 'Название',
- 'desc' => 'Описание',
- 'ocid' => 'Идентификатор 1C',
- 'catn' => 'Каталожный номер',
- 'imgs' => 'Изображения',
- 'time' => 'Срок доставки',
- 'oemn' => 'OEM номера',
- 'cost' => 'Стоимость',
- 'file' => 'Документ',
- 'group' => 'Группа'
+ 'catn' => 'Каталожный номер (catn)',
+ 'desc' => 'Описание (desc)',
+ 'ocid' => 'Идентификатор 1C (ocid)',
+ 'imgs' => 'Изображения (imgs)',
+ 'time' => 'Срок доставки (time)',
+ 'oemn' => 'OEM номера (oemn)',
+ 'cost' => 'Стоимость (cost)',
+ 'file' => 'Документ (file)',
+ 'group' => 'Группа (group)'
]
);
}
@@ -97,21 +100,12 @@ class Product extends Document
parent::rules(),
[
[
- [
- 'name',
- 'catn'
- ],
+ 'catn',
'required',
'message' => 'Заполните поля: {attribute}',
'on' => self::SCENARIO_WRITE,
'except' => self::SCENARIO_IMPORT
],
- [
- 'file',
- 'required',
- 'message' => 'Заполните поля: {attribute}',
- 'on' => self::SCENARIO_IMPORT
- ],
[
'catn',
'string',
@@ -125,6 +119,12 @@ class Product extends Document
'arrayValidator',
'message' => '{attribute} должен быть массивом.'
],
+ [
+ 'file',
+ 'required',
+ 'message' => 'Заполните поля: {attribute}',
+ 'on' => self::SCENARIO_IMPORT
+ ],
[
'file',
'file',
@@ -142,13 +142,13 @@ class Product extends Document
}
/**
- * Запись
+ * Инициализация продукта
*
* @param string $catn Артикул, каталожный номер
*/
public static function initEmpty(string $catn): self|array
{
- $oemn = self::convertOemn2Catn($catn);
+ $oemn = self::searchOemn($catn);
if (count($oemn) === 1) {
// Передан только один артикул
@@ -159,7 +159,7 @@ class Product extends Document
return $model;
}
- // Запись
+ // Запись пустого продукта
return self::writeEmpty($catn);
}
@@ -188,7 +188,7 @@ class Product extends Document
}
/**
- * Запись
+ * Запись пустого продукта
*/
public static function writeEmpty(string $catn): ?self
{
@@ -205,12 +205,14 @@ class Product extends Document
/**
* Поиск OEM номеров
*
- * @param string $oemn OEM номера
+ * @param string $oemn Необработанная строка с OEM-номерами
* @param string $delimiters Разделители
*
* @todo НЕ ЗАБЫТЬ СДЕЛАТЬ НАСТРОЙКУ РАЗДЕЛИТЕЛЕЙ
+ *
+ * @return array OEM-номера
*/
- public static function convertOemn2Catn(string $oemn, string $delimiters = '\s\+\/,'): array
+ public static function searchOemn(string $oemn, string $delimiters = '\s\+\/,'): array
{
// Инициализация
$catn = [];
@@ -229,20 +231,22 @@ class Product extends Document
*/
public function import(): bool
{
- // Инициализация массива данных
+ // Инициализация
$data = [];
+ $amount = 0;
if ($this->validate()) {
foreach ($this->file as $file) {
// Перебор файлов
- // Сохранение на диск
- if (!file_exists('../assets/import/excel/')) {
- mkdir('../assets/import/excel/', 0775, true);
- }
- $file->saveAs($path = '../assets/import/excel/' . $file->baseName . '.' . $file->extension);
+ // Инициализация
+ $dir = '../assets/import/' . date('Y_m_d#H-i', time()) . '/excel/';
- // Проверка файла пройдена
+ // Сохранение на диск
+ if (!file_exists($dir)) {
+ mkdir($dir, 0775, true);
+ }
+ $file->saveAs($path = $dir . $file->baseName . '.' . $file->extension);
$data[] = Excel::import($path, [
'setFirstRecordAsKeys' => true,
@@ -250,32 +254,59 @@ class Product extends Document
]);
}
- foreach ($data[0] as $doc) {
- // Перебор полученных документов
- // Сохранение в базе данных
- $product = new static($doc);
+ foreach ($data as $data) {
+ // Перебор конвертированных файлов
- if ($product->validate()) {
- // Проверка пройдена
+ if (count($data) < 1) {
+ // Не найдены строки с товарами
- // Запись документа
- $product->save();
-
- // Запись группы
- $group = static::class . 'Group';
- (new $group())->writeMember($product, $this->group);
+ $this->addError('erros', 'Не удалось найти данные товаров');
} else {
- // Проверка не пройдена
- foreach ($product->errors as $attribute => $error) {
- $this->addError($attribute, $error);
+ // Перебор найденных товаров
+
+ foreach ($data as $doc) {
+ // Перебор полученных документов
+
+ // Сохранение в базе данных
+ $product = new static($doc);
+
+ $product->scenario = $product::SCENARIO_WRITE;
+
+ if ($product->validate()) {
+ // Проверка пройдена
+
+ // Запись документа
+ $product->save();
+
+ // Постинкрементация счётчика
+ $amount++;
+
+ // Запись группы
+ // $group = static::class . 'Group';
+ // (new $group())->writeMember($product, $this->group);
+ } else {
+ // Проверка не пройдена
+ foreach ($product->errors as $attribute => $error) {
+ $this->addError($attribute, $error);
+ }
+ }
}
}
}
+ // Деинициализация
+ $this->file = '';
+
+ static::afterImportExcel($amount);
+
return true;
}
+ $this->addError('erros', 'Неизвестная ошибка');
+
+ static::afterImportExcel($amount);
+
return false;
}
@@ -310,4 +341,42 @@ class Product extends Document
return $query;
}
+
+ /**
+ * Вызывается после загрузки поставок из excel-документа
+ *
+ * @param int $amount Количество
+ */
+ public static function afterImportExcel(int $amount = 0): bool
+ {
+ // Инициализация
+ $model = new Notification;
+ $date = date('H:i d.m.Y', time());
+
+ // Настройка
+ $model->text = yii::$app->controller->renderPartial('/notification/system/afterImportExcel', compact('amount', 'date'));
+ $model->type = $model::TYPE_NOTICE;
+
+ // Отправка
+ return (bool) $model->write();
+ }
+
+ /**
+ * Вызывается после загрузки поставок из 1С
+ *
+ * @param int $amount Количество
+ */
+ public static function afterImportOnec(): bool
+ {
+ // Инициализация
+ $model = new Notification;
+ $date = date('H:i d.m.Y', time());
+
+ // Настройка
+ $model->text = yii::$app->controller->renderPartial('/notification/system/afterImportOnec', compact('amount', 'date'));
+ $model->type = $model::TYPE_NOTICE;
+
+ // Отправка
+ return (bool) $model->write();
+ }
}
diff --git a/mirzaev/skillparts/system/models/Search.php b/mirzaev/skillparts/system/models/Search.php
index c4b8f43..0e8ac4a 100644
--- a/mirzaev/skillparts/system/models/Search.php
+++ b/mirzaev/skillparts/system/models/Search.php
@@ -86,13 +86,13 @@ class Search extends Document
* Запись
*
* @param string $text Текст запроса
- * @param IdentityInterface|null $user Пользователь совершивший запрос
+ * @param Account|null $account Пользователь совершивший запрос
*/
- public static function write(string $text, IdentityInterface $user = null): ?self
+ public static function write(string $text, Account|null $account = null): ?self
{
// Инициализация
$vertex = new self;
- isset($user) && yii::$app->user->isGuest ?: $user = yii::$app->user->identity;
+ isset($account) && yii::$app->user->isGuest ?: $account = yii::$app->user->identity;
// Настройки
$vertex->text = $text;
@@ -101,7 +101,7 @@ class Search extends Document
// Поиск записан
// Запись ребра: АККАУНТ -> ПОИСК
- return $user && AccountEdgeSearch::writeSafe($user->id, $vertex->readId(), 'request') ? $vertex : null;
+ return $account && AccountEdgeSearch::writeSafe($account->id, $vertex->readId(), 'request') ? $vertex : null;
}
return null;
diff --git a/mirzaev/skillparts/system/models/Supply.php b/mirzaev/skillparts/system/models/Supply.php
index 09b9fb0..4e74276 100644
--- a/mirzaev/skillparts/system/models/Supply.php
+++ b/mirzaev/skillparts/system/models/Supply.php
@@ -4,13 +4,16 @@ declare(strict_types=1);
namespace app\models;
-use Yii;
+use yii;
+use yii\web\User;
+use app\models\Account;
use app\models\Product;
use app\models\SupplyEdgeProduct;
use app\models\traits\Xml2Array;
use carono\exchange1c\interfaces\ProductInterface;
+use carono\exchange1c\controllers\ApiController;
use exception;
@@ -73,7 +76,7 @@ class Supply extends Product implements ProductInterface
public function afterSave($data, $vars): void
{
if (AccountEdgeSupply::searchByVertex(yii::$app->user->id, $this->readId())) {
- // Ребро уже существует
+ // Ребро: "АККАУНТ -> ПОСТАВКА" уже существует
} else {
// Ребра не существует
@@ -97,20 +100,21 @@ class Supply extends Product implements ProductInterface
public function setGroup1c($group): mixed
{
// Чтение группы
- // if ($group = SupplyGroup::readByOnecId($group->id)) {
+ // if ($group = SupplyGroup::readByOcid($group->id)) {
// // Запись ребра: ПОСТАВКА => ГРУППА ПОСТАВОК
// return static::writeEdgeBetweenGroup(static::collectionName() . '/' . $this->_key, $group->collectionName() . '/' . $group->_key);
// }
return true;
}
+
/**
* Поиск через связь с аккаунтом
*
- * @param string $id Идентификатор пользователя
- * @param bool $select Запрашиваемые значения
+ * @param string|null $id Идентификатор пользователя
+ * @param string|array|null $select Запрашиваемые значения
*/
- public static function searchByAccount(string $id = null, string|array $select = []): array
+ public static function searchByAccount(string|null $id = null, string|array|null $select = null, int|null $limit = 10): array
{
isset($id) ?: $id = yii::$app->user->id ?? throw new Exception('Не найден идентификатор');
@@ -124,17 +128,7 @@ class Supply extends Product implements ProductInterface
],
where: 'supply._id == account_edge_supply[0]._to AND supply.onec["ЗначенияСвойств"] != null',
select: $select,
- // handle: function ($request) {
- // $response = $request->createCommand()->execute()->getAll();
-
- // foreach ($response as &$attribute) {
- // // Приведение всех свойств в массив и очистка от лишних данных
-
- // $attribute = $attribute->getAll();
- // }
-
- // return $response;
- // }
+ limit: $limit
);
}
@@ -146,13 +140,15 @@ class Supply extends Product implements ProductInterface
*
* @todo Понять что может храниться внутри "$model->onec['ЗначенияСвойств']['ЗначенияСвойства']" и переписать
*/
- public static function createProperties1c($properties): void
+ public static function createProperties1c($properties, Account|null $account = null): void
{
// Инициализация
- $models = self::searchByAccount(select: 'supply.onec["ЗначенияСвойств"]');
+ $account ?? $account = yii::$app->user->identity;
+ $models = self::searchByAccount($account->readId());
$properties = self::xml2array($properties->xml);
- // for ($i = 0; $i <= count($models); $i++)
+ $account->on(ApiController::EVENT_AFTER_OFFER_SYNC, self::afterImport());
+
foreach ($models as $model) {
// Перебор записей
@@ -161,7 +157,7 @@ class Supply extends Product implements ProductInterface
$transit = $model->onec;
foreach ($model->onec['ЗначенияСвойств'] as $attribute_name => $attribute_value) {
- // Перебор аттрибутовfw
+ // Перебор аттрибутов
foreach ($properties as $property) {
// Перебор свойств
@@ -174,8 +170,6 @@ class Supply extends Product implements ProductInterface
// Запись индикатора наличия изменений
$changes = true;
-
- // break;
} else {
// Объединение данных
$transit['ЗначенияСвойств'][$attribute_name] = $property;
@@ -186,19 +180,19 @@ class Supply extends Product implements ProductInterface
if ($changes) {
// Если указано, что записаны изменения
- // Настройка ($transit нужен из-за ограничений __set())
+ // Настройка ($transit нужен из-за особенностей __set())
$model->onec = $transit;
foreach ($model->onec['ЗначенияСвойств'] as $property) {
// Перебор всех свойств
if (is_array($property)) {
- if ($property['Ид'] === 'd99622fe-4526-11eb-b7f3-f3e52d0a06a9') {
- // Если идентификатор свойства совпадает с указанным в настройках свойства хранящего OEM номера
+ // if ($property['Ид'] === $account->opts['import_sections_oem']) {
+ // // Если идентификатор свойства совпадает с указанным в настройках свойства хранящего OEM номера
// Настройка
$model->catn = $property['Значение'];
- }
+ // }
}
}
@@ -273,6 +267,7 @@ class Supply extends Product implements ProductInterface
* Запись ребра (предложения от поставок к продуктам) из 1С
*
* @todo Разобраться зачем нужно возвращать SupplyEdgeProduct
+ * Вернуть создание карточек, но только по условиям (загрузка от админа, например)
*/
public function getOffer1c($offer): SupplyEdgeProduct
{
@@ -283,53 +278,55 @@ class Supply extends Product implements ProductInterface
return new SupplyEdgeProduct;
}
- // Инициализация п̸̨͇͑͋͠р̷̬̂́̀̊о̸̜̯̹̅͒͘͝д̴̨̨̨̟̈́̆у̴̨̭̮̠́͋̈́к̴̭͊̋̎т̵̛̣͈̔̐͆а̵̨͖͑
- $product = Product::initEmpty($this->catn);
+ // Создание продукта (временно заблокировано)
- if (!is_array($product)) {
- // Создался только один товар и вернулся в виде модели
+ // // Инициализация п̸̨͇͑͋͠р̷̬̂́̀̊о̸̜̯̹̅͒͘͝д̴̨̨̨̟̈́̆у̴̨̭̮̠́͋̈́к̴̭͊̋̎т̵̛̣͈̔̐͆а̵̨͖͑
+ // $product = Product::initEmpty($this->catn);
- $product = [$product];
- }
+ // if (!is_array($product)) {
+ // // Создался только один товар и вернулся в виде модели
- if (is_array($this->oemn)) {
- // Значение OEM было инициализировано
+ // $product = [$product];
+ // }
- foreach ($this->oemn as $oem) {
- // Перебор артикулов из массива ОЕМ-номеров
+ // if (is_array($this->oemn)) {
+ // // Значение OEM было инициализировано
- // Инициализация и запись
- $product[] = Product::initEmpty($oem);
- }
- }
+ // foreach ($this->oemn as $oem) {
+ // // Перебор артикулов из массива ОЕМ-номеров
- foreach ($product as $product) {
- // Перебор всех инициализированных продуктов
+ // // Инициализация и запись
+ // $product[] = Product::initEmpty($oem);
+ // }
+ // }
- if ($this->catn !== $product->catn) {
- // Каталожные номера не соответствуют друг другу
+ // foreach ($product as $product) {
+ // // Перебор всех инициализированных продуктов
- continue;
- }
+ // if ($this->catn !== $product->catn) {
+ // // Каталожные номера не соответствуют друг другу
- // Код ниже скорее всего устарел
+ // continue;
+ // }
- if (SupplyEdgeProduct::searchByVertex($this->readId(), $product->readId())) {
- // Ребро уже существует
+ // // Код ниже скорее всего устарел
- continue;
- }
+ // if (SupplyEdgeProduct::searchByVertex($this->readId(), $product->readId())) {
+ // // Ребро уже существует
- // Запись ребра: ПОСТАВКА -> ПРОДУКТ
- $return = (new SupplyEdgeProduct)->write(
- $this->readId(),
- $product->readId(),
- 'connect',
- [
- 'onec' => self::xml2array($offer->xml)
- ]
- );
- }
+ // continue;
+ // }
+
+ // // Запись ребра: ПОСТАВКА -> ПРОДУКТ
+ // $return = (new SupplyEdgeProduct)->write(
+ // $this->readId(),
+ // $product->readId(),
+ // 'connect',
+ // [
+ // 'onec' => self::xml2array($offer->xml)
+ // ]
+ // );
+ // }
// Возвращает последнее сохранённое ребро
// Надо будет с этим разобраться
@@ -337,14 +334,18 @@ class Supply extends Product implements ProductInterface
}
/**
- * Запись продукта из 1С
+ * Запись продукта из 1С (поставка)
+ *
+ * @see Supply
*
* @todo Понять что может храниться внутри "$model->onec['ЗначенияСвойств']['ЗначенияСвойства']" и переписать
+ * Разобраться и создать возможность загрузки от лица другого аккаунта
*/
public static function createModel1c($product): ?self
{
// Инициализация
- $model = self::searchByOnecId($id = (string) $product->Ид) ?? new self;
+ $model = self::searchByOcid($id = (string) $product->Ид) ?? new self;
+ $account ?? $account = yii::$app->user->identity;
// Настройка
$model->ocid = $id ?? null;
@@ -359,11 +360,11 @@ class Supply extends Product implements ProductInterface
// Перебор всех свойств
if (is_array($property)) {
- if ($property['Ид'] === 'd99622fe-4526-11eb-b7f3-f3e52d0a06a9') {
+ if (!empty($account->opts['import_sections_oem']) && $property['Ид'] === $account->opts['import_sections_oem']) {
// Если идентификатор свойства совпадает с указанным в настройках свойства хранящего OEM номера
// Настройка
- $model->oemn = array_merge(self::convertOemn2Catn($property['Значение']), self::convertOemn2Catn((string) $product->Артикул));
+ $model->oemn = array_merge(self::searchOemn($property['Значение']), self::searchOemn((string) $product->Артикул));
}
}
}
@@ -402,7 +403,7 @@ class Supply extends Product implements ProductInterface
*
* @return Supply|null
*/
- public static function searchByOnecId(string $ocid): ?Supply
+ public static function searchByOcid(string $ocid): ?Supply
{
return static::findOne([static::getIdFieldName1c() => $ocid]);
}
diff --git a/mirzaev/skillparts/system/models/traits/SearchByEdge.php b/mirzaev/skillparts/system/models/traits/SearchByEdge.php
index 3d39f89..6d51a34 100644
--- a/mirzaev/skillparts/system/models/traits/SearchByEdge.php
+++ b/mirzaev/skillparts/system/models/traits/SearchByEdge.php
@@ -21,19 +21,19 @@ trait SearchByEdge
public static function searchByEdge(
string $from,
string $to,
- string $edge = null,
- int $limit = 10,
- int $offset = 0,
+ string|null $edge = null,
+ int|null $limit = 10,
+ int|null $offset = 0,
array $sort = ['ASC'],
string|array $subquery_where = [],
array $foreach = [],
string|array $where = [],
string $direction = 'ANY',
- array $let = [],
+ array|null $let = [],
string|array $select = null,
- callable $handle = null,
+ callable|null $handle = null,
array $params = []
- ): ?array {
+ ): mixed {
$subquery = static::find()
->params($params)
->for([$from, $edge ?? $from . '_edge_' . $to])
diff --git a/mirzaev/skillparts/system/views/account/deauthentication.php b/mirzaev/skillparts/system/views/account/panel/authenticated.php
similarity index 65%
rename from mirzaev/skillparts/system/views/account/deauthentication.php
rename to mirzaev/skillparts/system/views/account/panel/authenticated.php
index f11d2fa..dd42b96 100644
--- a/mirzaev/skillparts/system/views/account/deauthentication.php
+++ b/mirzaev/skillparts/system/views/account/panel/authenticated.php
@@ -5,18 +5,20 @@ declare(strict_types=1);
use yii;
if (!yii::$app->user->isGuest) {
- $popup = yii::$app->controller->renderPartial('/notification/panel');
+ // $popup = yii::$app->controller->renderPartial('/notification/panel');
- echo <<
-
-
-
- HTML;
+ // echo <<
+ //
+ //
+ //
+ // HTML;
}
?>
+=$notifications_button?>
+=$notifications_panel?>
diff --git a/mirzaev/skillparts/system/views/account/authentication.php b/mirzaev/skillparts/system/views/account/panel/deauthenticated.php
similarity index 100%
rename from mirzaev/skillparts/system/views/account/authentication.php
rename to mirzaev/skillparts/system/views/account/panel/deauthenticated.php
diff --git a/mirzaev/skillparts/system/views/cart/index.php b/mirzaev/skillparts/system/views/cart/index.php
index 848957f..fc40f28 100644
--- a/mirzaev/skillparts/system/views/cart/index.php
+++ b/mirzaev/skillparts/system/views/cart/index.php
@@ -11,10 +11,10 @@
Артикул
-
+
Описание
-
+
Количество
@@ -30,16 +30,16 @@
echo <<
-
+
$supply->catn
-
+
$supply->desc
-
- $supply->amnt
+
+
$supply->time
diff --git a/mirzaev/skillparts/system/views/layouts/main.php b/mirzaev/skillparts/system/views/layouts/main.php
index 8b9675b..12bbabb 100644
--- a/mirzaev/skillparts/system/views/layouts/main.php
+++ b/mirzaev/skillparts/system/views/layouts/main.php
@@ -19,6 +19,25 @@ AppAsset::register($this);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
registerCsrfMetaTags() ?>
= Html::encode($this->title ?? 'SkillParts') ?>
head() ?>
diff --git a/mirzaev/skillparts/system/views/notification/button.php b/mirzaev/skillparts/system/views/notification/button.php
new file mode 100644
index 0000000..800ceaa
--- /dev/null
+++ b/mirzaev/skillparts/system/views/notification/button.php
@@ -0,0 +1,18 @@
+
+
+ if (empty($notifications_new_amount) || $notifications_new_amount < 1) {
+ // Новые уведомления не найдены
+
+ echo <<
+ HTML;
+ } else {
+ // Новые уведомления найдены
+
+ echo <<$notifications_new_amount
+
+ HTML;
+ }
+ ?>
+
\ No newline at end of file
diff --git a/mirzaev/skillparts/system/views/notification/content.php b/mirzaev/skillparts/system/views/notification/content.php
new file mode 100644
index 0000000..149f4bf
--- /dev/null
+++ b/mirzaev/skillparts/system/views/notification/content.php
@@ -0,0 +1,30 @@
+Уведомлений нет
+ HTML;
+
+ return;
+ }
+
+ foreach($notifications as $notification) {
+ // Перебор уведомлений
+
+ // Инициализация
+ $notification = $notification->getAttributes();
+
+ if ($notification['type'] === 'notice') {
+ // Уведомление
+
+ echo $notification['html'];
+ } else if ($notification['type'] === 'warning') {
+ // Предупреждение
+
+ echo $notification['html'];
+ } else {
+ // Неизвестно
+
+ echo $notification['html'] ?? '
ОШИБКА
';
+ }
+ }
+?>
\ No newline at end of file
diff --git a/mirzaev/skillparts/system/views/notification/panel.php b/mirzaev/skillparts/system/views/notification/panel.php
index 149f4bf..00502b6 100644
--- a/mirzaev/skillparts/system/views/notification/panel.php
+++ b/mirzaev/skillparts/system/views/notification/panel.php
@@ -1,30 +1,45 @@
Уведомлений нет
- HTML;
+ // Уведомления не найдены
- return;
- }
-
- foreach($notifications as $notification) {
- // Перебор уведомлений
+ $content = <<Уведомлений нет
+ HTML;
+ } else {
+ // Уведомления найдены
// Инициализация
- $notification = $notification->getAttributes();
+ $content = '';
- if ($notification['type'] === 'notice') {
- // Уведомление
+ foreach ($notifications as $notification) {
+ // Перебор уведомлений
- echo $notification['html'];
- } else if ($notification['type'] === 'warning') {
- // Предупреждение
+ // Инициализация
+ $notification = $notification->getAttributes();
- echo $notification['html'];
- } else {
- // Неизвестно
+ if ($notification['type'] === 'notice') {
+ // Уведомление
- echo $notification['html'] ?? '
ОШИБКА
';
+ $content .= $notification['html'];
+ } else if ($notification['type'] === 'warning') {
+ // Предупреждение
+
+ $content .= $notification['html'];
+ } else {
+ // Неизвестно
+
+ $content .= $notification['html'] ?? '
ОШИБКА
';
+ }
}
}
+
+ if($notifications_panel_full ?? false) {
+ echo <<
+ $content
+
+ HTML;
+ } else {
+ echo $content;
+ }
?>
\ No newline at end of file
diff --git a/mirzaev/skillparts/system/views/notification/system/afterImportExcel.php b/mirzaev/skillparts/system/views/notification/system/afterImportExcel.php
new file mode 100644
index 0000000..352eec4
--- /dev/null
+++ b/mirzaev/skillparts/system/views/notification/system/afterImportExcel.php
@@ -0,0 +1,13 @@
+ 0) {
+ echo <<Импортировано $amount товаров из excel-документа
($date)
+ HTML;
+} else {
+ echo <<Неудачная попытка импорта товаров из excel-документа
($date)
+ HTML;
+}
+
+?>
\ No newline at end of file
diff --git a/mirzaev/skillparts/system/views/notification/system/afterImportOnec.php b/mirzaev/skillparts/system/views/notification/system/afterImportOnec.php
new file mode 100644
index 0000000..ec4f15f
--- /dev/null
+++ b/mirzaev/skillparts/system/views/notification/system/afterImportOnec.php
@@ -0,0 +1,2 @@
+
+
Импортированы товары из 1C (= $date ?>)
\ No newline at end of file
diff --git a/mirzaev/skillparts/system/views/product/index.php b/mirzaev/skillparts/system/views/product/index.php
index 5e10402..79368ab 100644
--- a/mirzaev/skillparts/system/views/product/index.php
+++ b/mirzaev/skillparts/system/views/product/index.php
@@ -120,7 +120,7 @@ use app\models\Product;
Время для повышения релевантности в поисковиках
-
= date('d.m.Y', $model['date']) ?>
+
= empty($row->jrnl) ? '' : date('H:i d.m.Y', end($row->jrnl)['date']); ?>
diff --git a/mirzaev/skillparts/system/views/profile/index.php b/mirzaev/skillparts/system/views/profile/index.php
index ebe5edc..65b221e 100644
--- a/mirzaev/skillparts/system/views/profile/index.php
+++ b/mirzaev/skillparts/system/views/profile/index.php
@@ -5,7 +5,8 @@ declare(strict_types=1);
use yii;
use yii\bootstrap\ActiveForm;
-use app\models\Supply;
+// Инициализация
+$panel ?? $panel = 'profile_panel_settings_import';
?>
@@ -25,85 +26,44 @@ use app\models\Supply;
Импорт
-
+
/>
1
-
+
/>
2
-
+
/>
Параметры 1C
'form_profile_settings',
- 'action' => false,
- 'fieldConfig' => [
- 'template' => '{label}{input}',
- ],
- 'options' => [
- 'onsubmit' => 'return false;'
- ]
- ]);
+ $form = ActiveForm::begin([
+ 'id' => 'form_profile_settings',
+ 'action' => false,
+ 'fieldConfig' => [
+ 'template' => '{label}{input}',
+ ],
+ 'options' => [
+ 'onsubmit' => 'return false;'
+ ]
+ ]);
- /**
- * @todo Перенести в модель
- */
-
- // Инициализация
- $model ?? $model = yii::$app->user->identity;
- $supplies ?? $supplies = Supply::searchByAccount(select: 'supply.onec["ЗначенияСвойств"]');
- $list = [];
-
-
- // Перебор свойств поставок
- foreach ($supplies as $supply) {
- // Инициализация
-
- $id = $supply['ЗначенияСвойства']['Ид'];
-
- if (in_array($id, $list, true)) {
- // Если встретился дубликат (вызывается очень часто)
- continue;
- }
-
- // Генерация
- !isset($supply['ЗначенияСвойства']['Наименование']) or $list[$id] = $supply['ЗначенияСвойства']['Наименование'];
- }
-
- // Инициализация текущего значения параметра в начале массива
- if (isset($model->opts['import_sections_oem'])) {
- // Параметр 'import_sections_oem' найден в настройках аккаунта
-
- if (isset($list[$model->opts['import_sections_oem']])) {
- // Найдено совпадение сохранённого параметра с полученным списком из поставок
-
- // Буфер для сохранения параметра
- $buffer = $list[$model->opts['import_sections_oem']];
-
- // Удаление параметра
- unset($list[$model->opts['import_sections_oem']]);
-
- // Сохранение параметра в начале массива
- $list = array_merge([$model->opts['import_sections_oem'] => $buffer], $list);
- } else {
- // Совпадение не найдено
-
- // Сохранение параметра из данных аккаунта в начале массива
- $list = array_merge([$model->opts['import_sections_oem'] => $model->opts['import_sections_oem']], $list);
- }
- }
+ // Инициализация
+ $model ?? $model = yii::$app->user->identity;
+ $list or $list = ['Нет данных'];
?>
- = $form->field($model, 'opts[import_sections_oem]', ['options' => ['class' => "mb-1"]])->dropDownList($list ?? ['Нет данных'], ['onChange' => 'page_profile_settings(this.parentElement.parentElement)'])->label('OEM-номера'); ?>
+ = $form->field($model, 'opts[import_sections_oem]', ['options' => ['class' => "mb-1"]])
+ ->dropDownList($list, [
+ 'onChange' => 'page_profile_settings(this.parentElement.parentElement, \'profile_panel_settings_import\')',
+ 'disabled' => count($list) <= 1
+ ])->label('OEM-номера'); ?>
Выберите поле в котором хранятся ОЕМ-номера и повторите импорт
Значения взяты из импортированных товаров
-
diff --git a/mirzaev/skillparts/system/views/profile/monitoring.php b/mirzaev/skillparts/system/views/profile/monitoring.php
index 202be05..5604eef 100644
--- a/mirzaev/skillparts/system/views/profile/monitoring.php
+++ b/mirzaev/skillparts/system/views/profile/monitoring.php
@@ -2,6 +2,9 @@
declare(strict_types=1);
+// Инициализация
+$panel ?? $panel = 'profile_panel_monitoring_input_search_history';
+
?>
@@ -20,14 +23,14 @@ declare(strict_types=1);
Журнал действий
-
+
/>
История заказов в разработке
-
+
/>
-
-
+
/>
Журнал в разработке
diff --git a/mirzaev/skillparts/system/views/profile/sidebar.php b/mirzaev/skillparts/system/views/profile/sidebar.php
index 7b4d353..c3d2533 100644
--- a/mirzaev/skillparts/system/views/profile/sidebar.php
+++ b/mirzaev/skillparts/system/views/profile/sidebar.php
@@ -25,17 +25,17 @@ use app\models\SupplyEdgeProduct;
$targetUrl = '/profile/trusted';
if ('/' . yii::$app->request->pathInfo === $targetUrl) {
- // Запрошена эта страница
+ // Запрошена та же страница от которой послан запрос (текущая)
echo <<
-
Панель управления
+
Панель управления
HTML;
} else {
echo <<
-
Панель управления
+
Панель управления
HTML;
}
@@ -43,56 +43,56 @@ use app\models\SupplyEdgeProduct;
?>
request->pathInfo === '/profile/supplies'
+ || '/' . yii::$app->request->pathInfo === '/profile/import'
+ ) {
+ // Запрошена та же страница от которой послан запрос (текущая)
- if ('/' . yii::$app->request->pathInfo === $targetUrl) {
- // Запрошена эта страница
-
- echo <<Поставки
+ echo <<Поставки
HTML;
- } else {
- echo <<Поставки
+ } else {
+ echo <<Поставки
HTML;
- }
+ }
?>
request->pathInfo === $targetUrl) {
- // Запрошена эта страница
+ if ('/' . yii::$app->request->pathInfo === $targetUrl) {
+ // Запрошена та же страница от которой послан запрос (текущая)
- echo <<Мониторинг
+ echo <<Мониторинг
HTML;
- } else {
- echo <<Мониторинг
+ } else {
+ echo <<Мониторинг
HTML;
- }
+ }
?>
request->pathInfo === $targetUrl) {
- // Запрошена эта страница
+ if ('/' . yii::$app->request->pathInfo === $targetUrl) {
+ // Запрошена та же страница от которой послан запрос (текущая)
- echo <<Настройки
+ echo <<Настройки
HTML;
- } else {
- echo <<Настройки
+ } else {
+ echo <<Настройки
HTML;
- }
+ }
?>
diff --git a/mirzaev/skillparts/system/views/profile/supplies.php b/mirzaev/skillparts/system/views/profile/supplies.php
index 5b8a5f8..bea8d75 100644
--- a/mirzaev/skillparts/system/views/profile/supplies.php
+++ b/mirzaev/skillparts/system/views/profile/supplies.php
@@ -5,10 +5,11 @@ declare(strict_types=1);
use yii;
use yii\bootstrap\ActiveForm;
-use app\controllers\ProfileController;
-use app\models\Supply;
+// Инициализация
+$panel ?? $panel = 'profile_panel_supplies_input_import';
?>
+
@@ -18,33 +19,47 @@ use app\models\Supply;
-
Управление поставками
- 'form_product_import_excel',
- 'action' => false,
- 'fieldConfig' => [
- 'template' => '{label}{input}',
- 'options' => ['class' => '']
- ],
- 'options' => [
- 'class' => 'mb-3',
- 'onsubmit' => 'return false;'
- ]
- ]);
+
Управление поставками
+
+
+
- $model = $model ?? new Supply;
- $groups = ProfileController::readGroups();
+
/>
+
- ?>
+
/>
+
+
Импорт из Excel-документа
+
+ 'form_product_import_excel',
+ 'action' => false,
+ 'fieldConfig' => [
+ 'template' => '{label}{input}',
+ 'options' => ['class' => '']
+ ],
+ 'options' => [
+ 'class' => 'mb-3',
+ 'onsubmit' => 'return false;'
+ ]
+ ]);
+ ?>
- = $form->field($model, 'group', ['options' => ['class' => "mb-3"]])->dropDownList($groups ?? ['Нет данных']); ?>
- = $form->field($model, 'file', ['enableLabel' => false])->fileInput(['multiple' => true, 'onChange' => 'supply_import(this.parentElement.parentElement)']) ?>
+ //$form->field($model, 'group', ['options' => ['class' => "mb-3"]])->dropDownList($groups ?? ['Нет данных']); ?>
+ = $form->field($model, 'file', ['enableLabel' => false])->fileInput(['multiple' => true, 'class' => 'mb-2', 'onChange' => 'page_profile_supplies_import_excel(this.parentElement.parentElement, \'profile_panel_supplies_input_import\')']) ?>
- = $form->errorSummary($model, ['header' => 'В документе были допущены ошибки:' /*, 'footer' => 'Исправьте их и попробуйте снова'*/]); ?>
+ = $form->errorSummary($model, ['header' => 'В документе были допущены ошибки:' /*, 'footer' => 'Исправьте их и попробуйте снова'*/]); ?>
-
-
+
+
+
+
diff --git a/mirzaev/skillparts/system/views/profile/trusted.php b/mirzaev/skillparts/system/views/profile/trusted.php
index fb805f7..9ddb1c4 100644
--- a/mirzaev/skillparts/system/views/profile/trusted.php
+++ b/mirzaev/skillparts/system/views/profile/trusted.php
@@ -7,9 +7,12 @@ use yii\bootstrap\ActiveForm;
use yii\helpers\Html;
use app\models\Notification;
-use app\models\Settings;
+
+// Инициализация
+$panel ?? $panel = 'profile_panel_trusted_input_notifications';
?>
+
@@ -26,7 +29,7 @@ use app\models\Settings;
Настройки
-
+
/>
Отправка уведомления
@@ -43,15 +46,15 @@ use app\models\Settings;
]);
// Значения по умолчанию
- isset($model_notifications) or $model_notifications = new Notification;
- isset($model_notifications->trgt) or $model_notifications->trgt = null;
- isset($model_notifications->text) or $model_notifications->text = '';
+ $model_notifications ?? $model_notifications = new Notification;
+ $model_notifications->account ?? $model_notifications->account = null;
+ $model_notifications->text ?? $model_notifications->text = '';
?>
= $form->errorSummary($model_notifications) ?>
- = $form->field($model_notifications, 'trgt', ['options' => ['class' => "mb-1 col-9"]])->input('text', ['placeholder' => yii::$app->user->identity->_key]); ?>
+ = $form->field($model_notifications, 'account', ['options' => ['class' => "mb-1 col-9"]])->input('text', ['placeholder' => yii::$app->user->identity->_key]); ?>
= $form->field($model_notifications, 'type', ['options' => ['class' => "col pl-0"]])->dropDownList($model_notifications->typs); ?>
Множественная отправка: @all или перечислить через запятую
@@ -64,7 +67,8 @@ use app\models\Settings;
-
+
+
/>
errorSummary($model_settings, ['header' => 'Получены ошибки:']) ?>
- = $form->field($model_settings, 'search_period', ['options' => ['class' => "mb-1"]])->textInput(['value' => $model_settings['search_period'], 'onChange' => 'page_profile_trusted_settings(this.parentElement.parentElement)']); ?>
+ = $form->field($model_settings, 'search_period', ['options' => ['class' => "mb-1"]])->textInput(['value' => $model_settings['search_period'], 'onChange' => 'page_profile_trusted_settings(this.parentElement.parentElement, \'profile_panel_trusted_input_settings\')']); ?>
Время которое надо ждать для повторного поиска в секундах
@@ -124,7 +128,7 @@ use app\models\Settings;
}
?>
- = $form->field($model_settings, 'search_connect_keep', ['options' => ['class' => "mb-1"]])->dropDownList($list, ['onChange' => 'page_profile_trusted_settings(this.parentElement.parentElement)']); ?>
+ = $form->field($model_settings, 'search_connect_keep', ['options' => ['class' => "mb-1"]])->dropDownList($list, ['onChange' => 'page_profile_trusted_settings(this.parentElement.parentElement, \'profile_panel_trusted_input_settings\')']); ?>
Удерживать открытое соединение до истечения срока блокировки поиска?
При малой задержке позволяет снизить время загрузки страницы, но при большой будет казаться, что сайт завис
diff --git a/mirzaev/skillparts/system/views/search/index.php b/mirzaev/skillparts/system/views/search/index.php
index 2005eb9..be322fd 100644
--- a/mirzaev/skillparts/system/views/search/index.php
+++ b/mirzaev/skillparts/system/views/search/index.php
@@ -63,8 +63,8 @@
HTML;
} else {
$button_cart = <<
-
+
+
HTML;
}
diff --git a/mirzaev/skillparts/system/views/search/panel.php b/mirzaev/skillparts/system/views/search/panel.php
index 067d8cf..cd1c58a 100644
--- a/mirzaev/skillparts/system/views/search/panel.php
+++ b/mirzaev/skillparts/system/views/search/panel.php
@@ -24,7 +24,7 @@ if (isset($history) && $history) {
foreach ($rows as $row) {
// Инициализация
- $date = date('H:i d.m.Y', $row->date);
+ $date = empty($row->jrnl) ? '' : date('H:i d.m.Y', end($row->jrnl)['date']);
echo <<$row->text
$date
diff --git a/mirzaev/skillparts/system/web/css/notification.css b/mirzaev/skillparts/system/web/css/notification.css
index 1f08f2b..95f7439 100644
--- a/mirzaev/skillparts/system/web/css/notification.css
+++ b/mirzaev/skillparts/system/web/css/notification.css
@@ -1,5 +1,10 @@
+#notification_button .notification_button_active {
+ /* color: #123EAB; */
+ color: #0010ff;
+}
+
#notifications_popup_wrap>.notification {
- min-height : 100px;
+ min-height : 60px;
border : 1px solid #a39bb1;
background-color: #fff;
opacity: 0;
@@ -10,6 +15,7 @@
z-index : 100;
bottom : 0;
position: fixed;
+ width: 370px;
overflow: hidden;
}
diff --git a/mirzaev/skillparts/system/web/css/pages/profile.css b/mirzaev/skillparts/system/web/css/pages/profile.css
index 375225b..5a4c0e0 100644
--- a/mirzaev/skillparts/system/web/css/pages/profile.css
+++ b/mirzaev/skillparts/system/web/css/pages/profile.css
@@ -18,16 +18,16 @@
}
#page_profile [id^=profile_panel_]>.profile_panel_content>div>.header_blue {
- background-color: #123EAB;
+ background-color: #dbdde3;
}
#page_profile [id^=profile_panel_]>.profile_panel_content>div>.header_blue~.row:nth-child(2n) {
- background-color: #f0f5ff;
+ background-color: #f7f6f9;
}
-#page_profile [id^=profile_panel_]>.profile_panel_content>div>.header_blue~.row:nth-child(2n + 1) {
- background-color: #e7edf9;
-}
+/* #page_profile [id^=profile_panel_]>.profile_panel_content>div>.header_blue~.row:nth-child(2n + 1) {
+ background-color: #dbdde3;
+} */
/* Экстрабольшие девайсы (большие десктопы, >= 1200px) */
diff --git a/mirzaev/skillparts/system/web/favicon.ico b/mirzaev/skillparts/system/web/favicon.ico
index 580ed73..4a35d39 100644
Binary files a/mirzaev/skillparts/system/web/favicon.ico and b/mirzaev/skillparts/system/web/favicon.ico differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/android-icon-144x144.png b/mirzaev/skillparts/system/web/img/favicons/android-icon-144x144.png
new file mode 100644
index 0000000..88921ab
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/android-icon-144x144.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/android-icon-192x192.png b/mirzaev/skillparts/system/web/img/favicons/android-icon-192x192.png
new file mode 100644
index 0000000..c7fb267
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/android-icon-192x192.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/android-icon-36x36.png b/mirzaev/skillparts/system/web/img/favicons/android-icon-36x36.png
new file mode 100644
index 0000000..d5845ec
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/android-icon-36x36.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/android-icon-48x48.png b/mirzaev/skillparts/system/web/img/favicons/android-icon-48x48.png
new file mode 100644
index 0000000..c7cd0d5
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/android-icon-48x48.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/android-icon-72x72.png b/mirzaev/skillparts/system/web/img/favicons/android-icon-72x72.png
new file mode 100644
index 0000000..45ffc17
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/android-icon-72x72.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/android-icon-96x96.png b/mirzaev/skillparts/system/web/img/favicons/android-icon-96x96.png
new file mode 100644
index 0000000..72c29a0
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/android-icon-96x96.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/apple-icon-114x114.png b/mirzaev/skillparts/system/web/img/favicons/apple-icon-114x114.png
new file mode 100644
index 0000000..bfab262
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/apple-icon-114x114.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/apple-icon-120x120.png b/mirzaev/skillparts/system/web/img/favicons/apple-icon-120x120.png
new file mode 100644
index 0000000..46bd87b
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/apple-icon-120x120.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/apple-icon-144x144.png b/mirzaev/skillparts/system/web/img/favicons/apple-icon-144x144.png
new file mode 100644
index 0000000..88921ab
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/apple-icon-144x144.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/apple-icon-152x152.png b/mirzaev/skillparts/system/web/img/favicons/apple-icon-152x152.png
new file mode 100644
index 0000000..18588dd
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/apple-icon-152x152.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/apple-icon-180x180.png b/mirzaev/skillparts/system/web/img/favicons/apple-icon-180x180.png
new file mode 100644
index 0000000..5c3156e
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/apple-icon-180x180.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/apple-icon-57x57.png b/mirzaev/skillparts/system/web/img/favicons/apple-icon-57x57.png
new file mode 100644
index 0000000..a766f16
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/apple-icon-57x57.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/apple-icon-60x60.png b/mirzaev/skillparts/system/web/img/favicons/apple-icon-60x60.png
new file mode 100644
index 0000000..9a0a061
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/apple-icon-60x60.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/apple-icon-72x72.png b/mirzaev/skillparts/system/web/img/favicons/apple-icon-72x72.png
new file mode 100644
index 0000000..45ffc17
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/apple-icon-72x72.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/apple-icon-76x76.png b/mirzaev/skillparts/system/web/img/favicons/apple-icon-76x76.png
new file mode 100644
index 0000000..af9a5ba
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/apple-icon-76x76.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/apple-icon-precomposed.png b/mirzaev/skillparts/system/web/img/favicons/apple-icon-precomposed.png
new file mode 100644
index 0000000..dfbf7db
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/apple-icon-precomposed.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/apple-icon.png b/mirzaev/skillparts/system/web/img/favicons/apple-icon.png
new file mode 100644
index 0000000..dfbf7db
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/apple-icon.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/browserconfig.xml b/mirzaev/skillparts/system/web/img/favicons/browserconfig.xml
new file mode 100644
index 0000000..c554148
--- /dev/null
+++ b/mirzaev/skillparts/system/web/img/favicons/browserconfig.xml
@@ -0,0 +1,2 @@
+
+
#ffffff
\ No newline at end of file
diff --git a/mirzaev/skillparts/system/web/img/favicons/favicon-16x16.png b/mirzaev/skillparts/system/web/img/favicons/favicon-16x16.png
new file mode 100644
index 0000000..b14ab78
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/favicon-16x16.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/favicon-32x32.png b/mirzaev/skillparts/system/web/img/favicons/favicon-32x32.png
new file mode 100644
index 0000000..b63cd6b
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/favicon-32x32.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/favicon-96x96.png b/mirzaev/skillparts/system/web/img/favicons/favicon-96x96.png
new file mode 100644
index 0000000..72c29a0
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/favicon-96x96.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/favicon.ico b/mirzaev/skillparts/system/web/img/favicons/favicon.ico
new file mode 100644
index 0000000..cb5e221
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/favicon.ico differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/manifest.json b/mirzaev/skillparts/system/web/img/favicons/manifest.json
new file mode 100644
index 0000000..013d4a6
--- /dev/null
+++ b/mirzaev/skillparts/system/web/img/favicons/manifest.json
@@ -0,0 +1,41 @@
+{
+ "name": "App",
+ "icons": [
+ {
+ "src": "\/android-icon-36x36.png",
+ "sizes": "36x36",
+ "type": "image\/png",
+ "density": "0.75"
+ },
+ {
+ "src": "\/android-icon-48x48.png",
+ "sizes": "48x48",
+ "type": "image\/png",
+ "density": "1.0"
+ },
+ {
+ "src": "\/android-icon-72x72.png",
+ "sizes": "72x72",
+ "type": "image\/png",
+ "density": "1.5"
+ },
+ {
+ "src": "\/android-icon-96x96.png",
+ "sizes": "96x96",
+ "type": "image\/png",
+ "density": "2.0"
+ },
+ {
+ "src": "\/android-icon-144x144.png",
+ "sizes": "144x144",
+ "type": "image\/png",
+ "density": "3.0"
+ },
+ {
+ "src": "\/android-icon-192x192.png",
+ "sizes": "192x192",
+ "type": "image\/png",
+ "density": "4.0"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/mirzaev/skillparts/system/web/img/favicons/ms-icon-144x144.png b/mirzaev/skillparts/system/web/img/favicons/ms-icon-144x144.png
new file mode 100644
index 0000000..88921ab
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/ms-icon-144x144.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/ms-icon-150x150.png b/mirzaev/skillparts/system/web/img/favicons/ms-icon-150x150.png
new file mode 100644
index 0000000..5e570ff
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/ms-icon-150x150.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/ms-icon-310x310.png b/mirzaev/skillparts/system/web/img/favicons/ms-icon-310x310.png
new file mode 100644
index 0000000..ed1ba9f
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/ms-icon-310x310.png differ
diff --git a/mirzaev/skillparts/system/web/img/favicons/ms-icon-70x70.png b/mirzaev/skillparts/system/web/img/favicons/ms-icon-70x70.png
new file mode 100644
index 0000000..010bb5b
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/favicons/ms-icon-70x70.png differ
diff --git a/mirzaev/skillparts/system/web/img/logos/compressed/skillparts.png b/mirzaev/skillparts/system/web/img/logos/compressed/skillparts.png
new file mode 100644
index 0000000..5967fe9
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/logos/compressed/skillparts.png differ
diff --git a/mirzaev/skillparts/system/web/img/logos/compressed/skillparts.svg b/mirzaev/skillparts/system/web/img/logos/compressed/skillparts.svg
new file mode 100644
index 0000000..319c7e0
--- /dev/null
+++ b/mirzaev/skillparts/system/web/img/logos/compressed/skillparts.svg
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/mirzaev/skillparts/system/web/img/logos/compressed/skillparts_small.png b/mirzaev/skillparts/system/web/img/logos/compressed/skillparts_small.png
new file mode 100644
index 0000000..8fdc0d8
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/logos/compressed/skillparts_small.png differ
diff --git a/mirzaev/skillparts/system/web/img/logos/compressed/skillparts_small.svg b/mirzaev/skillparts/system/web/img/logos/compressed/skillparts_small.svg
new file mode 100644
index 0000000..6679d9a
--- /dev/null
+++ b/mirzaev/skillparts/system/web/img/logos/compressed/skillparts_small.svg
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/mirzaev/skillparts/system/web/img/logos/faviconRaw.png b/mirzaev/skillparts/system/web/img/logos/faviconRaw.png
new file mode 100644
index 0000000..95babca
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/logos/faviconRaw.png differ
diff --git a/mirzaev/skillparts/system/web/img/logos/faviconRaw2.png b/mirzaev/skillparts/system/web/img/logos/faviconRaw2.png
new file mode 100644
index 0000000..e043dd4
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/logos/faviconRaw2.png differ
diff --git a/mirzaev/skillparts/system/web/img/logos/skillparts.png b/mirzaev/skillparts/system/web/img/logos/skillparts.png
index 5f1ca7e..181c1f2 100644
Binary files a/mirzaev/skillparts/system/web/img/logos/skillparts.png and b/mirzaev/skillparts/system/web/img/logos/skillparts.png differ
diff --git a/mirzaev/skillparts/system/web/img/logos/skillparts.png-autosave.kra b/mirzaev/skillparts/system/web/img/logos/skillparts.png-autosave.kra
new file mode 100644
index 0000000..c5d83d0
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/logos/skillparts.png-autosave.kra differ
diff --git a/mirzaev/skillparts/system/web/img/logos/skillparts.svg b/mirzaev/skillparts/system/web/img/logos/skillparts.svg
index 98830fd..499fee3 100644
--- a/mirzaev/skillparts/system/web/img/logos/skillparts.svg
+++ b/mirzaev/skillparts/system/web/img/logos/skillparts.svg
@@ -5,9 +5,9 @@
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:krita="http://krita.org/namespaces/svg/krita"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- width="889.92pt"
+ width="888.48pt"
height="231.12pt"
- viewBox="0 0 889.92 231.12">
+ viewBox="0 0 888.48 231.12">
-
+
diff --git a/mirzaev/skillparts/system/web/img/logos/skillparts_small.png b/mirzaev/skillparts/system/web/img/logos/skillparts_small.png
new file mode 100644
index 0000000..8f0f997
Binary files /dev/null and b/mirzaev/skillparts/system/web/img/logos/skillparts_small.png differ
diff --git a/mirzaev/skillparts/system/web/img/logos/skillparts_small.svg b/mirzaev/skillparts/system/web/img/logos/skillparts_small.svg
new file mode 100644
index 0000000..e0a2144
--- /dev/null
+++ b/mirzaev/skillparts/system/web/img/logos/skillparts_small.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
diff --git a/mirzaev/skillparts/system/web/js/account.js b/mirzaev/skillparts/system/web/js/account.js
index e8f06bb..8d21e4f 100644
--- a/mirzaev/skillparts/system/web/js/account.js
+++ b/mirzaev/skillparts/system/web/js/account.js
@@ -128,7 +128,9 @@ function deauthentication() {
function registration(form) {
if (form == undefined) {
- form = { '_csrf': yii.getCsrfToken() };
+ form = {
+ '_csrf': yii.getCsrfToken()
+ };
} else {
form = $(form).serialize();
}
diff --git a/mirzaev/skillparts/system/web/js/cart.js b/mirzaev/skillparts/system/web/js/cart.js
index a74b9ee..e58bc62 100644
--- a/mirzaev/skillparts/system/web/js/cart.js
+++ b/mirzaev/skillparts/system/web/js/cart.js
@@ -1,22 +1,29 @@
+/**
+ * Записать в корзину (создать корзину, если не существует)
+ */
function cart_write(catn, amount = 1) {
+ // Инициализация
+ let data = {};
+ data[catn] = amount;
+
$.ajax({
url: '/order/write',
type: 'post',
dataType: 'json',
data: {
'_csrf': yii.getCsrfToken(),
- 'supplies': [
- catn,
- amount
- ]
+ 'supplies': data
},
- success: cart_success,
- error: cart_error
+ success: cart_response_success,
+ error: cart_response_error
});
return false;
}
+/**
+ * Удалить корзину
+ */
function cart_delete() {
$.ajax({
url: '/order/delete',
@@ -25,13 +32,16 @@ function cart_delete() {
data: {
'_csrf': yii.getCsrfToken()
},
- success: cart_success,
- error: cart_error
+ success: cart_response_success,
+ error: cart_response_error
});
return false;
}
+/**
+ * Сформировать заказ
+ */
function cart_pay() {
$.ajax({
url: '/order/pay',
@@ -40,13 +50,16 @@ function cart_pay() {
data: {
'_csrf': yii.getCsrfToken()
},
- success: cart_success,
- error: cart_error
+ success: cart_response_success,
+ error: cart_response_error
});
return false;
}
+/**
+ * Управление чекбоксами
+ */
function cart_list_checkbox(target) {
// Инициализация
@@ -57,12 +70,16 @@ function cart_list_checkbox(target) {
if (catn === 'all') {
if (target.checked === true) {
for ($i = 0; $i < elements.length; $i++) {
+ // Перебор всех выбранных элементов
+
elements[$i].getElementsByTagName('input')[0].checked = true;
}
target.checked = true;
} else {
for ($i = 0; $i < elements.length; $i++) {
+ // Перебор всех выбранных элементов
+
elements[$i].getElementsByTagName('input')[0].checked = false;
}
@@ -73,17 +90,33 @@ function cart_list_checkbox(target) {
}
}
-function cart_list_delete(dropdown) {
+/**
+ * Удалить из корзины
+ */
+function cart_list_delete(target, amount = 0) {
// Инициализация
- let elements = document.getElementsByClassName('cart_list_target');
- let reg = /^\w+_([^_]*)$/;
- let targets = [];
+ let targets = {};
- for ($i = 0; $i < elements.length; $i++) {
- let checkbox = elements[$i].getElementsByTagName('input')[0];
+ if (target !== undefined) {
+ // Обработка входных параметров
- if (checkbox.checked === true) {
- targets.push(reg.exec(checkbox.id)[1]);
+ targets[target] = amount;
+ } else {
+ // Обработка выбранных элементов в списке
+
+ // Инициализация
+ let elements = document.getElementsByClassName('cart_list_target');
+ let reg = /^\w+_([^_]*)$/;
+
+ for ($i = 0; $i < elements.length; $i++) {
+ // Перебор всех выбранных элементов
+
+ // Инициализация
+ let checkbox = elements[$i].getElementsByTagName('input')[0];
+
+ if (checkbox.checked === true) {
+ targets[reg.exec(checkbox.id)[1]] = 0;
+ }
}
}
@@ -95,27 +128,62 @@ function cart_list_delete(dropdown) {
'_csrf': yii.getCsrfToken(),
'targets': targets
},
- success: cart_success,
- error: cart_error
+ success: cart_response_success,
+ error: cart_response_error
});
+ // Реинициализация
document.getElementById('cart_list_action').value = 'none';
- // Подсчитывание стоимости
+ // Пересчитывание стоимости
cart_cost_calculate();
return false;
}
+/**
+ * Изменить количество товара в корзине
+ */
+function cart_list_amount_update(target, input) {
+ if (target !== undefined && input !== undefined) {
+ // Обработка входных параметров
+
+ // Инициализация
+ let targets = {};
+ targets[target] = input.value;
+
+ $.ajax({
+ url: '/order/amount-update',
+ type: 'post',
+ dataType: 'json',
+ data: {
+ '_csrf': yii.getCsrfToken(),
+ 'targets': targets
+ },
+ success: cart_response_success,
+ error: cart_response_error
+ });
+ }
+
+ // Пересчитывание стоимости
+ cart_cost_calculate();
+
+ return false;
+}
+
+/**
+ * Подсчёт стоимости
+ */
function cart_cost_calculate() {
let elements = document.getElementsByClassName('cart_list_target');
let reg = /^([0-9]*)\s*\w*/;
let costs = 0;
for ($i = 0; $i < elements.length; $i++) {
- let cost = elements[$i].getElementsByTagName('div')[5];
+ let cost = elements[$i].getElementsByTagName('div')[5].innerText;
+ let amount = elements[$i].getElementsByTagName('div')[3].children[0].value;
- costs += +reg.exec(cost.innerText)[1];
+ costs += +reg.exec(cost)[1] * amount;
}
document.getElementById('cart_cost').innerHTML = costs;
@@ -123,8 +191,8 @@ function cart_cost_calculate() {
cart_cost_calculate();
-function cart_success(data, status) {
- // Обработка ответов от удавшихся запросов
+function cart_response(data, status) {
+ // Обработка ответов
// Основной блок
if (data.main !== undefined) {
@@ -144,23 +212,17 @@ function cart_success(data, status) {
}
}
-function cart_error(data, status) {
+function cart_response_success(data, status) {
+ // Обработка ответов от удавшихся запросов
+
+ cart_response(data, status);
+}
+
+function cart_response_error(data, status) {
// Обработка ответов от неудавшихся запросов
- // Основной блок
- if (data.responseJSON.main !== undefined) {
- main = document.getElementsByTagName('main')[0];
+ // Инициализвация
+ data = data.responseJSON;
- // Обновление окна результатов поиска
- main.innerHTML = data.main;
-
- // Реинициализация
- reinitialization(main);
- }
-
- // CSRF-токен
- if (data.responseJSON._csrf !== undefined) {
- // Обновление документа
- $('meta[name=csrf-token]').prop("content", data.responseJSON._csrf);
- }
+ cart_response(data, status);
}
\ No newline at end of file
diff --git a/mirzaev/skillparts/system/web/js/notification.js b/mirzaev/skillparts/system/web/js/notification.js
index b552b6d..713caa2 100644
--- a/mirzaev/skillparts/system/web/js/notification.js
+++ b/mirzaev/skillparts/system/web/js/notification.js
@@ -17,9 +17,6 @@ function notification_last() {
// Проверка уведомлений
setInterval(notification_last, 5000);
-// Поиск уведомлений
-notification_stream();
-
function notification_popup_create(html, id) {
// Инициализация
let wrap = document.getElementById('notifications_popup_wrap');
@@ -40,7 +37,7 @@ function notification_popup_create(html, id) {
function notification_popup_delete(notification) {
// Эффект затухания (статус того, что уведомление прочитано)
- notification.style.opacity = 0.4;
+ notification.style.opacity = 0.75;
notification.style.borderColor = '#c0b7d0';
setTimeout(() => {
@@ -56,14 +53,15 @@ function notification_popup_delete(notification) {
return false;
};
-function notification_stream() {
+function notification_stream(preload = 0) {
$.ajax({
url: '/notification',
type: 'post',
dataType: 'json',
data: {
'_csrf': yii.getCsrfToken(),
- 'stream': 1
+ 'stream': 1,
+ 'preload': preload
},
success: notification_response_success,
error: notification_response_error
@@ -72,16 +70,26 @@ function notification_stream() {
return false;
};
-function notification_response_success(data, status) {
- if (data.main !== undefined) {
- main = document.getElementsByTagName('main')[0];
+// Предзагрузка уведомлений
+notification_stream(1);
- // Обновление документа
- main.innerHTML = data.main;
+function notification_response_success(data, status) {
+ // Кнопка уведомлений
+ if (data.button !== undefined) {
+ // Инициализация
+ button_old = document.getElementById('notification_button');
+
+ // Запись
+ button_old.insertAdjacentHTML("beforebegin", data.button);
+
+ // Запись
+ button_old.remove();
// Реинициализация
- reinitialization(main);
- };
+ $('#notification_button').dropdown().init();
+ }
+
+ // Панель уведомлений
if (data.panel !== undefined) {
// Инициализация
panel = document.getElementById('notification_button_panel');
@@ -91,36 +99,50 @@ function notification_response_success(data, status) {
// Реинициализация
reinitialization(panel);
- };
+ }
+
+ // Всплывающее окно
if (data.popup !== undefined && data.popup['html'] !== undefined && data.popup['id'] !== undefined) {
// Инициализация
popup = document.getElementById('notification_popup');
// Генерация
notification_popup_create(data.popup['html'], data.popup['id']);
- };
- if (data.redirect !== undefined) {
- // Перенаправление
- history.pushState({}, document.title, data.redirect);
- };
- if (data._csrf !== undefined) {
- // Обновление документа
- $('meta[name=csrf-token]').prop("content", data._csrf);
- };
-};
+ }
+
+ notification_response(data, status);
+}
function notification_response_error(data, status) {
- if (data.responseJSON.main !== undefined) {
+ // Инициализация
+ data = data.responseJSON;
+
+ notification_response(data, status);
+}
+
+function notification_response(data, status) {
+ // Основной блок
+ if (data.main !== undefined) {
+ // Инициализация
main = document.getElementsByTagName('main')[0];
- // Обновление окна результатов поиска
+ // Обновление документа
main.innerHTML = data.main;
// Реинициализация
reinitialization(main);
};
- if (data.responseJSON._csrf !== undefined) {
- // Обновление документа
- $('meta[name=csrf-token]').prop("content", data.responseJSON._csrf);
+
+ // Перенаправление
+ if (data.redirect !== undefined) {
+ // Перенаправление
+ history.pushState({}, document.title, data.redirect);
};
-};
\ No newline at end of file
+
+ // CSRF-токен
+ if (data._csrf !== undefined) {
+ // Обновление документа
+ $('meta[name=csrf-token]').prop("content", data._csrf);
+ };
+}
+
diff --git a/mirzaev/skillparts/system/web/js/profile.js b/mirzaev/skillparts/system/web/js/profile.js
index 24267e3..2975953 100644
--- a/mirzaev/skillparts/system/web/js/profile.js
+++ b/mirzaev/skillparts/system/web/js/profile.js
@@ -1,10 +1,47 @@
-function supply_import(form) {
- if (form == undefined) {
+function page_profile_supplies(form, panel) {
+ if (form === undefined) {
form = {
'_csrf': yii.getCsrfToken()
};
+
+ if (panel !== undefined) {
+ form.panel = panel;
+ }
} else {
form = new FormData(form);
+
+ if (panel !== undefined) {
+ form.append('panel', panel);
+ }
+ }
+
+ $.ajax({
+ url: '/profile/supplies',
+ type: 'post',
+ dataType: 'json',
+ data: form,
+ success: page_profile_response_success,
+ error: page_profile_response_error
+ });
+
+ return false;
+}
+
+function page_profile_supplies_import_excel(form, panel) {
+ if (form === undefined) {
+ form = {
+ '_csrf': yii.getCsrfToken()
+ };
+
+ if (panel !== undefined) {
+ form.panel = panel;
+ }
+ } else {
+ form = new FormData(form);
+
+ if (panel !== undefined) {
+ form.append('panel', panel);
+ }
}
$.ajax({
@@ -14,18 +51,29 @@ function supply_import(form) {
data: form,
processData: false,
contentType: false,
- success: page_profile_response_success,
+ success: page_profile_response_success,
error: page_profile_response_error
});
+
+ return false;
};
-function page_profile_settings(form) {
+function page_profile_settings(form, panel) {
if (form == undefined) {
form = {
'_csrf': yii.getCsrfToken()
};
+
+ if (panel !== undefined) {
+ form.panel = panel;
+ }
} else {
- form = $(form).serialize();
+ form = $(form).serializeArray();
+
+ form.push({
+ name: "panel",
+ value: panel
+ });
}
$.ajax({
@@ -33,82 +81,84 @@ function page_profile_settings(form) {
type: 'post',
dataType: 'json',
data: form,
- success: page_profile_response_success,
+ success: page_profile_response_success,
error: page_profile_response_error
});
+
+ // Реинициализация
+ initDropdownOem();
+
+ return false;
}
-function page_profile_monitoring(change = 1) {
+function page_profile_monitoring(change = 1, panel) {
// Инициализация
- url = new URL(document.location);
- search = url.searchParams.get('search');
+ let url = new URL(document.location);
+ let search = url.searchParams.get('search');
- if (search == undefined) {
+ if (search === null) {
search = 1;
+ } else {
+ search = +search + change;
}
+ // Предобработка
+ url.searchParams.set('search', search);
+
$.ajax({
url: '/profile/monitoring',
type: 'post',
dataType: 'json',
data: {
'_csrf': yii.getCsrfToken(),
- 'search': +search + change
+ 'search': search,
+ 'panel': panel
},
- success: function (data) {
+ success: function (data, status) {
+ page_profile_response_success(data, status);
+
+ // Ренициализация
+ let url = new URL(document.location);
+
// Запись параметра в URL
url.searchParams.set('search', data.search);
+
+ // Запись в историю
history.pushState('', document.title, url.toString());
-
- if (data.main !== undefined) {
- // Обновление документа
- document.getElementsByTagName('main')[0].innerHTML = data.main;
- }
- if (data._csrf !== undefined) {
- $('meta[name=csrf-token]').prop("content", data._csrf);
- }
-
- return false;
},
- error: function (data) {
- if (data.responseJSON.main !== undefined) {
- // Обновление документа
- document.getElementsByTagName('main')[0].innerHTML = data.responseJSON.main;
- }
- if (data.responseJSON._csrf !== undefined) {
- // Обновление документа
- $('meta[name=csrf-token]').prop("content", data.responseJSON._csrf);
- }
-
- return true;
- }
+ error: page_profile_response_error
});
- return true;
+ return false;
};
function page_profile_response_success(data, status) {
- if (data.main !== undefined) {
- main = document.getElementsByTagName('main')[0];
-
- // Обновление документа
- main.innerHTML = data.main;
-
- // Реинициализация
- reinitialization(main);
+ // Активная панель
+ if (data.panel_selected !== undefined) {
+ // Активация
+ document.getElementById(data.panel_selected).click()
}
+
+ // Перенаправление
if (data.redirect !== undefined) {
// Перенаправление
history.pushState({}, document.title, data.redirect);
}
- if (data._csrf !== undefined) {
- // Обновление документа
- $('meta[name=csrf-token]').prop("content", data._csrf);
- }
+
+ page_profile_response(data, status);
};
function page_profile_response_error(data, status) {
- if (data.responseJSON.main !== undefined) {
+ // Инициализация
+ data = data.responseJSON;
+
+ page_profile_response(data, status);
+};
+
+function page_profile_response(data, status) {
+ // Основной блок
+ if (data.main !== undefined) {
+ // Инициализация
main = document.getElementsByTagName('main')[0];
// Обновление окна результатов поиска
@@ -117,8 +167,21 @@ function page_profile_response_error(data, status) {
// Реинициализация
reinitialization(main);
}
- if (data.responseJSON._csrf !== undefined) {
+
+ // CSRF-токен
+ if (data._csrf !== undefined) {
// Обновление документа
- $('meta[name=csrf-token]').prop("content", data.responseJSON._csrf);
+ $('meta[name=csrf-token]').prop("content", data._csrf);
}
-};
\ No newline at end of file
+}
+
+// Сокрытие первого элемента
в списке
+function initDropdownOem() {
+ let dropdown = document.getElementById('account-opts-import_sections_oem');
+
+ if (dropdown !== null && dropdown.length > 1) {
+ dropdown.children[0].hidden = true;
+ }
+}
+
+initDropdownOem();
\ No newline at end of file
diff --git a/mirzaev/skillparts/system/web/js/profile_trusted.js b/mirzaev/skillparts/system/web/js/profile_trusted.js
index 24ed8fb..ee104c3 100644
--- a/mirzaev/skillparts/system/web/js/profile_trusted.js
+++ b/mirzaev/skillparts/system/web/js/profile_trusted.js
@@ -16,13 +16,22 @@ function page_profile_trusted_notification_create(form, html = 0) {
return page_profile_trusted_write(form);
}
-function page_profile_trusted_settings(form) {
+function page_profile_trusted_settings(form, panel) {
if (form == undefined) {
form = {
'_csrf': yii.getCsrfToken()
};
+
+ if (panel !== undefined) {
+ form.panel = panel;
+ }
} else {
form = $(form).serializeArray();
+
+ form.push({
+ name: "panel",
+ value: panel
+ });
}
return page_profile_trusted_write(form);