Factorizer/Cluster ERP WikiCluster ERP Türkçe
Home / Business modules

Module

Calendars module (calendars)

Module page for calendars, the shifts, weekly working-time templates, owned working calendars with base calendars, exceptions, holiday import, and the queries other modules use.

The calendars module in src/cluster_erp/modules/calendars/ holds working time. It keeps shifts, weekly working-time templates, and working calendars that an owner such as a party, a work center, or the company group can own. A calendar has a time zone, a template, an optional base calendar it inherits from, and date exceptions such as holidays. Other modules read effective working days and windows from it through the EventBus; the time math is on working time.

At a glance

Item Value Source
Package src/cluster_erp/modules/calendars/ (flat module: models.py, schemas.py, services.py, routes.py) folder
Module class Module src/cluster_erp/modules/calendars/module.py:16
name / version calendars / 0.1.0 src/cluster_erp/modules/calendars/module.py:18-23
API prefix /api/v1/calendars (ModuleBase.api_prefix) src/cluster_erp/core/module_base.py:37-38
Sub-modules none; one package folder listing
Tables 6: calendars_shifts, calendars_templates, calendars_template_lines, calendars_working_calendars, calendars_exceptions, calendars_exception_shifts __tablename__ in models.py
Entities in metadata 0; entities is empty src/cluster_erp/modules/calendars/module.py:223
Routes 23 route decorators grep for @router. in routes.py
Actions 0 ActionMeta entries grep "ActionMeta(" in the package
Migrations 7 files files in migrations/versions/ whose text contains one of the six table names
Web app presence Catalogue app calendars; custom widgets global_calendar and working_calendar from a gated bundle; the working_calendar widget is a tab on party and work center cards src/cluster_erp/modules/app_store/catalog.json (entry calendars), gated_apps/calendars/app.js:1018, src/cluster_erp/modules/production/module.py:1366
Desktop presence src/cluster_erp/desktop/modules/calendars/ (global_calendar_view.py) folder

What the module does

  • Keeps named shifts and weekly templates of per-weekday spans; several lines per day are split shifts, and an end at or before the start crosses midnight (src/cluster_erp/modules/calendars/models.py:1-14).
  • Keeps working calendars with a time zone, a template, an optional base calendar, and an optional owner (src/cluster_erp/modules/calendars/models.py:119-180).
  • Keeps date exceptions with a one-off, annual, or weekly recurrence, an open, closed, or inherit control, and optional custom hours (src/cluster_erp/modules/calendars/models.py:183-233).
  • Imports public holidays of a country into a calendar with the holidays library (src/cluster_erp/modules/calendars/services.py:455-516).
  • Answers queries for owner working days, effective calendars, and day windows (src/cluster_erp/modules/calendars/module.py:51-63).

Sub-modules

Sub-module Purpose Main entities Router Source
(package root) Shifts, templates, calendars, exceptions Shift, WorkingTimeTemplate, WorkingTimeTemplateLine, WorkingCalendar, WorkingCalendarException, WorkingCalendarExceptionShift /shifts, /templates, /calendars, /exceptions, /group, /holiday-countries src/cluster_erp/modules/calendars/routes.py:44

The router is mounted under the module prefix with require_app("calendars") (src/cluster_erp/modules/calendars/module.py:33-41).

Data model

Entity Table Key fields Notes Source
Shift calendars_shifts code, name, description code unique among live rows src/cluster_erp/modules/calendars/models.py:40-61
WorkingTimeTemplate calendars_templates code, name, description code unique among live rows src/cluster_erp/modules/calendars/models.py:63-88
WorkingTimeTemplateLine calendars_template_lines template_id, day_of_week, shift_id, start_time, end_time src/cluster_erp/modules/calendars/models.py:91-116
WorkingCalendar calendars_working_calendars code, name, timezone, template_id, base_calendar_id, owner_type, owner_id code unique among live rows src/cluster_erp/modules/calendars/models.py:119-180
WorkingCalendarException calendars_exceptions calendar_id, recurrence, control, date, day_of_week, note src/cluster_erp/modules/calendars/models.py:183-213
WorkingCalendarExceptionShift calendars_exception_shifts exception_id, start_time, end_time src/cluster_erp/modules/calendars/models.py:216-233

The owner is stored on the calendar, not on the owner's table, so that no module has to depend on calendars (src/cluster_erp/modules/calendars/models.py:163-168). Template and exception times are wall-clock times in the calendar's time zone (src/cluster_erp/modules/calendars/models.py:141-148).

Screens and metadata

get_metadata declares a sidebar group Calendars (Turkish Takvimler) with one custom section, Global Calendar (global_calendar) (src/cluster_erp/modules/calendars/module.py:204-219). The web widget overlays every working calendar on one month grid from the preview route (gated_apps/calendars/app.js:1-6). See gated app bundles and desktop module screens.

Status and actions

