diff --git a/mirzaev/skillparts/system/assets/AppAsset.php b/mirzaev/skillparts/system/assets/AppAsset.php index c801b8d..55e1348 100644 --- a/mirzaev/skillparts/system/assets/AppAsset.php +++ b/mirzaev/skillparts/system/assets/AppAsset.php @@ -45,7 +45,11 @@ class AppAsset extends AssetBundle 'js/search.js', 'js/notification.js', 'js/reinitialization.js', - 'js/geolocation.js' + 'https://api-maps.yandex.ru/2.1/?apikey=0c4ba9aa-c448-4bd0-9c8c-6181f21ede90&lang=ru_RU', + 'js/yandex/metrika.js', + 'js/yandex/geolocation.js', + 'https://www.googletagmanager.com/gtag/js?id=G-6XYKBJJWR4', + 'js/google/analytics.js' ]; public $jsOptions = [ // 'position' => View::POS_HEAD diff --git a/mirzaev/skillparts/system/controllers/InvoiceController.php b/mirzaev/skillparts/system/controllers/InvoiceController.php index 876ef89..c17cb17 100644 --- a/mirzaev/skillparts/system/controllers/InvoiceController.php +++ b/mirzaev/skillparts/system/controllers/InvoiceController.php @@ -16,7 +16,7 @@ class InvoiceController extends Controller if ($order = Order::searchById(Order::collectionName() . '/' . $order)) { return $this->renderPartial('/invoice/order/pattern', [ - 'account' => yii::$app->user->identity->_key, + 'account' => yii::$app->user->identity, 'order' => [ 'id' => $order->_key, 'date' => $order->date ?? time() // @todo доделать diff --git a/mirzaev/skillparts/system/controllers/NotificationController.php b/mirzaev/skillparts/system/controllers/NotificationController.php index 55c3d67..7691316 100644 --- a/mirzaev/skillparts/system/controllers/NotificationController.php +++ b/mirzaev/skillparts/system/controllers/NotificationController.php @@ -184,7 +184,7 @@ class NotificationController extends Controller $notification = $notifications[0]; $return['popup'] = [ - 'html' => $this->renderPartial('popup', compact('model', 'notification')), + 'html' => $this->renderPartial('popup', compact('model', 'notification', 'account')), 'id' => 'popup/' . $notification->readId() ]; } else if (yii::$app->request->post('stream')) { diff --git a/mirzaev/skillparts/system/controllers/OrderController.php b/mirzaev/skillparts/system/controllers/OrderController.php index eefce7a..d03a1ed 100644 --- a/mirzaev/skillparts/system/controllers/OrderController.php +++ b/mirzaev/skillparts/system/controllers/OrderController.php @@ -24,6 +24,7 @@ use app\models\Supply; use app\models\SupplyEdgeProduct; use Codeception\PHPUnit\ResultPrinter\HTML; + use DateTime; use Exception; use Throwable; @@ -306,7 +307,7 @@ class OrderController extends Controller return [ 'main' => $this->renderPartial('/orders/index', compact('orders', 'moderator_orders', 'search', 'from', 'to', 'window') - + ['panel' => $this->renderPartial('/orders/search/panel', ['response' => $orders[0]['supplies']])]), + + ['panel' => $this->renderPartial('/orders/search/panel', compact('account') + ['response' => @$orders[0]['supplies']] ?? null)]), 'title' => 'Заказы', 'redirect' => '/orders', '_csrf' => yii::$app->request->getCsrfToken() @@ -489,14 +490,14 @@ class OrderController extends Controller yii::$app->response->format = Response::FORMAT_JSON; return [ - 'main' => $this->renderPartial('/cart/index', compact('order', 'connections')), + 'main' => $this->renderPartial('/cart/index', compact('order', 'connections', 'account')), 'title' => 'Корзина', 'redirect' => '/cart', '_csrf' => yii::$app->request->getCsrfToken() ]; } - return $this->render('/cart/index', compact('order', 'connections')); + return $this->render('/cart/index', compact('order', 'connections', 'account')); } /** @@ -507,7 +508,7 @@ 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; + $account = yii::$app->user->identity; $order = Order::search(); $connections = $order->content(10, $page); @@ -566,14 +567,14 @@ class OrderController extends Controller yii::$app->response->format = Response::FORMAT_JSON; return [ - 'main' => $this->renderPartial('/cart/index', compact('order', 'connections')), + 'main' => $this->renderPartial('/cart/index', compact('order', 'connections', 'account')), 'title' => 'Корзина', 'redirect' => '/cart', '_csrf' => yii::$app->request->getCsrfToken() ]; } - return $this->render('/cart/index', compact('order', 'connections')); + return $this->render('/cart/index', compact('order', 'connections', 'account')); } /** @@ -681,7 +682,7 @@ class OrderController extends Controller } - if ($order_edge_supply = OrderEdgeSupply::searchById($_id = OrderEdgeSupply::collectionName() . '/' . $_key)) { + if ($order_edge_supply = OrderEdgeSupply::searchById($_id = OrderEdgeSupply::collectionName() . '/' . $catn)) { // Удалось найти инстанцию поставки // Инициализация ребра: ПОСТАВКА -> ТОВАР diff --git a/mirzaev/skillparts/system/controllers/ProfileController.php b/mirzaev/skillparts/system/controllers/ProfileController.php index c9be47b..5ab3680 100644 --- a/mirzaev/skillparts/system/controllers/ProfileController.php +++ b/mirzaev/skillparts/system/controllers/ProfileController.php @@ -286,12 +286,38 @@ class ProfileController extends Controller /** * Страница мониторинга */ - public function actionMonitoring(): string|array + public function actionMonitoring(Account|int|null $account = null): string|array { // Инициализация $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel'); $sidebar = $this->renderPartial('sidebar'); + if (is_null($account)) { + // Данные аккаунта не переданы + + if (yii::$app->user->isGuest) { + // Аккаунт не аутентифицирован + + return []; + } else { + // Аккаунт аутентифицирован + + // Инициализация + $account = yii::$app->user->identity; + } + } else { + if (is_int($account)) { + // Передан идентификатор (_key) аккаунта (подразумевается) + + // Инициализация (поиск в базе данных) + if (!$account = Account::searchById(Account::collectionName() . "/$account")) { + // Не удалось инициализировать аккаунт + + return []; + } + } + } + // Инициализация номера страницы $page_search_history = (yii::$app->request->post('search') ?? yii::$app->request->get('search')) - 1; @@ -368,7 +394,8 @@ class ProfileController extends Controller 'sidebar', 'search_history', 'page_search_history', - 'panel' + 'panel', + 'account' )); } @@ -483,32 +510,6 @@ class ProfileController extends Controller // Настройка ответа yii::$app->response->format = Response::FORMAT_JSON; - // if (is_null($account)) { - // // Данные аккаунта не переданы - - // if (yii::$app->user->isGuest) { - // // Аккаунт не аутентифицирован - - // return false; - // } else { - // // Аккаунт аутентифицирован - - // // Инициализация - // $account = yii::$app->user->identity; - // } - // } else { - // if (is_int($account)) { - // // Передан идентификатор (_key) аккаунта (подразумевается) - - // // Инициализация (поиск в базе данных) - // if (!$account = Account::searchById(Account::collectionName() . "/$account")) { - // // Не удалось инициализировать аккаунт - - // return false; - // } - // } - // } - // Инициализация аккаунта if (yii::$app->user->isGuest) { // Аккаунт не аутентифицирован @@ -524,47 +525,32 @@ class ProfileController extends Controller // Настройка ответа yii::$app->response->format = Response::FORMAT_JSON; - // Инициализация IP-адреса - $ip = yii::$app->request->userIp === 'localhost' || yii::$app->request->userIp === '127.0.0.1' ? '46.226.227.20' : yii::$app->request->userIp; + if (false !== $return = self::geolocationCheck($account)) { + // Удалось сгенерировать данные для возврата - // Проверка записи геолокации - if (isset($account->geol)) { - // Удалось найти данные геолокации - } else { - // Не удалось найти данные геолокации - - try { - // Инициализация данных геолокации - $dadata = new Dadata(yii::$app->params['dadata']['key'], yii::$app->params['dadata']['secret']); - - // Запись в буфер данных о геолокации - $account->geol = $dadata->iplocate($ip); - } catch (Throwable $t) { - return false; - } - - // Запись в буфер данных о типе геолокации - $account->geol = ['type' => 'ip'] + ($account->geol ?? []); - - self::syncGeolocationWithDellin($account); + return $return; } - return self::geolocationAccuracyCheck($account); + return [ + 'geolocation' => false, + '_csrf' => yii::$app->request->getCsrfToken() + ]; } return false; } /** - * Генерация ответа по данным геолокации - * - * Проверка точности и наличия данных о геолокации + * Проверка наличия записи о геолокации * * @param Account|string|null $account * * @return array|bool JSON, в случае успеха + * + * @todo + * 1. 👁_👁 */ - public static function geolocationAccuracyCheck(Account|int|null $account = null): array|bool + public static function geolocationCheck(Account|int|null $account = null): array|bool { if (is_null($account)) { // Данные аккаунта не переданы @@ -597,15 +583,15 @@ class ProfileController extends Controller // Генерация ответа return [ - 'requestGps' => match ($account->geol['type'] ?? null) { - 'gps' => false, - default => true - }, + 'geolocation' => true, '_csrf' => yii::$app->request->getCsrfToken() ]; } - return false; + return [ + 'geolocation' => false, + '_csrf' => yii::$app->request->getCsrfToken() + ]; } /** @@ -614,6 +600,9 @@ class ProfileController extends Controller * @param string|null $account Аккаунт * * @return array|bool JSON, в случае успеха + * + * @todo + * 1. Избавиться от второго запроса к DaData ($dadata->clean("address", $account->city);) */ public function actionGeolocationWrite(): array|bool { @@ -623,36 +612,13 @@ class ProfileController extends Controller // Настройка ответа yii::$app->response->format = Response::FORMAT_JSON; - // if (is_null($account)) { - // // Данные аккаунта не переданы - - // if (yii::$app->user->isGuest) { - // // Аккаунт не аутентифицирован - - // return false; - // } else { - // // Аккаунт аутентифицирован - - // // Инициализация - // $account = yii::$app->user->identity; - // } - // } else { - // if (is_int($account)) { - // // Передан идентификатор (_key) аккаунта (подразумевается) - - // // Инициализация (поиск в базе данных) - // if (!$account = Account::searchById(Account::collectionName() . "/$account")) { - // // Не удалось инициализировать аккаунт - - // return false; - // } - // } - // } - // Инициализация аккаунта if (yii::$app->user->isGuest) { // Аккаунт не аутентифицирован + // Запись кода ответа + yii::$app->response->statusCode = 401; + return false; } else { // Аккаунт аутентифицирован @@ -664,15 +630,21 @@ class ProfileController extends Controller // Настройка ответа yii::$app->response->format = Response::FORMAT_JSON; - // Инициализация широты - $latitude = yii::$app->request->post('latitude') ?? yii::$app->request->get('latitude'); + // Инициализация данных яндекса + $yandex = yii::$app->request->post('yandex') ?? yii::$app->request->get('yandex'); - // Инициализация долготы - $longitude = yii::$app->request->post('longitude') ?? yii::$app->request->get('longitude'); + // Инициализация широты (среднее значение из общего периметра) + $latitude = ($yandex['coordinates'][0][0] + $yandex['coordinates'][1][0]) / 2; + + // Инициализация долготы (среднее значение из общего периметра) + $longitude = ($yandex['coordinates'][0][1] + $yandex['coordinates'][1][1]) / 2; if (empty($latitude) || empty($longitude)) { // Широта или долгота не передана + // Запись кода ответа + yii::$app->response->statusCode = 500; + return false; } @@ -682,13 +654,31 @@ class ProfileController extends Controller // Запись в буфер данных о геолокации $account->geol = $dadata->geolocate("address", $latitude, $longitude)[0]; + + // Запись в буфер полученного города + $account->city = $account->geol['data']['city']; + + // Запись в буфер новых данных (непонятно почему, но только вторым запросом можно получать часовую зону) + $account->geol = $account->geol + $dadata->clean("address", $account->city); + + // Запись в буфер часовой зоны + $account->zone = $account->geol['data']['timezone']; + + if($account->update() < 1) { + // Не удалось записать данные + + // Запись кода ответа + yii::$app->response->statusCode = 500; + + return false; + }; } catch (Throwable $t) { + // Запись кода ответа + yii::$app->response->statusCode = 500; + return false; } - // Запись в буфер данных о типе геолокации - $account->geol = ['type' => 'gps'] + $account->geol; - return self::syncGeolocationWithDellin($account); } } diff --git a/mirzaev/skillparts/system/controllers/SearchController.php b/mirzaev/skillparts/system/controllers/SearchController.php index 89edb26..c23dde9 100644 --- a/mirzaev/skillparts/system/controllers/SearchController.php +++ b/mirzaev/skillparts/system/controllers/SearchController.php @@ -26,6 +26,7 @@ class SearchController extends Controller { // Инициализация параметров $auth_only = false; + $account = yii::$app->user->identity; if ($auth_only && yii::$app->user->isGuest) { // Если активирован режим "Поиск только аутентифицированным" и запрос пришел не от аутентифицированного @@ -49,7 +50,7 @@ class SearchController extends Controller yii::$app->response->format = Response::FORMAT_JSON; return [ - 'panel' => $this->renderPartial('/search/panel', ['history' => true]), + 'panel' => $this->renderPartial('/search/panel', compact('account') + ['history' => true]), '_csrf' => yii::$app->request->getCsrfToken() ]; } diff --git a/mirzaev/skillparts/system/controllers/VerifyController.php b/mirzaev/skillparts/system/controllers/VerifyController.php index c42370c..9d2ee99 100644 --- a/mirzaev/skillparts/system/controllers/VerifyController.php +++ b/mirzaev/skillparts/system/controllers/VerifyController.php @@ -6,9 +6,10 @@ namespace app\controllers; use yii; use yii\web\Controller; -use app\models\Account; use yii\web\Response; +use app\models\Account; + class VerifyController extends Controller { public function actionIndex(string $vrfy = null): string|Response @@ -36,6 +37,9 @@ class VerifyController extends Controller if (yii::$app->user->identity->vrfy === true) { // Регистрация аккаунта уже подтверждена + // Генерация хеша пароля + yii::$app->user->identity->pswd = yii::$app->security->generatePasswordHash(yii::$app->user->identity->pswd); + if (yii::$app->request->isPost) { // POST-запрос diff --git a/mirzaev/skillparts/system/models/Account.php b/mirzaev/skillparts/system/models/Account.php index 5b31838..a8e6ad5 100644 --- a/mirzaev/skillparts/system/models/Account.php +++ b/mirzaev/skillparts/system/models/Account.php @@ -44,6 +44,7 @@ class Account extends Document implements IdentityInterface, PartnerInterface 'name', 'simc', 'sity', + 'zone', 'comp', 'taxn', 'onec', @@ -72,6 +73,7 @@ class Account extends Document implements IdentityInterface, PartnerInterface 'name' => 'Имя', 'simc' => 'Номер', 'sity' => 'Город', + 'zone' => 'Часовой пояс', 'comp' => 'Компания', 'taxn' => 'ИНН', 'onec' => 'Данные 1C', @@ -116,7 +118,10 @@ class Account extends Document implements IdentityInterface, PartnerInterface 'message' => 'Атрибут {attribute} должен иметь уникальное значение' ], [ - 'indx', + [ + 'indx', + 'zone' + ], 'string' ], [ @@ -287,11 +292,18 @@ class Account extends Document implements IdentityInterface, PartnerInterface } /** - * Проверка пароля + * Проверка пароля с хешированием */ - public function validatePassword(string $pswd): bool + public function validatePasswordWithHash(string $pswd): bool + { + return yii::$app->security->validatePassword($pswd, $this->pswd); + } + + /** + * Проверка пароля без хеширования + */ + public function validatePasswordWithoutHash(string $pswd): bool { - // return yii::$app->security->validatePassword($pswd, $this->pswd); return $pswd === $this->pswd; } @@ -487,7 +499,7 @@ class Account extends Document implements IdentityInterface, PartnerInterface // Запись empty($terminal->city) && empty($terminal->strt) && empty($terminal->hous) - or $list[$terminal->dell] = (empty($terminal->city) ? '' : "г. $terminal->city"). (empty($terminal->strt) ? '' : ", ул. $terminal->strt") . (empty($terminal->hous) ? '' : ", д. $terminal->hous") . (empty($terminal->offs) ? '' : ", оф. $terminal->offs") . (empty($terminal->comm) ? '' : " ($terminal->comm)"); + or $list[$terminal->dell] = (empty($terminal->city) ? '' : "г. $terminal->city") . (empty($terminal->strt) ? '' : ", ул. $terminal->strt") . (empty($terminal->hous) ? '' : ", д. $terminal->hous") . (empty($terminal->offs) ? '' : ", оф. $terminal->offs") . (empty($terminal->comm) ? '' : " ($terminal->comm)"); } return $this->syncListWithSettings($list, 'delivery_to_terminal'); diff --git a/mirzaev/skillparts/system/models/AccountForm.php b/mirzaev/skillparts/system/models/AccountForm.php index 689997d..c2e0c26 100644 --- a/mirzaev/skillparts/system/models/AccountForm.php +++ b/mirzaev/skillparts/system/models/AccountForm.php @@ -8,6 +8,7 @@ use yii; use yii\base\Model; use app\models\Account; +use Exception; /** * AccountForm is the model behind the login form. @@ -146,10 +147,24 @@ class AccountForm extends Model return; } - if (!$account || !$account->validatePassword($this->pswd)) { - // Проверка не пройдена + if ($account) { + // Удалось инициализировать аккаунт - $this->addError($attribute, 'Проверьте пароль'); + try { + $account->validatePasswordWithHash($this->pswd); + } catch (Exception $e) { + // Проверка с хешем не пройдена + + try { + $account->validatePasswordWithoutHash($this->pswd); + } catch (Exception $e) { + // Проверка без хеша не пройдена + + $this->addError($attribute, 'Проверьте пароль'); + } + } + } else { + $this->addError($attribute, 'Не удалось идентифицировать аккаунт'); } } } diff --git a/mirzaev/skillparts/system/models/Notification.php b/mirzaev/skillparts/system/models/Notification.php index da6b5f5..37fdc05 100644 --- a/mirzaev/skillparts/system/models/Notification.php +++ b/mirzaev/skillparts/system/models/Notification.php @@ -168,7 +168,7 @@ class Notification extends Document $text = htmlspecialchars(strip_tags($text ?? null)); $model->html = <<$text

+

$text

HTML; } @@ -281,4 +281,19 @@ class Notification extends Document return $return ? $return : null; } + + /** + * Конвертация типа уведомления в версию для отображения + * + * @param string|null $type Тип уведомления + * + * @return string + */ + public function genTypeToRussian(string $type = null): string { + return match($type ?? $this->type) { + 'notice' => 'Уведомление', + 'warning' => 'Предупреждение', + 'error' => 'Ошибка' + }; + } } diff --git a/mirzaev/skillparts/system/models/Product.php b/mirzaev/skillparts/system/models/Product.php index 55912ba..9b4f335 100644 --- a/mirzaev/skillparts/system/models/Product.php +++ b/mirzaev/skillparts/system/models/Product.php @@ -7,10 +7,14 @@ namespace app\models; use yii; use yii\web\UploadedFile; use yii\imagine\Image; +use app\models\Settings; use app\models\traits\SearchByEdge; use moonland\phpexcel\Excel; +use DateTime; +use DateTimeZone; + use Exception; /** @@ -318,18 +322,45 @@ class Product extends Document * На данный момент обрабатывает только импорт из * файлов с расширением .excel */ - public function importExcel(): bool + public function importExcel(Account|int|null $account = null): bool { // Инициализация $data = []; $amount = 0; + if (is_null($account)) { + // Данные аккаунта не переданы + + if (yii::$app->user->isGuest) { + // Аккаунт не аутентифицирован + + return false; + } else { + // Аккаунт аутентифицирован + + // Инициализация + $account = yii::$app->user->identity; + } + } else { + if (is_int($account)) { + // Передан идентификатор (_key) аккаунта (подразумевается) + + // Инициализация (поиск в базе данных) + if (!$account = Account::searchById(Account::collectionName() . "/$account")) { + // Не удалось инициализировать аккаунт + + return false; + } + } + } + + if ($this->validate()) { foreach ($this->file_excel as $file) { // Перебор файлов // Инициализация - $dir = YII_PATH_PUBLIC . '../assets/import/' . date('Y-m-d', time()) . '/excel/' . (yii::$app->user->identity->_key ?? 'system') . '/' . time() . '/'; + $dir = YII_PATH_PUBLIC . '../assets/import/' . (new DateTime('now', new DateTimeZone($account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3'))) . '/excel/' . (yii::$app->user->identity->_key ?? 'system') . '/' . time() . '/'; // Сохранение на диск if (!file_exists($dir)) { @@ -467,9 +498,16 @@ class Product extends Document */ public static function afterImportExcel(int $amount = 0): bool { - // Инициализация + // Инициализация параметров $model = new Notification; - $date = date('H:i d.m.Y', time()); + $account = yii::$app->user->identity; + + // Инициализация часового пояса + preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone); + $timezone = $timezone[1][0]; + + // Инициализация даты + $date = (new DateTime('now', new DateTimeZone($timezone)))->format('H:i d.m.Y'); // Настройка $model->text = yii::$app->controller->renderPartial('@app/views/notification/system/afterImportExcel', compact('amount', 'date')); @@ -482,11 +520,42 @@ class Product extends Document /** * Вызывается после загрузки поставок из 1С */ - public static function afterImport1c(): bool + public static function afterImport1c(Account|int|null $account = null): bool { // Инициализация $model = new Notification; - $date = date('H:i d.m.Y', time()); + + if (is_null($account)) { + // Данные аккаунта не переданы + + if (yii::$app->user->isGuest) { + // Аккаунт не аутентифицирован + + return false; + } else { + // Аккаунт аутентифицирован + + // Инициализация + $account = yii::$app->user->identity; + } + } else { + if (is_int($account)) { + // Передан идентификатор (_key) аккаунта (подразумевается) + + // Инициализация (поиск в базе данных) + if (!$account = Account::searchById(Account::collectionName() . "/$account")) { + // Не удалось инициализировать аккаунт + + return false; + } + } + } + + // Инициализация часового пояса + preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone); + $timezone = $timezone[1][0]; + + $date = (new DateTime('now', new DateTimeZone($timezone)))->format('H:i d.m.Y'); // Настройка $model->text = yii::$app->controller->renderPartial('@app/views/notification/system/afterImport1c', compact('date')); diff --git a/mirzaev/skillparts/system/models/connection/Dellin.php b/mirzaev/skillparts/system/models/connection/Dellin.php index efacab5..56f601f 100644 --- a/mirzaev/skillparts/system/models/connection/Dellin.php +++ b/mirzaev/skillparts/system/models/connection/Dellin.php @@ -9,10 +9,14 @@ use yii\base\Model; use app\models\Dellin as DellinModel; use app\models\Product; +use app\models\Account; use app\models\Settings; + use GuzzleHttp\Client as Guzzle; use GuzzleHttp\Exception\ClientException as GuzzleException; +use DateTime; +use DateTimeZone; use Exception; class Dellin extends Model @@ -68,18 +72,44 @@ class Dellin extends Model * @param int $y Высота (cм) * @param int $z Длинна (cм) * @param int $amount Количество + * @param Account|int|null $account Аккаунт * * @return string * * @todo Загружать помимо терминалов ещё и адреса, чтобы доделать доставку малогабаритных грузов * Разрабраться с параметрами 0,54м * 0,39м * 0,39м (0.082134м) и 0.1 куб метр в чем разница */ - public static function calcDeliveryAdvanced(int $from, int $to, int $weight, int $x, int $y, int $z, int $amount = 1, bool $avia = false): array + public static function calcDeliveryAdvanced(int $from, int $to, int $weight, int $x, int $y, int $z, int $amount = 1, bool $avia = false, Account|int|null $account = null): array { - - return self::handle(function () use ($from, $to, $weight, $x, $y, $z, $amount, $avia) { + return self::handle(function () use ($from, $to, $weight, $x, $y, $z, $amount, $avia, $account) { // Всё готово к работе + if (is_null($account)) { + // Данные аккаунта не переданы + + if (yii::$app->user->isGuest) { + // Аккаунт не аутентифицирован + + return []; + } else { + // Аккаунт аутентифицирован + + // Инициализация + $account = yii::$app->user->identity; + } + } else { + if (is_int($account)) { + // Передан идентификатор (_key) аккаунта (подразумевается) + + // Инициализация (поиск в базе данных) + if (!$account = Account::searchById(Account::collectionName() . "/$account")) { + // Не удалось инициализировать аккаунт + + return []; + } + } + } + // Инициализация $from = DellinModel::searchByTerminalId($from, terminal_data_only: true); $to = DellinModel::searchByTerminalId($to, terminal_data_only: true); @@ -126,7 +156,8 @@ class Dellin extends Model $query = []; // Рассчёт типа доставки - if ( !$avia + if ( + !$avia && $weight <= 30 && ($length <= 0.54 && $width <= 0.39 && $height <= 0.39) && $length * $width * $height <= 0.1 @@ -164,6 +195,10 @@ class Dellin extends Model $query['delivery']['arrival']['terminalID'] = $to->id; } + // Инициализация часового пояса + preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone); + $timezone = $timezone[1][0]; + // Инициализация $query = array_merge_recursive( $query, @@ -172,8 +207,7 @@ class Dellin extends Model 'sessionID' => self::$session, 'delivery' => [ 'derival' => [ - // 'produceDate' => date('Y-m-d', time() + ($settings['delivery_handle_time'] ?? 86400)) - 'produceDate' => date('Y-m-d', time() + 86400 * 3) + 'produceDate' => (new DateTime())->setTimestamp(time())->setTimezone(new DateTimeZone($timezone))->format('Y-m-d') ] ], 'members' => [ @@ -273,146 +307,42 @@ class Dellin extends Model }); } - /** - * Импорт городов - * - * @return array|null Сохранённые города - */ - // public static function importCities(): ?int - // { - // return self::handle(function () { - // // Всё готово к работе - - // // Запрос ссылки на файл с городами, возвращает ['hash' => string, 'url' => string] - // $request = self::$browser->post('/v1/public/cities.json', [ - // 'json' => [ - // 'appkey' => yii::$app->params['dellin']['key'], - // ] - // ]); - - // if ($request->getStatusCode() === 200) { - // // Запрос прошел успешно - - // // Инициализация - // $response = json_decode((string) $request->getBody(), true); - // $hash_target = $response['hash']; - // $dir = YII_PATH_PUBLIC . '/../assets/import/' . date('Y-m-d', time()) . '/dellin/cities/' . (yii::$app->user->identity->_key ?? 'system') . '/'; - - // if (!file_exists($dir)) { - // // Директории не существует - - // mkdir($dir, 0775, true); - // } - - // $request = self::$browser->get($response['url'], [ - // 'sink' => $file = $dir . time() . '.csv' - // ]); - - // // Проверка хеша (оказалось это хеш запроса, бесполезный) - // // if ($hash_target === $hash_received = md5_file($file)) { - // // Удалось пройти проверку на хеши файлов - - // // Инициализация (чтение файла) - // $file = fopen($file, "r"); - // $first_raw_block = true; - - // while ($row = fgets($file, 4096)) { - // // Перебор строк - - // if ($first_raw_block) { - // // Сработала защита от чтения первой строки файла (указываются названия колонок) - - // // Отключение - // $first_raw_block = false; - - // // Пропуск цикла - // continue; - // } - - // // Инициализация - // $data = explode(',', $row, 4); - // $amount = 0; - - // // Очистка - // array_walk($data, fn (&$value) => $value = trim($value, '"')); - - // if ($city = City::searchByDellinId($data[0])) { - // // Удалось найти город в базе данных - - // $after_import_log = function () use ($city): void { - // // Запись в журнал - // $city->journal('update'); - - // if (yii::$app->getRequest()->isConsoleRequest) { - // // Вызов из терминала - - // echo 'Удалось перезаписать город: ' . $city->name . PHP_EOL; - // } - // }; - // } else { - // // Не удалось найти город в базе данных - - // $city = new City(); - - // $after_import_log = function () use ($city): void { - // if (yii::$app->getRequest()->isConsoleRequest) { - // // Вызов из терминала - - // echo 'Удалось записать город: ' . $city->name . PHP_EOL; - // } - // }; - // } - - // // Запись - // $city->indx = $data[0]; - // $city->name = $data[1]; - // $city->code = $data[2]; - // $city->term = (bool) $data[3]; - - // // Отправка в базу данных - // if ($city->save()) { - // // Удалось сохранить в базе данных - - // // Запись в журнал - // $after_import_log(); - - // // Постинкрементация счётчика - // $amount++; - - // continue; - // } else { - // // Не удалось сохранить в базе данных - - // throw new Exception('Не удалось сохранить город ' . $data[1] . ' в базу данных', 500); - // } - // } - - // // Деинициализация - // fclose($file); - - // return $amount; - // // } else { - // // // Не удалось пройти проверку на соответствие хешей файлов - - // // throw new Exception('Хеши файлов не совпадают. Должен быть: "' . $hash_target . '", получен: "' . $hash_received . '"', 500); - // // } - // } - - // throw new Exception('Не удалось синхронизировать данные городов с ДеловыеЛинии', 500); - // }); - // } - - /** * Импорт терминалов * * @return array|null Сохранённые терминалы */ - public static function importTerminals(): ?int + public static function importTerminals(Account|int|null $account = null): ?int { - return self::handle(function () { + return self::handle(function () use ($account) { // Всё готово к работе + if (is_null($account)) { + // Данные аккаунта не переданы + + if (yii::$app->user->isGuest) { + // Аккаунт не аутентифицирован + + return 0; + } else { + // Аккаунт аутентифицирован + + // Инициализация + $account = yii::$app->user->identity; + } + } else { + if (is_int($account)) { + // Передан идентификатор (_key) аккаунта (подразумевается) + + // Инициализация (поиск в базе данных) + if (!$account = Account::searchById(Account::collectionName() . "/$account")) { + // Не удалось инициализировать аккаунт + + return 0; + } + } + } + // Запрос ссылки на файл с городами, возвращает ['hash' => string, 'url' => string] $request = self::$browser->post('/v3/public/terminals.json', [ 'json' => [ @@ -423,9 +353,13 @@ class Dellin extends Model if ($request->getStatusCode() === 200) { // Запрос прошел успешно - // Инициализация + // Инициализация часового пояса + preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone); + $timezone = $timezone[1][0]; + + // Инициализация параметров $response = json_decode((string) $request->getBody(), true); - $dir = YII_PATH_PUBLIC . '/../assets/import/' . date('Y-m-d', time()) . '/dellin/terminals/' . (yii::$app->user->identity->_key ?? 'system') . '/'; + $dir = YII_PATH_PUBLIC . '/../assets/import/' . (new DateTime('now', new DateTimeZone($timezone)))->format('Y-m-d') . '/dellin/terminals/' . (yii::$app->user->identity->_key ?? 'system') . '/'; $amount = 0; if (!file_exists($dir)) { diff --git a/mirzaev/skillparts/system/views/invoice/order/pattern.php b/mirzaev/skillparts/system/views/invoice/order/pattern.php index 9a8dea0..15fce92 100644 --- a/mirzaev/skillparts/system/views/invoice/order/pattern.php +++ b/mirzaev/skillparts/system/views/invoice/order/pattern.php @@ -1,3 +1,8 @@ + @@ -78,7 +83,13 @@ - Счет на оплату № от + zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone); + $timezone = $timezone[1][0]; + ?> + Счет на оплату № от setTimestamp($order['date'])->setTimezone(new DateTimeZone($timezone))->format('d.m.Y') ?> @@ -144,7 +155,10 @@ - + + + + @@ -182,7 +196,7 @@ - + diff --git a/mirzaev/skillparts/system/views/layouts/main.php b/mirzaev/skillparts/system/views/layouts/main.php index e0430ed..1579cdf 100644 --- a/mirzaev/skillparts/system/views/layouts/main.php +++ b/mirzaev/skillparts/system/views/layouts/main.php @@ -20,23 +20,8 @@ AppAsset::register($this); - - - - - - - - - - - - - - - - - + + registerCsrfMetaTags() ?> <?= Html::encode($this->title ?? 'SkillParts') ?> @@ -46,7 +31,7 @@ AppAsset::register($this); beginBody() ?> -
+
diff --git a/mirzaev/skillparts/system/views/notification/index.php b/mirzaev/skillparts/system/views/notification/index.php deleted file mode 100644 index e69de29..0000000 diff --git a/mirzaev/skillparts/system/views/notification/popup.php b/mirzaev/skillparts/system/views/notification/popup.php index 9e87485..f711ab5 100644 --- a/mirzaev/skillparts/system/views/notification/popup.php +++ b/mirzaev/skillparts/system/views/notification/popup.php @@ -1,10 +1,34 @@ readId(); - $html = $notification->html; - echo << - $html -
- HTML; -?> \ No newline at end of file +use app\models\Settings; + +// Инициализация данных для генерации HTML +$id = 'popup/' . $notification->readId(); +$html = $notification->html; +$type = $notification->genTypeToRussian(); +$date = null; + +// Поиск даты создания +foreach ($notification->jrnl as $jrnl) { + if ($jrnl['action'] === 'create') { + // Найдена дата создания + + // Инициализация часового пояса + preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone); + $timezone = $timezone[1][0]; + + // Инициализация данных для генерации HTML + $date = (new DateTime())->setTimestamp($jrnl['date'])->setTimezone(new DateTimeZone($timezone))->format('H:i d.m.Y'); + } +} + +$title = <<$type$date +HTML; + +echo << + $title + $html + +HTML; diff --git a/mirzaev/skillparts/system/views/notification/system/orders/new.php b/mirzaev/skillparts/system/views/notification/system/orders/new.php index 86b9443..c2ff066 100644 --- a/mirzaev/skillparts/system/views/notification/system/orders/new.php +++ b/mirzaev/skillparts/system/views/notification/system/orders/new.php @@ -1 +1,3 @@ -Новый заказ +
+

Новый заказ: #

+
diff --git a/mirzaev/skillparts/system/views/orders/index.php b/mirzaev/skillparts/system/views/orders/index.php index da7dfa2..d1aab30 100644 --- a/mirzaev/skillparts/system/views/orders/index.php +++ b/mirzaev/skillparts/system/views/orders/index.php @@ -8,6 +8,9 @@ use yii\bootstrap\ActiveForm; use app\models\AccountEdgeOrder; use app\models\Order; use app\models\OrderEdgeSupply; +use app\models\Settings; + +use moonland\phpexcel\Excel; // Инициализация открытой панели if (empty($window)) { @@ -54,21 +57,27 @@ if (empty($window)) { $date = null; foreach ($order['order']['jrnl'] as $entry) { - // Перебор записей в журнал + // Перебор записей в журнале if ($entry['action'] === 'requested') { + // Найдена запись со временем запроса заказа + if (empty($date) || $date <= $entry['date']) { // Буфер не инициализирован или в него записано более старое событие - // Запись + // Запись в буфер $date = $entry['date']; } } } + preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone); + $timezone = $timezone[1][0]; + + // Конвертация данных из буфера $date = [ - 'H:i' => date('H:i', $date), - 'm.d.Y' => date('m.d.Y', $date) + 'H:i' => (new DateTime())->setTimestamp($date)->setTimezone(new DateTimeZone($timezone))->format('H:i'), + 'm.d.Y' => (new DateTime())->setTimestamp($date)->setTimezone(new DateTimeZone($timezone))->format('m.d.Y') ]; ?> @@ -87,8 +96,13 @@ if (empty($window)) { $count = 1; ?> - + + + if ($amount['auto'] > 0) { + // Найдены поставки с автоматической доставкой - - -

- - - -

-
+ if (Order::checkSuppliesStts($order_edge_supply)) { + $status = ''; + } else { + $status = ''; + } + + // Генерация HTML + echo << + +

+ {$product['catn']} x{$amount['auto']} + + $status +

+ + HTML; + } + + if ($amount['avia'] > 0) { + // Найдены поставки с автоматической доставкой + + if (Order::checkSuppliesStts($order_edge_supply)) { + $status = ''; + } else { + $status = ''; + } + + // Генерация HTML + echo << + +

+ {$product['catn']} x{$amount['avia']} + + $status +

+ + HTML; + } + + ?> @@ -242,13 +289,27 @@ if (empty($window)) { // Пропуск активного заказа (несформированного, корзины) if ($account_edge_order[0]['type'] === 'current') continue; - // Деинициализация мусора - unset($date); - // Инициализация времени подтверждения заказа - if (isset($order['jrnl'])) foreach ($order['jrnl'] as $entry) { - if ($entry['action'] === 'accepted') $date = date('H:i d.m.Y', $entry['date']); + if (isset($order['jrnl'])) { + // Журнал найден + + foreach ($order['jrnl'] as $entry) { + // Перебор записей в журнале + + if ($entry['action'] === 'accepted') { + // Найден принятый заказ + + // Инициализация часового пояса + preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone); + $timezone = $timezone[1][0]; + + // Запись данных о дате заказа + $date = (new DateTime())->setTimestamp($entry['date'])->setTimezone(new DateTimeZone($timezone))->format('H:i d.m.Y'); + } + } } + + // Инициализация значения по умолчанию $date ?? $date = 'Ожидается'; // Инициализация буфера поставок @@ -260,99 +321,158 @@ if (empty($window)) { if (isset($supplies)) { // Найдены поставки + // Инициализация максимального срока доставки + $delivery_max = 0; + // Инициализация поставок foreach ($supplies as $supply) { // Перебор поставок - // Инициализация окружения + // Инициализация переменных extract($supply); - // Инициализация связи поставки с заказом (подразумевается, что все одинаковые по основным параметрам) - $part = $order_edge_supply[0]; + // Инициализация цены + $price_raw = $cost; - // Инициализация доставки - if (isset($delivery['error'])) { - // Не удалось рассчитать доставку + // Инициализация комментария + $comment = $order_edge_supply['comm'] ?? 'Комментарий к заказу'; - // Инициализация индикатора - $date_icon = ''; + if ($amount['auto'] > 0) { + // Найдены поставки с автоматической доставкой + + // Инициализация цены + $price_auto = $price_raw['auto'] . ' ' . $currency; // Инициализация доставки - if (isset($part['date'])) { - // Найдены данные в инстанции поставки + if (!isset($delivery) || (isset($delivery['auto'], $delivery['auto']['error']) || $delivery === '?')) { + // Не удалось рассчитать доставку - // Запись в буфер вывода - // $time = $part['time'] . ' дн'; - $date = date('d.m.Y', $part['date']); - $date_html = "$date"; + // Инициализация времени + $delivery_auto = '?'; } else { - $date = 'Неизвестно'; - $date_html = "$date"; + // Удалось рассчитать доставку + + // Инициализация даты отправки + try { + // Взять данные из "arrivalToOspSender" (Дата прибытия на терминал-отправитель) + + $delivery_auto_send_date = DateTime::createFromFormat('Y-m-d', $delivery['auto']['orderDates']['arrivalToOspSender'])->getTimestamp(); + } catch (Throwable $e) { + // Взять данные из "pickup" (Дата передачи груза на адресе отправителя) + + $delivery_auto_send_date = DateTime::createFromFormat('Y-m-d', $delivery['auto']['orderDates']['pickup'])->getTimestamp(); + } + + // Инициализация времени доставки + try { + // Доставка по воздуху (подразумевается), данные из "giveoutFromOspReceiver" (Дата и время, с которого груз готов к выдаче на терминале) + + // Оставлено на всякий случай для дальнейших разбирательств + + $delivery_auto_converted = DateTime::createFromFormat('Y-m-d H:i:s', $delivery['auto']['orderDates']['giveoutFromOspReceiver'])->getTimestamp(); + } catch (Throwable $e) { + // Автоматическая доставка (подразумевается), данные из "arrivalToOspReceiver" (Дата прибытия натерминал-получатель) + + $delivery_auto_converted = DateTime::createFromFormat('Y-m-d', $delivery['auto']['orderDates']['arrivalToOspReceiver'])->getTimestamp(); + } + $delivery_auto = ceil(($delivery_auto_converted - ($delivery_auto_send_date ?? 0)) / 60 / 60 / 24) + 1; } - // Инициализация стоимости - if (isset($part['cost'])) $cost_html = '' . ($cost = $part['cost']) . ' ' . $currency . ''; - else $cost_html = '' . ($cost = 'Неизвестно') . ''; - } else { - // Удалось рассчитать доставку + // Инициализация статуса связи поставки + $status = OrderEdgeSupply::convertStatusToRussian($part['stts'] ?? ''); - // Инициализация типа доставки - $time_type = $part['dlvr']['type'] ?? 'auto'; - - // Инициализация индикатора - $date_icon = match ($time_type) { - 'avia' => '', - default => '' + // Инициализация класса для поставки (если необходимо) + $css = match ($part['stts'] ?? '') { + 'accepted' => ' supply_accepted', + default => '' }; - // Инициализация доставки - if (isset($part['date'])) { - // Найдены данные в инстанции поставки + // Реинициализация максимальной даты доставки + if ($delivery_max !== '?' && $delivery_max < $delivery_auto) $delivery_max = $delivery_auto; + else if ($delivery_auto === '?') $delivery_max = '?'; - // Запись в буфер вывода - // $time = $part['time'] . ' дн'; - $date = date('d.m.Y', $part['date']); - $date_html = "$date"; - } else { - // Рассчет времени из данных поставки - - try { - $time_converted = DateTime::createFromFormat('Y-m-d H:i:s', $delivery['auto']['orderDates']['giveoutFromOspReceiver'])->getTimestamp(); - } catch (Exception $e) { - $time_converted = DateTime::createFromFormat('Y-m-d', $delivery['auto']['orderDates']['arrivalToOspReceiver'])->getTimestamp(); - } - // $time = (ceil(($time_converted - time()) / 60 / 60 / 24) + 1) . ' дн'; - $date = date('d.m.Y', $time_converted); - $date_html = "$date"; - } - - // Инициализация стоимости - if (isset($part['cost'])) $cost_html = '' . ($cost = $part['cost']) . ' ' . $currency . ''; - else $cost_html = '' . ($cost = $cost['auto']) . ' ' . $currency . ''; + // Генерация HTML + // Пробела между supply и $css не должно быть + $supplies_html .= << +
{$supply['catn']}
+ $status +
$delivery_auto
+
{$amount['auto']}
+
$price_auto
+ + HTML; } - // Инициализация статуса связи поставки - $status = OrderEdgeSupply::convertStatusToRussian($part['stts'] ?? ''); + if ($amount['avia'] > 0) { + // Найдены поставки с доставкой по воздуху - // Инициализация класса для поставки (если необходимо) - $css = match ($part['stts'] ?? '') { - 'accepted' => ' supply_accepted', - default => '' - }; + // Инициализация цены + $price_avia = $price_raw['avia'] . ' ' . $currency; - // Пробела между supply и $css не должно быть - $supplies_html .= <<getTimestamp(); + } catch (Throwable $e) { + // Взять данные из "pickup" (Дата передачи груза на адресе отправителя) + + $delivery_avia_send_date = DateTime::createFromFormat('Y-m-d', $delivery['avia']['orderDates']['pickup'])->getTimestamp(); + } + + // Инициализация времени доставки + try { + // Доставка по воздуху (подразумевается), данные из "giveoutFromOspReceiver" (Дата и время, с которого груз готов к выдаче на терминале) + + $delivery_avia_converted = DateTime::createFromFormat('Y-m-d H:i:s', $delivery['avia']['orderDates']['giveoutFromOspReceiver'])->getTimestamp(); + } catch (Throwable $e) { + // Автоматическая доставка (подразумевается), данные из "arrivalToOspReceiver" (Дата прибытия натерминал-получатель) + + // Оставлено на всякий случай для дальнейших разбирательств + + $delivery_avia_converted = DateTime::createFromFormat('Y-m-d', $delivery['avia']['orderDates']['arrivalToOspReceiver'])->getTimestamp(); + } + $delivery_avia = ceil(($delivery_avia_converted - ($delivery_avia_send_date ?? 0)) / 60 / 60 / 24) + 1; + } + + // Инициализация статуса связи поставки + $status = OrderEdgeSupply::convertStatusToRussian($part['stts'] ?? ''); + + // Инициализация класса для поставки (если необходимо) + $css = match ($part['stts'] ?? '') { + 'accepted' => ' supply_accepted', + default => '' + }; + + // Реинициализация максимальной даты доставки + if ($delivery_max !== '?' && $delivery_max < $delivery_avia) $delivery_max = $delivery_avia; + else if ($delivery_avia === '?') $delivery_max = '?'; + + // Генерация HTML + // Пробела между supply и $css не должно быть + $supplies_html .= << -
{$supply['catn']}
-
$status
-
$date_html
-
{$amount['auto']}
-
$cost_html
+
{$supply['catn']}
+ $status +
$delivery_avia
+
{$amount['avia']}
+
$price_avia
HTML; + } - // Обновление общего счётчика цены - $sum += (int) $cost; + // Инициализация общей цены + $sum = $price_raw['avia'] * $amount['avia'] + $price_raw['auto'] * $amount['auto']; } } @@ -369,7 +489,7 @@ if (empty($window)) {
$invoice
$status
-
$date
+
$delivery_max
$sum руб
@@ -395,6 +515,11 @@ if (empty($window)) { // Инициализация индикатора готовности календаря orders_calendar_ready = false; + zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone); + $timezone = $timezone[1][0]; + ?> + if (document.readyState === "complete") { // Документ загружен @@ -409,7 +534,7 @@ if (empty($window)) { onSelect: orders_calendar_select }); - $('#orders_period_calendar').data('datepicker').selectDate([new Date(''), new Date('')]); + $('#orders_period_calendar').data('datepicker').selectDate([new Date('setTimestamp(time() - 604800)->setTimezone(new DateTimeZone($timezone))->format('Y-m-d') ?>'), new Date('format('Y-m-d') ?>')]); // Активация календаря orders_calendar_ready = true; @@ -431,7 +556,7 @@ if (empty($window)) { onSelect: orders_calendar_select }); - $('#orders_period_calendar').data('datepicker').selectDate([new Date(''), new Date('')]); + $('#orders_period_calendar').data('datepicker').selectDate([new Date('setTimestamp(time() - 604800)->setTimezone(new DateTimeZone($timezone))->format('Y-m-d') ?>'), new Date('format('Y-m-d') ?>')]); // Активация календаря orders_calendar_ready = true; diff --git a/mirzaev/skillparts/system/views/orders/search/panel.php b/mirzaev/skillparts/system/views/orders/search/panel.php index 286c16d..dc0bc2e 100644 --- a/mirzaev/skillparts/system/views/orders/search/panel.php +++ b/mirzaev/skillparts/system/views/orders/search/panel.php @@ -3,18 +3,13 @@ declare(strict_types=1); use app\models\Search; +use app\models\Settings; if (isset($history) && $history) { // Отображение истории if (yii::$app->user->isGuest) { // Не аутентифицирован - - // В будущем выводить историю из cookie - - echo <<Войдите для просмотра истории поиска

- HTML; } else if ($rows = Search::searchByEdge( from: 'account', to: 'search', @@ -23,31 +18,18 @@ if (isset($history) && $history) { )) { // История поиска существует + preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone); + $timezone = $timezone[1][0]; + foreach ($rows as $row) { // Инициализация $time = $row->jrnl; - $date = empty($time) ? '' : date('d.m.y', end($time)['date']); + $date = empty($time) ? '' : (new DateTime())->setTimestamp(end($time)['date'])->setTimezone(new DateTimeZone($timezone))->format('d.m.y'); echo <<$row->text$date HTML; } } -} else if (isset($response) && $response) { - // Ответ получен - - foreach ($response as $row) { - // Перебор найденных данных - - $catn = $row['supply']['catn']; - - echo <<$catn - HTML; - } -} else { - echo <<Ничего не найдено

- HTML; } ?> diff --git a/mirzaev/skillparts/system/views/profile/monitoring.php b/mirzaev/skillparts/system/views/profile/monitoring.php index ae67f0c..f5f2277 100644 --- a/mirzaev/skillparts/system/views/profile/monitoring.php +++ b/mirzaev/skillparts/system/views/profile/monitoring.php @@ -39,7 +39,12 @@ $panel ?? $panel = 'profile_panel_monitoring_input_search_history'; foreach ($search_history ?? [] as $row) { // Инициализация $time = $row->jrnl; - $date = empty($row->jrnl) ? '' : date('H:i d.m.Y', end($time)['date']); + + // Инициализация часового пояса + preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone); + $timezone = $timezone[1][0]; + + $date = empty($row->jrnl) ? '' : (new DateTime())->setTimestamp(end($time)['date'])->setTimezone(new DateTimeZone($timezone))->format('H:i d.m.Y'); echo << @@ -84,4 +89,4 @@ $panel ?? $panel = 'profile_panel_monitoring_input_search_history'; || yii::$app->user->identity->type === 'moderator') ) : ?> - \ No newline at end of file + diff --git a/mirzaev/skillparts/system/views/search/panel.php b/mirzaev/skillparts/system/views/search/panel.php index e605d70..ab5a2b8 100644 --- a/mirzaev/skillparts/system/views/search/panel.php +++ b/mirzaev/skillparts/system/views/search/panel.php @@ -3,6 +3,7 @@ declare(strict_types=1); use app\models\Search; +use app\models\Settings; if (isset($history) && $history) { // Отображение истории @@ -23,10 +24,13 @@ if (isset($history) && $history) { )) { // История поиска существует + preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone); + $timezone = $timezone[1][0]; + foreach ($rows as $row) { // Инициализация $time = $row->jrnl; - $date = empty($time) ? '' : date('H:i d.m.Y', end($time)['date']); + $date = empty($time) ? '' : (new DateTime())->setTimestamp(end($time)['date'])->setTimezone(new DateTimeZone($timezone))->format('H:i d.m.Y'); echo <<$row->text$date diff --git a/mirzaev/skillparts/system/web/css/notification.css b/mirzaev/skillparts/system/web/css/notification.css index 2569f3a..ba4411a 100644 --- a/mirzaev/skillparts/system/web/css/notification.css +++ b/mirzaev/skillparts/system/web/css/notification.css @@ -10,7 +10,6 @@ z-index : 100; bottom : 0; position: fixed; - width: 370px; overflow: hidden; } diff --git a/mirzaev/skillparts/system/web/favicon.ico b/mirzaev/skillparts/system/web/favicon.ico index 4a35d39..66bc35b 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/logos/favicon.old.ico b/mirzaev/skillparts/system/web/img/logos/favicon.old.ico new file mode 100644 index 0000000..4a35d39 Binary files /dev/null and b/mirzaev/skillparts/system/web/img/logos/favicon.old.ico differ diff --git a/mirzaev/skillparts/system/web/img/logos/faviconRaw3.png b/mirzaev/skillparts/system/web/img/logos/faviconRaw3.png new file mode 100644 index 0000000..7a35c05 Binary files /dev/null and b/mirzaev/skillparts/system/web/img/logos/faviconRaw3.png differ diff --git a/mirzaev/skillparts/system/web/img/logos/faviconRaw4.png b/mirzaev/skillparts/system/web/img/logos/faviconRaw4.png new file mode 100644 index 0000000..a7e091e Binary files /dev/null and b/mirzaev/skillparts/system/web/img/logos/faviconRaw4.png differ diff --git a/mirzaev/skillparts/system/web/js/account.js b/mirzaev/skillparts/system/web/js/account.js index 17db513..09183c2 100644 --- a/mirzaev/skillparts/system/web/js/account.js +++ b/mirzaev/skillparts/system/web/js/account.js @@ -303,14 +303,15 @@ function account_response(data, status, xhr) { function account_response_success(data, status, xhr) { // Обработка ответов от удавшихся запросов + account_response(data, status, xhr); + // Реинициализация панели поиска // Перенести в отдельный файл который подгружается в зависимости от настроек // search_panel_show(); // // Обновление панели поиска - // product_search(); + product_search(); - account_response(data, status, xhr); } function account_response_error(data, status, xhr) { diff --git a/mirzaev/skillparts/system/web/js/geolocation.js b/mirzaev/skillparts/system/web/js/geolocation.js index c75848c..14abc47 100644 --- a/mirzaev/skillparts/system/web/js/geolocation.js +++ b/mirzaev/skillparts/system/web/js/geolocation.js @@ -1,83 +1,83 @@ -// Инициализация геолокации (запись геолокации по айпи, если не существует) -function geolocation_init() { - $.ajax({ - url: '/profile/geolocation/init', - type: 'post', - dataType: 'json', - data: { '_csrf': yii.getCsrfToken() }, - success: geolocation_success, - error: geolocation_error - }); -}; +// // Инициализация геолокации (запись геолокации по айпи, если не существует) +// function geolocation_init() { +// $.ajax({ +// url: '/profile/geolocation/init', +// type: 'post', +// dataType: 'json', +// data: { '_csrf': yii.getCsrfToken() }, +// success: geolocation_success, +// error: geolocation_error +// }); +// }; -geolocation_init(); +// geolocation_init(); -// Запись геолокации (точный режим из браузера по запросу) -function geolocation_gps() { +// // Запись геолокации (точный режим из браузера по запросу) +// function geolocation_gps() { - // Запрос геолокации у пользователя - navigator.geolocation.getCurrentPosition( - geolocation_gps_success, - geolocation_gps_error, - { - enableHighAccuracy: true - } - ); -}; +// // Запрос геолокации у пользователя +// navigator.geolocation.getCurrentPosition( +// geolocation_gps_success, +// geolocation_gps_error, +// { +// enableHighAccuracy: true +// } +// ); +// }; -// Получено подтверждение выдачи геолокации от пользователя -function geolocation_gps_success({ coords }) { +// // Получено подтверждение выдачи геолокации от пользователя +// function geolocation_gps_success({ coords }) { - // Инициализация - const { latitude, longitude } = coords; +// // Инициализация +// const { latitude, longitude } = coords; - // Запрос - $.ajax({ - url: '/profile/geolocation/write', - type: 'post', - dataType: 'json', - data: { - 'latitude': latitude, - 'longitude': longitude, - '_csrf': yii.getCsrfToken() - }, - success: geolocation_success, - error: geolocation_error - }); -}; +// // Запрос +// $.ajax({ +// url: '/profile/geolocation/write', +// type: 'post', +// dataType: 'json', +// data: { +// 'latitude': latitude, +// 'longitude': longitude, +// '_csrf': yii.getCsrfToken() +// }, +// success: geolocation_success, +// error: geolocation_error +// }); +// }; -// Не получено подтверждение выдачи геолокации от пользователя -function geolocation_gps_error({ message }) { -}; +// // Не получено подтверждение выдачи геолокации от пользователя +// function geolocation_gps_error({ message }) { +// }; -function geolocation_responce(data, status, xhr) { - // Обработка ответов +// function geolocation_responce(data, status, xhr) { +// // Обработка ответов - main_response(data, status, xhr); -}; +// main_response(data, status, xhr); +// }; -function geolocation_success(data, status, xhr) { - // Обработка ответов от удавшихся запросов +// function geolocation_success(data, status, xhr) { +// // Обработка ответов от удавшихся запросов - if (data !== undefined) { - // Получены данные с сервера +// if (data !== undefined) { +// // Получены данные с сервера - // Запрос более точной геолокации - if (data.requestGps !== undefined && data.requestGps === true) { +// // Запрос более точной геолокации +// if (data.requestGps !== undefined && data.requestGps === true) { - geolocation_gps(); - } - }; +// geolocation_gps(); +// } +// }; - geolocation_responce(data, status, xhr); -}; +// geolocation_responce(data, status, xhr); +// }; -function geolocation_error(data, status, xhr) { - // Обработка ответов от неудавшихся запросов +// function geolocation_error(data, status, xhr) { +// // Обработка ответов от неудавшихся запросов - // Инициализация - data = data.responseJSON; +// // Инициализация +// data = data.responseJSON; - geolocation_responce(data, status, xhr); -}; +// geolocation_responce(data, status, xhr); +// }; diff --git a/mirzaev/skillparts/system/web/js/google/analytics.js b/mirzaev/skillparts/system/web/js/google/analytics.js new file mode 100644 index 0000000..771361e --- /dev/null +++ b/mirzaev/skillparts/system/web/js/google/analytics.js @@ -0,0 +1,5 @@ +window.dataLayer = window.dataLayer || []; +function gtag(){dataLayer.push(arguments);} +gtag('js', new Date()); + +gtag('config', 'G-6XYKBJJWR4'); diff --git a/mirzaev/skillparts/system/web/js/orders_panel.js b/mirzaev/skillparts/system/web/js/orders_panel.js index a1b0daf..2a3beaa 100644 --- a/mirzaev/skillparts/system/web/js/orders_panel.js +++ b/mirzaev/skillparts/system/web/js/orders_panel.js @@ -40,7 +40,7 @@ function order_accept(order_key) { return false; }; -function orders_supply_edit(supply_key, order_key) { +function orders_supply_edit(type, supply_key, order_key) { // Инициализация let supply = document.getElementById(supply_key + '_supply'); @@ -229,7 +229,7 @@ function orders_supply_edit(supply_key, order_key) { // Инициализация индикатора let span = document.createElement('span'); - span.setAttribute('id', supply.getAttribute('id') + '_stts_indicator_icon'); + span.setAttribute('id', supply.getAttribute('id') + '_' + type + '_supply_stts_indicator_icon'); span.setAttribute('class', 'ml-auto my-auto fas fa-check'); // Инициализация кнопки @@ -237,7 +237,7 @@ function orders_supply_edit(supply_key, order_key) { button.setAttribute('id', supply.getAttribute('id') + '_stts_button'); button.setAttribute('type', 'button'); button.setAttribute('role', 'button'); - button.setAttribute('onclick', 'return orders_supply_comm_write(this, \'' + supply_key + '\', \'' + order_key + '\');'); + button.setAttribute('onclick', 'return orders_supply_comm_write(this, \'' + type + '\' \'' + supply_key + '\', \'' + order_key + '\');'); if (data.stts === undefined || data.stts == 0) { button.setAttribute('class', 'col-12 btn button_blue button_clean'); button.innerText = 'Подтвердить'; @@ -246,9 +246,9 @@ function orders_supply_edit(supply_key, order_key) { button.innerText = 'Подтверждено'; // Инициализация - let title = document.getElementById(supply.getAttribute('id') + '_stts_indicator'); + let title = document.getElementById(supply.getAttribute('id') + '_' + type + '_supply_stts_indicator'); - if (title.children[0] === undefined) { + if (title.children[1] === undefined) { // Индикатор не найден // Запись индикатора @@ -273,7 +273,7 @@ function orders_supply_edit(supply_key, order_key) { return false; }; -function orders_supply_comm_write(button, supply_key, order_key) { +function orders_supply_comm_write(button, type, supply_key, order_key) { // Инициализация let supply = document.getElementById(supply_key + '_supply'); @@ -288,7 +288,7 @@ function orders_supply_comm_write(button, supply_key, order_key) { success: function (data, status, xhr) { // Инициализация индикатора let span = document.createElement('span'); - span.setAttribute('id', supply.getAttribute('id') + '_stts_indicator_icon'); + span.setAttribute('id', supply.getAttribute('id') + '_' + type + '_supply_stts_indicator_icon'); span.setAttribute('class', 'ml-auto my-auto fas fa-check'); if (data.stts === undefined || data.stts == 0) { @@ -299,7 +299,7 @@ function orders_supply_comm_write(button, supply_key, order_key) { button.innerText = 'Подтверждено'; // Инициализация - let title = document.getElementById(supply.getAttribute('id') + '_stts_indicator'); + let title = document.getElementById(supply.getAttribute('id') + '_' + type + '_supply_stts_indicator'); if (title.children[0] === undefined) { // Индикатор не найден diff --git a/mirzaev/skillparts/system/web/js/search.js b/mirzaev/skillparts/system/web/js/search.js index 0f180f2..453de5c 100644 --- a/mirzaev/skillparts/system/web/js/search.js +++ b/mirzaev/skillparts/system/web/js/search.js @@ -79,9 +79,6 @@ function search_panel_response(text, advanced, data, status, xhr) { // Обновление окна результатов поиска panel.innerHTML = data.panel; - // Отображение окна (потом надо переделать) - $('#search_line').dropdown('show'); - // Реинициализация reinitialization(panel); }; @@ -101,6 +98,11 @@ function search_panel_response(text, advanced, data, status, xhr) { }; }; + // Отображение окна поиска + if (data.search_line_window_show === 1) { + search_panel_show(); + }; + // Сокрытие окна поиска if (data.search_line_window_hide === 1) { search_panel_hide(); @@ -116,7 +118,7 @@ function search_panel_success(text, advanced, data, status, xhr) { search_panel_response(text, advanced, data, status, xhr); }; -function search_panel_error(text, advanced, data, status) { +function search_panel_error(text, advanced, data, status, xhr) { // Обработка ответов от неудавшихся запросов // Инициализация diff --git a/mirzaev/skillparts/system/web/js/yandex/geolocation.js b/mirzaev/skillparts/system/web/js/yandex/geolocation.js new file mode 100644 index 0000000..89b7957 --- /dev/null +++ b/mirzaev/skillparts/system/web/js/yandex/geolocation.js @@ -0,0 +1,73 @@ +'use strict' + +// Инициализация геолокации (запись геолокации по айпи, если не существует) +function yandex_geolocation_init() { + $.ajax({ + url: '/profile/geolocation/init', + type: 'post', + dataType: 'json', + data: { '_csrf': yii.getCsrfToken() }, + success: yandex_geolocation_success, + error: yandex_geolocation_error + }); +}; + +yandex_geolocation_init(); + +function yandex_geolocation_search() { + try { + ymaps.geolocation.get({ + autoReverseGeocode: true + }).then(function (result) { + // Запрос + $.ajax({ + url: '/profile/geolocation/write', + type: 'post', + dataType: 'json', + data: { + 'yandex': { + // 'metadata': result.geoObjects.get(0).properties.get('metaDataProperty'), + 'coordinates': result.geoObjects.get(0).properties.get('boundedBy') + }, + '_csrf': yii.getCsrfToken() + }, + success: yandex_geolocation_success, + error: yandex_geolocation_error + }); + }) + } catch (err) { + setTimeout(yandex_geolocation_search, 3000); + } +} + + +function yandex_geolocation_responce(data, status, xhr) { + // Обработка ответов + + main_response(data, status, xhr); +}; + +function yandex_geolocation_success(data, status, xhr) { + // Обработка ответов от удавшихся запросов + + if (data !== undefined) { + // Получены данные с сервера + + // Запрос геолокации + if (data.geolocation !== undefined && data.geolocation === false) { + + yandex_geolocation_search(); + } + }; + + yandex_geolocation_responce(data, status, xhr); +}; + +function yandex_geolocation_error(data, status, xhr) { + // Обработка ответов от неудавшихся запросов + + // Инициализация + data = data.responseJSON; + + yandex_geolocation_responce(data, status, xhr); +}; diff --git a/mirzaev/skillparts/system/web/js/yandex/metrika.js b/mirzaev/skillparts/system/web/js/yandex/metrika.js new file mode 100644 index 0000000..5458289 --- /dev/null +++ b/mirzaev/skillparts/system/web/js/yandex/metrika.js @@ -0,0 +1,12 @@ +(function (m, e, t, r, i, k, a) { + m[i] = m[i] || function () { (m[i].a = m[i].a || []).push(arguments) }; + m[i].l = 1 * new Date(); k = e.createElement(t), a = e.getElementsByTagName(t)[0], k.async = 1, k.src = r, a.parentNode.insertBefore(k, a) +}) + (window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym"); + +ym(84269905, "init", { + clickmap: true, + trackLinks: true, + accurateTrackBounce: true, + webvisor: true +});