# CompanyHoliday

## Description

CompanyHoliday is a **holiday-calendar fact** (holiday calendar) — one dated entry stating that a given date is a holiday and of which kind: `STATUTORY` (statutory holiday, the statutory rest day that carries a holiday premium) or `PRESCRIBED` (prescribed/company holiday, a company-prescribed non-working day). It replaces the legacy hardcoded holiday calendar: adding or moving a holiday is a **data change**, not a code change (issues #7, #9).

The calendar is read from two directions. Scheduling reads it to determine scheduled working-day status (whether a date is a scheduled working day) when building schedules and shifts. Calculation reads it, on the calculated date, to decide holiday classification and the correct holiday premium (statutory holiday vs prescribed holiday) — bound to the holiday *kind*, never to a display name (ADR-015). This is where ADR-017's open question is resolved: the holiday calendar lives in **work-rules** because its primary role is a *calculation input* (premium/holiday determination); scheduling consumes it as a read.

CompanyHoliday is a plain fact, not effective-dated: a holiday is a single dated statement, corrected in place if entered wrong, rather than a versioned attribute series (contrast the effective-dated rule models). Each entry belongs to exactly one [HolidayCalendar](HolidayCalendar.md) via a required `calendarId`, and `holidayDate` is unique **per `(calendarId, holidayDate)`** rather than globally: the same date can be a holiday in one calendar and an ordinary working day in another. This scoping — previously deferred as the Company scope seam (ADR-018) — is now implemented structurally through HolidayCalendar, enabling per-region/per-entity calendars and multi-country operation.

## Domain Model Definitions

### Model type

Standard

### Command Definitions

Command docs are out of scope for this design phase (ADR-011). Anticipated commands:

- createCompanyHoliday — register a date as a holiday with its `holidayKind` and `name`
- updateCompanyHoliday — correct a holiday's `name` or `holidayKind` in place
- deleteCompanyHoliday — remove a holiday entered in error

### Query Definitions

- getCompanyHoliday — retrieve a single holiday by id
- getCompanyHolidayByDate — resolve the holiday fact for a specific `(calendarId, holidayDate)` (the lookup calculation and scheduling use)
- listCompanyHolidays — paginated list of holidays, filterable by `calendarId` and by date range / year
### Models

- CompanyHoliday

### Invariants

- Each `CompanyHoliday` belongs to exactly one [HolidayCalendar](HolidayCalendar.md) via a required `calendarId`
- `holidayDate` is unique **per `(calendarId, holidayDate)`** — a date is registered at most once within a given calendar, but the same date may be a holiday in one calendar and a working day in another
- `holidayKind` is a normalized enum: `STATUTORY` (statutory holiday) or `PRESCRIBED` (prescribed/company holiday) — the same distinction as the `HOLIDAY_STATUTORY` / `HOLIDAY_PRESCRIBED` categories of `TimeEntryCode`
- Holiday classification and premium determination bind to `holidayKind`, never to `name` or any display label (ADR-015)
- CompanyHoliday is a dated fact, not effective-dated: it is corrected in place rather than versioned (a wrong entry is edited or removed, not superseded by a generation)
- The calendar is the single source of truth for holiday determination shared by scheduling (scheduled working-day status) and calculation (premium); neither re-derives holidays from hardcoded lists

### Relationships

- **Belongs to HolidayCalendar**: each entry references its owning [HolidayCalendar](HolidayCalendar.md) via a required `calendarId`; uniqueness of `holidayDate` is scoped to that calendar
- **Read by scheduling (cross-module, one-directional)**: WorkSchedule / Shift use the scoped calendar to determine whether a date is a scheduled working day (ADR-017)
- **Read by time-tracking calculation (cross-module, one-directional)**: the Reported → Calculated conversion classifies a date as a holiday only via the calendar resolved from the worker's effective `WorkRule.holidayCalendarId`, then uses `holidayKind` on the calculated date to determine premium (ADR-014)
