---
# System prepended metadata

title: 'Наработки по новому табелю:'

---

# Наработки по новому табелю:

## Концепция

* Каждая подключенная организация имеет собственное рабочее пространство `workspace`
* 

## Формулы вычисления рабочий дней

Для строки в табеле для хранения информации о графике теперь хранится только формула (строка - аналог `timetable` в старом табеле). Формулы бывают двух видов: дни недели и смены.

Общий вид формулы:

```
XXX:N1,N2,N3,...
```

Где:
* `XXX` - тип формулы:
    * `DOW` - дни недели (сокр. от days of week)
    * `WS` - смены (сокр. от work shift)
* `:` - разделитель между типом формулы и данными формулы
* `N1`, `N2` и тд - данные формулы:
    * для `DOW` перечисляются рабочие дни недели (где 0 - воскресенье)
    * для `WS` всегда 3 параметра:
        * `N1` - кол-во рабочих дней подряд
        * `N2` - кол-во выходных дней подряд
        * `N3` - дата отсчета (дата первого рабочего дня) в формате `YYYY-MM-DD`

Таким образом для вычисления по формуле дней недели надо просто проверять наличие его в массиве (`in_array`, `contains`). 

Для расчета рабочего дня по графику смен нужно использовать следующую формулу:

```
diffInDays(date, N3) mod (N1 + N2) < N1
```

Где:
* `date` - дата, на которую необходимо вычислить значение
* `N1`, `N2`, `N3` - данные формулы согласно описанию выше
* `diffInDays()` - метод вычисления разницы в днях между датами

При вычислении используем натуральную разницу в днях между датами. Например, между `2020-08-01` и `2020-08-28` разница будет `27`. Сравнение тоже используется строгое, не `<=`

**Важно**. В случае с типом формулы `WS`, в модели смены мы не храним дату начала работы формулы:
* в модели смены хранится формула в виде `WS:N1,N2`
* при создании модели расписания заполняется поле, когда начинает работать формула. Это поле никогда не отдается по апи, т.к. оно фигурирует в самой формуле. При создании расписания всегда передается `date_from`, а если выбрана формула `WS`, то помимо этого передается сдвиг `offset` относительно переданного `date_from`, когда начинается формула

## Фронт

https://docs.google.com/spreadsheets/d/1B0S6Qna6QsXTeuvtUEUS1zc9FjBV2cXGV16q78emitA/edit#gid=0

* Для дерева юзеров нужна может понадобиться модалка для согласований

## Публичное апи

Фронт сам по себе построен на том же апи, что и публичное. В `passport` есть инструмент выдачи `Personal Access Tokens`, пользователи могут самостоятельно выпускать токены апи для подключения по апи.

## Система оплаты

Идеи:
* Кол-во активных сотрудников
* Кол-во архивных сотрудников. При нежелании платить за архивного сотрудника его можно удалить полностью из системы, при этом можно будет скачать полный архив данных по сотруднику, а также он принудительно отправляется на почту админа (+ мы его будем хранить в течение, например, месяца) 
* Кол-во активных пользователей
* Кол-во активных объектов

## Заполнение рабочих дней

* Рабочие дни заполняются только по временным промежуткам, никакого заполнения часов. Выглядит примерно так: в UI блок отметки прихода/ухода, две кнопки - "сейчас" и "выбрать время".
* Нельзя одновременно иметь более одного открытого интервала по сотруднику в рамках одного расписания
* Если в рамках рабочего дня есть перерывы (обед), то заполняется уход и затем приход. Интервалы суммируются по дням
* Если рабочая смена начинается

## Работа с сотрудниками

* Проверка на доступ сотрудника к работе сейчас осуществляется соответствием кол-ва документов, необходимых для работы, у сотрудника и кол-ва документов, необходимых для работы, в рабочем пространстве. Здесь есть проблема - всегда при создании нового обязательного для работы документа все сотрудники становятся недоступными для заполнения. Нужно продумать механизм создания таких документов:
    * Можно выставлять дату начала действия правила этого документа
    * Можно явно хранить значение "canWork" в базе по сотрудникам и работать с ним явно, без вычислений
