fix #31 fix #35 fix #39 fix #40 fix #41 fix #42 fix #43 fix #47 fix #49

This commit is contained in:
Arsen Mirzaev Tatyano-Muradovich 2024-01-18 01:41:58 +07:00
parent 4d42e7dca4
commit f6d090f250
26 changed files with 218 additions and 128 deletions

View File

@ -1,10 +1,5 @@
# Ebala # Ebala
### Site for providing outsourced employees to retail stores Site-registry of tasks for outsourced employees
My customer uses this development to process thousands of applications throughout Krasnoyarsk and neighboring cities.<br/> From this project i earned **700 000** Russian rubles</br>
**9 000 000** Russian rubles pass through the site every **week** 🤟. *As long as commits appear in the repository, this means that i continue paid development*
For this project I received **600 000** Russian rubles. At the current exchange rate this is **$6000**.<br/>
If I had not been lazy and submitted the order a few months ago, it would have been **$8000** 😥 (super sad).
I did not sign any documents prohibiting the dissemination of information. You can use the code under the **WTFPL** license 🤝 (read ./LICENSE)

View File

@ -163,10 +163,14 @@ final class account extends core
'errors' => self::parse_only_text($this->errors) 'errors' => self::parse_only_text($this->errors)
]; ];
if ($password) $return['clipboard'] = <<<TEXT if ($password) $return['clipboard'] = match ($account->type) {
Идентификатор: {$account->getKey()} 'worker' => 'Номер: ' . model::worker($account->getId())?->number,
Пароль: {$parameters['password']} 'market' => 'Идентификатор: ' . model::market($account->getId())?->id,
TEXT; 'operator' => "Идентификатор: {$account->getKey()}",
'administrator' => "Идентификатор: {$account->getKey()}",
default => "Идентификатор: {$account->getKey()}"
}
. "\nПароль: {$parameters['password']}";
// Генерация ответа // Генерация ответа
echo json_encode($return); echo json_encode($return);

View File

@ -150,7 +150,7 @@ class core extends controller
$buffer = []; $buffer = [];
// Инициализация данных магазина для аккаунта для генерации представления // Инициализация данных магазина для аккаунта для генерации представления
foreach ($this->view->accounts as $vendor) $buffer[] = ['account' => $vendor, 'market' => account::market($vendor->getId(), errors: $this->errors['account'])]; foreach ($this->view->accounts as $account) $buffer[] = ['account' => $account, 'market' => account::market($account->getId(), errors: $this->errors['account'])];
// Запись в глобальную переменную из буфера // Запись в глобальную переменную из буфера
$this->view->accounts = $buffer; $this->view->accounts = $buffer;

View File

