# Spec Delta

## Purpose

Let internal users without login find spareparts through QR or a grouped catalogue and request controlled stock withdrawal.

## ADDED Requirements

### Requirement: Two discovery paths
The API SHALL support direct part resolution from a scanned identifier and a general catalogue searchable by name, product ID, or part number and filterable by group. Discovery SHALL be paginated, require no location input, and never create a movement.

#### Scenario: Room QR catalogue
- **WHEN** a user enters general checkout and selects a group with a search term
- **THEN** matching parts and current available quantities are returned without requiring an unfiltered full-catalogue scroll

#### Scenario: Part QR
- **WHEN** a valid part QR identifier is resolved
- **THEN** the matching active part is returned and stock is unchanged

#### Scenario: Ambiguous legacy part number
- **WHEN** a legacy QR value matches multiple part numbers
- **THEN** resolution reports ambiguity and does not choose a part arbitrarily

### Requirement: Public requester identity
Checkout SHALL be available without login and SHALL require requesterName on the existing StockMovement record. Public submission SHALL NOT infer or fabricate a user account. Client-supplied actor, approval, posting time, monetary fields, and stock deltas SHALL NOT control the operation.

#### Scenario: Forged approver
- **WHEN** a technician submits an approved status or another user as actor
- **THEN** the input is rejected without posting stock

### Requirement: Universal checkout approval
Every checkout SHALL create a PENDING issue without reducing or reserving stock. ADMIN/SUPERVISOR SHALL approve or reject it. Approval SHALL revalidate stock and target activity, plus account activity for historical authenticated requests before atomic posting. Rejection SHALL retain the request and reason without changing stock.

#### Scenario: Stock exhausted while waiting
- **WHEN** an approver approves a pending issue whose available stock is now insufficient
- **THEN** the API returns 409 and the request remains unposted and pending

#### Scenario: Urgent work does not bypass approval
- **WHEN** a technician requests goods for an urgent operational purpose
- **THEN** the request still requires ADMIN/SUPERVISOR approval regardless of legacy auto-approval settings

### Requirement: Logged-in checkout also waits
ADMIN/SUPERVISOR checkout SHALL also remain PENDING until a separate authenticated approval. Login SHALL NOT bypass approval.

#### Scenario: Admin checkout
- **WHEN** an admin requests an available positive quantity
- **THEN** the issue remains pending without changing stock until a separate approval posts it once

### Requirement: Review and requester visibility
ADMIN/SUPERVISOR SHALL access a paginated approval queue. Public requesters SHALL read an individual pending/rejected/posted request only with its matching UUID token. The global queue SHALL require authenticated ADMIN/SUPERVISOR access. Conflicting review decisions SHALL return 409; identical decision retries SHALL preserve the original approver and avoid duplicate effects.

#### Scenario: Approval races with rejection
- **WHEN** two reviewers make incompatible decisions on the same pending request
- **THEN** only one decision commits and the other receives 409

### Requirement: Independent technical withdrawal
Checkout SHALL require a nonblank purpose and SHALL NOT accept a Work Order reference in its input or query filters. Checkout SHALL NOT validate or infer any Work Order; usage remains unallocated. Work Order relationships belong to Maintenance and quarantine workflows. This technical workflow SHALL NOT calculate costs.

#### Scenario: General technical withdrawal
- **WHEN** a user requests a part without a WO and provides a purpose
- **THEN** normal role-based approval applies and no asset or WO is inferred

#### Scenario: Public retry and status
- **WHEN** a public caller retries with the same UUID and payload
- **THEN** the existing transaction is returned without duplicate movement or audit; another payload conflicts, and status access with another token returns no request
