# CreateSupplierAccount

## Permission Scope

partner

## Overview

Creates an active supplier transaction account with initial address and bank usages.

## Business Rules

- Account name is required and must not be empty or whitespace-only
- Within an account, each address and purpose combination and each bank account and purpose combination must be unique after applying all changes
- Partner must exist and have `status: ACTIVE`
- The partner row is locked until the transaction ends to serialize account creation with partner deactivation
- Referenced addresses are locked before bank accounts, each in ascending ID order, before ownership and availability are checked
- Company, optional preferred currency, and optional default expense account must exist
- The default expense account must be active, have type `EXPENSE`, and belong to the supplier account's company
- Account code must be non-empty and unique within the company
- Usage records must reference active address or bank records owned by the partner
- Only one default is allowed per usage purpose

## Process Flow

```mermaid
flowchart TD
    A[Receive request] --> A1[Lock partner row]
    A1 --> B{Partner, company and currency valid?}
    B -->|No| C[Return validation error]
    B -->|Yes| D{Code unique?}
    D -->|No| E[Return duplicate account]
    D -->|Yes| D1[Lock addresses then bank accounts in ID order]
    D1 --> D2{Usage references valid?}
    D2 -->|No| C
    D2 -->|Yes| F[Create active aggregate]
    F --> G[Save account and usages]
```

## External Dependencies

- [organization::Company](../../../organization/docs/model/Company.md) - Validates company scope
- [primitives::Currency](../../../primitives/docs/model/Currency.md) - Validates preferred currency
- [coa-management::Account](../../../coa-management/docs/model/Account.md) - Validates the default expense account

## Error Scenarios

- **INVALID_NAME**: Name is empty, whitespace-only, or not provided
- **PARTNER_NOT_FOUND**: Specified partner ID does not exist
- **PARTNER_NOT_ACTIVE**: Partner status is not `ACTIVE`
- **COMPANY_NOT_FOUND**: Company does not exist
- **CURRENCY_NOT_FOUND**: Referenced currency does not exist
- **DEFAULT_EXPENSE_ACCOUNT_NOT_FOUND**: Referenced default expense account does not exist
- **INVALID_DEFAULT_EXPENSE_ACCOUNT**: Default expense account is inactive, is not an EXPENSE account, or belongs to another company
- **INVALID_ACCOUNT_CODE**: Account code is empty
- **DUPLICATE_ACCOUNT**: Account code already exists in the company
- **ADDRESS_NOT_FOUND**: Specified address ID does not exist
- **BANK_ACCOUNT_NOT_FOUND**: Specified bank account ID does not exist
- **ADDRESS_INACTIVE**: Address is unavailable for a new usage
- **BANK_ACCOUNT_INACTIVE**: Bank account is unavailable for a new usage
- **ADDRESS_NOT_OWNED_BY_PARTNER**: Address belongs to another partner
- **BANK_ACCOUNT_NOT_OWNED_BY_PARTNER**: Bank account belongs to another partner
- **DUPLICATE_DEFAULT_USAGE**: More than one default was supplied for a purpose
- **DUPLICATE_ADDRESS_USAGE**: Address and purpose combination already exists in the account
- **DUPLICATE_BANK_ACCOUNT_USAGE**: Bank account and purpose combination already exists in the account

## Test Cases

- loads the partner aggregate under a lock
- returns DuplicateAddressUsageError without saving
- returns DuplicateBankAccountUsageError without saving
- locks the partner before creating the account
- creates an active supplier account with usages
- rejects an inactive partner
- rejects duplicate defaults for one purpose
- rejects a bank account owned by another partner
- rejects an inactive bank account
- rejects an inactive address
- passes account and usage custom fields through the repository
- creates an account with a valid default expense account
- rejects a missing default expense account
