# CreatePurchaseOrder

## Permission Scope

purchaseOrder

## Overview

CreatePurchaseOrder creates a new purchase order in `DRAFT` status with supplier, company, receiving context, and one or more commercial lines. Snapshots (supplier name, item name/SKU) are captured at creation time.

## Business Rules

- Company, supplier, currency, order date, and at least one line are required
- Company must exist and the currency must be the company's base currency
- Supplier account must exist, match the order company, and be available for transactions
- supplierSnapshotName captures the account-specific accountName
- Each line must reference an active item, a unit of measure, have quantity greater than zero, and have a non-negative unit price — ACTIVE is required because this is a new transaction entry point; inactive items should not start new procurement
- Each line's item must hold a [PurchaseItem](../model/PurchaseItem.md) record; an item that is not adopted for purchasing cannot be ordered
- `requiresPhysicalReceipt` is not a line input: it is resolved from the item's purchasing record and frozen onto the line
- A header-level receiving site is optional; when provided it must reference a valid site and serves as the default for lines that do not specify their own
- Lines may optionally override the header receiving site; if provided, the override must also reference a valid site
- Order is always created with `orderStatus` = `DRAFT`; `receiptStatus` and `billingStatus` are not set at creation

## Process Flow

```mermaid
flowchart TD
    A[Receive create request] --> B{Supplier valid and active?}
    B -->|No| C[Return supplier error]
    B -->|Yes| F{Validate each line item, purchasing record, and site}
    F -->|No| G[Return item or site error]
    F -->|Yes| H[Freeze receipt expectation from each purchasing record]
    H --> L{Company exists and currency is its base currency?}
    L -->|No| M[Return company or currency error]
    L -->|Yes| D{At least one line with valid quantity and price?}
    D -->|No| E[Return line validation error]
    D -->|Yes| J[Insert order and lines in DRAFT]
    J --> K[Return created order]
```

## External Dependencies

- [business-partner::GetSupplierAccount](../../../business-partner/docs/query/GetSupplierAccount.md) - Validate supplier account company and transaction availability
- [item-management::GetItem](../../../item-management/docs/query/GetItem.md) - Validate each referenced item and item status
- [organization::GetCompany](../../../organization/docs/query/GetCompany.md) - Validate the company and its base currency
- [organization::GetSite](../../../organization/docs/query/GetSite.md) - Validate receiving site references

## Error Scenarios

- **COMPANY_NOT_FOUND**: Referenced company does not exist
- **CURRENCY_MISMATCH**: Currency is not the company's base currency
- **SUPPLIER_NOT_FOUND**: Referenced supplier partner does not exist
- **SUPPLIER_NOT_ACTIVE**: Referenced supplier is not in ACTIVE status
- **SUPPLIER_ACCOUNT_COMPANY_MISMATCH**: Supplier account belongs to another company
- **EMPTY_PURCHASE_ORDER_LINES**: Purchase order has no lines
- **ITEM_NOT_FOUND**: Referenced item does not exist
- **ITEM_NOT_ACTIVE**: Referenced item is not in ACTIVE status
- **ITEM_NOT_PURCHASABLE**: Referenced item holds no purchasing record and cannot be purchased
- **INVALID_QUANTITY**: Quantity is zero or negative
- **INVALID_UNIT_PRICE**: Unit price is negative or otherwise invalid
- **RECEIVING_SITE_NOT_FOUND**: Referenced receiving site does not exist

## Test Cases

- creates a draft purchase order with valid supplier and lines
- returns error when the company does not exist
- returns error when the currency is not the company's base currency
- returns error when supplier does not exist
- returns error when supplier is inactive
- returns error when supplier account belongs to another company
- returns error when no lines are provided
- returns error when an item does not exist
- returns error when an item is inactive
- returns error when an item has no purchasing record
- returns error when quantity is zero or negative
- returns error when unit price is negative
- returns error when header receiving site does not exist
- returns error when line receiving site does not exist
- freezes the receipt expectation from the purchasing record onto each line
- passes line receivingSiteId as null to save when not provided (header is the default)
- creates a service-only purchase order without header receivingSiteId
- returns error when physical line has no receiving site and header has none
