# employee-contract-position Specification

## Purpose
TBD - created by archiving change add-contract-position. Update Purpose after archive.
## Requirements
### Requirement: Employee Contract Position Field
Each employee record SHALL have a `contract_position` text field that can be viewed and edited independently of the employee's current position assignment (`account_position`).

#### Scenario: Viewing an employee's contract position
- **WHEN** an admin retrieves an employee's profile
- **THEN** the response includes the employee's `contract_position` value

#### Scenario: Updating an employee's contract position
- **WHEN** an admin updates an employee record with a new `contract_position` value
- **THEN** the new value is persisted
- **AND** subsequent reads of that employee return the updated value

#### Scenario: Contract position is independent of current position
- **WHEN** an employee's current position assignment changes
- **THEN** the employee's `contract_position` value is not automatically changed

### Requirement: Contract Position Backfill on Introduction
When the `contract_position` field is introduced, every existing employee SHALL have it seeded from their current position, so no employee is left with a value that silently differs from what their contracts previously displayed.

#### Scenario: Employee with a current position assigned
- **WHEN** the `contract_position` field is added for an employee who has a current position assigned
- **THEN** `contract_position` is set to the name of that current position

#### Scenario: Employee with no current position assigned
- **WHEN** the `contract_position` field is added for an employee who has no current position assigned
- **THEN** `contract_position` is left empty

### Requirement: Filtering Employees by Contract Position
The admin employee list SHALL support filtering by `contract_position`, matching employees whose `contract_position` contains the given text.

#### Scenario: Filtering by a matching contract position
- **WHEN** an admin requests the employee list with a `contract_position` filter value
- **THEN** the response includes only employees whose `contract_position` contains that value

#### Scenario: Filtering with no matches
- **WHEN** an admin requests the employee list with a `contract_position` filter value that matches no employee
- **THEN** the response is an empty list

### Requirement: Contract Position in Employee Export
The employee export SHALL include a `contract_position` column, distinct from the existing live-position column.

#### Scenario: Exporting employees
- **WHEN** an admin exports the employee list
- **THEN** the exported data includes a "Vị trí HĐ" column with each employee's `contract_position` value
- **AND** the existing "Vị trí" column continues to show the employee's live current position, unchanged

### Requirement: Contract Document Position Source
Contract documents that render the `employee_position` field SHALL source its value from the employee's `contract_position`, not from the employee's live current position.

#### Scenario: Generating a contract document
- **WHEN** a contract document is generated or previewed for an employee and references the `employee_position` field
- **THEN** the rendered value equals that employee's `contract_position`
- **AND** it does so even if the employee's current position assignment has since changed to something different


### Requirement: Contract Position Default on Creation
When an employee is created through the admin create API or the employee Excel import, and the provided `contract_position` is blank (absent, `null`, empty, or whitespace-only), the system SHALL set `contract_position` to the name of the position assigned to that employee at creation. A non-blank provided value SHALL be stored as given (trimmed). This default SHALL apply only at creation. Updating an employee SHALL NOT apply it. The employee Excel import SHALL NOT assign a default position. A row whose "Vị trí" is blank or cannot be resolved SHALL be rejected, so no contract position is set for it.

#### Scenario: Create API without contract_position
- **WHEN** an admin creates an employee with assigned positions and does not send `contract_position`
- **THEN** the employee's `contract_position` equals the name of the first assigned position

#### Scenario: Create API with blank contract_position
- **WHEN** an admin creates an employee with assigned positions and sends `contract_position` as `null`, an empty string, or whitespace only
- **THEN** the employee's `contract_position` equals the name of the first assigned position

#### Scenario: Create API with a contract_position value
- **WHEN** an admin creates an employee and sends a non-blank `contract_position`
- **THEN** the employee's `contract_position` equals the sent value

#### Scenario: Import row with empty "Vị trí HĐ" and a valid "Vị trí"
- **WHEN** an admin imports employees and a row's "Vị trí" resolves to exactly one position and its "Vị trí HĐ" is blank
- **THEN** the created employee's `contract_position` equals that position's name

#### Scenario: Import row with empty "Vị trí HĐ" and an empty or unknown "Vị trí"
- **WHEN** an admin imports employees and a row has a blank or unresolvable "Vị trí"
- **THEN** the row is not imported and is reported as a failed row
- **AND** no default position is assigned

#### Scenario: Import row with a "Vị trí HĐ" value
- **WHEN** an admin imports employees and a row has a non-blank "Vị trí HĐ" and a resolvable "Vị trí"
- **THEN** the created employee's `contract_position` equals the trimmed cell value, regardless of the "Vị trí" value

#### Scenario: Clearing contract_position on update
- **WHEN** an admin updates an existing employee and sends `contract_position` as `null` or an empty string
- **THEN** the employee's `contract_position` is stored as empty
- **AND** it is not replaced with the employee's current position name