Calendars have no status and no ActionMeta. Records are changed through the routes listed under Permissions.

Business rules

  • The company group calendar is a singleton owned by ("group", nil id); GET /group creates it when missing. Organisations use it as their base to inherit group holidays (src/cluster_erp/modules/calendars/routes.py:74-94, src/cluster_erp/modules/calendars/services.py:224-312).
  • POST /calendars/for-owner gets or creates the calendar of an owner. With inherit_from, the new calendar copies the parent's template and time zone and uses it as base; otherwise it gets its own Monday to Friday 08:00 to 17:00 template (src/cluster_erp/modules/calendars/services.py:224-312).
  • A base calendar chain may not form a cycle (src/cluster_erp/modules/calendars/services.py:363-386).
  • An exception's recurrence and control are validated against the engine enums (src/cluster_erp/modules/calendars/schemas.py:192-205, src/cluster_erp/modules/calendars/services.py:631-646).
  • GET /calendars/{calendar_id}/preview returns the resolved days with shifts, exceptions, and holidays applied (src/cluster_erp/modules/calendars/routes.py:296-335, src/cluster_erp/modules/calendars/services.py:439-454).
  • Changes that affect effective hours emit WorkingCalendarChanged for each affected calendar, with its owner (src/cluster_erp/modules/calendars/routes.py:47-66).

Events and queries

The module consumes 4 contracts and produces 1, counted as on the parties module page. The full list is on the contracts reference.

Direction Contract class Handler or emitter Source
emits WorkingCalendarChanged _announce in the routes src/cluster_erp/modules/calendars/routes.py:47-66
answers query GetOwnerWorkingDays _handle_owner_working_days: open days of the first owner in a candidate chain that has a calendar src/cluster_erp/modules/calendars/module.py:60-98
answers query GetEffectiveWorkingCalendar, GetEffectiveWorkingCalendars _handle_effective_calendar(s) with _resolve_chain: time zone, weekly shifts, and calendar id of the first owner with a calendar src/cluster_erp/modules/calendars/module.py:52-59, src/cluster_erp/modules/calendars/module.py:99-158
answers query GetCalendarWindows _handle_get_windows: resolved day windows of one calendar over a date range src/cluster_erp/modules/calendars/module.py:51, src/cluster_erp/modules/calendars/module.py:159-184

Consumers include MRP lead times, the scheduling board, the project board, and the sales order delivery date check; see material requirements planning, production scheduling, and project board.

Permissions

Permission key Used by Source
work_calendar.read all reads, including preview and holiday countries src/cluster_erp/modules/calendars/routes.py:79-373
work_calendar.create create shifts, templates, calendars, exceptions; import holidays; for-owner src/cluster_erp/modules/calendars/routes.py:103-354
work_calendar.update, work_calendar.delete change and delete src/cluster_erp/modules/calendars/routes.py:143-398

Privacy, retention, and history

The module has no privacy_handlers.py. Deletes set deleted_at (src/cluster_erp/modules/calendars/services.py:77-88). Changes are captured by change history.

Analytics facts

This module has no analytics_facts.py.

Settings and reference data

Supported holiday countries come from the holidays library and are listed by GET /holiday-countries (src/cluster_erp/modules/calendars/services.py:510-516, src/cluster_erp/modules/calendars/routes.py:95).

Tests

Found by a grep for modules.calendars in tests/ and by file name and the path /calendars/ in web-client/.

Kind File Covers
pytest tests/test_calendar_owner_inherits_group_live.py an owner calendar inherits the group calendar
e2e web-client/_e2e_calendars_app.mjs the calendars app
e2e web-client/_e2e_capacity_units.mjs, web-client/_e2e_production_app.mjs calendars used by production
e2e web-client/_e2e_intranet.mjs, web-client/_e2e_intranet_selfservice.mjs calendars used by the intranet

Discrepancies

Terms introduced

Term Code identifier Definition Turkish term Source
working calendar WorkingCalendar A named calendar with a time zone, a weekly template, a base, and an owner. Çalışma takvimi src/cluster_erp/modules/calendars/models.py:119
working-time template WorkingTimeTemplate A reusable weekly pattern of working spans. Çalışma süresi şablonu src/cluster_erp/modules/calendars/models.py:63
calendar exception WorkingCalendarException A date rule that overrides the weekly working pattern of a calendar, opening or closing the days it covers. takvim istisnası src/cluster_erp/modules/calendars/models.py:183
base calendar base_calendar_id The calendar whose exceptions an inherit day defers to. Temel takvim src/cluster_erp/modules/calendars/models.py:155-160
group calendar ("group", nil id) owner The company-wide singleton calendar that organisations inherit from. Grup takvimi src/cluster_erp/modules/calendars/routes.py:74-76

Verified against commit 92f8051 on 2026-11-13.

Verified against commit 92f8051 · 2026-11-13