# UpdateWorkRule

## Permission Scope

`workRule`

## Overview

Records a parameter change — such as a revised premium-category pin or overtime threshold — as a new effective-dated `WorkRule` generation, absorbing a legal or policy change with no code change and keeping past calculations reproducible.

## Business Rules

- The change closes the current generation (`effectiveEnd` = day before the change date) and inserts a new generation effective on the change date; it never overwrites the existing record
- Generations sharing the same `versionOf` must not overlap in their effective ranges
- Revised rounding directions, night-window bounds, and premium-category pin keys follow the same validation as creation
- The optional `holidayCalendarId` may be revised in the new generation — set to a [HolidayCalendar](../model/HolidayCalendar.md) to scope holiday classification, or left null so the rule classifies no date as a holiday
- A future-dated new generation does not affect calculation until its `effectiveStart`; a past-dated correction triggers recomputation of the affected calculated time

## Process Flow

```mermaid
flowchart TD
    A[Receive WorkRule id and revised parameters/holidayCalendarId/effectiveStart] --> B{WorkRule exists?}
    B -- No --> C[Reject: WORK_RULE_NOT_FOUND]
    B -- Yes --> D{Revised parameters valid?}
    D -- No --> E[Reject: INVALID_ROUNDING_DIRECTION / INVALID_NIGHT_WINDOW / INVALID_TIME_ENTRY_CODE_REFERENCE]
    D -- Yes --> F{New effectiveStart overlaps existing generation?}
    F -- Yes --> G[Reject: EFFECTIVE_DATE_OVERLAP]
    F -- No --> H[Close current generation at effectiveStart - 1 day]
    H --> I[Insert new generation effective on effectiveStart]
    I --> J[Recalculate affected dates if past-dated correction]
```

## External Dependencies

- [time-tracking::WorkRule](../model/WorkRule.md) model — the entity this command mutates
- [time-tracking::TimeEntryCode](../model/TimeEntryCode.md) model — referenced by `category`/`key` for premium-category pins
- [time-tracking::HolidayCalendar](../model/HolidayCalendar.md) model — referenced by the optional `holidayCalendarId` for holiday classification

## Error Scenarios

- **WORK_RULE_NOT_FOUND**: no WorkRule exists for the given id, or no WorkRule is effective for the relevant date
- **INVALID_ROUNDING_DIRECTION**: a rounding direction is not UP / DOWN / NEAREST
- **INVALID_NIGHT_WINDOW**: nightWindowStart / nightWindowEnd is outside 0-1439
- **INVALID_TIME_ENTRY_CODE_REFERENCE**: a premiumRatePercent entry references a TimeEntryCode that does not resolve
- **EFFECTIVE_DATE_OVERLAP**: the new generation's effective range overlaps an existing generation

## Test Cases

- a premium-category-pin change closes the prior generation and inserts a new one with no range overlap
- a future-dated rate change is not applied before its `effectiveStart`
- recomputing a period with the same reported input and same rule generation yields identical calculated output
- revised fields are carried forward unchanged when omitted from the update
- a revised `holidayCalendarId` is carried into the new generation; clearing it to null leaves the new generation classifying no date as a holiday
- updating a non-existent WorkRule id is rejected
- rejects a revised rounding direction that is not UP / DOWN / NEAREST
- rejects a revised night-window bound outside 0-1439
- rejects a revised premiumRatePercent entry that does not resolve to a TimeEntryCode
- rejects a new effectiveStart that does not come after the current generation's effectiveStart

