Работа над сайтом 20

This commit is contained in:
Arsen Mirzaev Tatyano-Muradovich 2021-08-30 06:41:19 +10:00
parent fab247b4bc
commit d9337944b1
33 changed files with 765 additions and 487 deletions

View File

@ -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

View File

@ -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 доделать

View File

@ -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')) {

View File

@ -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)) {
// Удалось найти инстанцию поставки
// Инициализация ребра: ПОСТАВКА -> ТОВАР

View File

@ -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;
return $return;
}
// Запись в буфер данных о типе геолокации
$account->geol = ['type' => 'ip'] + ($account->geol ?? []);
self::syncGeolocationWithDellin($account);
}
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);
}
}

View File

@ -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()
];
}

View File

@ -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-запрос

View File

@ -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',
@ -115,8 +117,11 @@ class Account extends Document implements IdentityInterface, PartnerInterface
'unique',
'message' => 'Атрибут {attribute} должен иметь уникальное значение'
],
[
[
'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');

View File

@ -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,12 +147,26 @@ class AccountForm extends Model
return;
}
if (!$account || !$account->validatePassword($this->pswd)) {
// Проверка не пройдена
if ($account) {
// Удалось инициализировать аккаунт
try {
$account->validatePasswordWithHash($this->pswd);
} catch (Exception $e) {
// Проверка с хешем не пройдена
try {
$account->validatePasswordWithoutHash($this->pswd);
} catch (Exception $e) {
// Проверка без хеша не пройдена
$this->addError($attribute, 'Проверьте пароль');
}
}
} else {
$this->addError($attribute, 'Не удалось идентифицировать аккаунт');
}
}
}
/**

View File

@ -168,7 +168,7 @@ class Notification extends Document
$text = htmlspecialchars(strip_tags($text ?? null));
$model->html = <<<HTML
<p class="my-2 mx-3">$text</p>
<p>$text</p>
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' => 'Ошибка'
};
}
}

View File

@ -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'));

View File

@ -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 Высота ()
* @param int $z Длинна ()
* @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)) {

View File

@ -1,3 +1,8 @@
<?php
use app\models\Settings;
?>
<!DOCTYPE html>
<html>
@ -78,7 +83,13 @@
<tr>
<td style="text-indent: 2px; text-align: left; border-bottom: medium; font-size: 18rem;" colspan="13" rowspan="3" valign="center">
<b>Счет на оплату <?= $order['id'] ?> от <?= date('d.m.Y', $order['date']) ?></b>
<?php
// Инициализация часового пояса
preg_match_all('/UTC([\+\-0-9:]*)/', $account->zone ?? Settings::search()['timezone_default'] ?? 'UTC+3', $timezone);
$timezone = $timezone[1][0];
?>
<b>Счет на оплату <?= $order['id'] ?> от <?= (new DateTime())->setTimestamp($order['date'])->setTimezone(new DateTimeZone($timezone))->format('d.m.Y') ?></b>
</td>
</tr>
@ -144,7 +155,10 @@
<tr>
<td style="text-align: center; border: solid; border-left: thick;" colspan="1" valign="center"><?= $row++ ?></td>
<td style="text-align: left; border: solid;" colspan="6" valign="center"><?= $entry['title'] ?></td>
<td style="text-align: center; border: solid;" colspan="2" valign="center"><?= $entry['amount']['value'] ?></td>
<?php var_dump($entry) ?>
<td style="text-align: center; border: solid;" colspan="2" valign="center"><?= $entry['amount']['auto']['value'] ?></td>
<td style="text-align: center; border: solid;" valign="center"><?= $entry['cost']['value'] ?></td>
<td style="text-align: center; border: solid;" valign="center"><?= $entry['cost']['unit'] ?></td>
<td style="text-align: center; border: solid; border-right: thick;" colspan="2" valign="center"><?= $cost += $entry['cost']['value'] * $entry['amount']['value'] ?></td>
@ -182,7 +196,7 @@
</tr>
<tr>
<td style="width: 8pt;" colspan="13"><img src="<?= YII_PATH_PUBLIC . '/img/invoices/signature.png'?>" /></td>
<td style="width: 8pt;" colspan="13"><img src="<?= YII_PATH_PUBLIC . '/img/invoices/signature.png' ?>" /></td>
</tr>
</table>
</body>

View File

@ -20,23 +20,8 @@ AppAsset::register($this);
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="apple-touch-icon" sizes="57x57" href="/favicons/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/favicons/apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/favicons/apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/favicons/apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/favicons/apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/favicons/apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/favicons/apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/favicons/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/favicons/apple-icon-180x180.png">
<link rel="icon" type="image/png" sizes="192x192" href="/favicons/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="/favicons/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicons/favicon-16x16.png">
<link rel="manifest" href="/favicons/manifest.json">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="/favicons/ms-icon-144x144.png">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="/favicon.ico" type="image/x-icon">
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
<?php $this->registerCsrfMetaTags() ?>
<title><?= Html::encode($this->title ?? 'SkillParts') ?></title>
@ -46,7 +31,7 @@ AppAsset::register($this);
<body>
<?php $this->beginBody() ?>
<div id="notifications_popup_wrap" class="col-3 m-4"></div>
<div id="notifications_popup_wrap" class="m-4 col-6 col-sm-5 col-md-4 col-lg-4 col-xl-3"></div>
<header class="container pt-2 mt-1 mb-2 mb-sm-4 unselectable">
<div class="row h-100">

View File

@ -1,10 +1,34 @@
<?php
$id = 'popup/' . $notification->readId();
$html = $notification->html;
echo <<<HTML
<div id="$id" class="mt-3 p-0 notification rounded" onmouseleave="return notification_popup_delete(this);">
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 = <<<HTML
<b class="row mb-1 px-3"><small>$type<span class="ml-auto">$date</span></small></b>
HTML;
echo <<<HTML
<div id="$id" class="col mt-3 py-2 px-3 notification rounded" onmouseleave="return notification_popup_delete(this);">
$title
$html
</div>
HTML;
?>
HTML;

View File

@ -1 +1,3 @@
<a href="/orders#<?= $id ?>">Новый заказ</a>
<div class="p-3 h-100">
<p class="text-center my-auto">Новый заказ: <a href="/orders#<?= $id ?>">#<?= $id ?></a></p>
</div>

View File

@ -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;
?>
<?php foreach ($order['supplies'] as $supply) : ?>
<?php foreach ($order['supplies'] as $supply) :
// Перебор поставок
?>
<?php
// Инициализация окружения
extract($supply);
// Инициализация обложки
$covr = null;
@ -116,18 +130,51 @@ if (empty($window)) {
}
}
// Инициализация окружения
extract($supply);
?>
if ($amount['auto'] > 0) {
// Найдены поставки с автоматической доставкой
<a id="<?= $supply['catn'] ?>_supply" class="row mb-2 p-2 px-0 rounded row_supply" type="button" onclick="return orders_supply_edit('<?= $supply['catn'] ?>', <?= $order['order']['_key'] ?>);">
<img class="col-auto px-0 h-100 img-fluid rounded" src="<?= $covr ?>" />
<p id="<?= $supply['catn'] ?>_supply_stts_indicator" class="col d-flex text-dark"><?= $product['catn'] . ' x' . $amount['auto'] ?>
<?php if (Order::checkSuppliesStts($order_edge_supply)) : ?>
<span id="<?= $supply['catn'] ?>_supply_stts_indicator_icon" class="ml-auto my-auto fas fa-check"></span>
<?php endif ?>
if (Order::checkSuppliesStts($order_edge_supply)) {
$status = '<span id="' . $supply['catn'] . '_auto_supply_stts_indicator_icon" class="ml-auto my-auto fas fa-check"></span>';
} else {
$status = '';
}
// Генерация HTML
echo <<<HTML
<a id="{$supply['catn']}_auto_supply" class="row mb-2 p-2 px-0 rounded row_supply" type="button" onclick="return orders_supply_edit('{$supply['catn']}_auto', {$order['order']['_key']});">
<img class="col-auto px-0 h-100 img-fluid rounded" src="$covr" />
<p id="{$supply['catn']}_auto_supply_stts_indicator" class="col d-flex text-dark">
{$product['catn']} x{$amount['auto']}
<small class="ml-2 my-auto fas fa-truck"></small>
$status
</p>
</a>
HTML;
}
if ($amount['avia'] > 0) {
// Найдены поставки с автоматической доставкой
if (Order::checkSuppliesStts($order_edge_supply)) {
$status = '<span id="' . $supply['catn'] . '_avia_supply_stts_indicator_icon" class="ml-auto my-auto fas fa-check"></span>';
} else {
$status = '';
}
// Генерация HTML
echo <<<HTML
<a id="{$supply['catn']}_avia_supply" class="row mb-2 p-2 px-0 rounded row_supply" type="button" onclick="return orders_supply_edit('{$supply['catn']}_avia', {$order['order']['_key']});">
<img class="col-auto px-0 h-100 img-fluid rounded" src="$covr" />
<p id="{$supply['catn']}_avia_supply_stts_indicator" class="col d-flex text-dark">
{$product['catn']} x{$amount['avia']}
<small class="ml-2 my-auto fas fa-plane"></small>
$status
</p>
</a>
HTML;
}
?>
<?php if ($count++ < count($order['supplies'])) : ?>
<div class="dropdown-divider mb-2"></div>
@ -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,75 +321,61 @@ if (empty($window)) {
if (isset($supplies)) {
// Найдены поставки
// Инициализация максимального срока доставки
$delivery_max = 0;
// Инициализация поставок
foreach ($supplies as $supply) {
// Перебор поставок
// Инициализация окружения
// Инициализация переменных
extract($supply);
// Инициализация связи поставки с заказом (подразумевается, что все одинаковые по основным параметрам)
$part = $order_edge_supply[0];
// Инициализация цены
$price_raw = $cost;
// Инициализация комментария
$comment = $order_edge_supply['comm'] ?? 'Комментарий к заказу';
if ($amount['auto'] > 0) {
// Найдены поставки с автоматической доставкой
// Инициализация цены
$price_auto = $price_raw['auto'] . ' ' . $currency;
// Инициализация доставки
if (isset($delivery['error'])) {
if (!isset($delivery) || (isset($delivery['auto'], $delivery['auto']['error']) || $delivery === '?')) {
// Не удалось рассчитать доставку
// Инициализация индикатора
$date_icon = '';
// Инициализация доставки
if (isset($part['date'])) {
// Найдены данные в инстанции поставки
// Запись в буфер вывода
// $time = $part['time'] . ' дн';
$date = date('d.m.Y', $part['date']);
$date_html = "<span class=\"m-auto\">$date</span>";
} else {
$date = 'Неизвестно';
$date_html = "<small class=\"m-auto\">$date</small>";
}
// Инициализация стоимости
if (isset($part['cost'])) $cost_html = '<span class="m-auto">' . ($cost = $part['cost']) . ' <small>' . $currency . '</small></span>';
else $cost_html = '<small class="m-auto">' . ($cost = 'Неизвестно') . '</small>';
// Инициализация времени
$delivery_auto = '?';
} else {
// Удалось рассчитать доставку
// Инициализация типа доставки
$time_type = $part['dlvr']['type'] ?? 'auto';
// Инициализация индикатора
$date_icon = match ($time_type) {
'avia' => '<i class="ml-1 fas fa-plane"></i>',
default => '<i class="ml-1 fas fa-truck"></i>'
};
// Инициализация доставки
if (isset($part['date'])) {
// Найдены данные в инстанции поставки
// Запись в буфер вывода
// $time = $part['time'] . ' дн';
$date = date('d.m.Y', $part['date']);
$date_html = "<span class=\"m-auto\">$date</span>";
} 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 = "<span class=\"m-auto\">$date</span>";
// Взять данные из "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();
}
// Инициализация стоимости
if (isset($part['cost'])) $cost_html = '<span class="m-auto">' . ($cost = $part['cost']) . ' <small>' . $currency . '</small></span>';
else $cost_html = '<span class="m-auto">' . ($cost = $cost['auto']) . ' <small>' . $currency . '</small></span>';
// Инициализация времени доставки
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;
}
// Инициализация статуса связи поставки
@ -340,19 +387,92 @@ if (empty($window)) {
default => ''
};
// Реинициализация максимальной даты доставки
if ($delivery_max !== '?' && $delivery_max < $delivery_auto) $delivery_max = $delivery_auto;
else if ($delivery_auto === '?') $delivery_max = '?';
// Генерация HTML
// Пробела между supply и $css не должно быть
$supplies_html .= <<<HTML
<div class="row py-2 supply$css text-center">
<div class="col-2">{$supply['catn']}</div>
<div class="col-3 d-flex"><small class="m-auto">$status</small></div>
<div class="col-3 d-flex">$date_html</div>
<div class="col-2">{$amount['auto']}</div>
<div class="col-2 d-flex">$cost_html</div>
<div class="m-auto col-2">{$supply['catn']}</div>
<small class="m-auto col-3">$status</small>
<div class="m-auto col-3">$delivery_auto <small class="mr-1 fas fa-truck"></small></div>
<div class="m-auto col-2">{$amount['auto']}</div>
<div class="m-auto col-2">$price_auto</div>
</div>
HTML;
}
// Обновление общего счётчика цены
$sum += (int) $cost;
if ($amount['avia'] > 0) {
// Найдены поставки с доставкой по воздуху
// Инициализация цены
$price_avia = $price_raw['avia'] . ' ' . $currency;
// Инициализация доставки
if (!isset($delivery) || (isset($delivery['avia'], $delivery['avia']['error']) || $delivery === '?')) {
// Не удалось рассчитать доставку
// Инициализация времени
$delivery_avia = '?';
} else {
// Удалось рассчитать доставку
// Инициализация даты отправки
try {
// Взять данные из "arrivalToOspSender" (Дата прибытия на терминал-отправитель)
$delivery_avia_send_date = DateTime::createFromFormat('Y-m-d', $delivery['avia']['orderDates']['arrivalToOspSender'])->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 .= <<<HTML
<div class="row py-2 supply$css text-center">
<div class="m-auto col-2">{$supply['catn']}</div>
<small class="m-auto col-3">$status</small>
<div class="m-auto col-3">$delivery_avia <small class="mr-1 fas fa-plane"></small></div>
<div class="m-auto col-2">{$amount['avia']}</div>
<div class="m-auto col-2">$price_avia</div>
</div>
HTML;
}
// Инициализация общей цены
$sum = $price_raw['avia'] * $amount['avia'] + $price_raw['auto'] * $amount['auto'];
}
}
@ -369,7 +489,7 @@ if (empty($window)) {
<div class="row py-2 cart_list_target_total text-center">
<div class="col-2">$invoice</div>
<div class="col-3"><b>$status</b></div>
<div class="col-3"><b>$date</b></div>
<div class="col-3"><b>$delivery_max</b></div>
<div class="col-2"></div>
<div class="col-2"><b>$sum <small><b>руб</b></small></b></div>
</div>
@ -395,6 +515,11 @@ if (empty($window)) {
// Инициализация индикатора готовности календаря
orders_calendar_ready = false;
<?php
preg_match_all('/UTC([\+\-0-9:]*)/', $account->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('<?= $from ?? date('Y-m-d', time() - 604800) ?>'), new Date('<?= $to ?? date('Y-m-d', time()) ?>')]);
$('#orders_period_calendar').data('datepicker').selectDate([new Date('<?= $from ?? (new DateTime())->setTimestamp(time() - 604800)->setTimezone(new DateTimeZone($timezone))->format('Y-m-d') ?>'), new Date('<?= $to ?? (new DateTime('now', new DateTimeZone($timezone)))->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('<?= $from ?? date('Y-m-d', time() - 604800) ?>'), new Date('<?= $to ?? date('Y-m-d', time()) ?>')]);
$('#orders_period_calendar').data('datepicker').selectDate([new Date('<?= $from ?? (new DateTime())->setTimestamp(time() - 604800)->setTimezone(new DateTimeZone($timezone))->format('Y-m-d') ?>'), new Date('<?= $to ?? (new DateTime('now', new DateTimeZone($timezone)))->format('Y-m-d') ?>')]);
// Активация календаря
orders_calendar_ready = true;

View File

@ -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
<p class="m-0 py-2 d-flex justify-content-center">Войдите для просмотра истории поиска</p>
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 <<<HTML
<a class="dropdown-item d-flex button_white text-dark" href="/search?type=product&q=$row->text">$row->text<span class="ml-auto">$date</span></a>
HTML;
}
}
} else if (isset($response) && $response) {
// Ответ получен
foreach ($response as $row) {
// Перебор найденных данных
$catn = $row['supply']['catn'];
echo <<<HTML
<a class="dropdown-item button_white text-dark" href="/product/$catn">$catn</a>
HTML;
}
} else {
echo <<<HTML
<p class="m-0 py-2 d-flex justify-content-center">Ничего не найдено</p>
HTML;
}
?>

View File

@ -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 <<<HTML
<div class="row py-1">

View File

@ -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 <<<HTML
<a class="dropdown-item d-flex button_white text-dark" href="/search?type=product&q=$row->text">$row->text<span class="ml-auto">$date</span></a>

View File

@ -10,7 +10,6 @@
z-index : 100;
bottom : 0;
position: fixed;
width: 370px;
overflow: hidden;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

View File

@ -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) {

View File

@ -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);
// };

View File

@ -0,0 +1,5 @@
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-6XYKBJJWR4');

View File

@ -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) {
// Индикатор не найден

View File

@ -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) {
// Обработка ответов от неудавшихся запросов
// Инициализация

View File

@ -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);
};

View File

@ -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
});