Перейти к содержанию

Работа с календарём рабочих дней (для разработчика)

Настройка через SiteSettings

  • В системных настройках (SiteSettings) указывается ключ меры календаря рабочих дней: working_days_calendar__is_working_day.
  • Если настройка не указана, расчёты ведутся по календарным дням.

Требования к параметру календаря

  • Мера: тип INTEGER, значения: 1 — рабочий, 0 — нерабочий.
  • Параметр должен быть связан с уровнем иерархии "День" (horizon__day).
  • Ключи:
    • Меры: WORKING_DAYS_CALENDAR_MEASURE_KEY (см. horizons/models.py)
    • Уровня: HORIZON_DAY_LEVEL_KEY (см. horizons/models.py)

Ключевые константы и настройки

  • WORKING_DAYS_CALENDAR_MEASURE_KEY: "working_days_calendar__is_working_day" — ключ для SiteSettings, определяет меру календаря рабочих дней.
  • HORIZON_DAY_LEVEL_KEY: "horizon__day" — ключ уровня иерархии для дней.

Структура параметра и меры

  • Parameter (core/parameters/models.py):
  • key = "working_days_calendar"
  • dimensions — обязательно содержит Dimension с key="horizon__day"
  • Measure (core/parameters/models.py):
  • key = "working_days_calendar__is_working_day"
  • type = 1 (INTEGER)
  • Значения: 1 — рабочий, 0 — нерабочий
  • Dimension:
  • key = "horizon__day"
  • hierarchy_level — ссылка на уровень иерархии "День"

Модель HorizonItem (core/horizons/models.py)

  • Поля: num, start_date, end_date, period, level (ForeignKey на уровень иерархии)
  • Используется для хранения дат и идентификаторов дней

Сценарий автоматического заполнения

  • Сценарий: fill_working_days (core/horizons/scripts/fill_working_days.py).
  • Аргументы: start_date, end_date, holidays_key (страна), create_measure_if_missing.
  • Если мера или параметр отсутствуют — создаются автоматически.
  • Используется библиотека workalendar для определения рабочих дней.

Методы расчёта дат и длительности

  • calculate_due_date(start_date, duration_days) — возвращает дату окончания задачи с учётом рабочих дней (если календарь настроен), иначе — по календарным дням.
  • calculate_duration(start_date, due_date) — возвращает длительность задачи в рабочих днях (если календарь настроен), иначе — по календарным дням.
  • Оба метода реализованы в core/workflow/utils.py.

⚠️ Важное поведение: Если в SiteSettings указан ключ меры календаря, но мера отсутствует, методы calculate_due_date() и calculate_duration() в core/workflow/models.py выбрасывают ValueError. Это может привести к ошибкам при создании рабочих процессов.

Методы расчёта (core/workflow/utils.py)

  • _get_working_days_from_db(start_date, end_date=None): возвращает словарь {дата: 1/0} из БД по мере календаря
  • calculate_due_date(start_date: date, duration_days: int) -> date: возвращает дату окончания задачи, учитывая только рабочие дни (если календарь настроен)
  • calculate_duration(start_date: date, due_date: date) -> int: возвращает количество рабочих дней между датами (включительно)
  • get_critical_path_duration(obj): рекурсивно вычисляет длительность по критическому пути для задач с вложенностью и последовательностью

Примеры из тестов

  • Тесты: core/workflow/tests/test_issue_working_days.py.
  • Проверяются случаи:
    • Расчёт через выходные и праздники.
    • Корректный пересчёт при изменении дат/длительности.
    • Fallback на календарные дни, если календарь не настроен.

Важно

  • Все расчёты дат и длительностей в workflow используют эти методы.
  • Если календарь не настроен — используется обычный календарь.
  • Для ручного редактирования меры используйте метод корректировки set_equal.

См. также

Ручное редактирование

  • Для ручного редактирования меры календаря рабочих дней используйте метод корректировки set_equal (привязывается через админку к мере)

SQL-структуры

  • Таблица фактов для параметра создаётся автоматически методом param.sync()

Подробнее о синхронизации: См. Синхронизация параметров (для разработчиков) — как работает автоматическое создание таблиц. - Для dimension: dim_<key>, для measure: m_<key>

Примеры использования

  • Пример создания параметра и меры см. в тестах: core/workflow/tests/test_issue_working_days.py
  • Пример вызова сценария:
    fill_working_days(start_date='2024-01-01', end_date='2024-12-31', holidays_key='RU')
    

Ссылки на код

  • Константы: src/planiqum/core/horizons/models.py
  • Сценарий: src/planiqum/core/horizons/scripts/fill_working_days.py
  • Методы расчёта: src/planiqum/core/workflow/utils.py
  • Модели: src/planiqum/core/parameters/models.py, src/planiqum/core/horizons/models.py
  • Тесты: src/planiqum/core/workflow/tests/test_issue_working_days.py