Доработка поиска, поиск аттрибутов

This commit is contained in:
RedHood 2021-01-31 11:31:22 +10:00
parent 5d18c95dc4
commit 25709ee380
16 changed files with 656 additions and 250 deletions

View File

@ -22,11 +22,9 @@ class MainController extends Controller
} }
/** /**
* Displays homepage. * Главная страница
*
* @return string
*/ */
public function actionIndex() public function actionIndex(): string|array
{ {
if (Yii::$app->request->isAjax) { if (Yii::$app->request->isAjax) {
// AJAX-POST-запрос // AJAX-POST-запрос

View File

@ -1,4 +1,5 @@
<?php <?php
declare(strict_types=1);
namespace app\controllers; namespace app\controllers;
@ -8,6 +9,7 @@ use yii\web\Controller;
use yii\web\Response; use yii\web\Response;
use yii\web\Cookie; use yii\web\Cookie;
use yii\web\UploadedFile; use yii\web\UploadedFile;
use app\models\Supply; use app\models\Supply;
use app\models\SupplyGroup; use app\models\SupplyGroup;
@ -56,10 +58,16 @@ class ProfileController extends Controller
]); ]);
} }
public function actionIndex() /**
* Страница с настройками аккаунта
*/
public function actionIndex(): string|array
{ {
// Инициализация // Инициализация
$model = new Supply(Yii::$app->request->post('Supply') ?? Yii::$app->request->get('Supply')); $model = Yii::$app->user->identity;
// Генерация
$sidebar = $this->renderPartial('sidebar');
if (Yii::$app->request->isAjax) { if (Yii::$app->request->isAjax) {
// AJAX-POST-запрос // AJAX-POST-запрос
@ -67,13 +75,39 @@ class ProfileController extends Controller
Yii::$app->response->format = Response::FORMAT_JSON; Yii::$app->response->format = Response::FORMAT_JSON;
return [ return [
'main' => $this->renderPartial('index'), 'main' => $this->renderPartial('index', compact('model', 'sidebar')),
'redirect' => '/profile', 'redirect' => '/profile',
'_csrf' => Yii::$app->request->getCsrfToken() '_csrf' => Yii::$app->request->getCsrfToken()
]; ];
} }
return $this->render('index', compact('model')); return $this->render('index', compact('model', 'sidebar'));
}
/**
* Страницка поставок
*/
public function actionSupplies(): string|array
{
// Инициализация
$model = new Supply(Yii::$app->request->post('Supply') ?? Yii::$app->request->get('Supply'));
// Генерация
$sidebar = $this->renderPartial('sidebar', compact('model'));
if (Yii::$app->request->isAjax) {
// AJAX-POST-запрос
Yii::$app->response->format = Response::FORMAT_JSON;
return [
'main' => $this->renderPartial('supplies', compact('model', 'sidebar')),
'redirect' => '/profile/supplies',
'_csrf' => Yii::$app->request->getCsrfToken()
];
}
return $this->render('supplies', compact('model', 'sidebar'));
} }
public function actionImport() public function actionImport()
@ -82,6 +116,9 @@ class ProfileController extends Controller
$model = new Supply(Yii::$app->request->post('Supply') ?? Yii::$app->request->get('Supply')); $model = new Supply(Yii::$app->request->post('Supply') ?? Yii::$app->request->get('Supply'));
$model->scenario = $model::SCENARIO_IMPORT; $model->scenario = $model::SCENARIO_IMPORT;
// Генерация
$sidebar = $this->renderPartial('sidebar', compact('model'));
if (Yii::$app->request->isAjax) { if (Yii::$app->request->isAjax) {
// AJAX-POST-запрос // AJAX-POST-запрос
@ -94,12 +131,12 @@ class ProfileController extends Controller
} }
return [ return [
'main' => $this->renderPartial('index', compact('model')), 'main' => $this->renderPartial('supplies', compact('model', 'sidebar')),
'_csrf' => Yii::$app->request->getCsrfToken() '_csrf' => Yii::$app->request->getCsrfToken()
]; ];
} }
return $this->render('index', compact('model')); return $this->render('supplies', compact('model', 'sidebar'));
} }
public static function readGroups() public static function readGroups()

View File

