diff --git a/mirzaev/skillparts/system/controllers/CartController.php b/mirzaev/skillparts/system/controllers/CartController.php index bd1b797..0bd79e4 100644 --- a/mirzaev/skillparts/system/controllers/CartController.php +++ b/mirzaev/skillparts/system/controllers/CartController.php @@ -10,13 +10,68 @@ use yii\filters\AccessControl; use yii\web\Controller; use yii\web\Response; +use app\models\Product; use app\models\Order; use app\models\OrderEdgeSupply; use Exception; +use yii\web\Cookie; class CartController extends Controller { + public function behaviors() + { + return [ + 'access' => [ + 'class' => AccessControl::class, + 'rules' => [ + [ + 'allow' => true, + 'roles' => ['@'], + 'actions' => [ + 'index', + 'edit-comm' + ] + ], + [ + 'allow' => false, + 'roles' => ['?'], + 'denyCallback' => [$this, 'accessDenied'] + ] + ] + ] + ]; + } + + public function accessDenied() + { + // Инициализация + $cookies = yii::$app->response->cookies; + + // Запись cookie с редиректом, который выполнится после авторизации + $cookies->add(new Cookie([ + 'name' => 'redirect', + 'value' => yii::$app->request->pathInfo + ])); + + if (yii::$app->request->isPost) { + // POST-запрос + + // Настройка + yii::$app->response->format = Response::FORMAT_JSON; + + // Генерация ответа + yii::$app->response->content = json_encode([ + 'main' => $this->renderPartial('/account/index'), + 'redirect' => '/cart', + '_csrf' => yii::$app->request->getCsrfToken() + ]); + } else if (yii::$app->request->isGet) { + // GET-запрос + + $this->redirect('/authentication'); + } + } /** * Страница: "Корзина" * diff --git a/mirzaev/skillparts/system/controllers/ErrorController.php b/mirzaev/skillparts/system/controllers/ErrorController.php index 684b353..10943f1 100644 --- a/mirzaev/skillparts/system/controllers/ErrorController.php +++ b/mirzaev/skillparts/system/controllers/ErrorController.php @@ -7,7 +7,7 @@ use yii\web\Controller; class ErrorController extends Controller { - public function actionIndex() + public function actionIndex(): string { $exception = Yii::$app->errorHandler->exception; @@ -15,21 +15,26 @@ class ErrorController extends Controller // Исключение не выброшено // Запись кода ошибки - $statusCode = $exception->statusCode ?? $exception->getCode() ?? 0; + $code = $exception->statusCode ?? $exception->getCode() ?? 0; // Запись названия ошибки - $name = match ($statusCode) { + $title = match ($code) { 404 => '404 (Не найдено)', default => $exception->getName() }; // Запись сообщения об ошибке - $message = match ($statusCode) { + $description = match ($code) { 404 => 'Страница не найдена', default => $exception->getMessage() }; - return $this->render('/error', compact('exception', 'statusCode', 'name', 'message')); + return $this->render('/error', compact('exception', 'code', 'title', 'description')); } } + + public static function throw(string $title, string $description): string { + + return yii::$app->controller->render('/error', compact('title', 'description')); + } } diff --git a/mirzaev/skillparts/system/controllers/OfferController.php b/mirzaev/skillparts/system/controllers/OfferController.php index 412baf7..9cf748b 100644 --- a/mirzaev/skillparts/system/controllers/OfferController.php +++ b/mirzaev/skillparts/system/controllers/OfferController.php @@ -44,16 +44,16 @@ class OfferController extends Controller 'value' => yii::$app->request->pathInfo ])); - if (Yii::$app->request->isPost) { + if (yii::$app->request->isPost) { // POST-запрос // Настройка - Yii::$app->response->format = Response::FORMAT_JSON; + yii::$app->response->format = Response::FORMAT_JSON; // Генерация ответа - Yii::$app->response->content = json_encode([ + yii::$app->response->content = json_encode([ 'redirect' => '/authentication', - '_csrf' => Yii::$app->request->getCsrfToken() + '_csrf' => yii::$app->request->getCsrfToken() ]); } else if (Yii::$app->request->isGet) { // GET-запрос diff --git a/mirzaev/skillparts/system/controllers/OrderController.php b/mirzaev/skillparts/system/controllers/OrderController.php index 010c0a7..058aa8c 100644 --- a/mirzaev/skillparts/system/controllers/OrderController.php +++ b/mirzaev/skillparts/system/controllers/OrderController.php @@ -42,7 +42,7 @@ class OrderController extends Controller 'write', 'delete', 'amount-update', - 'pay', + 'request', 'supply-read', 'supply-write-stts', 'supply-edit-time', @@ -71,19 +71,19 @@ class OrderController extends Controller 'value' => yii::$app->request->pathInfo ])); - if (Yii::$app->request->isPost) { + if (yii::$app->request->isPost) { // POST-запрос // Настройка - Yii::$app->response->format = Response::FORMAT_JSON; + yii::$app->response->format = Response::FORMAT_JSON; // Генерация ответа - Yii::$app->response->content = json_encode([ - 'main' => $this->renderPartial('/orders/index'), - 'redirect' => '/authentication', - '_csrf' => Yii::$app->request->getCsrfToken() + yii::$app->response->content = json_encode([ + 'main' => $this->renderPartial('/account/index'), + 'redirect' => '/order', + '_csrf' => yii::$app->request->getCsrfToken() ]); - } else if (Yii::$app->request->isGet) { + } else if (yii::$app->request->isGet) { // GET-запрос $this->redirect('/authentication'); @@ -357,9 +357,9 @@ class OrderController extends Controller } /** - * Оплата + * Запросить заказ */ - public function actionPay(): string|array|null + public function actionRequest(): string|array|null { // Инициализация $model = Order::search(supplies: true); diff --git a/mirzaev/skillparts/system/controllers/RegistrationController.php b/mirzaev/skillparts/system/controllers/RegistrationController.php index caaaa59..b3f2f91 100644 --- a/mirzaev/skillparts/system/controllers/RegistrationController.php +++ b/mirzaev/skillparts/system/controllers/RegistrationController.php @@ -32,9 +32,24 @@ class RegistrationController extends Controller if ($type === 'registration' && (!yii::$app->user->isGuest || $model->registration())) { // Данные прошли проверку и аккаунт был создан + echo 1; die; + // Аутентификация $model->scenario = $model::SCENARIO_AUTHENTICATION; - $model->authentication(); + + if (!$model->authentication()) { + // Не удалось аутентифицироваться + + yii::$app->response->statusCode = 401; + + $model->scenario = $model::SCENARIO_REGISTRATION; + + return [ + 'main' => $this->renderPartial('/account/index', compact('model') + ['registration' => true]), + 'redirect' => '/registration', + '_csrf' => yii::$app->request->getCsrfToken() + ]; + } // Инициализация $notifications_button = $this->renderPartial('/notification/button'); diff --git a/mirzaev/skillparts/system/controllers/SearchController.php b/mirzaev/skillparts/system/controllers/SearchController.php index fddc09f..da9b6e6 100644 --- a/mirzaev/skillparts/system/controllers/SearchController.php +++ b/mirzaev/skillparts/system/controllers/SearchController.php @@ -14,7 +14,7 @@ use app\models\Supply; use app\models\Search; use app\models\connection\Dellin; - +use app\models\Settings; use Exception; class SearchController extends Controller @@ -181,23 +181,62 @@ class SearchController extends Controller // Инициализация аккаунта $connection['account'] = Account::searchBySupplyId($connection['supply_edge_product'][0]['_from']); + // Инициализация продукта + $connection['product'] = Product::searchBySupplyId($connection['supply_edge_product'][0]['_from']); + try { - // Инициализация доставки (автоматическая) - $connection['delivery'] = Dellin::calcDeliveryAdvanced( - $connection['account']['opts']['delivery_from_terminal'], - yii::$app->user->identity->opts['delivery_to_terminal'], - (int) ($connection['product']['wght'] ?? 0), - (int) ($connection['product']['dmns']['x'] ?? 0), - (int) ($connection['product']['dmns']['y'] ?? 0), - (int) ($connection['product']['dmns']['z'] ?? 0) - ); - $connection['delivery']['type'] = 'auto'; + // Инициализация данных геолокации + try { + $from = (int) $connection['account']['opts']['delivery_from_terminal'] ?? Settings::search()->delivery_from_default ?? 36; + } catch (Exception $e) { + $from = (int) Settings::search()->delivery_from_default ?? 36; + } + + try { + $to = (int) yii::$app->user->identity->opts['delivery_to_terminal'] ?? 36; + } catch (Exception $e) { + $to = 36; + } + + if ($buffer_connection = $connection['product']['bffr']["$from-$to"] ?? false) { + // Найдены данные доставки в буфере + + if (time() < $buffer_connection['expires']) { + // Срок хранения не превышен, информация актуальна + + // Запись в буфер вывода + $connection['delivery'] = $buffer_connection['data']; + $connection['delivery']['type'] = 'auto'; + } + } else { + // Инициализация инстанции продукта в базе данных + $product = Product::searchByCatn($connection['product']['catn']); + + // Инициализация доставки Dellin (автоматическая) + $product->bffr = ($product->bffr ?? []) + [ + "$from-$to" => [ + 'data' => $connection['delivery'] = Dellin::calcDeliveryAdvanced( + $from, + $to, + (int) ($connection['product']['wght'] ?? 0), + (int) ($connection['product']['dmns']['x'] ?? 0), + (int) ($connection['product']['dmns']['y'] ?? 0), + (int) ($connection['product']['dmns']['z'] ?? 0) + ), + 'expires' => time() + 86400 + ] + ]; + $connection['delivery']['type'] = 'auto'; + + // Отправка в базу данных + $product->update(); + } } catch (Exception $e) { $connection['delivery']['error'] = true; - // var_dump($e->getMessage()); - // var_dump($e->getTrace()); - // var_dump($e->getFile()); + var_dump($e->getMessage()); + var_dump($e->getTrace()); + var_dump($e->getFile()); // var_dump(json_decode($e->getMessage(), true)['errors']); // die; @@ -209,18 +248,53 @@ class SearchController extends Controller // Инициализация версии для рассчета доставки по воздуху $buffer = $connection; - try { - // Инициализация доставки Dellin (самолётом) - $buffer['delivery'] = Dellin::calcDeliveryAdvanced( - $buffer['account']['opts']['delivery_from_terminal'], - yii::$app->user->identity->opts['delivery_to_terminal'], - (int) ($buffer['product']['wght'] ?? 0), - (int) ($buffer['product']['dmns']['x'] ?? 0), - (int) ($buffer['product']['dmns']['y'] ?? 0), - (int) ($buffer['product']['dmns']['z'] ?? 0), - avia: true - ); - $buffer['delivery']['type'] = 'avia'; + try {// Инициализация данных геолокации + try { + $from = (int) $connection['account']['opts']['delivery_from_terminal'] ?? Settings::search()->delivery_from_default ?? 36; + } catch (Exception $e) { + $from = (int) Settings::search()->delivery_from_default ?? 36; + } + + try { + $to = (int) yii::$app->user->identity->opts['delivery_to_terminal'] ?? 36; + } catch (Exception $e) { + $to = 36; + } + + if ($buffer_connection = $connection['product']['bffr']["$from-$to-avia"] ?? false) { + // Найдены данные доставки в буфере + + if (time() < $buffer_connection['expires']) { + // Срок хранения не превышен, информация актуальна + + // Запись в буфер вывода + $connection['delivery'] = $buffer_connection['data']; + $connection['delivery']['type'] = 'avia'; + } + } else { + // Инициализация инстанции продукта в базе данных + $product = Product::searchByCatn($connection['product']['catn']); + + // Инициализация доставки Dellin (автоматическая) + $product->bffr = ($product->bffr ?? []) + [ + "$from-$to-avia" => [ + 'data' => $connection['delivery'] = Dellin::calcDeliveryAdvanced( + $from, + $to, + (int) ($connection['product']['wght'] ?? 0), + (int) ($connection['product']['dmns']['x'] ?? 0), + (int) ($connection['product']['dmns']['y'] ?? 0), + (int) ($connection['product']['dmns']['z'] ?? 0), + avia: true + ), + 'expires' => time() + 86400 + ] + ]; + $connection['delivery']['type'] = 'avia'; + + // Отправка в базу данных + $product->update(); + } } catch (Exception $e) { $buffer['delivery']['error'] = true; diff --git a/mirzaev/skillparts/system/controllers/VerifyController.php b/mirzaev/skillparts/system/controllers/VerifyController.php new file mode 100644 index 0000000..a57c20c --- /dev/null +++ b/mirzaev/skillparts/system/controllers/VerifyController.php @@ -0,0 +1,60 @@ +redirect('/'); + } + + return ErrorController::throw('Ошибка подтверждения регистрации', 'Код подтверждения не совпадает с тем, что мы отправили вам на почту, либо регистрация уже была подтверждена. Свяжитесь с администрацией'); + } else { + // Простой запрос + + return $this->render('/account/verify'); + } + } + + /** + * Отправить запрос на активацию + * + * @return string + */ + public function actionSend(): string|array + { + yii::$app->user->identity->verifyRegenerate(); + + yii::$app->user->identity->sendMailVerify(); + + if (yii::$app->request->isPost) { + // POST-запрос + + yii::$app->response->format = Response::FORMAT_JSON; + + return [ + 'main' => $this->renderPartial('/account/verify'), + 'title' => 'Корзина', + '_csrf' => yii::$app->request->getCsrfToken() + ]; + } else { + // Подразумевается как GET-запрос + + return $this->render('/account/verify'); + } + } +} diff --git a/mirzaev/skillparts/system/models/Account.php b/mirzaev/skillparts/system/models/Account.php index 2b0c813..442cc3d 100644 --- a/mirzaev/skillparts/system/models/Account.php +++ b/mirzaev/skillparts/system/models/Account.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace app\models; -use Yii; +use yii; use yii\web\IdentityInterface; use carono\exchange1c\interfaces\PartnerInterface; @@ -50,6 +50,7 @@ class Account extends Document implements IdentityInterface, PartnerInterface 'opts', 'agnt', 'type', + 'vrfy', 'acpt' ] ); @@ -76,6 +77,7 @@ class Account extends Document implements IdentityInterface, PartnerInterface 'opts' => 'Параметры', 'agnt' => 'Агент (поставщик)', 'type' => 'Тип аккаунта', + 'vrfy' => 'Статус подтверждения владением почты', 'acpt' => 'Согласие с офертой' ] ); @@ -114,6 +116,10 @@ class Account extends Document implements IdentityInterface, PartnerInterface [ 'indx', 'string' + ], + [ + 'vrfy', + 'validateVrfyUnique' ] ] ); @@ -129,7 +135,8 @@ class Account extends Document implements IdentityInterface, PartnerInterface { if (parent::beforeSave($data)) { if ($this->isNewRecord) { - $this->auth = Yii::$app->security->generateRandomString(); + $this->auth = yii::$app->security->generateRandomString(); + $this->vrfy = yii::$app->security->generateRandomString(); } return true; @@ -204,6 +211,17 @@ class Account extends Document implements IdentityInterface, PartnerInterface return static::findOne(['mail' => $mail]); } + /** + * Поиск по статусу активации почты + * + * @todo Подождать обновление Yii2 и добавить + * проверку типов передаваемых параметров + */ + public static function findByVrfy($vrfy): ?self + { + return static::findOne(['vrfy' => $vrfy]); + } + /** * Поиск по идентификатору * @@ -244,10 +262,66 @@ class Account extends Document implements IdentityInterface, PartnerInterface */ public static function validateMail(string $mail): bool { - if (static::findByMail($mail)) { + if ($account = static::findByMail($mail)) { // Почта найдена в базе данных - return true; + if (isset($account) && $account->vrfy === true) { + // Регистрация подтверждена + + return true; + } + } + + return false; + } + + /** + * Проверка статуса подтверждения регистрации + */ + public static function validateVrfy(string $vrfy): bool + { + if ($account = static::findByVrfy($vrfy)) { + // Статус найден в базе данных + + if ($account->vrfy === true) { + // Регистрация подтверждена + + return true; + } + } + + return false; + } + + /** + * Проверка данных для поля подтверждения регистрации + */ + public function validateVrfyUnique($attribute, $params) + { + if (!$this->hasErrors()) { + // Проблем нет + + if ($attribute !== true && $this->validateVrfy($attribute)) { + // Проверка не пройдена + + $this->addError($attribute, 'Ключ подтверждения регистрации уже используется'); + } + } + } + + /** + * Подтверждение регистрации + */ + public static function verification(string $vrfy): bool + { + if ($account = static::findByVrfy($vrfy)) { + // Аккаунт найден + + // Запись в буфер + $account->vrfy = true; + + // Отправка изменений + return $account->update() > 0 ? true : false; } return false; @@ -258,7 +332,8 @@ class Account extends Document implements IdentityInterface, PartnerInterface */ public function validatePassword(string $pswd): bool { - return Yii::$app->security->validatePassword($pswd, $this->pswd); + // return yii::$app->security->validatePassword($pswd, $this->pswd); + return $pswd === $this->pswd; } /** @@ -546,11 +621,118 @@ class Account extends Document implements IdentityInterface, PartnerInterface */ public function statusLabel(): string { - return match($this->type) { + return match ($this->type) { 'administrator', 'admin' => 'Администратор', 'moderator', 'moder' => 'Модератор', 'supplier' => 'Поставщик', default => 'Покупатель', }; } + + public function sendMailVerify(): bool + { + if (isset($this->mail, $this->vrfy) && !$this->validateVrfy($this->vrfy)) { + // Данные инициализированы, а регистрация ещё не была подтверждена + + // Отправка письма + yii::$app->mail_system->compose() + ->setFrom(yii::$app->params['mail']['system']) + ->setTo($this->mail) + ->setSubject('Подтверждение регистрации') + ->setHtmlBody(yii::$app->controller->renderPartial('/mails/verify', ['vrfy' => $this->vrfy, 'password' => $this->pswd])) + ->send(); + } + + return false; + } + + /** + * Гениальный генератор пароля + * + * 35 * 19 * 9 = 5985 комбинаций + * + * @return string|null + */ + public static function passwordGenerate(): ?string + { + return match (rand(1, 35)) { + 1 => 'салазки', + 2 => 'запчасти', + 3 => 'инструменты', + 4 => 'детали', + 5 => 'компоненты', + 6 => 'ремни', + 7 => 'шестерни', + 8 => 'блоки', + 9 => 'коронки', + 10 => 'вал', + 11 => 'пыльник', + 12 => 'шкив', + 13 => 'станок', + 14 => 'сальник', + 15 => 'кольцо', + 16 => 'цепь', + 17 => 'редуктор', + 18 => 'фильтр', + 19 => 'клапан', + 20 => 'фару', + 21 => 'мотор', + 22 => 'подшипник', + 23 => 'болт', + 24 => 'стартер', + 25 => 'двигатель', + 26 => 'трубку', + 27 => 'прокладку', + 28 => 'помпу', + 29 => 'запчасть', + 30 => 'втулку', + 31 => 'уплотнение', + 32 => 'ролик', + 33 => 'датчик', + 34 => 'насос', + default => 'машину' + } + . ' ' . match (rand(1, 15)) { + 1 => 'забыли', + 2 => 'отжали', + 3 => 'забрали', + 4 => 'порвали', + 5 => 'украли', + 6 => 'обменяли', + 7 => 'угнали', + 8 => 'взорвали', + 9 => 'поломали', + 1 => 'доломали', + 11 => 'утопили', + 12 => 'испортили', + 13 => 'добили', + 14 => 'разбили', + default => 'сломали' + } + . ' ' . match (rand(1, 9)) { + 1 => 'закажу', + 2 => 'найду', + 3 => 'отыщу', + 4 => 'запрошу', + 5 => 'поищу', + 6 => 'оформлю', + 7 => 'заменю', + 8 => 'поменяю', + default => 'куплю' + } + . ' в скиллпартсе'; + } + + /** + * Пересоздать ключ подтверждения регистрации и пароль к аккаунту + * + * @return bool + */ + public function verifyRegenerate(): bool + { + $this->pswd = static::passwordGenerate(); + $this->vrfy = yii::$app->security->generateRandomString(); + + return $this->update() > 0 ? true : false; + } } diff --git a/mirzaev/skillparts/system/models/AccountForm.php b/mirzaev/skillparts/system/models/AccountForm.php index 634ac4a..7360abd 100644 --- a/mirzaev/skillparts/system/models/AccountForm.php +++ b/mirzaev/skillparts/system/models/AccountForm.php @@ -37,37 +37,45 @@ class AccountForm extends Model [ [ 'mail', - 'pswd' ], 'required', 'message' => 'Заполните поле' ], - // Обязательные поля для регистрации + // Обязательные поля для аутентификации [ [ - 'rept', - 'pols' + 'pswd', ], 'required', 'message' => 'Заполните поле', - 'on' => self::SCENARIO_REGISTRATION + 'on' => self::SCENARIO_AUTHENTICATION ], + // Обязательные поля для регистрации + // [ + // [ + // 'rept', + // 'pols' + // ], + // 'required', + // 'message' => 'Заполните поле', + // 'on' => self::SCENARIO_REGISTRATION + // ], // Повтор пароля - [ - 'rept', - 'compare', - 'compareAttribute' => 'pswd', - 'message' => "Пароли не совпадают", - 'on' => self::SCENARIO_REGISTRATION, - ], + // [ + // 'rept', + // 'compare', + // 'compareAttribute' => 'pswd', + // 'message' => "Пароли не совпадают", + // 'on' => self::SCENARIO_REGISTRATION, + // ], // Принятие политики конфидециальности - [ - 'pols', - 'compare', - 'compareValue' => 'on', - 'message' => "Чтобы продолжить примите нашу политику конфидециальности", - 'on' => self::SCENARIO_REGISTRATION, - ], + // [ + // 'pols', + // 'compare', + // 'compareValue' => 'on', + // 'message' => "Чтобы продолжить примите нашу политику конфидециальности", + // 'on' => self::SCENARIO_REGISTRATION, + // ], // Функция "Запомнить меня" [ 'auto', @@ -180,15 +188,26 @@ class AccountForm extends Model // Запись параметров $this->account->mail = $this->mail; - $this->account->pswd = yii::$app->security->generatePasswordHash($this->pswd); + // $this->account->pswd = yii::$app->security->generatePasswordHash(Account::passwordGenerate()); + $this->account->pswd = $this->pswd = Account::passwordGenerate(); + + if (($account = Account::findByMail($this->mail)) || isset($account) && $account->vrfy !== true) { + // Аккаунт найден, но не подтверждён + + // Удаление аккаунта (сейчас его создадим снова) + $account->delete(); + } // Регистрация if ($this->account->save()) { - // Успешно завершена регистрация + // Успешно завершена регистрация или обновлены данные не до конца зарегистрировавшегося пользователя // Генерация индекса Account::generateIndexes([$this->account]); + // Отправка письма для подтверждения почты + $this->account->sendMailVerify(); + return true; } } diff --git a/mirzaev/skillparts/system/models/Dellin.php b/mirzaev/skillparts/system/models/Dellin.php index c4ebcce..8bb26d1 100644 --- a/mirzaev/skillparts/system/models/Dellin.php +++ b/mirzaev/skillparts/system/models/Dellin.php @@ -46,10 +46,10 @@ class Dellin extends Document /** * Поиск по идентификатору терминала * - * @param string $id Идентификатор терминала + * @param int $id Идентификатор терминала * @param bool $terminal_data_only Запрос только данных терминала */ - public static function searchByTerminalId(string $id, bool $terminal_data_only = false): bool|static|array|null|ArangoDBDocument + public static function searchByTerminalId(int $id, bool $terminal_data_only = false): bool|static|array|null|ArangoDBDocument { if ($terminal_data_only) { return static::find()->foreach(['terminal' => self::collectionName() . '.data["terminals"]["terminal"]'])->where(['terminal["id"] == "' . $id . '"'])->select('terminal')->createCommand()->execute()->getAll()[0]; diff --git a/mirzaev/skillparts/system/models/Order.php b/mirzaev/skillparts/system/models/Order.php index 95184f1..87702a0 100644 --- a/mirzaev/skillparts/system/models/Order.php +++ b/mirzaev/skillparts/system/models/Order.php @@ -465,22 +465,58 @@ class Order extends Document implements DocumentInterface // Доставка автоматическая try { - // Инициализация доставки Dellin (автоматическая) - $connection['delivery'] = Dellin::calcDeliveryAdvanced( - $connection['account']['opts']['delivery_from_terminal'], - yii::$app->user->identity->opts['delivery_to_terminal'], - (int) ($connection['product']['wght'] ?? 0), - (int) ($connection['product']['dmns']['x'] ?? 0), - (int) ($connection['product']['dmns']['y'] ?? 0), - (int) ($connection['product']['dmns']['z'] ?? 0), - count($connection['order_edge_supply']) - ); + // Инициализация данных геолокации + try { + $from = (int) $connection['account']['opts']['delivery_from_terminal'] ?? Settings::search()->delivery_from_default ?? 36; + } catch (Exception $e) { + $from = (int) Settings::search()->delivery_from_default ?? 36; + } + + try { + $to = (int) yii::$app->user->identity->opts['delivery_to_terminal'] ?? 36; + } catch (Exception $e) { + $to = 36; + } + + if ($buffer_connection = $connection['product']['bffr']["$from-$to"] ?? false) { + // Найдены данные доставки в буфере + + if (time() < $buffer_connection['expires']) { + // Срок хранения не превышен, информация актуальна + + // Запись в буфер вывода + $connection['delivery'] = $buffer_connection['data']; + } + } else { + // Инициализация инстанции продукта в базе данных + $product = Product::searchByCatn($connection['product']['catn']); + + // Инициализация доставки Dellin (автоматическая) + $product->bffr = ($product->bffr ?? []) + [ + "$from-$to" => [ + 'data' => $connection['delivery'] = Dellin::calcDeliveryAdvanced( + $from, + $to, + (int) ($connection['product']['wght'] ?? 0), + (int) ($connection['product']['dmns']['x'] ?? 0), + (int) ($connection['product']['dmns']['y'] ?? 0), + (int) ($connection['product']['dmns']['z'] ?? 0), + count($connection['order_edge_supply']) + ), + 'expires' => time() + 86400 + ] + ]; + + // Отправка в базу данных + $product->update(); + } } catch (Exception $e) { $connection['delivery']['error'] = true; - var_dump($e->getMessage()); - var_dump($e->getTrace()); - var_dump($e->getFile()); die; + // var_dump($e->getMessage()); + // var_dump($e->getTrace()); + // var_dump($e->getFile()); + // die; // var_dump(json_decode($e->getMessage(), true)['errors']); die; } @@ -491,23 +527,59 @@ class Order extends Document implements DocumentInterface // Доставка самолётом try { - // Инициализация доставки Dellin (самолётом) - $connection['delivery'] = Dellin::calcDeliveryAdvanced( - $connection['account']['opts']['delivery_from_terminal'], - yii::$app->user->identity->opts['delivery_to_terminal'], - (int) ($connection['product']['wght'] ?? 0), - (int) ($connection['product']['dmns']['x'] ?? 0), - (int) ($connection['product']['dmns']['y'] ?? 0), - (int) ($connection['product']['dmns']['z'] ?? 0), - count($connection['order_edge_supply']), - avia: true - ); + // Инициализация данных геолокации + try { + $from = (int) $connection['account']['opts']['delivery_from_terminal'] ?? Settings::search()->delivery_from_default ?? 36; + } catch (Exception $e) { + $from = (int) Settings::search()->delivery_from_default ?? 36; + } + + try { + $to = (int) yii::$app->user->identity->opts['delivery_to_terminal'] ?? 36; + } catch (Exception $e) { + $to = 36; + } + + if ($buffer_connection = $connection['product']['bffr']["$from-$to-avia"] ?? false) { + // Найдены данные доставки в буфере + + if (time() < $buffer_connection['expires']) { + // Срок хранения не превышен, информация актуальна + + // Запись в буфер вывода + $connection['delivery'] = $buffer_connection['data']; + } + } else { + // Инициализация инстанции продукта в базе данных + $product = Product::searchByCatn($connection['product']['catn']); + + // Инициализация доставки Dellin (автоматическая) + $product->bffr = ($product->bffr ?? []) + [ + "$from-$to-avia" => [ + 'data' => $connection['delivery'] = Dellin::calcDeliveryAdvanced( + $from, + $to, + (int) ($connection['product']['wght'] ?? 0), + (int) ($connection['product']['dmns']['x'] ?? 0), + (int) ($connection['product']['dmns']['y'] ?? 0), + (int) ($connection['product']['dmns']['z'] ?? 0), + count($connection['order_edge_supply']), + avia: true + ), + 'expires' => time() + 86400 + ] + ]; + + // Отправка в базу данных + $product->update(); + } } catch (Exception $e) { $connection['delivery']['error'] = true; - var_dump($e->getMessage()); - var_dump($e->getTrace()); - var_dump($e->getFile()); die; + // var_dump($e->getMessage()); + // var_dump($e->getTrace()); + // var_dump($e->getFile()); + // die; // var_dump(json_decode($e->getMessage(), true)['errors']); die; } diff --git a/mirzaev/skillparts/system/models/Product.php b/mirzaev/skillparts/system/models/Product.php index 62edebb..e4739ce 100644 --- a/mirzaev/skillparts/system/models/Product.php +++ b/mirzaev/skillparts/system/models/Product.php @@ -82,7 +82,8 @@ class Product extends Document 'dmns', 'wght', 'imgs', - 'time' + 'time', + 'bffr', ] ); } @@ -103,6 +104,7 @@ class Product extends Document 'wght' => 'Вес (wght)', 'imgs' => 'Изображения (imgs)', 'time' => 'Срок доставки (time)', + 'bffr' => 'Буфер', 'file_excel' => 'Документ (file_excel)', 'file_image' => 'Изображение (file_image)', 'group' => 'Группа (group)' diff --git a/mirzaev/skillparts/system/models/Settings.php b/mirzaev/skillparts/system/models/Settings.php index 9465304..61842a4 100644 --- a/mirzaev/skillparts/system/models/Settings.php +++ b/mirzaev/skillparts/system/models/Settings.php @@ -26,7 +26,8 @@ class Settings extends Document parent::attributes(), [ 'search_period', - 'search_connect_keep' + 'search_connect_keep', + 'delivery_from_default' ] ); } @@ -40,7 +41,8 @@ class Settings extends Document parent::attributeLabels(), [ 'search_period' => 'Поисковый период', - 'search_connect_keep' => 'Режим удержания' + 'search_connect_keep' => 'Режим удержания', + 'delivery_from_default' => 'Место отправки поставки по умолчанию' ] ); } @@ -55,7 +57,8 @@ class Settings extends Document [ [ [ - 'search_period' + 'search_period', + 'delivery_from_default' ], 'integer', 'message' => '{attribute} должен хранить цифровое значение' @@ -70,4 +73,14 @@ class Settings extends Document ] ); } + + /** + * Найти активную запись с настройками + * + * @todo Доделать + */ + public static function search(): ?self + { + return static::findOne(['active' => true]); + } } diff --git a/mirzaev/skillparts/system/models/connection/Dellin.php b/mirzaev/skillparts/system/models/connection/Dellin.php index 3cf3460..335ac11 100644 --- a/mirzaev/skillparts/system/models/connection/Dellin.php +++ b/mirzaev/skillparts/system/models/connection/Dellin.php @@ -8,7 +8,8 @@ use yii; use yii\base\Model; use app\models\Dellin as DellinModel; - +use app\models\Product; +use app\models\Settings; use GuzzleHttp\Client as Guzzle; use GuzzleHttp\Exception\ClientException as GuzzleException; @@ -54,15 +55,14 @@ class Dellin extends Model // ]) // }); // } - /** * Рассчет доставки (расширенный) * * Рассчет нескольких товаров идет через простое перемножение результатов доставки одного товара * В API всегда идет рассчет для одного товара, так было решено * - * @param string $from Идентификатор терминала Dellin - * @param string $to Идентификатор терминала Dellin + * @param int $from Идентификатор терминала Dellin + * @param int $to Идентификатор терминала Dellin * @param int $weight Вес (г) * @param int $x Ширина (cм) * @param int $y Высота (cм) @@ -74,8 +74,9 @@ class Dellin extends Model * @todo Загружать помимо терминалов ещё и адреса, чтобы доделать доставку малогабаритных грузов * Разрабраться с параметрами 0,54м * 0,39м * 0,39м (0.082134м) и 0.1 куб метр в чем разница */ - public static function calcDeliveryAdvanced(string $from, string $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): array { + return self::handle(function () use ($from, $to, $weight, $x, $y, $z, $amount, $avia) { // Всё готово к работе @@ -85,7 +86,7 @@ class Dellin extends Model // Значения по умолчанию, если указан 0 $x === 0 and $x = 25; - $y === 0 and $y = 55; + $y === 0 and $y = 50; $z === 0 and $z = 25; $weight === 0 and $weight = 300; diff --git a/mirzaev/skillparts/system/views/account/index.php b/mirzaev/skillparts/system/views/account/index.php index d81ecf7..1aa2743 100644 --- a/mirzaev/skillparts/system/views/account/index.php +++ b/mirzaev/skillparts/system/views/account/index.php @@ -72,12 +72,18 @@ use app\models\AccountForm; diff --git a/mirzaev/skillparts/system/views/account/verify.php b/mirzaev/skillparts/system/views/account/verify.php new file mode 100644 index 0000000..e45f856 --- /dev/null +++ b/mirzaev/skillparts/system/views/account/verify.php @@ -0,0 +1,11 @@ +
$delivery_icon $delivery дн
+$delivery_icon $delivery дн
Ваш пароль: "= $password ?? 'Ошибка' ?>"
+ Нажимая на кнопку ниже вы соглашаетесь с политикой конфиденциальности + Принять и подтвердить +