# Наработки по новому табелю: ## Концепция * Каждая подключенная организация имеет собственное рабочее пространство `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)