# Company Holiday Calendar

## Overview

Company Holiday Calendar maintains `CompanyHoliday` — dated facts stating that a given date is a holiday and of which kind: `STATUTORY` (statutory holiday, a statutory rest day carrying a holiday premium) or `PRESCRIBED` (prescribed/company holiday, a company-prescribed non-working day). It replaces the legacy hardcoded holiday calendar with data, so adding or moving a holiday is a data change rather than a code change (issues #7, #9). The calendar is read by scheduling for scheduled working-day determination and by calculation for holiday classification and premium — resolving ADR-017's open question by placing the calendar in work-rules as a calculation input.

## Business Purpose

- Replace hardcoded holiday lists with a data-driven calendar so holidays are added/moved without code change or redeploy (issues #7, #9)
- Distinguish statutory holidays from prescribed (company) holidays by a stable `holidayKind`, so holiday classification and premium bind to the kind, not to a name (ADR-015)
- Serve as the single source of holiday truth shared by scheduling (scheduled working-day determination) and calculation (holiday premium), resolving ADR-017's placement question
- Keep the model a plain dated fact (not versioned) while leaving a Company-scope seam for future multi-entity calendars (ADR-018)

## Process Flow

```mermaid
flowchart TD
    A[Register CompanyHoliday: date, holidayKind, name] --> B[Holiday fact stored, unique per date]
    B --> C[Scheduling reads calendar to determine scheduled working days]
    B --> D[Calculation reads holidayKind on the calculated date]
    D --> E{holidayKind}
    E -- LEGAL statutory holiday --> F[Apply statutory holiday premium]
    E -- COMPANY prescribed holiday --> G[Apply company-holiday treatment]
    A --> H{Correction}
    H -- Yes --> I[Edit or remove the dated fact in place]
```

## Scenario Patterns

- **Register a statutory holiday**: add a date with `holidayKind = LEGAL` (statutory holiday) for holiday-premium determination
- **Register a company holiday**: add a date with `holidayKind = COMPANY` (prescribed holiday) as a non-working day
- **Scheduling determination**: scheduling reads the calendar to decide whether a date is a scheduled working day
- **Calculation premium**: calculation looks up `holidayKind` on the calculated date and applies the matching premium
- **In-place correction**: a wrongly entered holiday is edited or removed, not superseded by a generation (not effective-dated)
- **Add a new holiday**: a newly declared national holiday is added as data, with no code change (contrast the legacy hardcoded calendar)

## Test Cases

- registering two holidays on the same date is rejected (`holidayDate` unique)
- `holidayKind` accepts only LEGAL / COMPANY (rejects unknown values)
- calculation resolves holiday treatment via `getCompanyHolidayByDate` and `holidayKind`, not via `name`
- a LEGAL holiday triggers statutory holiday premium; a COMPANY holiday does not
- correcting a holiday edits the fact in place rather than creating a new generation
- adding a new holiday requires no code change (data-only)

## Reference Links

- Data-model design research (holiday calendar as data, not code): https://github.com/tailor-sandbox/Omakase-ERP-attendance/issues/7
- Feature-gap analysis (legacy hardcoded holiday calendar; make it data): https://github.com/tailor-sandbox/Omakase-ERP-attendance/issues/9
- Customization reality (holidays as configuration, no code changes to add): https://github.com/tailor-sandbox/Omakase-ERP-attendance/issues/13