@ -13,7 +13,7 @@ class SearchController extends Controller
public function actionIndex(): array|string public function actionIndex(): array|string
{ {
// Инициализация // Инициализация
$request = Yii::$app->request->post('request') ?? Yii::$app->request->get('q'); $query = Yii::$app->request->post('request') ?? Yii::$app->request->get('q');
if (Yii::$app->request->post('type') === 'product' || Yii::$app->request->get('type') === 'product') { if (Yii::$app->request->post('type') === 'product' || Yii::$app->request->get('type') === 'product') {
// Поиск по продуктам // Поиск по продуктам
@ -51,8 +51,10 @@ class SearchController extends Controller
// Здесь запись истории запросов (в базе данных) // Здесь запись истории запросов (в базе данных)
// //
if ($response = Product::search($request)) { $limit = Yii::$app->request->isAjax ? 10 : 30;
// Данные найдены
if ($response = Product::searchByCatn($query, $limit)) {
// Данные найдены по поиску в полях Каталожного номера
// Запись ответа // Запись ответа
$return = [ $return = [
@ -66,9 +68,10 @@ class SearchController extends Controller
// Запись ответа // Запись ответа
$return['main'] = $this->renderPartial('/search/index', compact('response')); $return['main'] = $this->renderPartial('/search/index', compact('response'));
$return['search_line_window_hide'] = 1; $return['search_line_window_hide'] = 1;
$return['redirect'] = '/search?type=product&q=' . $request; $return['redirect'] = '/search?type=product&q=' . $query;
} }
} else { } else {
// Данные не найдены // Данные не найдены
Yii::$app->response->statusCode = 404; Yii::$app->response->statusCode = 404;

View File

@ -1,23 +1,39 @@
<?php <?php
declare(strict_types=1);
namespace app\models; namespace app\models;
use Yii; use Yii;
use yii\web\IdentityInterface; use yii\web\IdentityInterface;
use carono\exchange1c\interfaces\PartnerInterface; use carono\exchange1c\interfaces\PartnerInterface;
/**
* Аккаунт
*
* Реализует аккаунты пользователей и поставщиков
*/
class Account extends Document implements IdentityInterface, PartnerInterface class Account extends Document implements IdentityInterface, PartnerInterface
{ {
public static function collectionName() public $opts;
/**
* Имя коллекции
*/
public static function collectionName(): string
{ {
return 'account'; return 'account';
} }
public function attributes() /**
* Свойства
*/
public function attributes(): array
{ {
return array_merge( return array_merge(
parent::attributes(), parent::attributes(),
[ [
'auth',
'mail', 'mail',
'pswd', 'pswd',
'name', 'name',
@ -25,12 +41,38 @@ class Account extends Document implements IdentityInterface, PartnerInterface
'sity', 'sity',
'comp', 'comp',
'taxn', 'taxn',
'auth' 'onec',
'opts'
] ]
); );
} }
public function rules() /**
* Метки свойств
*/
public function attributeLabels(): array
{
return array_merge(
parent::attributeLabels(),
[
'auth' => 'Аутентификационный хеш',
'mail' => 'Почта',
'pswd' => 'Пароль',
'name' => 'Имя',
'simc' => 'Номер',
'sity' => 'Город',
'comp' => 'Компания',
'taxn' => 'ИНН',
'onec' => 'Данные 1C',
'opts' => 'Параметры'
]
);
}
/**
* Правила
*/
public function rules(): array
{ {
return array_merge( return array_merge(
parent::rules(), parent::rules(),
@ -42,24 +84,13 @@ class Account extends Document implements IdentityInterface, PartnerInterface
); );
} }
public function attributeLabels() /**
{ * Перед сохранением
return array_merge( *
parent::attributeLabels(), * @todo Подождать обновление от ебаного Yii2 и добавить
[ * проверку типов передаваемых параметров
'mail' => 'Почта', */
'pswd' => 'Пароль', public function beforeSave($data): bool
'name' => 'Имя',
'simc' => 'Номер',
'sity' => 'Город',
'comp' => 'Компания',
'taxn' => 'ИНН',
'auth' => 'Аутентификационный хеш'
]
);
}
public function beforeSave($data)
{ {
if (parent::beforeSave($data)) { if (parent::beforeSave($data)) {
if ($this->isNewRecord) { if ($this->isNewRecord) {
@ -71,70 +102,143 @@ class Account extends Document implements IdentityInterface, PartnerInterface
return false; return false;
} }
public function getExportFields1c($context = null) /**
* Чтение полей для экспорта из 1С
*/
public function getExportFields1c($context = null): array
{ {
return [ return [];
'Ид' => 'id',
'Наименование' => 'username',
'ПолноеНаименование' => 'full_name',
'Фамилия' => 'surname',
'Имя' => 'name',
];
} }
/**
* Чтение идентификатора
*
* @see IdentityInterface
*/
public function getId(): string public function getId(): string
{ {
return $this->_key; return self::collectionName() . '/' . $this->_key;
} }
/**
* Чтение идентификатора
*/
public function readId(): string public function readId(): string
{ {
return self::collectionName() . '/' . $this->getId(); return $this->getId();
} }
public function getAuthKey() /**
* Чтение аутентификационного ключа
*/
public function getAuthKey(): string
{ {
return $this->auth; return $this->auth;
} }
public static function findIdentity($_key) /**
* Идентификация
*
* @todo Подождать обновление от ебаного Yii2 и добавить
* проверку типов передаваемых параметров
*/
public static function findIdentity($_id): self
{ {
return static::findByKey($_key); return static::findById($_id);
} }
public static function findIdentityByAccessToken($pass, $type = null) /**
* Поиск по ключу
*
* @todo Подождать обновление от ебаного Yii2 и добавить
* проверку типов передаваемых параметров
*/
public static function findIdentityByAccessToken($pass, $type = null): self
{ {
return static::findOne(['pass' => $pass]); return static::findOne(['pass' => $pass]);
} }
public static function findByMail($mail) /**
* Поиск по почте
*
* @todo Подождать обновление Yii2 и добавить
* проверку типов передаваемых параметров
*/
public static function findByMail($mail): self
{ {
return static::findOne(['mail' => $mail]); return static::findOne(['mail' => $mail]);
} }
public static function findByKey($_key) /**
* Поиск по идентификатору
*
* @todo Подождать обновление Yii2 и добавить
* проверку типов передаваемых параметров
*/
public static function findById($_id): self
{ {
return static::findOne(['_key' => $_key]); return static::searchById($_id);
} }
public static function validateMail($mail) /**
* Проверка почты
*/
public static function validateMail(string $mail): bool
{ {
if (static::findByMail($mail)) { if (static::findByMail($mail)) {
// Почта найдена в базе данных // Почта найдена в базе данных
return false;
}
return true; return true;
} }
public function validatePassword($pswd) return false;
}
/**
* Проверка пароля
*/
public function validatePassword(string $pswd): bool
{ {
return Yii::$app->security->validatePassword($pswd, $this->pswd); return Yii::$app->security->validatePassword($pswd, $this->pswd);
} }
public function validateAuthKey($auth) /**
* Проверка аутентификационного ключа
*
* @todo Подождать обновление Yii2 и добавить
* проверку типов передаваемых параметров
*/
public function validateAuthKey($auth): bool
{ {
return $this->getAuthKey() === $auth; return $this->getAuthKey() === $auth;
} }
/**
* Записать параметр
*
* @param string $name Название параметра
* @param mixed $value Значение параметра
*/
public function writeOption(string $name, mixed $value = null): bool
{
// Запись
$this->opts[$name] = $value;
// Отправка
return $this->save();
}
/**
* Удалить параметр
*
* @param string $name Название параметра
*/
public function deleteOption(string $name): bool
{
// Удаление
unset($this->opts[$name]);
// Отправка
return $this->save();
}
} }

View File

@ -56,7 +56,7 @@ class AccountForm extends Model
$account = $this->getAccount(); $account = $this->getAccount();
if (!$account || !$account->validateMail($this->mail)) { if (!$account || $account->validateMail($this->mail)) {
// Проверка не пройдена // Проверка не пройдена
$this->addError($attribute, 'Почта уже привязана'); $this->addError($attribute, 'Почта уже привязана');

View File

@ -1,13 +1,31 @@
<?php <?php
declare(strict_types=1);
namespace app\models; namespace app\models;
use Yii; use Yii;
use mirzaev\yii2\arangodb\ActiveRecord; use mirzaev\yii2\arangodb\ActiveRecord;
use Exception;
/**
* Документ
*/
abstract class Document extends ActiveRecord abstract class Document extends ActiveRecord
{ {
public function attributes() /**
* Имя коллекции
*/
public static function collectionName(): string
{
return throw new Exception('Не установлено название коллекции');
}
/**
* Свойства
*/
public function attributes(): array
{ {
return [ return [
'_key', '_key',
@ -16,7 +34,10 @@ abstract class Document extends ActiveRecord
]; ];
} }
public function attributeLabels() /**
* Метки свойств
*/
public function attributeLabels(): array
{ {
return [ return [
'date' => 'Дата', 'date' => 'Дата',
@ -24,25 +45,36 @@ abstract class Document extends ActiveRecord
]; ];
} }
public function rules()
/**
* Правила
*
* @todo Добавить проверку существования аккаунта
*/
public function rules(): array
{ {
return [ return [
[ [
'writer', 'writer',
'string' 'string'
// Надо добавить проверку существования аккаунта
] ]
]; ];
} }
public function beforeSave($data) /**
* Перед сохранением
*
* @todo Подождать обновление от ебаного Yii2 и добавить
* проверку типов передаваемых параметров
*/
public function beforeSave($data): bool
{ {
if (parent::beforeSave($data)) { if (parent::beforeSave($data)) {
if ($this->isNewRecord) { if ($this->isNewRecord) {
} }
$this->date = time(); $this->date = time();
$this->writer = $this->writer ?? Yii::$app->user->identity->readId(); $this->writer = $this->writer ?? Yii::$app->user->id;
return true; return true;
} }
@ -50,11 +82,25 @@ abstract class Document extends ActiveRecord
return false; return false;
} }
/**
* Чтение идентификатора
*/
public function readId(): ?string public function readId(): ?string
{ {
return isset($this->_key) ? static::collectionName() . '/' . $this->_key : null; return isset($this->_key) && static::collectionName() ? static::collectionName() . '/' . $this->_key : null;
} }
/**
* Поиск по идентификатору
*/
public static function searchById(string $_id): ?static
{
return static::findOne(['_id' => $_id]);
}
/**
* Чтение количества записей
*/
public static function readAmount(): int public static function readAmount(): int
{ {
return static::find()->count(); return static::find()->count();

View File

@ -1,10 +1,17 @@
<?php <?php
declare(strict_types=1);
namespace app\models; namespace app\models;
/**
* Ребро
*/
abstract class Edge extends Document abstract class Edge extends Document
{ {
public function attributes() /**
* Свойства
*/
public function attributes(): array
{ {
return array_merge( return array_merge(
parent::attributes(), parent::attributes(),
@ -16,7 +23,10 @@ abstract class Edge extends Document
); );
} }
public function attributeLabels() /**
* Метки свойств
*/
public function attributeLabels(): array
{ {
return array_merge( return array_merge(
parent::attributeLabels(), parent::attributeLabels(),
@ -28,7 +38,10 @@ abstract class Edge extends Document
); );
} }
public function rules() /**
* Правила
*/
public function rules(): array
{ {
return array_merge( return array_merge(
parent::rules(), parent::rules(),
@ -49,10 +62,10 @@ abstract class Edge extends Document
/** /**
* Записать * Записать
*/ */
public function write(string $_from, string $_to, string $type = '', array $data = []): ?static public static function write(string $_from, string $_to, string $type = '', array $data = []): ?static
{ {
// Инициализация // Инициализация
$edge = isset($this->_key) ? $this : new static; $edge = new static;
// Настройка // Настройка
$edge->_from = $_from; $edge->_from = $_from;
@ -77,7 +90,14 @@ abstract class Edge extends Document
return $edge; return $edge;
} }
public function beforeSave($data)
/**
* Перед сохранением
*
* @todo Подождать обновление от ебаного Yii2 и добавить
* проверку типов передаваемых параметров
*/
public function beforeSave($data): bool
{ {
if (parent::beforeSave($data)) { if (parent::beforeSave($data)) {
if ($this->isNewRecord) { if ($this->isNewRecord) {

View File

@ -1,23 +1,52 @@
<?php <?php
declare(strict_types=1);
namespace app\models; namespace app\models;
use moonland\phpexcel\Excel; use moonland\phpexcel\Excel;
use mirzaev\yii2\arangodb\Query; use mirzaev\yii2\arangodb\Query;
/**
* Продукт (в ассортименте магазина)
*
* Представляет собой лот состоящий из предложений от поставщиков
*
* @see Supply Поставки для продуктов
*/
class Product extends Document class Product extends Document
{ {
/**
* Сценарий импорта из .excel докумекнт
*/
const SCENARIO_IMPORT = 'import'; const SCENARIO_IMPORT = 'import';
/**
* Сценарий записи товара
*/
const SCENARIO_WRITE = 'write'; const SCENARIO_WRITE = 'write';
public $file; /**
public $group; * Файл .excel для импорта товаров
*/
public Excel|null $file = null;
/**
* Группа в которой состоит товар
*/
public ProductGroup|null $group = null;
/**
* Имя коллекции
*/
public static function collectionName(): string public static function collectionName(): string
{ {
return 'product'; return 'product';
} }
/**
* Свойства
*/
public function attributes(): array public function attributes(): array
{ {
return array_merge( return array_merge(
@ -34,6 +63,30 @@ class Product extends Document
); );
} }
/**
* Метки свойств
*/
public function attributeLabels(): array
{
return array_merge(
parent::attributeLabels(),
[
'name' => 'Название (name)',
'ocid' => 'Идентификатор 1C (ocid)',
'catn' => 'Каталожный номер (catn)',
'oemn' => 'OEM номера (oemn)',
// 'data' => 'Данные товара (data)',
// 'cost' => 'Цены (cost)',
// 'time' => 'Сроки доставки (time)',
'file' => 'Документ',
'group' => 'Группа'
]
);
}
/**
* Правила
*/
public function rules(): array public function rules(): array
{ {
return array_merge( return array_merge(
@ -70,25 +123,13 @@ class Product extends Document
); );
} }
public function attributeLabels(): array /**
{ * Импорт товаров
return array_merge( *
parent::attributeLabels(), * На данный момент обрабатывает только импорт из
[ * файлов с расширением .excel
'name' => 'Название (name)', */
'ocid' => 'Идентификатор 1C (ocid)', public function import(): bool
'catn' => 'Каталожный номер (catn)',
'oemn' => 'OEM номера (oemn)',
// 'data' => 'Данные товара (data)',
// 'cost' => 'Цены (cost)',
// 'time' => 'Сроки доставки (time)',
'file' => 'Документ',
'group' => 'Группа'
]
);
}
public function import()
{ {
// Инициализация массива данных // Инициализация массива данных
$data = []; $data = [];
@ -140,47 +181,15 @@ class Product extends Document
return false; return false;
} }
public static function search(string $text): array
{
return (new Query)->limit(10)->search('product_search', ['id' => '_key', 'catn' => 'catn'], ['catn' => $text], 1);
}
private static function writeEdgeBetweenGroup(string $from, string $to): bool
{
// Инициализация
$edge = new SupplyEdgeSupplyGroup();
// Настройка
$edge->_from = $from;
$edge->_to = $to;
// Запись
return $edge->save();
}
private static function writeEdgeBetweenRequisite(string $from, string $to): bool
{
// Инициализация
$edge = new SupplyEdgeRequisite();
// Настройка
$edge->_from = $from;
$edge->_to = $to;
// Запись
return $edge->save();
}
public static function readById(string $_key): ?Product
{
return self::findOne(['_key' => $_key]);
}
/** /**
* Поиск по каталожному номеру * Поиск по каталожному номеру
*/ */
public static function readByCatn(string $catn): ?Product public static function searchByCatn(string $query, int $limit = 1): Product|array|null
{ {
return self::findOne(['catn' => $catn]); if ($limit <= 1) {
return static::findOne(['catn' => $query]);
}
return self::find()->limit($limit)->view('product_search', ['id' => '_key', 'catn' => 'catn'], ['catn' => $query], 'START');
} }
} }

View File

@ -1,26 +1,56 @@
<?php <?php
declare(strict_types=1);
namespace app\models; namespace app\models;
use carono\exchange1c\interfaces\GroupInterface; use carono\exchange1c\interfaces\GroupInterface;
use Zenwalker\CommerceML\Model\Group; use Zenwalker\CommerceML\Model\Group;
/**
* Группировка продуктов
*/
class ProductGroup extends Document implements GroupInterface class ProductGroup extends Document implements GroupInterface
{ {
public static function collectionName() /**
* Имя коллекции
*/
public static function collectionName(): string
{ {
return 'product_group'; return 'product_group';
} }
public function attributes() /**
* Свойства
*/
public function attributes(): array
{ {
return array_merge( return array_merge(
parent::attributes(), parent::attributes(),
['name', 'onec_id', 'onec_prnt_id'] [
'name'
]
); );
} }
public function rules() /**
* Метки свойств
*/
public function attributeLabels(): array
{
return array_merge(
parent::attributeLabels(),
[
'name' => 'Название (name)'
]
);
}
/**
* Правила
*/
public function rules(): array
{ {
return array_merge( return array_merge(
parent::rules(), parent::rules(),
@ -34,34 +64,18 @@ class ProductGroup extends Document implements GroupInterface
); );
} }
public function attributeLabels() /**
* Запись члена группы
*/
public function writeMember(Product $member): ProductEdgeProductGroup
{ {
return array_merge( return ProductEdgeProductGroup::write($member->readId(), $this->readId(), 'member');
parent::attributeLabels(),
[
'name' => 'Название (name)',
'onec_id' => 'Название 1C (onec_id)',
'onec_prnt_id' => 'Название родителя 1C (onec_prnt_id)',
]
);
}
public function writeMember(Document $member, string $group)
{
if (isset($member->_key)) {
return static::writeEdgeBetweenMember($member->collectionName() . '/' . $member->_key, $this->collectionName() . '/' . $group);
}
return false;
} }
/** /**
* Создание дерева групп * Запись рёбер групп
* в параметр передаётся массив всех групп (import.xml > Классификатор > Группы)
* $groups[0]->parent - родительская группа
* $groups[0]->children - дочерние группы
* *
* @param Group[] $groups * Создание взаимоотношений между группами по типу древовидной системы
*/ */
public static function createTree1c($groups): Document|null public static function createTree1c($groups): Document|null
{ {
@ -88,10 +102,11 @@ class ProductGroup extends Document implements GroupInterface
} }
/** /**
* Создаём группу по модели группы CommerceML * Запись группы
* проверяем все дерево родителей группы, если родителя нет в базе - создаём
* *
* @param Group $group * Создаём группу по модели группы CommerceML
* проверяем все дерево родителей группы,
* если родителя нет в базе - создаём
*/ */
public static function createByML(Group $group): static|array|null public static function createByML(Group $group): static|array|null
{ {
@ -124,19 +139,6 @@ class ProductGroup extends Document implements GroupInterface
return $model; return $model;
} }
private static function writeEdgeBetweenMember(string $from, string $to): bool
{
// Инициализация
$edge = new ProductEdgeProductGroup();
// Настройка
$edge->_from = $from;
$edge->_to = $to;
// Запись
return $edge->save();
}
private static function writeEdgeBetweenGroup(string $from, string $to): bool private static function writeEdgeBetweenGroup(string $from, string $to): bool
{ {
// Инициализация // Инициализация

View File

@ -1,24 +1,46 @@
<?php <?php
declare(strict_types=1);
namespace app\models; namespace app\models;
use Yii; use Yii;
use app\models\Account; use app\models\Account;
use app\models\Product; use app\models\Product;
use app\models\SupplyEdgeProduct; use app\models\SupplyEdgeProduct;
use app\models\traits\Xml2Array; use app\models\traits\Xml2Array;
use carono\exchange1c\interfaces\ProductInterface; use carono\exchange1c\interfaces\ProductInterface;
// class Supply extends Product implements OfferInterface use mirzaev\yii2\arangodb\Query;
/**
* Поставка (выгрузка товаров от поставщиков)
*
* Представляет собой предложения от поставщиков которые добавляются
* в универсальные лоты товаров в асспортименте магазина
*
* @see Product Продукт (туда добавляются поставки)
*/
class Supply extends Product implements ProductInterface class Supply extends Product implements ProductInterface
{ {
/**
* Метод для конвертации XML в Array
*/
use Xml2Array; use Xml2Array;
/**
* Имя коллекции
*/
public static function collectionName(): string public static function collectionName(): string
{ {
return 'supply'; return 'supply';
} }
/**
* Свойства
*/
public function attributes(): array public function attributes(): array
{ {
return array_merge( return array_merge(
@ -29,29 +51,38 @@ class Supply extends Product implements ProductInterface
); );
} }
/**
* Метки свойств
*/
public function attributeLabels(): array public function attributeLabels(): array
{ {
return array_merge( return array_merge(
parent::attributeLabels(), parent::attributeLabels(),
[ [
'onec' => 'Данные 1C' 'onec' => 'Данные 1С'
] ]
); );
} }
/**
* После сохранения
*/
public function afterSave($data, $vars): void public function afterSave($data, $vars): void
{ {
// Запись ребра: АККАУНТ -> ПОСТАВКА // Запись ребра: АККАУНТ -> ПОСТАВКА
(new AccountEdgeSupply)->write(Yii::$app->user->identity->readId(), $this->readId(), 'import'); (new AccountEdgeSupply)->write(Yii::$app->user->id, $this->readId(), 'import');
} }
/**
* Запись реквизитов из 1С
*/
public function setRequisite1c($name, $value): mixed public function setRequisite1c($name, $value): mixed
{ {
return true; return true;
} }
/** /**
* Установка группы, где находится продукт * Запись группы из 1С
*/ */
public function setGroup1c($group): mixed public function setGroup1c($group): mixed
{ {
@ -64,23 +95,66 @@ class Supply extends Product implements ProductInterface
return true; return true;
} }
public static function createProperties1c($properties): mixed /**
* Запись данных свойств по UUID 1C
*
* Ищет записанные свойства из 1C по их идентификатору и добавляет к ним
* недостающие данные. Это костыль оставшийся от реляционных баз данных
*/
public static function createProperties1c($properties): void
{ {
return true; // Инициализация
$models = static::searchOnecByAccountId(Yii::$app->user->id, true);
$properties = self::xml2array($properties->xml);
foreach ($models as $model) {
// Перебор записей
// Инициализация
$changes = false;
foreach ($model->onec['ЗначенияСвойств'] as &$attribute) {
// Перебор аттрибутов
foreach ($properties as $property) {
// Перебор свойств
if ($attribute['ЗначенияСвойства']['Ид'] === $property['Свойство']['Ид']) {
// Совпадение идентификаторов
// Объединение данных
array_merge($attribute, $property);
// Запись индикатора наличия изменений
$changes = true;
}
}
} }
if ($changes) {
$model->save();
}
}
}
/**
* Запись параметров из 1С
*/
public function setProperty1c($property): mixed public function setProperty1c($property): mixed
{ {
return true; return true;
} }
/**
* Запись изображений из 1С
*/
public function addImage1c($path, $caption): mixed public function addImage1c($path, $caption): mixed
{ {
return true; return true;
} }
/** /**
* Запись ребра (предложения от поставки к продукту) * Запись ребра (предложения от поставок к продуктам) из 1С
*/ */
public function getOffer1c($offer): SupplyEdgeProduct public function getOffer1c($offer): SupplyEdgeProduct
{ {
@ -89,7 +163,7 @@ class Supply extends Product implements ProductInterface
// Разработчику библеотеки надо дать по жопе // Разработчику библеотеки надо дать по жопе
return new SupplyEdgeProduct; return new SupplyEdgeProduct;
} else if (!$catn = Product::readByCatn($this->catn)) { } else if (!$product = Product::searchByCatn($this->catn)) {
// Продукт не найден // Продукт не найден
if (!$this->initProduct()) { if (!$this->initProduct()) {
@ -100,12 +174,12 @@ class Supply extends Product implements ProductInterface
} }
} }
$catn = Product::readByCatn($this->catn); $product = Product::searchByCatn($this->catn);
// Запись ребра: ПОСТАВКА -> ПРОДУКТ // Запись ребра: ПОСТАВКА -> ПРОДУКТ
return (new SupplyEdgeProduct)->write( return (new SupplyEdgeProduct)->write(
$this->readId(), $this->readId(),
$catn->readId(), $product->readId(),
'sell', 'sell',
[ [
'onec' => self::xml2array($offer->xml) 'onec' => self::xml2array($offer->xml)
@ -114,26 +188,27 @@ class Supply extends Product implements ProductInterface
} }
/** /**
* Создать продукт * Запись продукта из 1С
*/ */
public static function createModel1c($product): self public static function createModel1c($product): ?self
{ {
// Инициализация // Инициализация
$model = self::readByOnecId($id = (string) $product->Ид) ?? new self; $model = self::searchByOnecId($id = (string) $product->Ид) ?? new self;
// Настройки // Настройка
$model->ocid = $id ?? null; $model->ocid = $id ?? null;
$model->catn = (string) $product->Артикул; $model->catn = (string) $product->Артикул;
$model->oemn = null; $model->oemn = null;
$model->onec = self::xml2array($product->xml); $model->onec = self::xml2array($product->xml);
// Запись // Запись
$model->save(); return $model->save() ? $model : null;
return $model;
} }
protected function initProduct(): bool /**
* Инициализация продукта
*/
protected function initProduct(): ?Product
{ {
// Надо не забыть сделать выборку полей и ручное подключение // Надо не забыть сделать выборку полей и ручное подключение
@ -141,7 +216,7 @@ class Supply extends Product implements ProductInterface
// Не передан каталожный номер // Не передан каталожный номер
return false; return false;
} else if (Product::readByCatn($this->catn)) { } else if (Product::searchByCatn($this->catn)) {
// Продукт уже был инициализирован // Продукт уже был инициализирован
return true; return true;
@ -154,34 +229,79 @@ class Supply extends Product implements ProductInterface
$product->catn = $this->catn; $product->catn = $this->catn;
// Запись // Запись
return $product->save(); return $product->save() ? $product : null;
} }
/**
public function setPrice1c($price): void * Запись цены из 1С
*/
public function setPrice1c($price): mixed
{ {
return true;
} }
/**
* Запись данных на случай ошибки при экспорте из 1С
*/
public function setRaw1cData($cml, $object): bool public function setRaw1cData($cml, $object): bool
{ {
return false; return true;
} }
public static function readByOnecId(string $ocid): ?Supply /**
* Поиск по идентификатору из 1С
*
* @param string $ocid Идентификатор из 1С
*
* @return Supply|null
*/
public static function searchByOnecId(string $ocid): ?Supply
{ {
return self::findOne([self::getIdFieldName1c() => $ocid]); return static::findOne([static::getIdFieldName1c() => $ocid]);
} }
public function getGroup1c(): SupplyGroup /**
* Чтение группы из 1С
*/
public function getGroup1c(): ?SupplyGroup
{ {
return $this->group; return $this->group;
} }
/** /**
* Название поля в котором хранится ID из 1C * Чтение названия поля в котором хранится идентификатор из 1С
*/ */
public static function getIdFieldName1c(): string public static function getIdFieldName1c(): string
{ {
return 'ocid'; return 'ocid';
} }
public static function searchOnecByAccountId(string $id, bool $full = false): array
{
$subquery = static::find()
->for(['account', 'account_edge_supply'])
->traversal('supply')->in('account_edge_supply')
->where(['account._id' => $id])
->select('account_edge_supply')
->createCommand();
$query = static::find()
->addParams($subquery->getBindVars())
->let('account_edge_supply', '(' . (string) $subquery . ')')
->where('supply._id == account_edge_supply[0]._to')
->andWhere('supply.onec["ЗначенияСвойств"] != null');
if ($full) {
// Если указан полный поиск
return $query->select('supply')->all();
}
$query = $query->select('supply.onec["ЗначенияСвойств"]')->createCommand()->execute()->getAll();
foreach ($query as &$attribute) {
$attribute = $attribute->getAll();
}
return $query;
}
} }

View File

@ -1,37 +1,18 @@
<?php <?php
declare(strict_types=1);
namespace app\models; namespace app\models;
/**
* Группировка поставок
*/
class SupplyGroup extends ProductGroup class SupplyGroup extends ProductGroup
{ {
public static function collectionName() /**
* Имя коллекции
*/
public static function collectionName(): string
{ {
return 'supply_group'; return 'supply_group';
} }
protected static function writeEdgeBetweenMember(string $from, string $to): bool
{
// Инициализация
$edge = new SupplyEdgeSupplyGroup();
// Настройка
$edge->_from = $from;
$edge->_to = $to;
// Запись
return $edge->save();
}
protected static function writeEdgeBetweenGroup(string $from, string $to): bool
{
// Инициализация
$edge = new SupplyGroupEdgeSupplyGroup();
// Настройка
$edge->_from = $from;
$edge->_to = $to;
// Запись
return $edge->save();
}
} }

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
use yii\helpers\Html; use yii\helpers\Html;
use yii\bootstrap\ActiveForm; use yii\bootstrap\ActiveForm;
use app\models\AccountForm; use app\models\AccountForm;

View File

@ -2,7 +2,6 @@
use yii\bootstrap\ActiveForm; use yii\bootstrap\ActiveForm;
use app\controllers\ProfileController; use app\controllers\ProfileController;
use app\models\Product;
use app\models\Supply; use app\models\Supply;
?> ?>
@ -11,21 +10,15 @@ use app\models\Supply;
<div id="page_profile" class="container h-100"> <div id="page_profile" class="container h-100">
<div class="row h-100 py-3"> <div class="row h-100 py-3">
<nav class="col-3"> <nav class="col-3">
<div class="p-3 rounded"> <?= $sidebar ?>
<div class="d-flex">
<p>Почта: </p>
<p class="ml-auto"><?php echo Yii::$app->user->identity->mail ?></p>
</div>
</div>
</nav> </nav>
<article class="col-9"> <article class="col-9">
<div class="h-100 p-3 rounded"> <div class="h-100 p-4 rounded">
<h4 class="ml-4">Личный кабинет</h4> <h4 class="ml-4 mb-4">Настройки аккаунта</h4>
<div class="dropdown-divider"></div> <p>Пока не сделана нормальная панель управления я просто буду добавлять все настройки сюда</p>
<p>Не знаю что сюда пока добавить</p>
<?php <?php
$form = ActiveForm::begin([ $form = ActiveForm::begin([
'id' => 'form_product_import_excel', 'id' => 'form_profile_options',
'action' => false, 'action' => false,
'fieldConfig' => [ 'fieldConfig' => [
'template' => '{label}{input}', 'template' => '{label}{input}',
@ -37,20 +30,26 @@ use app\models\Supply;
] ]
]); ]);
$model = $model ?? new Supply; $model = $model ?? Yii::$app->user->identity;
$groups = ProfileController::readGroups(); var_dump($attributes = Supply::searchOnecByAccountId(Yii::$app->user->id));
// $list = [];
// //
// foreach ($attributes as $attribute) {
// $id = $attribute['ЗначенияСвойства']['Ид'];
// if (in_array($id, $list, true)) {
// continue;
// }
// $list[] = $id;
// }
?> ?>
<?= "a" //$form->field($model, 'opts[import_sections_oem]', ['options' => ['class' => "mb-3"]])->dropDownList($list ?? ['Нет данных']); ?>
<?= $form->field($model, 'group', ['options' => ['class' => "mb-3"]])->dropDownList($groups ?? ['Нет данных']); ?>
<?= $form->field($model, 'file', ['enableLabel' => false])->fileInput(['multiple' => true, 'onChange' => 'supply_import(this.parentElement.parentElement)']) ?>
<?= $form->errorSummary($model, ['header' => 'В документе были допущены ошибки:' /*, 'footer' => 'Исправьте их и попробуйте снова'*/]); ?>
<?php ActiveForm::end(); ?> <?php ActiveForm::end(); ?>
<p>Всего товаров: <?php echo Product::readAmount() ?></p>
<p>Всего поставок: <?php echo Supply::readAmount() ?></p>
</div> </div>
</article> </article>
</div> </div>

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
use Yii;
use app\models\Product;
use app\models\Supply;
?>
<div class="p-3 rounded">
<div class="row px-3">
<p class="ml-0">Почта: </p>
<p class="mr-0"><?= Yii::$app->user->identity->mail ?></p>
</div>
<div class="dropdown-divider my-3"></div>
<dl class="m-0">
<dt>
<a class="row text-dark mb-3 px-3 font-weight-normal" href="/profile">Настройки аккаунта</a>
</dt>
<dt>
<a class="row text-dark px-3 font-weight-normal" href="/profile/supplies">Управление поставками</a>
</dt>
</dl>
<div class="dropdown-divider my-3"></div>
<div class="row px-3">
<p class="ml-0">Товары:</p>
<p class="mr-0"><?= Product::readAmount() ?></p>
</div>
<div class="row px-3">
<p class="ml-0">Поставки:</p>
<p class="mr-0"><?= Supply::readAmount() ?></p>
</div>
</div>

View File

@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
use yii\bootstrap\ActiveForm;
use app\controllers\ProfileController;
use app\models\Supply;
?>
<link href="/css/pages/profile.css" rel="stylesheet">
<div id="page_profile" class="container h-100">
<div class="row h-100 py-3">
<nav class="col-3">
<?= $sidebar ?>
</nav>
<article class="col-9">
<div class="h-100 p-4 rounded">
<h4 class="ml-4 mb-4">Управление поставками</h4>
<?php
$form = ActiveForm::begin([
'id' => 'form_product_import_excel',
'action' => false,
'fieldConfig' => [
'template' => '{label}{input}',
'options' => ['class' => '']
],
'options' => [
'class' => 'mb-3',
'onsubmit' => 'return false;'
]
]);
$model = $model ?? new Supply;
$groups = ProfileController::readGroups();
?>
<?= $form->field($model, 'group', ['options' => ['class' => "mb-3"]])->dropDownList($groups ?? ['Нет данных']); ?>
<?= $form->field($model, 'file', ['enableLabel' => false])->fileInput(['multiple' => true, 'onChange' => 'supply_import(this.parentElement.parentElement)']) ?>
<?= $form->errorSummary($model, ['header' => 'В документе были допущены ошибки:' /*, 'footer' => 'Исправьте их и попробуйте снова'*/]); ?>
<?php ActiveForm::end(); ?>
</div>
</article>
</div>
</div>
<script src="/js/profile.js" defer></script>