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

This commit is contained in:
Arsen Mirzaev Tatyano-Muradovich 2021-07-07 06:54:33 +10:00
parent 83295650c9
commit fc59eff6db
26 changed files with 808 additions and 195 deletions

View File

@ -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');
}
}
/**
* Страница: "Корзина"
*

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace app\controllers;
use yii;
use yii\web\Controller;
use app\models\Account;
use yii\web\Response;
class VerifyController extends Controller
{
public function actionIndex(string $vrfy = null): string|Response
{
if (isset($vrfy)) {
// Подтверждение регистрации
if (Account::verification($vrfy)) {
// Успешно подтверждена регистрация
return $this->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');
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 Ширина ()
* @param int $y Высота ()
@ -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;

View File

@ -72,12 +72,18 @@ use app\models\AccountForm;
<?php if ($registration ?? false) : ?>
<script defer>
document.addEventListener('DOMContentLoaded', function() {
let registration_start_macros = function() {
let form = document.getElementById('<?= $form_id ?>');
$(form).on('afterInit', function(e) {
registration_start(form);
});
}, false);
};
if (document.readyState === "complete") {
registration_start_macros();
} else {
document.addEventListener('DOMContentLoaded', registration_start_macros(), false);
}
</script>
<?php endif ?>

View File

@ -0,0 +1,11 @@
<div class="container d-flex flex-column">
<div class="my-auto">
<div class="col-md-10 col-lg-8 mx-auto p-5 alert alert_white d-flex flex-column">
<h4 class="text-center"><b>Подтвердите аккаунт</b></h4>
<p class="text-center mb-5">Мы выслали вам письмо с паролем и ссылкой на активацию</p>
<a class="btn button_blue button_clean mx-auto" type="button" onclick="return verify_resend();">Повторить</a>
</div>
</div>
</div>
<script src="/js/verify.js" defer></script>

View File

@ -95,7 +95,7 @@ use DateTime;
<input id="cart_list_amnt_{$connection['supply']['catn']}" class="form-control text-center" type="text" value="{$connection['amount']}" onchange="return cart_list_amount_update('{$connection['supply']['catn']}', this)" aria-invalid="false">
</div>
<div class="col-2 my-auto text-right">
<p>$delivery_icon $delivery дн</p>
<p title="Ориентировочно">$delivery_icon $delivery дн</p>
</div>
<div class="col-2 my-auto mr-3 text-right">
$cost
@ -134,7 +134,7 @@ use DateTime;
<span id="cart_cost">0</span>
руб
</p>
<a class="btn button_clean button_blue" title="Оформить заказ" href="/pay" role="button" onclick="return cart_pay();">
<a class="btn button_clean button_blue" title="Оформить заказ" href="/orders" role="button" onclick="return cart_request();">
Оформить заказ
</a>
</div>
@ -143,3 +143,12 @@ use DateTime;
<script src="/js/textarea.js" defer></script>
<script src="/js/cart.js" defer></script>
<script defer>
if (document.readyState === "complete") {
cart_cost_calculate();
} else {
document.addEventListener('DOMContentLoaded', function() {
cart_cost_calculate();
}, false);
}
</script>

View File

@ -2,16 +2,16 @@
use yii\helpers\Html;
$this->title = $name;
$this->title = $title;
?>
<div id="page_error" class="container d-flex flex-column">
<div class="my-auto">
<h1 class="text-center mb-4 gilroy"><b><?= Html::encode($this->title) ?></b></h1>
<h1 class="text-center mb-4 gilroy"><b><?= Html::encode($title) ?></b></h1>
<div class="col-md-8 col-lg-6 mx-auto alert alert_white">
<?= nl2br(Html::encode($message)) ?>
<div class="col-md-10 col-lg-8 mx-auto p-5 alert alert_white">
<?= nl2br(Html::encode($description)) ?>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,17 @@
<div style="padding: 0 14%;">
<div style="background: #fff; padding: 25px 0;">
<a title="SkillParts" href="https://skillparts.ru">
<img style="width: 150px;" src="https://skillparts.ru/img/logos/skillparts.svg" alt="SkillParts">
</a>
</div>
<div style="background: #f0eefb; padding: 40px; margin: 30px 0;">
<h3 style="text-align: center; margin-bottom: 30px;"><b>Подтвердите регистрацию</b></h3>
<p style="margin: 0 40px; margin-bottom: 8px;"><b>Ваш пароль: </b>"<?= $password ?? 'Ошибка' ?>"</p>
<small style="display: block; margin: 0 40px; margin-bottom: 40px;">Нажимая на кнопку ниже вы соглашаетесь с <a href="https://skillparts.ru/policy">политикой конфиденциальности</a></small>
<a style="display: block; text-align: center;" href="https://skillparts.ru/verify/<?= $vrfy ?? '' ?>">Принять и подтвердить</a>
</div>
<div style="background: #fff;">
<small>Вы получили это сообщение потому, что на ваш почтовый адрес была совершена регистрация</small>
<small>Если это были не вы, проверьте безопасность ваших аккаунтов и свяжитесь с администрацией</small>
</div>
</div>

View File

@ -4,7 +4,7 @@
<article class="p-5 rounded overflow-hidden">
<div class="row mb-5">
<div class="col">
<h3 class="mb-5 text-center"><b>Политика конфидециальности</b></h3>
<h3 class="mb-5 text-center"><b>Политика конфиденциальности</b></h3>
В данной Политике обработки персональных данных (далее Политика) мы информируем Вас о порядке обработки Ваших персональных данных при использовании нашего веб-сайта https://skillparts.ru/ (далее - «Сайт») в целях исполнения заключенных договоров.
</br></br>

View File

@ -13,12 +13,12 @@
}
a {
color: #0b3397;
color: #123EAB;
cursor: pointer;
}
a:hover {
color: #001752;
color: #09246a;
}
p {

View File

@ -142,86 +142,96 @@ function registration_start(form, type) {
// Удаление кнопок аутентификации
form.children[4].remove();
// Инициализация поля ввода пароля
let password = form.children[3];
// Инициализация поля ввода почты
let mail = form.children[2];
// Изменение стиля
password.classList.add('mb-2');
// // Инициализация поля ввода пароля
// let password = form.children[3];
// Инициализация кнопки регистрации
let registration = form.children[4];
// Изменение размера
// Изменение отступа поля
mail.classList.add('mb-4');
// // Изменение стиля
// password.classList.add('mb-2');
// Удаление поля ввода пароля
form.children[3].remove();
// Изменение размера кнопки регистрации
registration.classList.remove('btn-sm');
registration.classList.add('btn');
// Изменение вызываемой функции
registration.setAttribute('onclick', 'return registration_end(this.parentElement);');
// Инициализация оболочки поля повтора пароля
let password_repeat_wrap = document.createElement('div');
password_repeat_wrap.setAttribute('class', 'mb-3 field-accountform-rept required');
// // Инициализация оболочки поля повтора пароля
// let password_repeat_wrap = document.createElement('div');
// password_repeat_wrap.setAttribute('class', 'mb-3 field-accountform-rept required');
// Инициализация поля повтора пароля
let password_repeat = document.createElement('input');
password_repeat.setAttribute('id', 'accountform-rept' + postfix);
password_repeat.classList.add('form-control');
password_repeat.setAttribute('type', 'password');
password_repeat.setAttribute('name', 'AccountForm[rept]');
password_repeat.setAttribute('placeholder', 'Повтор пароля');
password_repeat.setAttribute('aria-required', 'true');
password_repeat.setAttribute('aria-invalid', 'true');
// // Инициализация поля повтора пароля
// let password_repeat = document.createElement('input');
// password_repeat.setAttribute('id', 'accountform-rept' + postfix);
// password_repeat.classList.add('form-control');
// password_repeat.setAttribute('type', 'password');
// password_repeat.setAttribute('name', 'AccountForm[rept]');
// password_repeat.setAttribute('placeholder', 'Повтор пароля');
// password_repeat.setAttribute('aria-required', 'true');
// password_repeat.setAttribute('aria-invalid', 'true');
// Инициализация элемента с текстом ошибок поля повтора пароля
let password_repeat_errors = document.createElement('p');
password_repeat_errors.setAttribute('class', 'help-block help-block-error small');
// // Инициализация элемента с текстом ошибок поля повтора пароля
// let password_repeat_errors = document.createElement('p');
// password_repeat_errors.setAttribute('class', 'help-block help-block-error small');
// Инициализация оболочки элемента с подтверждением политики персональных данных
let private_policy_wrap = document.createElement('div');
private_policy_wrap.setAttribute('class', 'mb-3 field-accountform-pols required');
// // Инициализация оболочки элемента с подтверждением политики персональных данных
// let private_policy_wrap = document.createElement('div');
// private_policy_wrap.setAttribute('class', 'mb-3 field-accountform-pols required');
// Инициализация оболочки для класса checkbox для элемента с подтверждением политики персональных данных
let private_policy_checkbox = document.createElement('div');
private_policy_checkbox.classList.add('checkbox');
private_policy_checkbox.classList.add('text-center');
// // Инициализация оболочки для класса checkbox для элемента с подтверждением политики персональных данных
// let private_policy_checkbox = document.createElement('div');
// private_policy_checkbox.classList.add('checkbox');
// private_policy_checkbox.classList.add('text-center');
// Инициализация оболочки для класса label для элемента с подтверждением политики персональных данных
let private_policy_label = document.createElement('label');
private_policy_label.setAttribute('for', 'accountform-pols');
// // Инициализация оболочки для класса label для элемента с подтверждением политики персональных данных
// let private_policy_label = document.createElement('label');
// private_policy_label.setAttribute('for', 'accountform-pols');
// Инициализация скрытого элемента с подтверждением политики персональных данных
let private_policy_hidden = document.createElement('input');
private_policy_hidden.setAttribute('type', 'hidden');
private_policy_hidden.setAttribute('name', 'AccountForm[pols]');
private_policy_hidden.setAttribute('value', '0');
// // Инициализация скрытого элемента с подтверждением политики персональных данных
// let private_policy_hidden = document.createElement('input');
// private_policy_hidden.setAttribute('type', 'hidden');
// private_policy_hidden.setAttribute('name', 'AccountForm[pols]');
// private_policy_hidden.setAttribute('value', '0');
// Инициализация элемента с подтверждением политики персональных данных
let private_policy = document.createElement('input');
private_policy.setAttribute('id', 'accountform-pols' + postfix);
private_policy.setAttribute('type', 'checkbox');
private_policy.setAttribute('name', 'AccountForm[pols]');
private_policy.setAttribute('placeholder', 'Политика конфиденциальности');
// // Инициализация элемента с подтверждением политики персональных данных
// let private_policy = document.createElement('input');
// private_policy.setAttribute('id', 'accountform-pols' + postfix);
// private_policy.setAttribute('type', 'checkbox');
// private_policy.setAttribute('name', 'AccountForm[pols]');
// private_policy.setAttribute('placeholder', 'Политика конфиденциальности');
// Инициализация оболочки элемента с текстом элемента с подтверждением политики персональных данных
let private_policy_text_wrap = document.createElement('small');
private_policy_text_wrap.setAttribute('class', 'ml-2');
// // Инициализация оболочки элемента с текстом элемента с подтверждением политики персональных данных
// let private_policy_text_wrap = document.createElement('small');
// private_policy_text_wrap.setAttribute('class', 'ml-2');
// Инициализация элемента с текстом элемента с подтверждением политики персональных данных
let private_policy_text = document.createElement('a');
private_policy_text.setAttribute('href', '/policy');
private_policy_text.innerText = 'Политика';
// // Инициализация элемента с текстом элемента с подтверждением политики персональных данных
// let private_policy_text = document.createElement('a');
// private_policy_text.setAttribute('href', '/policy');
// private_policy_text.innerText = 'Политика';
// Запись в документ
form.insertBefore(password_repeat_wrap, registration);
password_repeat_wrap.appendChild(password_repeat);
password_repeat_wrap.appendChild(password_repeat_errors);
form.insertBefore(private_policy_wrap, registration);
private_policy_wrap.appendChild(private_policy_checkbox);
private_policy_checkbox.appendChild(private_policy_label);
private_policy_label.appendChild(private_policy);
private_policy_label.appendChild(private_policy_text_wrap);
private_policy_text_wrap.appendChild(private_policy_text);
private_policy_text_wrap.appendChild(document.createTextNode(' конфиденциальности'));
// // Запись в документ
// form.insertBefore(password_repeat_wrap, registration);
// password_repeat_wrap.appendChild(password_repeat);
// password_repeat_wrap.appendChild(password_repeat_errors);
// form.insertBefore(private_policy_wrap, registration);
// private_policy_wrap.appendChild(private_policy_checkbox);
// private_policy_checkbox.appendChild(private_policy_label);
// private_policy_label.appendChild(private_policy);
// private_policy_label.appendChild(private_policy_text_wrap);
// private_policy_text_wrap.appendChild(private_policy_text);
// private_policy_text_wrap.appendChild(document.createTextNode(' конфиденциальности'));
// Инициализация заголовка
let title = form.children[1];

View File

@ -42,9 +42,9 @@ function cart_delete() {
/**
* Сформировать заказ
*/
function cart_pay() {
function cart_request() {
$.ajax({
url: '/order/pay',
url: '/order/request',
type: 'post',
dataType: 'json',
data: {
@ -298,8 +298,6 @@ function cart_list_comment_save(catn, element) {
return true;
}
cart_cost_calculate();
function cart_response(data, status) {
// Обработка ответов

View File

@ -141,4 +141,4 @@ function menu_error(data, status) {
// Обновление документа
$('meta[name=csrf-token]').prop("content", data._csrf);
}
}
}

View File

@ -2,8 +2,8 @@ function reinitialization(target) {
// Уничтожает все внешние файлы загруженные внутри блока с переданным ID и загружает их в <head> и <body>
if (target !== undefined) {
links = target.getElementsByTagName('link');
scripts = target.getElementsByTagName('script');
let links = target.getElementsByTagName('link');
let scripts = target.getElementsByTagName('script');
// Запись CSS
for (link of links) {
@ -16,14 +16,19 @@ function reinitialization(target) {
// Запись JS
for (script of scripts) {
new_script = document.createElement("script");
new_script.src = script.src;
document.getElementsByTagName("body")[0].appendChild(new_script);
script.remove();
if (script.getAttribute('src') !== null) {
new_script = document.createElement("script");
new_script.src = script.src;
document.getElementsByTagName("body")[0].appendChild(new_script);
} else {
eval(script.innerText);
}
// script.remove(); По каким-то причинам не работает, надо бы доделать
}
return true;
}
return false;
};
};

View File

@ -0,0 +1,59 @@
/**
* Записать в корзину (создать корзину, если не существует)
*/
function verify_resend() {
// Инициализация
$.ajax({
url: '/verify/send',
type: 'post',
dataType: 'json',
success: verify_response_success,
error: verify_response_error
});
return false;
}
function verify_response(data, status) {
// Обработка ответов
// Основной блок
if (data.main !== undefined) {
main = document.getElementsByTagName('main')[0];
// Обновление документа
main.innerHTML = data.main;
// Реинициализация
reinitialization(main);
}
// Перенаправление
if (data.redirect !== undefined) {
// Перенаправление
history.pushState({}, document.title, data.redirect);
}
// CSRF-токен
if (data._csrf !== undefined) {
// Обновление документа
$('meta[name=csrf-token]').prop("content", data._csrf);
}
}
function verify_response_success(data, status) {
// Обработка ответов от удавшихся запросов
verify_response(data, status);
}
function verify_response_error(data, status) {
// Обработка ответов от неудавшихся запросов
// Инициализвация
data = data.responseJSON;
verify_response(data, status);
}