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
holidayslibrary (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 /groupcreates 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-ownergets or creates the calendar of an owner. Withinherit_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}/previewreturns 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
WorkingCalendarChangedfor 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 |
Related pages¶
- Modules index
- Working time
- Production scheduling
- Material requirements planning
- API reference for this module
Verified against commit 92f8051 on 2026-11-13.