# CreateAccount

## Permission Scope

accountManagement

## Overview

createAccount establishes a new GL account in DRAFT status within a Chart of Accounts. Each account carries a structured numeric code, name, account type, account classification, and optional attributes (currency restriction, reconciliation flag, default tax code, tags, account group assignment). The parent CoA must be in DRAFT or ACTIVE status.

## Business Rules

- Account code is required, must be a structured numeric identifier, and must be unique within the CoA
- Account name is required and must be non-empty
- Account type must be one of ASSET, LIABILITY, EQUITY, REVENUE, or EXPENSE
- Account classification must be one of REGULAR, RECEIVABLE, PAYABLE, BANK_CASH, FIXED_ASSET, RETAINED_EARNINGS, or NON_POSTING; defaults to REGULAR
- Classification must be compatible with account type: RECEIVABLE, BANK_CASH, and FIXED_ASSET require ASSET; PAYABLE requires LIABILITY; RETAINED_EARNINGS requires EQUITY; REGULAR and NON_POSTING are allowed with any type
- Only one account per CoA may carry the RETAINED_EARNINGS classification
- Accounts with RECEIVABLE, PAYABLE, or BANK_CASH classification must have reconciliation enabled; attempting to set reconciliation to false for these classifications is rejected
- Reconciliation flag defaults to false when not explicitly set for REGULAR, FIXED_ASSET, RETAINED_EARNINGS, and NON_POSTING classifications
- NON_POSTING classification marks the account as excluded from journal entry posting target selection; this constraint is stored on the account and enforced by downstream posting modules
- RECEIVABLE and PAYABLE classifications mark the account as a sub-ledger control account; direct manual journal postings are blocked (only automated sub-ledger module postings are permitted). This constraint is stored on the account and enforced by the GL/posting layer
- Currency restriction, when provided, must reference a valid currency from the primitives module. An account with currency restriction only accepts postings denominated in that currency (enforced by downstream posting modules)
- Account group, when provided, must belong to the same CoA and account code must fall within the group's number range (if defined)
- Parent CoA must exist and be in DRAFT or ACTIVE status
- Account is always created in DRAFT status

## Process Flow

```mermaid
flowchart TD
    A[Receive create request] --> B{CoA exists and is DRAFT or ACTIVE?}
    B -->|No| C[Return error: CoA not found or invalid status]
    B -->|Yes| D{Account code unique within CoA?}
    D -->|No| E[Return error: duplicate code]
    D -->|Yes| F{Classification compatible with type?}
    F -->|No| G[Return error: incompatible classification]
    F -->|Yes| H{RETAINED_EARNINGS unique in CoA?}
    H -->|No| I[Return error: duplicate retained earnings]
    H -->|Yes| J{Currency valid if provided?}
    J -->|No| K[Return error: currency not found]
    J -->|Yes| L{Group valid if provided?}
    L -->|No| M[Return error: group not found or code out of range]
    L -->|Yes| N{Reconciliation valid for classification?}
    N -->|No| Q[Return error: reconciliation required]
    N -->|Yes| O[Create account in DRAFT]
    O --> P[Return created account]
```

## External Dependencies

- [primitives::getCurrency](../../../primitives/docs/queries/GetCurrency.md) - Validates that the referenced currency exists and is active

## Error Scenarios

- **CHART_OF_ACCOUNTS_NOT_FOUND**: Referenced CoA does not exist
- **DUPLICATE_ACCOUNT_CODE**: An account with the same code already exists in the CoA
- **INCOMPATIBLE_CLASSIFICATION**: Account classification is not compatible with the account type
- **DUPLICATE_RETAINED_EARNINGS**: Another account in the CoA already has RETAINED_EARNINGS classification
- **CURRENCY_NOT_FOUND**: Referenced currency does not exist or is not active
- **ACCOUNT_GROUP_NOT_FOUND**: Referenced account group does not exist or belongs to a different CoA
- **CODE_OUT_OF_RANGE**: Account code does not fall within the assigned group's number range
- **NAME_REQUIRED**: Name is empty, whitespace-only, or not provided
- **INVALID_ACCOUNT_CODE**: Account code is not a valid structured numeric identifier
- **RECONCILIATION_REQUIRED**: Reconciliation cannot be disabled for RECEIVABLE, PAYABLE, or BANK_CASH classifications

## Test Cases

- returns error when CoA does not exist
- returns error when CoA is ARCHIVED
- returns error when account code already exists in CoA
- returns error when account code is not a valid numeric identifier
- returns error when name is empty
- returns error when classification is incompatible with type
- returns error when RETAINED_EARNINGS already exists in CoA
- returns error when currency does not exist
- returns error when account group belongs to different CoA
- returns error when account code is outside group number range
- creates account in DRAFT status with defaults
- creates account with RECEIVABLE classification and enforces reconciliation
- creates account with PAYABLE classification and enforces reconciliation
- creates account with BANK_CASH classification and enforces reconciliation
- creates NON_POSTING account that is marked as excluded from journal entry posting
- creates RECEIVABLE account that is marked as control account blocking manual postings
- creates PAYABLE account that is marked as control account blocking manual postings
- creates account with currency restriction that constrains posting currency
- creates account with optional currency restriction
- creates account with optional tags
- creates account with optional default tax code
- creates account assigned to a group
- defaults classification to REGULAR when not specified
- returns error when reconciliation explicitly set to false for RECEIVABLE classification
- returns error when reconciliation explicitly set to false for PAYABLE classification
- returns error when reconciliation explicitly set to false for BANK_CASH classification
- passes custom fields through to insert
