# InternalOrder

## Description

InternalOrder is a temporary cost collector entity for tracking expenses associated with specific short-to-medium-term activities such as projects, marketing campaigns, R&D initiatives, and corporate events. Each internal order carries a unique order number, order type (OVERHEAD, INVESTMENT, or ACCRUAL), description, responsible person, responsible cost center reference, company scope, optional validity dates, and a status. Unlike cost centers which are permanent organizational units, internal orders are purpose-bound objects with a defined lifecycle that follows a four-stage progression: CREATED, RELEASED, TECHNICALLY_COMPLETED, and CLOSED. Cost postings are only permitted while the order is in RELEASED status, and orders may optionally have a budget assigned to control spending limits.

## Domain Model Definitions

### Model type

Stateful

#### State Transitions

```mermaid
stateDiagram-v2
    [*] --> Created: createInternalOrder
    Created --> Released: releaseInternalOrder
    Released --> TechnicallyCompleted: technicallyCompleteInternalOrder
    TechnicallyCompleted --> Closed: closeInternalOrder
    Created --> [*]: deleteInternalOrder
```

### Command Definitions

- [createInternalOrder](../commands/CreateInternalOrder.md) - Create a new internal order in CREATED status with order type, description, responsible person, and cost center
- [updateInternalOrder](../commands/UpdateInternalOrder.md) - Update mutable fields of an internal order (description, responsible person, cost center, validity dates)
- [releaseInternalOrder](../commands/ReleaseInternalOrder.md) - Release a CREATED internal order, enabling cost postings
- [technicallyCompleteInternalOrder](../commands/TechnicallyCompleteInternalOrder.md) - Technically complete a RELEASED order, stopping new postings and beginning final review
- [closeInternalOrder](../commands/CloseInternalOrder.md) - Close a TECHNICALLY_COMPLETED order, archiving it permanently
- [deleteInternalOrder](../commands/DeleteInternalOrder.md) - Delete a CREATED internal order that has not been released

### Query Definitions

- [GetInternalOrder](../queries/GetInternalOrder.md) - Retrieve an internal order by id
- [ListInternalOrders](../queries/ListInternalOrders.md) - List internal orders with filters (type, status, company, cost center)

### Models

- InternalOrder

### Invariants

- Internal order can only be created in CREATED status
- Internal order requires a unique order number within the company scope
- Internal order requires a valid order type (OVERHEAD, INVESTMENT, ACCRUAL)
- Internal order requires a description and a responsible person
- Internal order must reference a valid companyId; the company must be in ACTIVE status
- Internal order must reference a valid responsible cost center within the same company
- Validity dates are optional; when both are provided, valid-from must precede valid-to
- Cost postings are only accepted when the internal order is in RELEASED status
- Cost postings to an order in CREATED, TECHNICALLY_COMPLETED, or CLOSED status are rejected
- Cost postings with a date outside the order's validity period are rejected when validity dates are set
- Only CREATED orders can be released; releasing an order in any other status fails
- Only RELEASED orders can be technically completed
- Only TECHNICALLY_COMPLETED orders can be closed
- CLOSED orders cannot transition to any other status
- Only CREATED orders can be deleted; RELEASED, TECHNICALLY_COMPLETED, and CLOSED orders cannot be deleted
- Order type cannot be changed after the order is released
- Internal order fields can be updated while in CREATED or RELEASED status but not in TECHNICALLY_COMPLETED or CLOSED status
- Cost postings to an internal order with a budget must not exceed the assigned budget amount
- Internal orders are scoped to a company; orders from different companies are fully isolated

### Relationships

- **References Company**: Each internal order is scoped to a Company via companyId (organization module)
- **References CostCenter**: Each internal order references a responsible CostCenter via costCenterId (accounting module)
