The scheduling board lives in src/cluster_erp/modules/production/scheduling/. It shows work orders as bars on work-center rows over time, computed against each work center's effective working calendar, and it moves, resizes, or auto-schedules them. The web app (scheduling_board) and the desktop (scheduling_board.py) draw the same data. Work order fields are on work orders; calendar math is on working time.
In short¶
GET /api/v1/production/scheduling/boardreturns one read model: work centers with shifts and holidays, scheduled bars, the unscheduled pool, conflicts, capacity cells, and dependencies (src/cluster_erp/modules/production/scheduling/routes.py:41-86,src/cluster_erp/modules/production/scheduling/services.py:170-313).- Each work center's calendar is resolved through the owner chain work center, then the party of its organisation or of the headquarters, then the company group calendar (
src/cluster_erp/modules/production/scheduling/services.py:72-94). - A work order's end is always derived from its duration laid over working hours; a caller cannot set it (
src/cluster_erp/modules/production/scheduling/services.py:314-388). - The time math comes from the shared engine
core.working_time, re-exported byscheduling/calendar.py(src/cluster_erp/modules/production/scheduling/calendar.py:1-30).
How it works¶
The diagram shows the data path of a board read.
flowchart TD R["GET /scheduling/board with date range and filters"] --> WC["_load_work_centers"] WC --> SH["_load_shifts: calendar_candidates per work center"] SH --> EC["GetEffectiveWorkingCalendars in one query"] EC --> HO["_load_holidays: GetCalendarWindows per calendar"] HO --> CA["_load_capabilities"] CA --> WO["_load_work_orders: bars and unscheduled pool"] WO --> OV["_flag_overlaps with capacity_units"] OV --> CP["_compute_capacity: cells and utilization"] CP --> DP["_compute_dependencies: finish-to-start"] DP --> RS["BoardResponse"]
In prose:
- The route takes
date_from,date_to, and optional work center, production order, project, andscopefilters; it needswork_order.read(src/cluster_erp/modules/production/scheduling/routes.py:41-86). - The service loads the work centers and resolves each one's effective calendar with one
GetEffectiveWorkingCalendarsquery over the owner chains (src/cluster_erp/modules/production/scheduling/services.py:891-946). - Holidays and exceptions per date come from
GetCalendarWindows; the effective time zone comes from the calendar, the organisation, orGetCompanyDefaultTimezone(src/cluster_erp/modules/production/scheduling/services.py:780-874,src/cluster_erp/modules/production/scheduling/services.py:982-1016). - Work orders in the window become bars; pending ones without a schedule form the unscheduled pool (
src/cluster_erp/modules/production/scheduling/services.py:1038-1204). - Overlaps are flagged per work center, allowing up to
capacity_unitsparallel bars; capacity cells and over-capacity days are computed; finish-to-start dependencies and predecessor violations are added (src/cluster_erp/modules/production/scheduling/services.py:1205-1384).
Writes:
PUT /scheduling/work-orders/{work_order_id}/schedulemoves, resizes, reassigns, or unschedules one pending work order. It checks the record version, snaps an explicit start forward to the next working instant, and derives the end (src/cluster_erp/modules/production/scheduling/routes.py:87-109,src/cluster_erp/modules/production/scheduling/services.py:314-388).POST /scheduling/work-orders/{work_order_id}/auto-schedulesnaps a work order to the nearest valid free slot after its predecessors; no slot gives a 422 (src/cluster_erp/modules/production/scheduling/routes.py:110-135,src/cluster_erp/modules/production/scheduling/services.py:389-426).POST /scheduling/production-orders/{order_id}/auto-scheduleschedules all pending, unlocked work orders of an order forward in operation order (src/cluster_erp/modules/production/scheduling/routes.py:136-174,src/cluster_erp/modules/production/scheduling/services.py:427-496).POST /scheduling/recomputere-derives the ends of stale scheduled work orders over the current calendar, keeps the starts, and clears the stale marks (src/cluster_erp/modules/production/scheduling/routes.py:175-190,src/cluster_erp/modules/production/scheduling/services.py:605-657).
Why it is built this way¶
Code comments state three reasons. Only pending work orders are schedulable because started or completed ones are pinned by their actuals (src/cluster_erp/modules/production/scheduling/services.py:321-323). The end is derived because a job's length is a function of quantity and routing (src/cluster_erp/modules/production/scheduling/services.py:363-368). The organisation's calendar is owned by its party, so the chain asks for the party (src/cluster_erp/modules/production/scheduling/services.py:77-84). Other rationale is not stated in code or in the project's written engineering rules.
Rules and boundaries¶
- Writes need
work_order.update(src/cluster_erp/modules/production/scheduling/routes.py:91-178). scope=minewithout an employee link gives an empty board (src/cluster_erp/modules/production/scheduling/services.py:182-187).- A working calendar change marks the affected scheduled work orders stale through
WorkingCalendarChanged(src/cluster_erp/modules/production/module.py:1119-1138).
Interaction with other parts¶
| Contract | Answered by | Purpose | Source |
|---|---|---|---|
GetEffectiveWorkingCalendars, GetEffectiveWorkingCalendar |
calendars |
the effective calendar per owner chain | src/cluster_erp/modules/production/scheduling/services.py:927, src/cluster_erp/modules/production/scheduling/services.py:836 |
GetCalendarWindows |
calendars |
holidays and exceptions per date | src/cluster_erp/modules/production/scheduling/services.py:792, src/cluster_erp/modules/production/scheduling/services.py:1000 |
GetCompanyDefaultTimezone |
owned_organisations |
default time zone | src/cluster_erp/modules/production/scheduling/services.py:865, src/cluster_erp/modules/production/scheduling/services.py:976 |
GetOrganisationById |
owned_organisations |
the organisation's party | src/cluster_erp/modules/production/scheduling/services.py:960 |
WorkingCalendarChanged |
emitted by calendars |
stale marks | src/cluster_erp/modules/production/module.py:183 |
The contracts reference lists the answering modules. The projects board reads scheduled work orders through GetProjectProductionSchedule; see project board.
Limits and open points¶
Not determined from code: a limit on the number of work orders the board returns per call; the code reads all work orders that overlap the window (src/cluster_erp/modules/production/scheduling/services.py:1038-1204).
Terms introduced¶
| Term | Code identifier | Definition | Turkish term | Source |
|---|---|---|---|---|
| scheduling board | SchedulingBoardService |
The read model and write service that places work orders on work-center rows over time. | Çizelgeleme panosu | src/cluster_erp/modules/production/scheduling/services.py:163 |
| calendar owner chain | calendar_candidates |
The ordered owners whose calendar applies to a work center. | Takvim sahip zinciri | src/cluster_erp/modules/production/scheduling/services.py:72 |
| unscheduled pool | BoardUnscheduled |
Pending work orders that have no scheduled time yet. | Çizelgelenmemiş havuz | src/cluster_erp/modules/production/scheduling/schemas.py:90 |
Related pages¶
Verified against commit 92f8051 on 2026-11-13.