# CreateAssignment

## Permission Scope

`appointment`

## Overview

CreateAssignment places an active WorkerEmployment into a Position, opening the initial Assignment generation — as the employment's primary post, or as an additional concurrent post.

## Business Rules

- Every Assignment references exactly one WorkerEmployment and exactly one Position
- The Position referenced must be effective on the Assignment's effective date
- The Assignment's effective range must fall within its WorkerEmployment's effective range
- At any given date, an employment has at most one primary open Assignment; additional simultaneously-open assignments must be flagged non-primary (concurrent)
- The count of current open primary Assignments on a Position must not exceed the Position's `headcount`
- Assigning to a Position not effective on the assignment date is rejected
- Assigning outside the employment's effective range is rejected
- Assigning to a terminated employment (its `terminationDate` is set) is rejected — a newly opened Assignment is open-ended and would extend past the employment's end

## Process Flow

```mermaid
flowchart TD
    A[Assign employment to a Position] --> T{Employment terminated?}
    T -- Yes --> XT[Reject: EMPLOYMENT_TERMINATED]
    T -- No --> B{Employment active/effective on date?}
    B -- No --> X[Reject: OUTSIDE_EMPLOYMENT_RANGE]
    B -- Yes --> C{Position effective on assignment date?}
    C -- No --> Y[Reject: POSITION_NOT_EFFECTIVE]
    C -- Yes --> D{Primary requested and one already open?}
    D -- Yes --> W[Reject: DUPLICATE_PRIMARY_ASSIGNMENT]
    D -- No --> E{Headcount exceeded by current primaries?}
    E -- Yes --> V[Reject: POSITION_HEADCOUNT_EXCEEDED]
    E -- No --> F[Create open Assignment generation: primary or concurrent]
```

## External Dependencies

- [workforce::WorkerEmployment](../model/WorkerEmployment.md) model — the employment being posted
- [workforce::Position](../model/Position.md) model — the post being occupied

## Error Scenarios

- **EMPLOYMENT_NOT_FOUND**: the specified WorkerEmployment does not exist
- **EMPLOYMENT_TERMINATED**: the WorkerEmployment has been terminated and cannot receive a new assignment
- **OUTSIDE_EMPLOYMENT_RANGE**: the effective date falls outside the employment's effective range
- **POSITION_NOT_FOUND**: the specified Position does not exist
- **POSITION_NOT_EFFECTIVE**: the Position is not effective on the given effective date
- **POSITION_HEADCOUNT_EXCEEDED**: the Position's headcount would be exceeded
- **DUPLICATE_PRIMARY_ASSIGNMENT**: the employment already has an open primary Assignment

## Test Cases

- assigning an active employment to an effective Position creates one open primary Assignment
- opening a concurrent assignment yields exactly one primary among the open assignments
- assigning outside the employment's effective range is rejected
- assigning to a terminated employment is rejected
- assigning to a non-existent Position is rejected
- assigning to a Position not effective on the assignment date is rejected
- creating a primary assignment that would exceed the Position's headcount is rejected
- creating a primary assignment when one is already open for the employment is rejected
- creating an assignment for a non-existent employment is rejected