* Согласование документов сейчас выглядит как выбор согласующего по каждому типу документа. Можно сделать систему с типами согласования (на фронте), в базе для типа хранить массив `id` согласующих. Типы согласования:
    * Выбрать конкретных пользователей
    * Кол-во уровней вверх по дереву (мб просто сделать по дереву до директора без указания уровней или указать конечного согласующего и привязывать всех кто между ними по дереву)

## Настройки рабочего пространства

* Строгая проверка обязательных документов
* Напоминание об истечении срока действия документов:
    * Параметр `notify_before` отвечает за кол-во дней, за сколько напоминать
    * Параметр `notify_users` отвечает за пользователей, которых оповещать
* 

## Прочие фичи

* Табель теперь не разбит на конкретный временные промежутки и по сути непрерывен
* Настройка воркспейса - включить прием на работу. В этом режиме при добавлении сотрудника требуется заполнение документа "трудовой договор" и только после его одобрения сотрудник становится доступным и активным
* При вышеописанной фиче по истечению срока действия всех трудовых договоров он автоматически отправляется в архив
* У одной должности (рабочего места) может быть много расписаний, но в один момент может быть активно только одно расписание, таким образом при создании нового расписания старые закрываются датой начала действия нового
* Назначение сотрудника на должность тоже должно быть обеспечено только одно. При назначении нового сотрудника `date_to` у текущего выставляется в `date_from` нового
* Юзеры выстраиваются в дерево, аналогично текущему табелю. Для вывода дерева лучше использовать рекурсивные запросы, доступные в postgresql (https://bitworks.software/2017-10-20-storing-trees-in-rdbms.html). Чтобы не сильно лезть в eloquent, можно сделать первый запрос на получение дерева чистым sql и только с id, parent_id, затем из результата вытащить одномерный массив участвующих id, сделать запрос на получение всех этих пользователей и замапать дерево по id
* В модели `employee_document_types` есть параметр `depreciates_in`, означающий срок амортизации. Если с момента `valid_from` этого документа до `valid_to` трудового договора прошло меньше месяцев, чем `depreciates_in`, то этот документ отмечается как неполностью амортизированный и в списке документов сотрудника будет видно, что он имеет задолженнность
* Поля `agreement_with_id` можно сделать массивами `id`, поля `agreed` назвать `agreed_by` и тоже сделать массивами и вычислять итоговое значение `agreed` по их равенству
* Можно сделать отдельный модуль ТМЦ, оплачиваемый отдельно и реализующий работу с инвентарем и товарами
* Работа с зонами объектов:
    * Создается модель зоны объекта, в которой хранится информация об объеме работы (в часах), возможно создание собственных формул (т.к. в разных сферах расчет сложности вычисляется по-разному). Заполняется также информация о периодах активности и нагрузке в эти периоды (например, основное помещение днем убирается в совокупности 200ч, а ночью 50).
    * По зонам заполняется также информация по сотрудникам - какие оклады и допустимые рамки режимов работы, специфики, влияющие на максимальное кол-во рабочих часов
    * По заполненным данным вычисляется оптимальное кол-во сотрудников и их графики
* Связь между периодами нетрудоспособности и документами сотрудников, создание второго при создании первого

## Вопросы

* Как обрабатывать замены? Нужно решение, максимально сопоставимое с реальным оформлением замен в бухгалтерии. Идеи:
    * Делать `replacer_id` как в старом табеле, что усложняет вычисления отчетов по зп
    * Создать некую сущность с доплатами и удержаниями, как в старом табеле, ввести учет и согласование доплат и удержаний (можно хранить список согласующих в массиве PostgreSQL)