# Time Entry Codes

## Overview

Time Entry Codes is the **semantic time-type catalog** (work codes) that every calculation and pay mapping binds to. It maintains `TimeEntryCode` records — each a stable `key`, a `category` (an open, normalized string key defined by the calculation strategy; the default JP strategy uses WORK / OVERTIME_WITHIN_STATUTORY / OVERTIME_BEYOND_STATUTORY / NIGHT / HOLIDAY_STATUTORY / HOLIDAY_PRESCRIBED / BREAK / LEAVE as examples, with room for other jurisdictions), a UI-only `displayName`, and a `payMapKey`. The catalog is the vocabulary; the rules (WorkRule, EligibilityRule) and the downstream calculation all reference a time type by its `key`, never by its label.

## Business Purpose

- Give calculation and payroll a single, stable vocabulary of time types so logic is written against machine keys, not human labels
- Eliminate the issue #14 cautionary-lesson failure mode where the legacy engine matched overtime logic against Japanese display-name strings and broke when a label was renamed
- Provide the key-to-key seam (`payMapKey`) from a calculated time type to a future payroll earnings code, keeping the payroll boundary name-independent (ADR-018)
- Let labels be renamed or localized freely without any calculation side effect

## Process Flow

```mermaid
flowchart TD
    A[Register TimeEntryCode: stable key, category, displayName, payMapKey] --> B[Rules bind to key: WorkRule, EligibilityRule]
    B --> C[Time-tracking calculation resolves time type by key]
    C --> D[CalculatedTimeBlock stamped with CalculationTag carrying the key]
    D --> E[payMapKey routes calculated time to a future payroll code]
    A --> F{Rename displayName?}
    F -- Yes --> G[UI label changes; key unchanged; calculation unaffected]
```

## Scenario Patterns

- **Register a code**: create a code with a stable `key`, a normalized `category`, a display name, and a `payMapKey`
- **Rename display name**: changing `displayName` updates only the UI; the `key` and every calculation binding are untouched
- **Key immutability**: once a rule references a `key`, the key cannot change — a genuinely new time type is a new code
- **Category-driven premium**: a WorkRule pins its premium-category code by the code's `category` (e.g. NIGHT, HOLIDAY_STATUTORY), not by its label
- **Pay mapping**: `payMapKey` maps the code to a downstream earnings code by key, never by name
- **Delete guard**: a code referenced by any rule is preserved and cannot be hard-deleted

## Test Cases

- creating a code with a duplicate `key` is rejected
- renaming `displayName` leaves the `key` and all calculation results unchanged
- calculation resolves a time type via `getTimeEntryCodeByKey`, not via display name
- deleting a code referenced by a WorkRule / EligibilityRule is rejected
- an arbitrary category key is accepted
- a code's `payMapKey` is preserved verbatim for downstream pay routing

## Reference Links

- Data-model design research (rule/pay-code catalogs, semantic keys): https://github.com/tailor-sandbox/Omakase-ERP-attendance/issues/7
- Customization reality (configuration absorbs change, no per-customer code): https://github.com/tailor-sandbox/Omakase-ERP-attendance/issues/13
- Cautionary lesson: legacy calculation bound to Japanese display-name strings and broke on rename: https://github.com/tailor-sandbox/Omakase-ERP-attendance/issues/14