@ -144,6 +144,7 @@ final class market extends core
a.commentary IN TOKENS(@search, 'text_ru') a.commentary IN TOKENS(@search, 'text_ru')
|| a.address IN TOKENS(@search, 'text_ru') || a.address IN TOKENS(@search, 'text_ru')
|| STARTS_WITH(a._key, @search) || STARTS_WITH(a._key, @search)
|| STARTS_WITH(a.id, @search)
|| STARTS_WITH(a.name.first, @search) || STARTS_WITH(a.name.first, @search)
|| STARTS_WITH(a.name.second, @search) || STARTS_WITH(a.name.second, @search)
|| STARTS_WITH(a.name.last, @search) || STARTS_WITH(a.name.last, @search)
@ -152,6 +153,7 @@ final class market extends core
|| STARTS_WITH(a.number, @search) || STARTS_WITH(a.number, @search)
|| STARTS_WITH(a.mail, @search) || STARTS_WITH(a.mail, @search)
|| (LENGTH(@search) > 5 && LEVENSHTEIN_MATCH(a._key, TOKENS(@search, 'text_en')[0], 2, true)) || (LENGTH(@search) > 5 && LEVENSHTEIN_MATCH(a._key, TOKENS(@search, 'text_en')[0], 2, true))
|| (LENGTH(@search) > 2 && LEVENSHTEIN_MATCH(a.id, TOKENS(@search, 'text_en')[0], 1, true))
|| (LENGTH(@search) > 3 && LEVENSHTEIN_MATCH(a.name.first, TOKENS(@search, 'text_ru')[0], 2, true)) || (LENGTH(@search) > 3 && LEVENSHTEIN_MATCH(a.name.first, TOKENS(@search, 'text_ru')[0], 2, true))
|| (LENGTH(@search) > 3 && LEVENSHTEIN_MATCH(a.name.second, TOKENS(@search, 'text_ru')[0], 2, true)) || (LENGTH(@search) > 3 && LEVENSHTEIN_MATCH(a.name.second, TOKENS(@search, 'text_ru')[0], 2, true))
|| (LENGTH(@search) > 3 && LEVENSHTEIN_MATCH(a.name.last, TOKENS(@search, 'text_ru')[0], 2, true)) || (LENGTH(@search) > 3 && LEVENSHTEIN_MATCH(a.name.last, TOKENS(@search, 'text_ru')[0], 2, true))
@ -274,8 +276,8 @@ final class market extends core
]; ];
} }
// Инициализация идентификатора аккаунта (ключ документа инстанции аккаунта в базе данных) // Инициализация идентификатора магазина
$_key = preg_replace('/.+\//', '', $account ?? ''); $id = model::id();
// Запись заголовков ответа // Запись заголовков ответа
header('Content-Type: application/json'); header('Content-Type: application/json');
@ -289,7 +291,7 @@ final class market extends core
echo json_encode( echo json_encode(
[ [
'clipboard' => empty($this->errors['account']) ? <<<TEXT 'clipboard' => empty($this->errors['account']) ? <<<TEXT
Идентификатор: $_key Идентификатор: $id
Пароль: {$parameters['account_password']} Пароль: {$parameters['account_password']}
TEXT : '', TEXT : '',
'errors' => self::parse_only_text($this->errors['account']) 'errors' => self::parse_only_text($this->errors['account'])
@ -307,6 +309,7 @@ final class market extends core
// Создание магазина // Создание магазина
$market = model::create( $market = model::create(
data: [ data: [
'id' => $id,
'name' => [ 'name' => [
'first' => $parameters['market_name_first'], 'first' => $parameters['market_name_first'],
'second' => $parameters['market_name_second'], 'second' => $parameters['market_name_second'],
@ -350,7 +353,7 @@ final class market extends core
// Авторизован аккаунт администратора или оператора // Авторизован аккаунт администратора или оператора
// Инициализация данных магазина // Инициализация данных магазина
$market = model::read('d._key == "' . $parameters['id'] . '"', return: '{ name: d.name, number: d.number, mail: d.mail, type: d.type, city: d.city, district: d.district, address: d.address}')->getAll(); $market = model::read('d.id == "' . $parameters['id'] . '"', return: '{ name: d.name, number: d.number, mail: d.mail, type: d.type, city: d.city, district: d.district, address: d.address}')->getAll();
if (!empty($market)) { if (!empty($market)) {
// Найдены данные магазина // Найдены данные магазина
@ -390,7 +393,7 @@ final class market extends core
// Авторизован аккаунт администратора или оператора // Авторизован аккаунт администратора или оператора
// Инициализация данных магазина // Инициализация данных магазина
$market = model::read('d._key == "' . $parameters['id'] . '"'); $market = model::read('d.id == "' . $parameters['id'] . '"');
if (!empty($market)) { if (!empty($market)) {
// Найден магазин // Найден магазин
@ -472,7 +475,7 @@ final class market extends core
// Авторизован аккаунт оператора или магазина // Авторизован аккаунт оператора или магазина
// Инициализация данных магазинов // Инициализация данных магазинов
$this->view->markets = model::read(filter: 'd.active == true', amount: 10000, return: '{ _key: d._key, name: d.name }'); $this->view->markets = model::read(filter: 'd.active == true', amount: 10000, return: '{ id: d.id, name: d.name }');
// Универсализация // Универсализация
if ($this->view->markets instanceof _document) $this->view->markets = [$this->view->markets]; if ($this->view->markets instanceof _document) $this->view->markets = [$this->view->markets];

View File

@ -8,6 +8,7 @@ namespace mirzaev\ebala\controllers;
use mirzaev\ebala\controllers\core, use mirzaev\ebala\controllers\core,
mirzaev\ebala\controllers\traits\errors, mirzaev\ebala\controllers\traits\errors,
mirzaev\ebala\models\account, mirzaev\ebala\models\account,
mirzaev\ebala\models\worker,
mirzaev\ebala\models\market; mirzaev\ebala\models\market;
// Библиотека для ArangoDB // Библиотека для ArangoDB
@ -76,11 +77,11 @@ final class session extends core
} }
// Поиск аккаунта // Поиск аккаунта
$account = account::read('d.number == "' . $parameters['worker'] . '"', amount: 1); $worker = worker::read('d.number == "' . $parameters['worker'] . '"', amount: 1);
// Генерация ответа по запрашиваемым параметрам // Генерация ответа по запрашиваемым параметрам
foreach ($return as $parameter) match ($parameter) { foreach ($return as $parameter) match ($parameter) {
'exist' => $buffer['exist'] = isset($account), 'exist' => $buffer['exist'] = isset($worker),
'account' => (function () use ($parameters, $remember, &$buffer) { 'account' => (function () use ($parameters, $remember, &$buffer) {
// Запись в буфер сессии // Запись в буфер сессии
if ($remember) $this->session->write(['entry' => ['number' => $parameters['worker']]], $this->errors); if ($remember) $this->session->write(['entry' => ['number' => $parameters['worker']]], $this->errors);
@ -370,7 +371,7 @@ final class session extends core
// Запрошено запоминание // Запрошено запоминание
// Запись в cookie // Запись в cookie
setcookie('entry__key', $parameters['market'], [ setcookie('entry_id', $parameters['market'], [
'expires' => strtotime('+1 day'), 'expires' => strtotime('+1 day'),
'path' => '/', 'path' => '/',
'secure' => true, 'secure' => true,
@ -379,15 +380,15 @@ final class session extends core
]); ]);
} }
// Поиск аккаунта // Поиск магазина
$account = account::read('d._key == "' . $parameters['market'] . '"', amount: 1); $market = market::read('d.id == "' . $parameters['market'] . '"', amount: 1);
// Генерация ответа по запрашиваемым параметрам // Генерация ответа по запрашиваемым параметрам
foreach ($return as $parameter) match ($parameter) { foreach ($return as $parameter) match ($parameter) {
'exist' => $buffer['exist'] = isset($account), 'exist' => $buffer['exist'] = isset($market),
'account' => (function () use ($parameters, $remember, &$buffer) { 'account' => (function () use ($parameters, $remember, &$buffer) {
// Запись в буфер сессии // Запись в буфер сессии
if ($remember) $this->session->write(['entry' => ['_key' => $parameters['market']]], $this->errors); if ($remember) $this->session->write(['entry' => ['id' => $parameters['market']]], $this->errors);
// Поиск аккаунта и запись в буфер вывода // Поиск аккаунта и запись в буфер вывода
$buffer['account'] = (new account($this->session, 'market', $this->errors))?->instance() instanceof _document; $buffer['account'] = (new account($this->session, 'market', $this->errors))?->instance() instanceof _document;
@ -429,7 +430,7 @@ final class session extends core
// Запись в буфер сессии // Запись в буфер сессии
if (!in_array('account', $return, true) && ($remember ?? false)) if (!in_array('account', $return, true) && ($remember ?? false))
$this->session->write(['entry' => ['_key' => $parameters['market']]]); $this->session->write(['entry' => ['id' => $parameters['market']]]);
} }
/** /**

View File

@ -48,10 +48,10 @@ final class task extends core
$this->errors['tasks'] ??= []; $this->errors['tasks'] ??= [];
// Создание строк // Создание строк
for ($i = 0, $parameters['cashiers'] = (int) $parameters['cashiers']; $i < $parameters['cashiers']; ++$i) model::create(work: 'Кассир', market: $this->account->type === 'market' ? account::market($this->account->getId())?->getKey() : null, start: $parameters['start'], end: $parameters['end'], date: $parameters['date'], errors: $this->errors['tasks']); for ($i = 0, $parameters['cashiers'] = (int) $parameters['cashiers']; $i < $parameters['cashiers']; ++$i) model::create(work: 'Кассир', market: $this->account->type === 'market' ? account::market($this->account->getId())?->id : null, start: $parameters['start'], end: $parameters['end'], date: $parameters['date'], errors: $this->errors['tasks']);
for ($i = 0, $parameters['displayers'] = (int) $parameters['displayers']; $i < $parameters['displayers']; ++$i) model::create(work: 'Выкладчик', market: $this->account->type === 'market' ? account::market($this->account->getId())?->getKey() : null, start: $parameters['start'], end: $parameters['end'], date: $parameters['date'], errors: $this->errors['tasks']); for ($i = 0, $parameters['displayers'] = (int) $parameters['displayers']; $i < $parameters['displayers']; ++$i) model::create(work: 'Выкладчик', market: $this->account->type === 'market' ? account::market($this->account->getId())?->id : null, start: $parameters['start'], end: $parameters['end'], date: $parameters['date'], errors: $this->errors['tasks']);
for ($i = 0, $parameters['loaders'] = (int) $parameters['loaders']; $i < $parameters['loaders']; ++$i) model::create(work: 'Грузчик', market: $this->account->type === 'market' ? account::market($this->account->getId())?->getKey() : null, start: $parameters['start'], end: $parameters['end'], date: $parameters['date'], errors: $this->errors['tasks']); for ($i = 0, $parameters['loaders'] = (int) $parameters['loaders']; $i < $parameters['loaders']; ++$i) model::create(work: 'Грузчик', market: $this->account->type === 'market' ? account::market($this->account->getId())?->id : null, start: $parameters['start'], end: $parameters['end'], date: $parameters['date'], errors: $this->errors['tasks']);
for ($i = 0, $parameters['gastronomes'] = (int) $parameters['gastronomes']; $i < $parameters['gastronomes']; ++$i) model::create(work: 'Гастроном', market: $this->account->type === 'market' ? account::market($this->account->getId())?->getKey() : null, start: $parameters['start'], end: $parameters['end'], date: $parameters['date'], errors: $this->errors['tasks']); for ($i = 0, $parameters['gastronomes'] = (int) $parameters['gastronomes']; $i < $parameters['gastronomes']; ++$i) model::create(work: 'Гастроном', market: $this->account->type === 'market' ? account::market($this->account->getId())?->id : null, start: $parameters['start'], end: $parameters['end'], date: $parameters['date'], errors: $this->errors['tasks']);
// Запись заголовков ответа // Запись заголовков ответа
header('Content-Type: application/json'); header('Content-Type: application/json');
@ -205,11 +205,11 @@ final class task extends core
// Инициализация данных для генерации HTML-документа с таблицей // Инициализация данных для генерации HTML-документа с таблицей
if ($_SERVER['INTERFACE'] === 'worker') if ($_SERVER['INTERFACE'] === 'worker')
$this->view->rows = model::list(before: 'FILTER task.worker == "' . account::worker($this->account->getId())?->getKey() . '"' . " && ($filters)"); $this->view->rows = model::list(before: 'FILTER task.worker == "' . account::worker($this->account->getId())?->id . '"' . " && ($filters)");
else if ($_SERVER['INTERFACE'] === 'operator') else if ($_SERVER['INTERFACE'] === 'operator')
$this->view->rows = model::list(before: "FILTER ($filters)"); $this->view->rows = model::list(before: "FILTER ($filters)");
else if ($_SERVER['INTERFACE'] === 'market') else if ($_SERVER['INTERFACE'] === 'market')
$this->view->rows = model::list(before: 'FILTER task.market == "' . account::market($this->account->getId())?->getKey() . '"' . " && ($filters)"); $this->view->rows = model::list(before: 'FILTER task.market == "' . account::market($this->account->getId())?->id . '"' . " && ($filters)");
else if ($_SERVER['INTERFACE'] === 'administrator') else if ($_SERVER['INTERFACE'] === 'administrator')
$this->view->rows = model::list(before: "FILTER ($filters)"); $this->view->rows = model::list(before: "FILTER ($filters)");
else $this->view->rows = []; else $this->view->rows = [];
@ -237,7 +237,9 @@ final class task extends core
AQL; AQL;
// Инициализация данных для генерации HTML-документа с таблицей // Инициализация данных для генерации HTML-документа с таблицей
if ($_SERVER['INTERFACE'] === 'worker') if ($_SERVER['INTERFACE'] === 'worker') {
// Сотрудник
$this->view->rows = model::list( $this->view->rows = model::list(
before: sprintf( before: sprintf(
<<<AQL <<<AQL
@ -249,9 +251,11 @@ AQL;
), ),
page: (int) $this->session->buffer['worker']['tasks']['page'], page: (int) $this->session->buffer['worker']['tasks']['page'],
target: empty($search) ? model::COLLECTION : 'registry_tasks', target: empty($search) ? model::COLLECTION : 'registry_tasks',
binds: ['worker' => account::worker($this->account->getId())?->getKey()] + (empty($search) ? [] : ['search' => $search]) binds: ['worker' => account::worker($this->account->getId())?->id] + (empty($search) ? [] : ['search' => $search])
); );
else if ($_SERVER['INTERFACE'] === 'market') } else if ($_SERVER['INTERFACE'] === 'market') {
// Магазин
$this->view->rows = model::list( $this->view->rows = model::list(
before: sprintf( before: sprintf(
<<<AQL <<<AQL
@ -263,9 +267,11 @@ AQL;
), ),
page: (int) $this->session->buffer['market']['tasks']['page'], page: (int) $this->session->buffer['market']['tasks']['page'],
target: empty($search) ? model::COLLECTION : 'registry_tasks', target: empty($search) ? model::COLLECTION : 'registry_tasks',
binds: ['market' => account::market($this->account->getId())?->getKey()] + (empty($search) ? [] : ['search' => $search]) binds: ['market' => account::market($this->account->getId())?->id] + (empty($search) ? [] : ['search' => $search])
); );
else if ($_SERVER['INTERFACE'] === 'operator') } else if ($_SERVER['INTERFACE'] === 'operator') {
// Оператор
$this->view->rows = model::list( $this->view->rows = model::list(
before: sprintf( before: sprintf(
<<<AQL <<<AQL
@ -281,7 +287,9 @@ AQL;
'search' => $search 'search' => $search
] ]
); );
else if ($_SERVER['INTERFACE'] === 'administrator') } else if ($_SERVER['INTERFACE'] === 'administrator') {
// Администратор
$this->view->rows = model::list( $this->view->rows = model::list(
before: sprintf( before: sprintf(
<<<AQL <<<AQL
@ -297,9 +305,9 @@ AQL;
'search' => $search 'search' => $search
] ]
); );
else $this->view->rows = []; } else $this->view->rows = [];
// Запись в cookie (только таким методом можно записать "hostonly: true") // Запись в cookie
setcookie( setcookie(
'tasks_page', 'tasks_page',
(string) $this->session->buffer[$_SERVER['INTERFACE']]['tasks']['page'], (string) $this->session->buffer[$_SERVER['INTERFACE']]['tasks']['page'],
@ -503,7 +511,7 @@ AQL;
// Найдена заявка // Найдена заявка
// Заявка не принадлежит запросившему магазину? // Заявка не принадлежит запросившему магазину?
if ($this->account->type === 'market' and $task->market !== account::market($this->account->getId())?->getKey()) if ($this->account->type === 'market' and $task->market !== account::market($this->account->getId())?->id)
throw new exception('Вы не авторизованы для редактирования этой заявки'); throw new exception('Вы не авторизованы для редактирования этой заявки');
// Заявка подтверждена? // Заявка подтверждена?
@ -557,14 +565,14 @@ AQL;
} else { } else {
// Записать нового сотрудника // Записать нового сотрудника
if (($worker = worker::read('d._key == "' . $parameters['worker'] . '" && d.active == true', amount: 1)) instanceof _document) { if (($worker = worker::read('d.id == "' . $parameters['worker'] . '" && d.active == true', amount: 1)) instanceof _document) {
// Найден сотрудник (запрашиваемый для записи сотрудник существует в базе данных) // Найден сотрудник (запрашиваемый для записи сотрудник существует в базе данных)
if ($task->worker !== $parameters['worker']) { if ($task->worker !== $parameters['worker']) {
// Идентификатор запрашиваемого сотрудника не равен актуальному // Идентификатор запрашиваемого сотрудника не равен актуальному
// Запись сотрудника // Запись сотрудника
$task->worker = $worker->getKey(); $task->worker = $worker->id;
// Снятие с публикации // Снятие с публикации
$task->published = false; $task->published = false;
@ -653,14 +661,14 @@ AQL;
} else { } else {
// Записать новый магазин // Записать новый магазин
if (($market = market::read('d._key == "' . $parameters['market'] . '" && d.active == true', amount: 1)) instanceof _document) { if (($market = market::read('d.id == "' . $parameters['market'] . '" && d.active == true', amount: 1)) instanceof _document) {
// Найден магазин (запрашиваемый для записи магазин существует в базе данных) // Найден магазин (запрашиваемый для записи магазин существует в базе данных)
if ($task->market !== $parameters['market']) { if ($task->market !== $parameters['market']) {
// Идентификатор запрашиваемого сотрудника не равен актуальному // Идентификатор запрашиваемого сотрудника не равен актуальному
// Запись магазина // Запись магазина
$task->market = $market->getKey(); $task->market = $market->id;
if (_core::update($task)) { if (_core::update($task)) {
// Записано изменение в базу данных // Записано изменение в базу данных
@ -757,7 +765,7 @@ AQL;
)->getAll(); )->getAll();
// Заявка не принадлежит запросившему магазину? // Заявка не принадлежит запросившему магазину?
if ($this->account->type === 'market' and $this->view->task['market'] !== account::market($this->account->getId())?->getKey()) if ($this->account->type === 'market' and $this->view->task['market'] !== account::market($this->account->getId())?->id)
throw new exception('Вы не авторизованы для чтения этой заявки'); throw new exception('Вы не авторизованы для чтения этой заявки');
// Удаление данных из выдачи // Удаление данных из выдачи
@ -892,9 +900,9 @@ AQL;
// Инициализация данных сотрудника // Инициализация данных сотрудника
$this->view->worker = worker::read( $this->view->worker = worker::read(
'd._key == "' . $parameters['worker'] . '"', 'd.id == "' . $parameters['worker'] . '"',
return: $this->account->type === 'market' return: $this->account->type === 'market'
? '{_key: d._key, created: d.created, updated: d.updated, name: d.name, number: d.number, mail: d.mail, birth: d.birth, rating: d.rating}' ? '{id: d.id, created: d.created, updated: d.updated, name: d.name, number: d.number, mail: d.mail, birth: d.birth, rating: d.rating}'
: 'd' : 'd'
)->getAll(); )->getAll();
@ -1011,7 +1019,7 @@ AQL;
// Авторизован аккаунт администратора или оператора // Авторизован аккаунт администратора или оператора
// Инициализация данных // Инициализация данных
$this->view->market = market::read('d._key == "' . $parameters['market'] . '"')?->getAll(); $this->view->market = market::read('d.id == "' . $parameters['market'] . '"')?->getAll();
if (!empty($this->view->market)) { if (!empty($this->view->market)) {
// Найдены данные магазина // Найдены данные магазина
@ -1210,7 +1218,7 @@ AQL;
$task = model::read('d._key == "' . $parameters['task'] . '"'); $task = model::read('d._key == "' . $parameters['task'] . '"');
// Заявка не принадлежит запросившему магазину? // Заявка не принадлежит запросившему магазину?
if ($this->account->type === 'market' and $task->market !== account::market($this->account->getId())?->getKey()) if ($this->account->type === 'market' and $task->market !== account::market($this->account->getId())?->id)
throw new exception('Вы не авторизованы для заявления о проблеме с этой заявкой'); throw new exception('Вы не авторизованы для заявления о проблеме с этой заявкой');
// Инициализация даты // Инициализация даты
@ -1329,7 +1337,7 @@ AQL;
$task = model::read('d._key == "' . $parameters['task'] . '"'); $task = model::read('d._key == "' . $parameters['task'] . '"');
// Заявка не принадлежит запросившему магазину? // Заявка не принадлежит запросившему магазину?
if ($this->account->type === 'market' and $task->market !== account::market($this->account->getId())?->getKey()) if ($this->account->type === 'market' and $task->market !== account::market($this->account->getId())?->id)
throw new exception('Вы не авторизованы для завершения этой заявки'); throw new exception('Вы не авторизованы для завершения этой заявки');
// Заявка завершена? // Заявка завершена?
@ -1552,7 +1560,7 @@ AQL;
$task = model::read('d._key == "' . $parameters['task'] . '"'); $task = model::read('d._key == "' . $parameters['task'] . '"');
// Заявка не принадлежит запросившему магазину? // Заявка не принадлежит запросившему магазину?
if ($this->account->type === 'market' and $task->market !== account::market($this->account->getId())?->getKey()) if ($this->account->type === 'market' and $task->market !== account::market($this->account->getId())?->id)
throw new exception('Вы не авторизованы для редактирования типа работы этой заявки'); throw new exception('Вы не авторизованы для редактирования типа работы этой заявки');
// Заявка подтверждена? // Заявка подтверждена?
@ -1665,7 +1673,7 @@ AQL;
$task = model::read('d._key == "' . $parameters['task'] . '"'); $task = model::read('d._key == "' . $parameters['task'] . '"');
// Заявка не принадлежит запросившему магазину? // Заявка не принадлежит запросившему магазину?
if ($this->account->type === 'market' and $task->market !== account::market($this->account->getId())?->getKey()) if ($this->account->type === 'market' and $task->market !== account::market($this->account->getId())?->id)
throw new exception('Вы не авторизованы для чтения параметров этой заявки'); throw new exception('Вы не авторизованы для чтения параметров этой заявки');
if ($task instanceof _document) { if ($task instanceof _document) {
@ -1828,7 +1836,7 @@ AQL;
$task = model::read('d._key == "' . $parameters['task'] . '"'); $task = model::read('d._key == "' . $parameters['task'] . '"');
// Заявка не принадлежит запросившему магазину? // Заявка не принадлежит запросившему магазину?
if ($this->account->type === 'market' and $task->market !== account::market($this->account->getId())?->getKey()) if ($this->account->type === 'market' and $task->market !== account::market($this->account->getId())?->id)
throw new exception('Вы не авторизованы для редактирования типа работы этой заявки'); throw new exception('Вы не авторизованы для редактирования типа работы этой заявки');
// Заявка подтверждена? // Заявка подтверждена?
@ -1947,7 +1955,7 @@ AQL;
$task = model::read('d._key == "' . $parameters['task'] . '"'); $task = model::read('d._key == "' . $parameters['task'] . '"');
// Заявка не принадлежит запросившему магазину? // Заявка не принадлежит запросившему магазину?
if ($this->account->type === 'market' and $task->market !== account::market($this->account->getId())?->getKey()) if ($this->account->type === 'market' and $task->market !== account::market($this->account->getId())?->id)
throw new exception('Вы не авторизованы для редактирования описания этой заявки'); throw new exception('Вы не авторизованы для редактирования описания этой заявки');
// Заявка подтверждена? // Заявка подтверждена?
@ -2056,7 +2064,7 @@ AQL;
$task = model::read('d._key == "' . $parameters['task'] . '"'); $task = model::read('d._key == "' . $parameters['task'] . '"');
// Заявка не принадлежит запросившему магазину? // Заявка не принадлежит запросившему магазину?
if ($this->account->type === 'market' and $task->market !== account::market($this->account->getId())?->getKey()) if ($this->account->type === 'market' and $task->market !== account::market($this->account->getId())?->id)
throw new exception('Вы не авторизованы для редактирования даты и времени этой заявки'); throw new exception('Вы не авторизованы для редактирования даты и времени этой заявки');
// Заявка подтверждена? // Заявка подтверждена?
@ -2447,7 +2455,7 @@ AQL;
if ( if (
$this->account->type === 'operator' $this->account->type === 'operator'
|| $this->account->type === 'administrator' || $this->account->type === 'administrator'
|| ($this->account->type === 'worker' && $task->worker === account::worker($this->account->getId())?->getKey()) || ($this->account->type === 'worker' && $task->worker === account::worker($this->account->getId())?->id)
) { ) {
// Авторизован аккаунт (если сотрудник, то назначен на эту заявку) // Авторизован аккаунт (если сотрудник, то назначен на эту заявку)
@ -2513,7 +2521,7 @@ AQL;
if ( if (
$this->account->type === 'operator' $this->account->type === 'operator'
|| $this->account->type === 'administrator' || $this->account->type === 'administrator'
|| ($this->account->type === 'market' && $task->market === account::market($this->account->getId())?->getKey()) || ($this->account->type === 'market' && $task->market === account::market($this->account->getId())?->id)
) { ) {
// Авторизован аккаунт (если магазин, то назначен на эту заявку) // Авторизован аккаунт (если магазин, то назначен на эту заявку)
@ -2664,7 +2672,7 @@ AQL;
if ( if (
$this->account->type === 'operator' $this->account->type === 'operator'
|| $this->account->type === 'administrator' || $this->account->type === 'administrator'
|| ($this->account->type === 'worker' && $task->worker === account::worker($this->account->getId())?->getKey()) || ($this->account->type === 'worker' && $task->worker === account::worker($this->account->getId())?->id)
) { ) {
// Авторизован аккаунт (если сотрудник, то назначен на эту заявку) // Авторизован аккаунт (если сотрудник, то назначен на эту заявку)
@ -2678,7 +2686,7 @@ AQL;
'from' => [ 'from' => [
'_key' => $this->account->getKey(), '_key' => $this->account->getKey(),
'type' => $this->account->type 'type' => $this->account->type
], ] + ($this->account->type === 'worker' ? ['id' => $task->worker] : []),
'type' => $parameters['type'] ?? 'message', 'type' => $parameters['type'] ?? 'message',
'text' => $parameters['text'], 'text' => $parameters['text'],
'readed' => [$this->account->getKey() => 0], 'readed' => [$this->account->getKey() => 0],
@ -2736,7 +2744,7 @@ AQL;
if ( if (
$this->account->type === 'operator' $this->account->type === 'operator'
|| $this->account->type === 'administrator' || $this->account->type === 'administrator'
|| ($this->account->type === 'market' && $task->market === account::market($this->account->getId())?->getKey()) || ($this->account->type === 'market' && $task->market === account::market($this->account->getId())?->id)
) { ) {
// Авторизован аккаунт (если магазин, то назначен на эту заявку) // Авторизован аккаунт (если магазин, то назначен на эту заявку)
@ -2750,7 +2758,7 @@ AQL;
'from' => [ 'from' => [
'_key' => $this->account->getKey(), '_key' => $this->account->getKey(),
'type' => $this->account->type 'type' => $this->account->type
], ] + ($this->account->type === 'market' ? ['id' => $task->market] : []),
'type' => $parameters['type'] ?? 'message', 'type' => $parameters['type'] ?? 'message',
'text' => $parameters['text'], 'text' => $parameters['text'],
'readed' => [$this->account->getKey() => 0], 'readed' => [$this->account->getKey() => 0],

View File

@ -147,6 +147,7 @@ final class worker extends core
|| a.department.address IN TOKENS(@search, 'text_ru') || a.department.address IN TOKENS(@search, 'text_ru')
|| a.requisites IN TOKENS(@search, 'text_ru') || a.requisites IN TOKENS(@search, 'text_ru')
|| STARTS_WITH(a._key, @search) || STARTS_WITH(a._key, @search)
|| STARTS_WITH(a.id, @search)
|| STARTS_WITH(a.name.first, @search) || STARTS_WITH(a.name.first, @search)
|| STARTS_WITH(a.name.second, @search) || STARTS_WITH(a.name.second, @search)
|| STARTS_WITH(a.name.last, @search) || STARTS_WITH(a.name.last, @search)
@ -161,6 +162,7 @@ final class worker extends core
|| STARTS_WITH(a.requisites, @search) || STARTS_WITH(a.requisites, @search)
|| STARTS_WITH(a.tax, @search) || STARTS_WITH(a.tax, @search)
|| (LENGTH(@search) > 5 && LEVENSHTEIN_MATCH(a._key, TOKENS(@search, 'text_en')[0], 2, true)) || (LENGTH(@search) > 5 && LEVENSHTEIN_MATCH(a._key, TOKENS(@search, 'text_en')[0], 2, true))
|| (LENGTH(@search) > 4 && LEVENSHTEIN_MATCH(a.id, TOKENS(@search, 'text_en')[0], 1, true))
|| (LENGTH(@search) > 3 && LEVENSHTEIN_MATCH(a.name.first, TOKENS(@search, 'text_ru')[0], 2, true)) || (LENGTH(@search) > 3 && LEVENSHTEIN_MATCH(a.name.first, TOKENS(@search, 'text_ru')[0], 2, true))
|| (LENGTH(@search) > 3 && LEVENSHTEIN_MATCH(a.name.second, TOKENS(@search, 'text_ru')[0], 2, true)) || (LENGTH(@search) > 3 && LEVENSHTEIN_MATCH(a.name.second, TOKENS(@search, 'text_ru')[0], 2, true))
|| (LENGTH(@search) > 3 && LEVENSHTEIN_MATCH(a.name.last, TOKENS(@search, 'text_ru')[0], 2, true)) || (LENGTH(@search) > 3 && LEVENSHTEIN_MATCH(a.name.last, TOKENS(@search, 'text_ru')[0], 2, true))
@ -269,7 +271,7 @@ final class worker extends core
'second' => $parameters['account_name_second'], 'second' => $parameters['account_name_second'],
'last' => $parameters['account_name_last'] 'last' => $parameters['account_name_last']
], ],
'number' => $parameters['account_number'] === 0 ? '' : $parameters['account_number'], 'number' => $parameters['account_number'],
'mail' => $parameters['account_mail'], 'mail' => $parameters['account_mail'],
'password' => sodium_crypto_pwhash_str( 'password' => sodium_crypto_pwhash_str(
$parameters['account_password'], $parameters['account_password'],
@ -293,9 +295,6 @@ final class worker extends core
]; ];
} }
// Инициализация идентификатора аккаунта (ключ документа инстанции аккаунта в базе данных)
$_key = preg_replace('/.+\//', '', $account ?? '');
// Запись заголовков ответа // Запись заголовков ответа
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Content-Encoding: none'); header('Content-Encoding: none');
@ -308,7 +307,7 @@ final class worker extends core
echo json_encode( echo json_encode(
[ [
'clipboard' => empty($this->errors['account']) ? <<<TEXT 'clipboard' => empty($this->errors['account']) ? <<<TEXT
Идентификатор: $_key Номер: {$parameters['account_number']}
Пароль: {$parameters['account_password']} Пароль: {$parameters['account_password']}
TEXT : '', TEXT : '',
'errors' => self::parse_only_text($this->errors['account']) 'errors' => self::parse_only_text($this->errors['account'])
@ -326,12 +325,13 @@ final class worker extends core
// Создание сотрудника // Создание сотрудника
$worker = model::create( $worker = model::create(
data: [ data: [
'id' => model::id(),
'name' => [ 'name' => [
'first' => $parameters['worker_name_first'], 'first' => $parameters['worker_name_first'],
'second' => $parameters['worker_name_second'], 'second' => $parameters['worker_name_second'],
'last' => $parameters['worker_name_last'] 'last' => $parameters['worker_name_last']
], ],
'number' => $parameters['worker_number'] === 0 ? '' : $parameters['worker_number'], 'number' => $parameters['worker_number'],
'mail' => $parameters['worker_mail'], 'mail' => $parameters['worker_mail'],
'birth' => $parameters['worker_birth'], 'birth' => $parameters['worker_birth'],
'passport' => $parameters['worker_passport'], 'passport' => $parameters['worker_passport'],
@ -380,7 +380,7 @@ final class worker extends core
// Авторизован аккаунт администратора или оператора // Авторизован аккаунт администратора или оператора
// Инициализация данных сотрудника // Инициализация данных сотрудника
$worker = model::read('d._key == "' . $parameters['id'] . '"', return: '{ name: d.name, number: d.number, mail: d.mail, birth: d.birth, passport: d.passport, issued: d.issued, department: d.department, requisites: d.requisites, payment: d.payment, tax: d.tax, city: d.city, district: d.district, address: d.address, hiring: d.hiring}')->getAll(); $worker = model::read('d.id == "' . $parameters['id'] . '"', return: '{ name: d.name, number: d.number, mail: d.mail, birth: d.birth, passport: d.passport, issued: d.issued, department: d.department, requisites: d.requisites, payment: d.payment, tax: d.tax, city: d.city, district: d.district, address: d.address, hiring: d.hiring}')->getAll();
if (!empty($worker)) { if (!empty($worker)) {
// Найдены данные сотрудника // Найдены данные сотрудника
@ -420,7 +420,7 @@ final class worker extends core
// Авторизован аккаунт администратора или оператора // Авторизован аккаунт администратора или оператора
// Инициализация данных сотрудника // Инициализация данных сотрудника
$worker = model::read('d._key == "' . $parameters['id'] . '"'); $worker = model::read('d.id == "' . $parameters['id'] . '"');
if (!empty($worker)) { if (!empty($worker)) {
// Найден сотрудник // Найден сотрудник
@ -515,7 +515,7 @@ final class worker extends core
// Авторизован аккаунт оператора или магазина // Авторизован аккаунт оператора или магазина
// Инициализация данных сотрудников // Инициализация данных сотрудников
$this->view->workers = model::read(filter: 'd.active == true', amount: 10000, return: '{ _key: d._key, name: d.name }'); $this->view->workers = model::read(filter: 'd.active == true', amount: 10000, return: '{ id: d.id, name: d.name }');
// Универсализация // Универсализация
if ($this->view->workers instanceof _document) $this->view->workers = [$this->view->workers]; if ($this->view->workers instanceof _document) $this->view->workers = [$this->view->workers];

View File

@ -129,13 +129,13 @@ final class account extends core
throw new exception('Неизвестная ошибка на этапе проверки пароля'); throw new exception('Неизвестная ошибка на этапе проверки пароля');
} }
} else throw new exception('Не найден пароль в буфере сессии'); } else throw new exception('Не найден пароль в буфере сессии');
} else if (!empty($session->buffer['market']['entry']['_key'])) { } else if (!empty($session->buffer['market']['entry']['id'])) {
// Найден идентификатор магазина в буфере сессии // Найден идентификатор магазина в буфере сессии
if (!empty($session->buffer['market']['entry']['password'])) { if (!empty($session->buffer['market']['entry']['password'])) {
// Найден пароль в буфере сессии // Найден пароль в буфере сессии
if (($account = self::read('d._key == "' . $session->buffer['market']['entry']['_key'] . '" && d.type == "market"', amount: 1)) instanceof _document) { if (($account = market::account(market::read('d.id == "' . $session->buffer['market']['entry']['id'] . '"', amount: 1)?->getId())) instanceof _document) {
// Найден аккаунт (игнорируются ошибки) // Найден аккаунт (игнорируются ошибки)
if (sodium_crypto_pwhash_str_verify($account->password, $session->buffer['market']['entry']['password'])) { if (sodium_crypto_pwhash_str_verify($account->password, $session->buffer['market']['entry']['password'])) {
@ -286,7 +286,7 @@ final class account extends core
RETURN e RETURN e
) )
FILTER d._id == e[0]._to && d.active == true FILTER d._id == e[0]._to && d.active == true
SORT d.created DESC, d._key DESC SORT d.created DESC, d.id DESC
LIMIT 1 LIMIT 1
RETURN d RETURN d
AQL, AQL,
@ -316,7 +316,7 @@ final class account extends core
* *
* Ищет связь аккаунта с сотрудником, если не находит, то создаёт её * Ищет связь аккаунта с сотрудником, если не находит, то создаёт её
* *
* @param string $worker Идентификатор инстанции документа аккаунта в базе данных * @param string $account Идентификатор инстанции документа аккаунта в базе данных
* @param string $target Идентификатор инстанции документа цели в базе данны (подразумевается сотрудник или магазин) * @param string $target Идентификатор инстанции документа цели в базе данны (подразумевается сотрудник или магазин)
* @param string $type Тип подключения (worker|market) * @param string $type Тип подключения (worker|market)
* @param array &$errors Реестр ошибок * @param array &$errors Реестр ошибок
@ -342,11 +342,11 @@ final class account extends core
LIMIT 1 LIMIT 1
RETURN d RETURN d
AQL, AQL,
self::COLLECTION . '_edge_' . worker::COLLECTION, self::COLLECTION . "_edge_$type",
$account, $account,
$target $target
)) instanceof _document )) instanceof _document
|| $id = document::write(static::$arangodb->session, self::COLLECTION . "_edge_$type", [ || document::write(static::$arangodb->session, self::COLLECTION . "_edge_$type", [
'_from' => $account, '_from' => $account,
'_to' => $target '_to' => $target
]) ])

View File

@ -132,6 +132,71 @@ class core extends model
return null; return null;
} }
/**
* Count documents in ArangoDB
*
* @param ?string $collection Коллекция для подсчёта
* @param array &$errors Реестр ошибок
*
* @return int|null Количество документов в базе данных, если найдены
*/
public static function count(?string $collection = null, array &$errors = []): int|null {
try {
if (collection::init(static::$arangodb->session, static::COLLECTION)) {
// Инициализирована коллекция
// Exit (success)
return collection::search(
static::$arangodb->session,
sprintf(
<<<'AQL'
RETURN LENGTH(%s)
AQL,
$collection ?? static::COLLECTION
)
);
} else throw new exception('Не удалось инициализировать коллекцию');
} catch (exception $e) {
// Запись в реестр ошибок
$errors[] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
// Exit (fail)
return null;
}
/**
* Сгенерировать идентификатор
*
* @param array &$errors Реестр ошибок
*
* @return int Свободный идентификатор (подразумевается)
*/
public static function id(array &$errors = []): int
{
try {
if (collection::init(static::$arangodb->session, static::COLLECTION))
return static::count(static::COLLECTION, $errors) ?? 0;
else throw new exception('Не удалось инициализировать коллекцию');
} catch (exception $e) {
// Запись в реестр ошибок
$errors[] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
return 0;
}
/** /**
* Delete from ArangoDB * Delete from ArangoDB
* *

View File

@ -145,8 +145,8 @@ final class task extends core
<<<AQL <<<AQL
FOR task IN %s FOR task IN %s
%s %s
LET worker = (FOR worker in %s FILTER worker._key LIKE task.worker SORT worker.created DESC, worker._key DESC LIMIT 1 RETURN worker)[0] LET worker = (FOR worker in %s FILTER worker.id LIKE task.worker SORT worker.created DESC, worker.id DESC LIMIT 1 RETURN worker)[0]
LET market = (FOR market in %s FILTER market._key LIKE task.market SORT market.created DESC, market._key DESC LIMIT 1 RETURN market)[0] LET market = (FOR market in %s FILTER market.id LIKE task.market SORT market.created DESC, market.id DESC LIMIT 1 RETURN market)[0]
%s %s
SORT %s SORT %s
LIMIT %d, %d LIMIT %d, %d

View File

@ -32,12 +32,6 @@ section#administrators.panel.list > div.row > span[data-column="account"] {
text-align: center; text-align: center;
} }
section#administrators.panel.list
> div.row:nth-of-type(1)
> span[data-column="account"] {
margin-top: 6px;
}
section#administrators.panel.list > div.row > span[data-column="name"] { section#administrators.panel.list > div.row > span[data-column="name"] {
min-width: 130px; min-width: 130px;
width: 130px; width: 130px;

View File

@ -30,18 +30,22 @@ section#markets.panel.list
} }
section#markets.panel.list > div.row > span:is([data-column="account"], [data-column="market"]) { section#markets.panel.list > div.row > span:is([data-column="account"], [data-column="market"]) {
min-width: 102px;
width: 102px;
font-weight: bold; font-weight: bold;
}
section#markets.panel.list > div.row:nth-of-type(1) > span[data-column="account"] {
text-align: center; text-align: center;
} }
section#workers.panel.list > div.row:nth-of-type(1) > span[data-column="account"] { section#markets.panel.list > div.row > span[data-column="account"] {
margin-top: 6px; min-width: 102px;
width: 102px;
text-align: center;
} }
section#workers.panel.list > div.row:nth-of-type(1) > span[data-column="market"] { section#markets.panel.list > div.row > span[data-column="market"] {
margin-top: 0px; min-width: 67px;
width: 67px;
} }
section#markets.panel.list > div.row > span[data-column="name"] { section#markets.panel.list > div.row > span[data-column="name"] {

View File

@ -32,10 +32,6 @@ section#operators.panel.list > div.row > span[data-column="account"] {
text-align: center; text-align: center;
} }
section#operators.panel.list > div.row:nth-of-type(1) > span[data-column="account"] {
margin-top: 6px;
}
section#operators.panel.list > div.row > span[data-column="name"] { section#operators.panel.list > div.row > span[data-column="name"] {
min-width: 130px; min-width: 130px;
width: 130px; width: 130px;

View File

@ -34,16 +34,28 @@ section#tasks.panel.list > div.row > span[data-column="date"] {
font-weight: bold; font-weight: bold;
} }
section#tasks.panel.list > div.row > span:is([data-column="worker"], [data-column="market"]) { section#tasks.panel.list > div.row > span:is([data-column="market"], [data-column="worker"]) {
min-width: 102px;
width: 102px;
font-weight: bold; font-weight: bold;
} }
section#tasks.panel.list > div.row:nth-of-type(1) > span[data-column="market"] {
text-align: center;
}
section#tasks.panel.list > div.row:nth-of-type(1) > span[data-column="worker"] { section#tasks.panel.list > div.row:nth-of-type(1) > span[data-column="worker"] {
margin-top: 8px; margin-top: 8px;
} }
section#tasks.panel.list > div.row > span[data-column="market"] {
min-width: 67px;
width: 67px;
text-align: right;
}
section#tasks.panel.list > div.row > span[data-column="worker"] {
min-width: 67px;
width: 67px;
}
section#tasks.panel.list > div.row > span[data-column="name"] { section#tasks.panel.list > div.row > span[data-column="name"] {
min-width: 130px; min-width: 130px;
width: 130px; width: 130px;

View File

@ -32,20 +32,28 @@ section#workers.panel.list
} }
section#workers.panel.list > div.row > span:is([data-column="account"], [data-column="worker"]) { section#workers.panel.list > div.row > span:is([data-column="account"], [data-column="worker"]) {
min-width: 102px;
width: 102px;
font-weight: bold; font-weight: bold;
text-align: center;
} }
section#workers.panel.list > div.row:nth-of-type(1) > span[data-column="account"] { section#workers.panel.list > div.row:nth-of-type(1) > span[data-column="account"] {
margin-top: 6px; text-align: center;
} }
section#workers.panel.list > div.row:nth-of-type(1) > span[data-column="worker"] { section#workers.panel.list > div.row:nth-of-type(1) > span[data-column="worker"] {
margin-top: 8px; margin-top: 8px;
} }
section#workers.panel.list > div.row > span[data-column="account"] {
min-width: 102px;
width: 102px;
text-align: center;
}
section#workers.panel.list > div.row > span[data-column="worker"] {
min-width: 67px;
width: 67px;
}
section#workers.panel.list > div.row > span[data-column="name"] { section#workers.panel.list > div.row > span[data-column="name"] {
min-width: 130px; min-width: 130px;
width: 130px; width: 130px;

View File

@ -275,7 +275,7 @@ if (typeof window.markets !== "function") {
"Content-Type": "application/x-www-form-urlencoded", "Content-Type": "application/x-www-form-urlencoded",
}, },
body: body:
`market_name_first=${market_name_first.value}&market_name_second=${market_name_second.value}&market_name_last=${market_name_last.value}&market_number=${market_number.mask.unmaskedValue}&market_mail=${market_mail.value}&market_type=${market_type.value}&market_city=${market_city.value}&market_district=${market_district.value}&market_address=${market_address.value}&account_name_first=${account_name_first.value}&account_name_second=${account_name_second.value}&account_name_last=${account_name_last.value}&account_number=${account_number.unmaskedValue}&account_mail=${account_mail.value}&account_password=${account_password.value}&account_commentary=${account_commentary.value}`, `market_name_first=${market_name_first.value}&market_name_second=${market_name_second.value}&market_name_last=${market_name_last.value}&market_number=${market_number.mask.unmaskedValue}&market_mail=${market_mail.value}&market_type=${market_type.value}&market_city=${market_city.value}&market_district=${market_district.value}&market_address=${market_address.value}&account_name_first=${account_name_first.value}&account_name_second=${account_name_second.value}&account_name_last=${account_name_last.value}&account_number=${account_number.mask.unmaskedValue}&account_mail=${account_mail.value}&account_password=${account_password.value}&account_commentary=${account_commentary.value}`,
}) })
.then((response) => response.json()) .then((response) => response.json())
.then((data) => { .then((data) => {
@ -1159,7 +1159,7 @@ if (typeof window.markets !== "function") {
this.body.wrap.remove(); this.body.wrap.remove();
// Удаление статуса активной строки // Удаление статуса активной строки
row.removeAttribute("data-selected"); // row.removeAttribute("data-selected"); // Это окно создания строки, её ещё не существует
// Деинициализация быстрых действий по кнопкам // Деинициализация быстрых действий по кнопкам
document.removeEventListener("keydown", this.buttons); document.removeEventListener("keydown", this.buttons);

View File

@ -1,7 +1,7 @@
<section class="row merged chat cloud rounded" data-chat-element="messages"> <section class="row merged chat cloud rounded" data-chat-element="messages">
{% for message in messages %} {% for message in messages %}
<div class="message {% if message.type != 'message' %}{{ message.type }}{% endif %}"> <div class="message {% if message.type != 'message' %}{{ message.type }}{% endif %}">
<h3 class="coal"><b>{{ message.from._key }}</b> <span class="unselectable">{{ message.from.type|account_type_to_russian }}</span> <span class="date unselectable"><b>{{ message.date|date('H:i d.m.Y') }}</b></span></h3> <h3 class="coal"><b>{{ message.from.id ?? message.from._key }}</b> <span class="unselectable">{{ message.from.type|account_type_to_russian }}</span> <span class="date unselectable"><b>{{ message.date|date('H:i d.m.Y') }}</b></span></h3>
<p>{{ message.text }}</p> <p>{{ message.text }}</p>
</div> </div>
{% endfor %} {% endfor %}

View File

@ -1,5 +1,5 @@
<!-- MARKET #{{ market.id.value }} --> <!-- MARKET #{{ market.id.value }} -->
{% for key, data in market | filter((data, key) => key != '_key') -%} {% for key, data in market | filter((data, key) => key != 'id') -%}
{% if key == 'created' or key == 'updated' %} {% if key == 'created' or key == 'updated' %}
<span id="{{ market.id.value }}_{{ key }}"><b>{{ data.label }}:</b>{{ data.value is empty ? 'Никогда' : <span id="{{ market.id.value }}_{{ key }}"><b>{{ data.label }}:</b>{{ data.value is empty ? 'Никогда' :
data.value|date('Y.m.d H:i:s') }}</span> data.value|date('Y.m.d H:i:s') }}</span>
@ -7,10 +7,10 @@
<span id="{{ market.id.value }}_number"><b>{{ data.label }}:</b><a href="tel:{{ data.value }}" title="Позвонить">{{ <span id="{{ market.id.value }}_number"><b>{{ data.label }}:</b><a href="tel:{{ data.value }}" title="Позвонить">{{
data.value }}</a></span> data.value }}</a></span>
{% elseif key == 'mail' %} {% elseif key == 'mail' %}
<span id="{{ worker.id.value }}_number"><b>{{ data.label }}:</b><a href="mailto:{{ data.value }}" title="Написать">{{ <span id="{{ market.id.value }}_number"><b>{{ data.label }}:</b><a href="mailto:{{ data.value }}" title="Написать">{{
data.value }}</a></span> data.value }}</a></span>
{% elseif key == 'name' %} {% elseif key == 'name' %}
<span id="{{ worker._key.value }}_{{ key }}"><b>{{ data.label }}:</b>{% if data.value.first is not empty %}{{ data.value.first }}{% endif %}{% if data.value.second is not empty %} {{ data.value.second }}{% endif %}{% if data.value.last is not empty %} {{ data.value.last }}{% endif %}</span> <span id="{{ market.id.value }}_{{ key }}"><b>{{ data.label }}:</b>{% if data.value.first is not empty %}{{ data.value.first }}{% endif %}{% if data.value.second is not empty %} {{ data.value.second }}{% endif %}{% if data.value.last is not empty %} {{ data.value.last }}{% endif %}</span>
{% else %} {% else %}
<span id="{{ market.id.value }}_{{ key }}"><b>{{ data.label }}:</b>{% if data.value is same as(true) %}Да{% elseif data.value is same as(false) %}Нет{% elseif data.value is empty %}{% else %}{{ data.value }}{% endif %}</span> <span id="{{ market.id.value }}_{{ key }}"><b>{{ data.label }}:</b>{% if data.value is same as(true) %}Да{% elseif data.value is same as(false) %}Нет{% elseif data.value is empty %}{% else %}{{ data.value }}{% endif %}</span>
{% endif %} {% endif %}

View File

@ -2,7 +2,7 @@
{% for key, data in task | filter((data, key) => key != '_key') -%} {% for key, data in task | filter((data, key) => key != '_key') -%}
{% if (key == 'created' or key == 'updated' or key == 'start' or key == 'end') %} {% if (key == 'created' or key == 'updated' or key == 'start' or key == 'end') %}
<span id="{{ task.id.value }}_{{ key }}"><b>{{ data.label }}:</b>{{ data.value is empty ? 'Никогда' : <span id="{{ task.id.value }}_{{ key }}"><b>{{ data.label }}:</b>{{ data.value is empty ? 'Никогда' :
data.value|date('d.m.Y H:i', ) }}</span> data.value|date('d.m.Y H:i') }}</span>
{% elseif key == 'confirmed' or key == 'hided' %} {% elseif key == 'confirmed' or key == 'hided' %}
<span id="{{ task.id.value }}_{{ key }}"><b>{{ data.label }}:</b>{% if data.value is same as(true) %}Да{% elseif <span id="{{ task.id.value }}_{{ key }}"><b>{{ data.label }}:</b>{% if data.value is same as(true) %}Да{% elseif
data.value is same as(false) or data.value is empty %}Нет{% else %}{{ data.value }}{% endif %}</span> data.value is same as(false) or data.value is empty %}Нет{% else %}{{ data.value }}{% endif %}</span>

View File

@ -1,21 +1,21 @@
<!-- WORKER #{{ worker.id.value }} --> <!-- WORKER #{{ worker.id.value }} -->
{% for key, data in worker | filter((data, key) => key != '_key') -%} {% for key, data in worker | filter((data, key) => key != 'id') -%}
{% if key == 'created' or key == 'updated' %} {% if key == 'created' or key == 'updated' %}
<span id="{{ worker._key.value }}_{{ key }}"><b>{{ data.label }}:</b>{{ data.value is empty ? 'Никогда' : <span id="{{ worker.id.value }}_{{ key }}"><b>{{ data.label }}:</b>{{ data.value is empty ? 'Никогда' :
data.value|date('Y.m.d H:i:s') }}</span> data.value|date('Y.m.d H:i:s') }}</span>
{% elseif key == 'hiring' or key == 'birth' or key == 'issued' %} {% elseif key == 'hiring' or key == 'birth' or key == 'issued' %}
<span id="{{ worker._key.value }}_{{ key }}"><b>{{ data.label }}:</b>{{ data.value|date('Y.m.d') }}</span> <span id="{{ worker.id.value }}_{{ key }}"><b>{{ data.label }}:</b>{{ data.value|date('Y.m.d') }}</span>
{% elseif key == 'number' %} {% elseif key == 'number' %}
<span id="{{ worker._key.value }}_number"><b>{{ data.label }}:</b><a href="tel:{{ data.value }}" title="Позвонить">{{ <span id="{{ worker.id.value }}_number"><b>{{ data.label }}:</b><a href="tel:{{ data.value }}" title="Позвонить">{{
data.value }}</a></span> data.value }}</a></span>
{% elseif key == 'mail' %} {% elseif key == 'mail' %}
<span id="{{ worker.id.value }}_number"><b>{{ data.label }}:</b><a href="mailto:{{ data.value }}" title="Написать">{{ <span id="{{ worker.id.value }}_number"><b>{{ data.label }}:</b><a href="mailto:{{ data.value }}" title="Написать">{{
data.value }}</a></span> data.value }}</a></span>
{% elseif key == 'name' %} {% elseif key == 'name' %}
<span id="{{ worker._key.value }}_{{ key }}"><b>{{ data.label }}:</b>{% if data.value.first is not empty %}{{ data.value.first }}{% endif %}{% if data.value.second is not empty %} {{ data.value.second }}{% endif %}{% if data.value.last is not empty %} {{ data.value.last }}{% endif %}</span> <span id="{{ worker.id.value }}_{{ key }}"><b>{{ data.label }}:</b>{% if data.value.first is not empty %}{{ data.value.first }}{% endif %}{% if data.value.second is not empty %} {{ data.value.second }}{% endif %}{% if data.value.last is not empty %} {{ data.value.last }}{% endif %}</span>
{% elseif key == 'department' %} {% elseif key == 'department' %}
<span id="{{ worker._key.value }}_{{ key }}"><b>{{ data.label }}:</b>{{ (data.value.number ~ ' ' ~ data.value.address)|trim }}</span> <span id="{{ worker.id.value }}_{{ key }}"><b>{{ data.label }}:</b>{{ (data.value.number ~ ' ' ~ data.value.address)|trim }}</span>
{% else %} {% else %}
<span id="{{ worker._key.value }}_{{ key }}"><b>{{ data.label }}:</b>{% if data.value is same as(true) %}Да{% elseif data.value is same as(false) %}Нет{% elseif data.value is empty %}{% else %}{{ data.value }}{% endif %}</span> <span id="{{ worker.id.value }}_{{ key }}"><b>{{ data.label }}:</b>{% if data.value is same as(true) %}Да{% elseif data.value is same as(false) %}Нет{% elseif data.value is empty %}{% else %}{{ data.value }}{% endif %}</span>
{% endif %} {% endif %}
{% endfor %} {% endfor %}

View File

@ -2,7 +2,7 @@
{% for row in rows %} {% for row in rows %}
<div id="{{ row.account._key }}" class="row{% if row.account.active is same as(true) %} active{% else %} hided{% endif %}" data-row="market"> <div id="{{ row.account._key }}" class="row{% if row.account.active is same as(true) %} active{% else %} hided{% endif %}" data-row="market">
<span class="unselectable interactive" data-column="account" title="Аккаунт" onclick="markets.account.update(this.parentElement)">{{ row.account._key }}</span> <span class="unselectable interactive" data-column="account" title="Аккаунт" onclick="markets.account.update(this.parentElement)">{{ row.account._key }}</span>
<span class="unselectable interactive" data-column="market" title="Магазин" onclick="markets.update(this.parentElement)">{{ row.market._key }}</span> <span class="unselectable interactive" data-column="market" title="Магазин" onclick="markets.update(this.parentElement)">{{ row.market.id }}</span>
<span class="unselectable interactive" data-column="name" title="{% if row.market.name.first is not empty %}{{ row.market.name.first }}{% endif %}{% if row.market.name.second is not empty %} {{ row.market.name.second }}{% endif %}{% if row.market.name.last is not empty %} {{ row.market.name.last }}{% endif %}">{% if row.market.name.first is not empty %}{{ row.market.name.first|slice(0, 1)|upper }}.{% endif %}{% if row.market.name.last is not empty %} {{ row.market.name.last|slice(0, 1)|upper }}.{% endif %}{% if row.market.name.second is not empty %} {{ row.market.name.second }}{% endif %}</span> <span class="unselectable interactive" data-column="name" title="{% if row.market.name.first is not empty %}{{ row.market.name.first }}{% endif %}{% if row.market.name.second is not empty %} {{ row.market.name.second }}{% endif %}{% if row.market.name.last is not empty %} {{ row.market.name.last }}{% endif %}">{% if row.market.name.first is not empty %}{{ row.market.name.first|slice(0, 1)|upper }}.{% endif %}{% if row.market.name.last is not empty %} {{ row.market.name.last|slice(0, 1)|upper }}.{% endif %}{% if row.market.name.second is not empty %} {{ row.market.name.second }}{% endif %}</span>
<span class="unselectable interactive" data-column="number"><a href="tel:{{ row.market.number }}" title="Позвонить">{{ row.market.number|storaged_number_to_readable }}</a></span> <span class="unselectable interactive" data-column="number"><a href="tel:{{ row.market.number }}" title="Позвонить">{{ row.market.number|storaged_number_to_readable }}</a></span>
<span class="unselectable interactive" data-column="mail"><a href="mailto:{{ row.market.mail }}" title="Написать письмо">{{ row.market.mail }}</a></span> <span class="unselectable interactive" data-column="mail"><a href="mailto:{{ row.market.mail }}" title="Написать письмо">{{ row.market.mail }}</a></span>

View File

@ -10,7 +10,7 @@
}}</span> }}</span>
<span class="unselectable interactive" data-column="worker" title="{{ row.worker.id }}" {% if account.type !='worker' <span class="unselectable interactive" data-column="worker" title="{{ row.worker.id }}" {% if account.type !='worker'
%}onclick="tasks.worker.popup(this.parentElement)" {% endif %}>{{ %}onclick="tasks.worker.popup(this.parentElement)" {% endif %}>{{
row.worker._key }}</span> row.worker.id }}</span>
<span class="unselectable interactive" data-column="name" <span class="unselectable interactive" data-column="name"
title="{% if row.worker.name.first is not empty %}{{ row.worker.name.first }}{% endif %}{% if row.worker.name.second is not empty %} {{ row.worker.name.second }}{% endif %}{% if row.worker.name.last is not empty %} {{ row.worker.name.last }}{% endif %}">{% title="{% if row.worker.name.first is not empty %}{{ row.worker.name.first }}{% endif %}{% if row.worker.name.second is not empty %} {{ row.worker.name.second }}{% endif %}{% if row.worker.name.last is not empty %} {{ row.worker.name.last }}{% endif %}">{%
if row.worker.name.first is not empty %}{{ if row.worker.name.first is not empty %}{{
@ -27,7 +27,7 @@
row.task.generated.hours }}</span> row.task.generated.hours }}</span>
<span class="unselectable interactive" data-column="market" {% if account.type !='market' and account.type !='worker' <span class="unselectable interactive" data-column="market" {% if account.type !='market' and account.type !='worker'
%}onclick="tasks.market.popup(this.parentElement)" {% endif %}>{{ %}onclick="tasks.market.popup(this.parentElement)" {% endif %}>{{
row.market._key }}</span> row.market.id }}</span>
<span class="unselectable interactive" data-column="address" <span class="unselectable interactive" data-column="address"
title="{% if row.market.city is not null %}{{ row.market.city }}, {% endif %}{{ row.market.address }}">{% if title="{% if row.market.city is not null %}{{ row.market.city }}, {% endif %}{{ row.market.address }}">{% if
row.market.city is not null %}{{ row.market.city }}, {% endif row.market.city is not null %}{{ row.market.city }}, {% endif

View File

@ -5,7 +5,7 @@
<span class="unselectable interactive" data-column="account" title="Настройки аккаунта" onclick="workers.account.update(this.parentElement)">{{ <span class="unselectable interactive" data-column="account" title="Настройки аккаунта" onclick="workers.account.update(this.parentElement)">{{
row.account._key }}</span> row.account._key }}</span>
<span class="unselectable interactive" data-column="worker" title="Настройки сотрудника" onclick="workers.update(this.parentElement)">{{ <span class="unselectable interactive" data-column="worker" title="Настройки сотрудника" onclick="workers.update(this.parentElement)">{{
row.worker._key }}</span> row.worker.id }}</span>
<span class="unselectable interactive" data-column="name" <span class="unselectable interactive" data-column="name"
title="{% if row.worker.name.first is not empty %}{{ row.worker.name.first }}{% endif %}{% if row.worker.name.second is not empty %} {{ row.worker.name.second }}{% endif %}{% if row.worker.name.last is not empty %} {{ row.worker.name.last }}{% endif %}{% if row.worker.birth is not empty %} {{ row.worker.birth|date('d.m.Y') }}{% endif %}" onclick="navigator.clipboard.writeText('{% if row.worker.name.first is not empty %}{{ row.worker.name.first }}{% endif %}{% if row.worker.name.second is not empty %} {{ row.worker.name.second }}{% endif %}{% if row.worker.name.last is not empty %} {{ row.worker.name.last }}{% endif %}{% if row.worker.birth is not empty %} {{ row.worker.birth|date('d.m.Y') }}{% endif %}')">{% title="{% if row.worker.name.first is not empty %}{{ row.worker.name.first }}{% endif %}{% if row.worker.name.second is not empty %} {{ row.worker.name.second }}{% endif %}{% if row.worker.name.last is not empty %} {{ row.worker.name.last }}{% endif %}{% if row.worker.birth is not empty %} {{ row.worker.birth|date('d.m.Y') }}{% endif %}" onclick="navigator.clipboard.writeText('{% if row.worker.name.first is not empty %}{{ row.worker.name.first }}{% endif %}{% if row.worker.name.second is not empty %} {{ row.worker.name.second }}{% endif %}{% if row.worker.name.last is not empty %} {{ row.worker.name.last }}{% endif %}{% if row.worker.birth is not empty %} {{ row.worker.birth|date('d.m.Y') }}{% endif %}')">{%
if row.worker.name.first is not empty %}{{ if row.worker.name.first is not empty %}{{

View File

@ -1,5 +1,5 @@
{% for market in markets %} {% for market in markets %}
<option value="{{ market.getKey() }}">{{ market.getKey() }}{% if market.name.first is not empty %} {{ <option value="{{ market.id }}">{{ market.id }}{% if market.name.first is not empty %} {{
market.name.first|slice(0, 1)|upper }}.{% endif %}{% if market.name.last is not empty %} {{ market.name.last|slice(0, market.name.first|slice(0, 1)|upper }}.{% endif %}{% if market.name.last is not empty %} {{ market.name.last|slice(0,
1)|upper }}.{% endif %}{% if market.name.second is not empty %} {{ market.name.second }}{% endif %}</option> 1)|upper }}.{% endif %}{% if market.name.second is not empty %} {{ market.name.second }}{% endif %}</option>
{% endfor %} {% endfor %}

View File

@ -1,5 +1,5 @@
{% for worker in workers %} {% for worker in workers %}
<option value="{{ worker.getKey() }}">{{ worker.getKey() }}{% if worker.name.first is not empty %} {{ <option value="{{ worker.id }}">{{ worker.id }}{% if worker.name.first is not empty %} {{
worker.name.first|slice(0, 1)|upper }}.{% endif %}{% if worker.name.last is not empty %} {{ worker.name.first|slice(0, 1)|upper }}.{% endif %}{% if worker.name.last is not empty %} {{
worker.name.last|slice(0, 1)|upper }}.{% endif %}{% if worker.name.second is not empty %} {{ worker.name.last|slice(0, 1)|upper }}.{% endif %}{% if worker.name.second is not empty %} {{
worker.name.second }}{% endif %}</option> worker.name.second }}{% endif %}</option>

View File

@ -25,8 +25,8 @@
class="icon arrow right"></i></button> class="icon arrow right"></i></button>
<datalist id="markets"> <datalist id="markets">
{% for account in accounts %} {% for account in accounts %}
<option value="{{ account.account.getKey() }}">{{ account.account.getKey()}} {{ <option value="{{ account.market }}">{{ account.market }} {{
account.account.name.first }} {{ account.account.name.second }}</option> account.market.name.first }} {{ account.market.name.second }}</option>
{% endfor %} {% endfor %}
</datalist> </datalist>
</label> </label>