diff --git a/mirzaev/ebala/system/controllers/account.php b/mirzaev/ebala/system/controllers/account.php index d440252..2891c3e 100755 --- a/mirzaev/ebala/system/controllers/account.php +++ b/mirzaev/ebala/system/controllers/account.php @@ -8,6 +8,7 @@ namespace mirzaev\ebala\controllers; use mirzaev\ebala\controllers\core, mirzaev\ebala\controllers\traits\errors, mirzaev\ebala\models\account as model, + mirzaev\ebala\models\task, mirzaev\ebala\models\registry, mirzaev\ebala\models\core as _core; @@ -27,6 +28,37 @@ final class account extends core { use errors; + /** + * Страница аккаунта + * + * @param array $parameters Параметры запроса + */ + public function index(array $parameters = []): ?string + { + if ($this->account->status()) { + // Авторизован аккаунт + + // Инициализация истории заявок + $this->view->history = task::list(before: 'FILTER task.worker == "' . model::worker($this->account->getId())?->id . '"'); + + // Инициализация баланса счёта + // В будущем сделать перебор по всем связанным с аккаунтам сотрудникам и магазинам (сейчас только 1 сотрудник может быть) + $this->view->balance = 0; + foreach (task::list(before: 'FILTER task.worker == "' . model::worker($this->account->getId())?->id . '" && task.result.processed == false') as $task) $this->view->balance += $task->task['result']['hours'] * $task->task['result']['hour'] + $task->task['result']['penalty'] + $task->task['result']['bonus']; + + // Генерация представления + $main = $this->view->render(DIRECTORY_SEPARATOR . 'pages' . DIRECTORY_SEPARATOR . 'account.html'); + } else $main = $this->authorization(); + + // Возврат (успех) + if ($_SERVER['REQUEST_METHOD'] === 'GET') return $this->view->render(DIRECTORY_SEPARATOR . 'index.html', ['main' => $main]); + else if ($_SERVER['REQUEST_METHOD'] === 'POST') return $main; + + // Возврат (провал) + return null; + } + + /** * Прочитать данные * diff --git a/mirzaev/ebala/system/controllers/market.php b/mirzaev/ebala/system/controllers/market.php index 4a955d7..cdbad44 100755 --- a/mirzaev/ebala/system/controllers/market.php +++ b/mirzaev/ebala/system/controllers/market.php @@ -388,6 +388,166 @@ final class market extends core return null; } + /** + * Заблокировать сотрудника в магазине + * + * @param array $parameters Параметры запроса + */ + public function ban(array $parameters = []): ?string + { + if ($this->account->status() && $this->account->type === 'market') { + // Авторизован аккаунт магазина + + // Инициализация данных магазина + $market = account::market($this->account->getId()); + + if ($market instanceof _document) { + // Найден магазин + + // Блокировка сотрудника + if (!in_array($parameters['worker'], $market->bans ??= [], true)) $market->bans = $market->bans + [$parameters['worker']]; + + if (_core::update($market)) { + // Записаны данные магазина + + // Запись в глобальную переменную шаблонизатора обрабатываемой страницы (отключение) + $this->view->page = null; + + // Запись заголовков ответа + header('Content-Type: application/json'); + header('Content-Encoding: none'); + header('X-Accel-Buffering: no'); + + // Инициализация буфера вывода + ob_start(); + + // Инициализация буфера ответа + $return = [ + 'banned' => true, + 'errors' => self::parse_only_text($this->errors) + ]; + + // Генерация ответа + echo json_encode($return); + + // Запись заголовков ответа + header('Content-Length: ' . ob_get_length()); + + // Отправка и деинициализация буфера вывода + ob_end_flush(); + flush(); + } else throw new exception('Не удалось записать изменения в базу данных'); + } else throw new exception('Не удалось найти магазин'); + } + + // Возврат (провал) + return null; + } + + /** + * Разблокировать сотрудника в магазине + * + * @param array $parameters Параметры запроса + */ + public function unban(array $parameters = []): ?string + { + if ($this->account->status() && $this->account->type === 'market') { + // Авторизован аккаунт магазина + + // Инициализация данных магазина + $market = account::market($this->account->getId()); + + if ($market instanceof _document) { + // Найден магазин + + // Разблокировка сотрудника + if (in_array($parameters['worker'], $market->bans ??= [], true)) $market->bans = array_diff($market->bans ??= [], [$parameters['worker']]); + + if (_core::update($market)) { + // Записаны данные магазина + + // Запись в глобальную переменную шаблонизатора обрабатываемой страницы (отключение) + $this->view->page = null; + + // Запись заголовков ответа + header('Content-Type: application/json'); + header('Content-Encoding: none'); + header('X-Accel-Buffering: no'); + + // Инициализация буфера вывода + ob_start(); + + // Инициализация буфера ответа + $return = [ + 'unbanned' => true, + 'errors' => self::parse_only_text($this->errors) + ]; + + // Генерация ответа + echo json_encode($return); + + // Запись заголовков ответа + header('Content-Length: ' . ob_get_length()); + + // Отправка и деинициализация буфера вывода + ob_end_flush(); + flush(); + } else throw new exception('Не удалось записать изменения в базу данных'); + } else throw new exception('Не удалось найти магазин'); + } + + // Возврат (провал) + return null; + } + + /** + * Проверить наличие сотрудника в реестре заблокированных + * + * @param array $parameters Параметры запроса + */ + public function banned(array $parameters = []): ?string + { + if ($this->account->status() && $this->account->type === 'market') { + // Авторизован аккаунт магазина + + // Инициализация данных магазина + $market = account::market($this->account->getId()); + + if ($market instanceof _document) { + // Найден магазин + + // Запись в глобальную переменную шаблонизатора обрабатываемой страницы (отключение) + $this->view->page = null; + + // Запись заголовков ответа + header('Content-Type: application/json'); + header('Content-Encoding: none'); + header('X-Accel-Buffering: no'); + + // Инициализация буфера вывода + ob_start(); + + // Инициализация буфера ответа + $return = [ + 'banned' => in_array($parameters['worker'], $market->bans ?? [], true), + 'errors' => self::parse_only_text($this->errors) + ]; + + // Генерация ответа + echo json_encode($return); + + // Запись заголовков ответа + header('Content-Length: ' . ob_get_length()); + + // Отправка и деинициализация буфера вывода + ob_end_flush(); + flush(); + } else throw new exception('Не удалось найти магазин'); + } + + return null; + } + /** * Обновить данные * @@ -416,6 +576,7 @@ final class market extends core if ($parameters['city'] !== $market->city) $market->city = $parameters['city']; if ($parameters['district'] !== $market->district) $market->district = $parameters['district']; if ($parameters['address'] !== $market->address) $market->address = $parameters['address']; + if (!in_array($parameters['ban'], $market->bans, true)) $market->bans[] = $parameters['ban']; if (_core::update($market)) { // Записаны данные магазина diff --git a/mirzaev/ebala/system/controllers/payments.php b/mirzaev/ebala/system/controllers/payments.php index 2ddfcc8..6675c1d 100755 --- a/mirzaev/ebala/system/controllers/payments.php +++ b/mirzaev/ebala/system/controllers/payments.php @@ -76,7 +76,7 @@ final class payments extends core } else throw new exception('Вы не авторизованы'); } catch (exception $e) { // Запись в реестр ошибок - $this->errors[] = [ + $this->errors['export'][] = [ 'text' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine(), @@ -110,7 +110,7 @@ final class payments extends core /** * Магазины * - * Расчитать ... (сверку?) за выбранный период и сгенерировать excel-документ + * Расчитать прибыль с магазинов за выбранный период и сгенерировать excel-документ * * @param array $parameters Параметры запроса * @@ -161,7 +161,7 @@ final class payments extends core } else throw new exception('Вы не авторизованы'); } catch (exception $e) { // Запись в реестр ошибок - $this->errors[] = [ + $this->errors['export'][] = [ 'text' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine(), @@ -192,4 +192,74 @@ final class payments extends core } } + /** + * Подтвердить + * + * Подтвердить выполнение операций с документом (магазины или сотрудники) + * + * @param array $parameters Параметры запроса + * + * @return void + */ + public function confirm(array $parameters = []): void + { + try { + if ($this->account->status() && ($this->account->type === 'administrator' || $this->account->type === 'operator')) { + // Авторизован аккаунт администратора или оператора + + // Инициализация буфера ошибок + $this->errors['confirm'] ??= []; + + if (!empty($from = (int) ($_COOKIE["tasks_filter_from"] ?? @$this->session->buffer[$_SERVER['INTERFACE']]['tasks']['filters']['from']))) { + // Инициализирован параметр: from + + if (!empty($to = (int) ($_COOKIE["tasks_filter_to"] ?? @$this->session->buffer[$_SERVER['INTERFACE']]['tasks']['filters']['to']))) { + // Инициализирован параметр: to + + // Запуск процедуры подтверждения + model::confirm( + $from, + $to, + match ($parameters['type']) { + 'workers' => 'workers', + 'markets' => 'markets', + default => throw new exception('Для подтверждения обработки документа необходимо передать его тип: workers, markets') + }, + $this->errors['confirm'] + ); + } else throw new exception('Не инициализирован параметр: to'); + } else throw new exception('Не инициализирован параметр: from'); + } else throw new exception('Вы не авторизованы'); + } catch (exception $e) { + // Запись в реестр ошибок + $this->errors['confirm'][] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + + // Запись заголовков ответа + header('Content-Type: application/json'); + header('Content-Encoding: none'); + header('X-Accel-Buffering: no'); + + // Инициализация буфера вывода + ob_start(); + + // Генерация ответа + echo json_encode( + [ + 'errors' => self::parse_only_text($this->errors) + ] + ); + + // Запись заголовков ответа + header('Content-Length: ' . ob_get_length()); + + // Отправка и деинициализация буфера вывода + ob_end_flush(); + flush(); + } + } } diff --git a/mirzaev/ebala/system/controllers/task.php b/mirzaev/ebala/system/controllers/task.php index 84b8c7f..8f78a04 100755 --- a/mirzaev/ebala/system/controllers/task.php +++ b/mirzaev/ebala/system/controllers/task.php @@ -558,15 +558,15 @@ final class task extends core $end = $date->setTime((int) $end->format('H'), (int) $end->format('i'))->format('U'); // Заявка уже начата? - if (time() - $start > 0) + if (time() - $start > 0 && time() - $end < 0) throw new exception('Запрещено редактировать начатую заявку'); // Заявка уже прошла? - if (time() - $end > 0) + else if (time() - $end > 0 && $task->completed !== true) throw new exception('Запрещено редактировать прошедшую заявку'); // Заявка уже завершена? - if ($task->completed === true) + else if ($task->completed === true) throw new exception('Запрещено редактировать завершённую заявку'); // Прошло более 30 минут после создания заявки? (1800 секунд = 30 минут) @@ -861,7 +861,7 @@ final class task extends core // Перевод ключей на русский язык foreach ($this->view->task as $key => $value) if ($key === 'updates') - foreach ($value as $key => $value) $buffer['updates'][$key] = [ + foreach ($value ?? [] as $key => $value) $buffer['updates'][$key] = [ 'label' => match ($key) { 'operator' => 'Оператор', 'market' => 'Магазин', @@ -1473,31 +1473,41 @@ final class task extends core // Иниализация сотрудника $worker = worker::read('d.id == "' . $task->worker . '"'); - // Инициализация магазина - $market = market::read('d.id == "' . $task->market . '"'); + if ($worker instanceof _document) { + // Найден сотрудник - // Подсчёт часов работы - $hours = model::hours($task->start, $task->end, $this->errors); + // Инициализация магазина + $market = market::read('d.id == "' . $task->market . '"'); - // Инициализация цены работы за 1 час - $hour = payments::hour($market->city, $task->work); + if ($market instanceof _document) { + // Найден магазин - // Подсчёт оплаты за работу - $payment = $hour * $hours; + // Подсчёт часов работы + $hours = model::hours($task->start, $task->end, $this->errors); - // Инициализация штрафа - $penalty = payments::penalty($task->rating ?? null); + // Инициализация цены работы сотрудника за 1 час + $hour = payments::hour('worker', $market->city, $task->work); - // Инициализация премии - $bonus = payments::bonus($task->rating ?? null); + // Подсчёт оплаты за работу + $payment = $hour * $hours; - // Инициализация транзакции к оплате сотруднику - model::transaction( - $task->getId(), - $worker->getId(), - $payment - ($penalty === null ? $payment : -$penalty) + $bonus, - $this->errors - ); + // Инициализация штрафа + $penalty = payments::penalty($task->rating ?? null); + if ($penalty === null) $penalty = -$payment; + + // Инициализация премии + $bonus = payments::bonus($task->rating ?? null); + + // Запись результатов + $task->result = [ + 'hours' => $hours, + 'hour' => $hour, + 'penalty' => $penalty, + 'bonus' => $bonus, + 'processed' => false + ]; + } + } } // Запись в реcстре последних обновивших @@ -1709,15 +1719,15 @@ final class task extends core $end = $date->setTime((int) $end->format('H'), (int) $end->format('i'))->format('U'); // Заявка уже начата? - if (time() - $start > 0) + if (time() - $start > 0 && time() - $end < 0) throw new exception('Запрещено удалять начатую заявку'); // Заявка уже прошла? - if (time() - $end > 0) + else if (time() - $end > 0 && $task->completed !== true) throw new exception('Запрещено удалять прошедшую заявку'); // Заявка уже завершена? - if ($task->completed === true) + else if ($task->completed === true) throw new exception('Запрещено удалять завершённую заявку'); // Прошло более 30 минут после создания заявки? (1800 секунд = 30 минут) @@ -2092,15 +2102,15 @@ final class task extends core $end = $date->setTime((int) $end->format('H'), (int) $end->format('i'))->format('U'); // Заявка уже начата? - if (time() - $start > 0) + if (time() - $start > 0 && time() - $end < 0) throw new exception('Запрещено редактировать тип работы начатой заявки'); // Заявка уже прошла? - if (time() - $end > 0) + else if (time() - $end > 0 && $task->completed !== true) throw new exception('Запрещено редактировать тип работы прошедшей заявки'); // Заявка уже завершена? - if ($task->completed === true) + else if ($task->completed === true) throw new exception('Запрещено редактировать тип работы завершённой заявки'); // Прошло более 30 минут после создания заявки? (1800 секунд = 30 минут) @@ -2348,15 +2358,15 @@ final class task extends core $end = $date->setTime((int) $end->format('H'), (int) $end->format('i'))->format('U'); // Заявка уже начата? - if (time() - $start > 0) + if (time() - $start > 0 && time() - $end < 0) throw new exception('Запрещено редактировать дату и время начатой заявки'); // Заявка уже прошла? - if (time() - $end > 0) + else if (time() - $end > 0 && $task->completed !== true) throw new exception('Запрещено редактировать дату и время прошедшей заявки'); // Заявка уже завершена? - if ($task->completed === true) + else if ($task->completed === true) throw new exception('Запрещено редактировать дату и время завершённой заявки'); // Прошло более 30 минут после создания заявки? (1800 секунд = 30 минут) diff --git a/mirzaev/ebala/system/controllers/worker.php b/mirzaev/ebala/system/controllers/worker.php index 6d2df95..cad1696 100755 --- a/mirzaev/ebala/system/controllers/worker.php +++ b/mirzaev/ebala/system/controllers/worker.php @@ -146,41 +146,55 @@ final class worker extends core ? null : << 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.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) > 7 && LEVENSHTEIN_MATCH(a.address, TOKENS(@search, 'text_ru')[0], 2, true)) - || (LENGTH(@search) > 4 && LEVENSHTEIN_MATCH(a.city, TOKENS(@search, 'text_ru')[0], 1, true)) - || (LENGTH(@search) > 4 && LEVENSHTEIN_MATCH(a.district, TOKENS(@search, 'text_ru')[0], 1, true)) + || (LENGTH(@search) > 5 && LEVENSHTEIN_MATCH(b._key, TOKENS(@search, 'text_en')[0], 2, true)) + || (LENGTH(@search) > 4 && LEVENSHTEIN_MATCH(b.id, TOKENS(@search, 'text_en')[0], 1, true)) + || (LENGTH(@search) > 3 && LEVENSHTEIN_MATCH(b.name.first, TOKENS(@search, 'text_ru')[0], 2, true)) + || (LENGTH(@search) > 3 && LEVENSHTEIN_MATCH(b.name.second, TOKENS(@search, 'text_ru')[0], 2, true)) + || (LENGTH(@search) > 3 && LEVENSHTEIN_MATCH(b.name.last, TOKENS(@search, 'text_ru')[0], 2, true)) + || (LENGTH(@search) > 7 && LEVENSHTEIN_MATCH(b.address, TOKENS(@search, 'text_ru')[0], 2, true)) + || (LENGTH(@search) > 4 && LEVENSHTEIN_MATCH(b.city, TOKENS(@search, 'text_ru')[0], 1, true)) + || (LENGTH(@search) > 4 && LEVENSHTEIN_MATCH(b.district, TOKENS(@search, 'text_ru')[0], 1, true)) || (LENGTH(@search) > 5 && LEVENSHTEIN_MATCH(a.number, TOKENS(@search, 'text_en')[0], 2, true)) + || (LENGTH(@search) > 5 && LEVENSHTEIN_MATCH(b.number, TOKENS(@search, 'text_en')[0], 2, true)) || (LENGTH(@search) > 5 && LEVENSHTEIN_MATCH(a.mail, TOKENS(@search, 'text_en')[0], 2, true)) - || (LENGTH(@search) > 5 && LEVENSHTEIN_MATCH(a.passport, TOKENS(@search, 'text_ru')[0], 1, true)) - || (LENGTH(@search) > 6 && LEVENSHTEIN_MATCH(a.department.number, TOKENS(@search, 'text_en')[0], 1, true)) - || (LENGTH(@search) > 5 && LEVENSHTEIN_MATCH(a.department.address, TOKENS(@search, 'text_ru')[0], 1, true)) - || (LENGTH(@search) > 4 && LEVENSHTEIN_MATCH(a.requisites, TOKENS(@search, 'text_ru')[0], 1, true)) - || (LENGTH(@search) > 7 && LEVENSHTEIN_MATCH(a.tax, TOKENS(@search, 'text_ru')[0], 1, true)) + || (LENGTH(@search) > 5 && LEVENSHTEIN_MATCH(b.mail, TOKENS(@search, 'text_en')[0], 2, true)) + || (LENGTH(@search) > 5 && LEVENSHTEIN_MATCH(b.passport, TOKENS(@search, 'text_ru')[0], 1, true)) + || (LENGTH(@search) > 6 && LEVENSHTEIN_MATCH(b.department.number, TOKENS(@search, 'text_en')[0], 1, true)) + || (LENGTH(@search) > 5 && LEVENSHTEIN_MATCH(b.department.address, TOKENS(@search, 'text_ru')[0], 1, true)) + || (LENGTH(@search) > 4 && LEVENSHTEIN_MATCH(b.requisites, TOKENS(@search, 'text_ru')[0], 1, true)) + || (LENGTH(@search) > 7 && LEVENSHTEIN_MATCH(b.tax, TOKENS(@search, 'text_ru')[0], 1, true)) OPTIONS { collections: ["account", "worker"] } AQL; diff --git a/mirzaev/ebala/system/models/payments.php b/mirzaev/ebala/system/models/payments.php index ae14ac0..f828143 100755 --- a/mirzaev/ebala/system/models/payments.php +++ b/mirzaev/ebala/system/models/payments.php @@ -46,7 +46,7 @@ final class payments extends core { try { // Чтение заявок - $tasks = @task::read("d.date >= $from && d.date <= $to && d.problematic == false && d.completed == true", amount: 999999, return: '{worker: d.worker, market: d.market, date: d.date, work: d.work, start: d.start, end: d.end, commentary: d.commentary, rating: d.rating, review: d.review}', errors: $errors); + $tasks = @task::read("d.date >= $from && d.date <= $to && d.problematic == false && d.completed == true && d.result.processed != true", amount: 999999, return: '{worker: d.worker, market: d.market, date: d.date, work: d.work, start: d.start, end: d.end, commentary: d.commentary, rating: d.rating, review: d.review}', errors: $errors); if (is_array($tasks) && count($tasks) > 0) { // Найдены заявки @@ -208,9 +208,9 @@ final class payments extends core ->setCellValue("M$row", $worker->name['second'] . ' ' . $worker->name['first'] . ' ' . $worker->name['last']) ->setCellValue("N$row", $hour = static::hour('worker', $market->city, $task->work)) ->setCellValue("O$row", $payment = $hour * $hours) - ->setCellValue("P$row", ($penalty = static::penalty($task->rating ?? null)) === null ? $payment : $penalty) + ->setCellValue("P$row", ($penalty = static::penalty($task->rating ?? null)) === null ? -$payment : $penalty) ->setCellValue("Q$row", $bonus = static::bonus($task->rating ?? null)) - ->setCellValue("R$row", $payment + (($penalty = static::penalty($task->rating ?? null)) === null ? $payment : $penalty) + $bonus) + ->setCellValue("R$row", $payment + ($penalty === null ? -$payment : $penalty) + $bonus) ->setCellValue("S$row", '') ->setCellValue("T$row", $worker->payment) // Наличные? ->setCellValue("U$row", '') @@ -253,7 +253,7 @@ final class payments extends core /** * Магазины * - * Расчитать ... и сгенерировать excel-документ + * Расчитать прибыль с магазинов и сгенерировать excel-документ * * @param int $from Начальная дата для выборки заявок (unixtime) * @param int $to Конечная дата для выборки заявок (unixtime) @@ -488,7 +488,15 @@ final class payments extends core // Инкрементация счётчика для генерации следующей строки ++$row; } - } + } // Чтение заявок + $tasks = @task::collect( + "d.date >= $from && d.date <= $to && d.problematic == false && d.completed == true", + sort: 'd.date DESC', + amount: 999999, + index: 'd.date', + return: '{worker: d.worker, market: d.market, date: d.date, work: d.work, start: d.start, end: d.end, commentary: d.commentary, rating: d.rating, review: d.review}', + errors: $errors + ); // Запись строки с общими данными магазина $spreadsheet @@ -575,6 +583,60 @@ final class payments extends core return false; } + /** + * Подтвердить обработку + * + * Отметить в базе данных то, что выбранные заявки были обработаны + * + * @param int $from Начальная дата для выборки заявок (unixtime) + * @param int $to Конечная дата для выборки заявок (unixtime) + * @param string $type Тип документа для подтверждения (workers, markets) + * @param array $errors Errors registry + * + * @return void + */ + public static function confirm(int $from, int $to, string $type, array &$errors = []): bool + { + try { + + // Чтение заявок + $tasks = @task::read("d.date >= $from && d.date <= $to && d.problematic == false && d.completed == true && d.result.processed != true", amount: 999999, errors: $errors); + + if (is_array($tasks) && count($tasks) > 0) { + // Найдены заявки + + if ($type === 'workers') { + // Подтверждена обработка зарплат сотрудников за выбранный период + + foreach ($tasks as $task) { + // Перебор заявок + + // Подтверждение того, что заявка обработана (выплачены деньги сотруднику) + $task->result = ['processed' => true] + ($task->result ?? []); + + // Запись обновления в базу данных + core::update($task); + } + } + + // Exit (success) + return true; + } + throw new exception('Не найдены заявки'); + } catch (exception $e) { + // Write to the errors registry + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Exit (fail) + return false; + } + /** * Determine tariff diff --git a/mirzaev/ebala/system/models/task.php b/mirzaev/ebala/system/models/task.php index 70ce49e..b5142fc 100755 --- a/mirzaev/ebala/system/models/task.php +++ b/mirzaev/ebala/system/models/task.php @@ -259,7 +259,7 @@ final class task extends core public static function transaction( string $task, string $worker, - int $amount = 0, + int|float $amount = 0, array &$errors = [] ): ?string { try { diff --git a/mirzaev/ebala/system/public/css/list.css b/mirzaev/ebala/system/public/css/list.css index 3fc0161..14df95e 100755 --- a/mirzaev/ebala/system/public/css/list.css +++ b/mirzaev/ebala/system/public/css/list.css @@ -44,6 +44,12 @@ div#popup>section.list>div.row.endless { height: auto; } +section.panel.list> :is(form, search).row.menu>label>div:has(>button) { + position: relative; + display: flex; + height: 30px; +} + section.panel.list> :is(form, search).row.menu>label>button { position: relative; display: flex; diff --git a/mirzaev/ebala/system/public/index.php b/mirzaev/ebala/system/public/index.php index 625e479..465d095 100755 --- a/mirzaev/ebala/system/public/index.php +++ b/mirzaev/ebala/system/public/index.php @@ -49,6 +49,9 @@ $router->write('/workers/create', 'worker', 'create', 'POST'); $router->write('/market/$market/read', 'task', 'market', 'POST'); $router->write('/market/$id/fields', 'market', 'fields', 'POST'); $router->write('/market/$id/update', 'market', 'update', 'POST'); +$router->write('/market/ban/$worker', 'market', 'ban', 'POST'); +$router->write('/market/unban/$worker', 'market', 'unban', 'POST'); +$router->write('/market/banned/$worker', 'market', 'banned', 'POST'); $router->write('/markets', 'market', 'index', 'GET'); $router->write('/markets', 'market', 'index', 'POST'); $router->write('/markets/read', 'market', 'read', 'POST'); @@ -103,6 +106,7 @@ $router->write('/task/$task/chat/send', 'task', 'message', 'POST'); $router->write('/elements/menu', 'index', 'menu', 'POST'); $router->write('/payments/workers', 'payments', 'workers', 'POST'); $router->write('/payments/markets', 'payments', 'markets', 'POST'); +$router->write('/payments/confirm/$type', 'payments', 'confirm', 'POST'); // Инициализация ядра $core = new core(namespace: __NAMESPACE__, router: $router, controller: new controller(false), model: new model(false)); diff --git a/mirzaev/ebala/system/public/js/loader.js b/mirzaev/ebala/system/public/js/loader.js index afa3e97..b7f637f 100755 --- a/mirzaev/ebala/system/public/js/loader.js +++ b/mirzaev/ebala/system/public/js/loader.js @@ -185,10 +185,7 @@ if (typeof window.loader !== "function") { * * @return {void} */ - static async account() { - // Initialization of the account identifier - account = Cookies.get(`account_id`) ?? "account"; - + static async account(account = Cookies.get(`account_id`) ?? "account") { return await fetch(`/${account}`, { method: "POST", headers: { @@ -198,10 +195,10 @@ if (typeof window.loader !== "function") { .then((response) => response.text()) .then((data) => { // Write path in history - history.pushState(this.storage, "/account", "/account"); + history.pushState(this.storage, `/${account}`, `/${account}`); // Write path to the current directory buffer - core.page = 'account'; + core.page = account; // Write content in document document.body.getElementsByTagName("main")[0].innerHTML = data; diff --git a/mirzaev/ebala/system/public/js/markets.js b/mirzaev/ebala/system/public/js/markets.js index 1b402eb..048318f 100644 --- a/mirzaev/ebala/system/public/js/markets.js +++ b/mirzaev/ebala/system/public/js/markets.js @@ -1,613 +1,612 @@ "use strict"; if (typeof window.markets !== "function") { - // Not initialized - - // Initialize of the class in global namespace - window.markets = class markets { - /** - * Заблокировать функцию закрытия всплывающего окна? - */ - static freeze = false; - - /** - * Тело всплывающего окна (массив) - */ - static body = {}; - - /** - * Инициализирован класс? - */ - static initialized = false; - - /** - * Управление кнопками (escape, enter...) - * - * Содержит функцию инициализирующую обработчики событий keydown для document - * функция деинициализируется с document при закрытии окна - */ - static buttons; - - /** - * Ожидание зависимости: ядро - * - * @param {function} execute Функция, которая будет встроена в демпфер - * @param {mixed} args Аргументы встраиваемой функции - * - * @return {void} - */ - static core(execute, ...args) { - if (typeof execute === "function") { - // Получена функция - - // Инициализация интервала для ожидания загрузки зависимостей - const interval = setInterval(() => { - if (typeof core === "function") { - // Инициализировано ядро - - // Деинициализация интервала для ожидания загрузки записимостей - clearInterval(interval); - - // Запуск выполнения - return execute(...args); - } - }, 100); - - // Инициализация деинициализации интервала для ожидания загрузки зависимостей спустя большой срок времени - setTimeout(() => clearInterval(interval), 3000); - } - } - - /** - * Ожидание зависимости: демпфер - * - * @param {function} execute Функция, которая будет встроена в демпфер - * @param {number} timer Количество миллисекунд для демпфера - * @param {mixed} args Аргументы встраиваемой функции - * - * @return {void} - */ - static damper(execute, timer = 3000, ...args) { - if (typeof execute === "function") { - // Получена функция - - // Инициализация интервала для ожидания загрузки зависимостей - const interval = setInterval(() => { - if (typeof damper === "function") { - // Инициализирован демпфер - - // Деинициализация интервала для ожидания загрузки записимостей - clearInterval(interval); - - // Запуск выполнения - return damper(() => execute(...args), timer); - } - }, 100); - - // Инициализация деинициализации интервала для ожидания загрузки зависимостей спустя большой срок времени - setTimeout(() => clearInterval(interval), 3000); - } - } - - /** - * Авторизация - * - * @param {function} execute Функция, которая будет встроена в демпфер - * @param {mixed} args Аргументы встраиваемой функции - * - * @return {void} - */ - static authorization(execute, ...args) { - if (typeof execute === "function") { - // Получена функция - - if (core.page === this.page) { - // Пройдена проверка на страницу - - // Запуск выполнения - return execute(...args); - } - } - } - - /** - * Создать аккаунт и магазин (вызов демпфера) - * - * @param {HTMLElement} button Кнопка