# TANRAIL ONE — Phase 3.3.1 Financial Core Hardening Report

## Executive Summary
Phase 3.3.1 resolves all critical and high-priority architectural gaps in the TANRAIL ONE business-agnostic Finance Core identified in the Phase 3.3 audit. Brittle, hardcoded account resolution has been eliminated in favor of a dynamic `FinancialSettings` architecture with deterministic Business Unit to Organization fallback. The Chart of Accounts now supports hierarchical trees with circular and cross-organizational validation. Tax categories route liabilities to dedicated ledger accounts, and journals support typed classification (`JournalType`).

## 1. Architectural Changes Implemented

### 1.1 Financial Settings & Dynamic Account Resolution
- **Problem**: Operational financial event listeners (`RecordSalesPaymentListener`, `RecordSupplierPaymentListener`) previously relied on brittle string lookups (`Account::where('code', 'CASH')`), which would silently fail or crash if account codes differed.
- **Solution**: Created `financial_settings` table and `FinancialSettings` model. Created `AccountResolver` service to resolve operational ledger accounts based on payment methods and operational contexts:
  - Supports Organization-level default settings (`business_unit_id = null`).
  - Supports Business Unit-specific overrides (`business_unit_id = X`).
  - Implements deterministic fallback: BU settings -> Organization defaults -> explicit `FinancialConfigurationException`.
  - Enforces Organization ownership validation on all configured accounts.

### 1.2 Tax Liability Routing
- **Problem**: `TaxCategory` previously stored tax percentages without connection to general ledger liability accounts.
- **Solution**: Extended `tax_categories` table with `organization_id` and `liability_account_id` (foreign key to `accounts`).
  - Enables routing of tax liability entries during billing and invoicing.
  - Enforces cross-organization validation: a `TaxCategory` belonging to Organization A cannot route liability to an Account in Organization B.
  - Resolves via `AccountResolver::resolveTaxLiabilityAccount($taxCategory, $businessUnit)`.

### 1.3 Chart of Accounts Hierarchy
- **Problem**: Accounts were flat nominal structures unable to represent hierarchical trees (Assets -> Current Assets -> Cash) required for consolidated reporting.
- **Solution**: Added nullable `parent_id` (foreign key to `accounts.id`) to `accounts` table.
  - Root accounts have `parent_id = null`.
  - Child accounts reference parent in the same Organization.
  - Enforced validation rules in `Account::booted()`:
    1. Prevents self-parenting (`$account->parent_id === $account->id`).
    2. Prevents cross-Organization parent relationships (`$parent->organization_id === $account->organization_id`).
    3. Prevents circular hierarchy loops (recursive ancestor tree traversal).

### 1.4 Journal Types
- **Problem**: All journals were treated generically, preventing distinction between daily sales, manual journals, opening balance migrations, and closing entries.
- **Solution**: Introduced `JournalType` enum:
  - `OPERATIONAL`
  - `MANUAL`
  - `OPENING_BALANCE`
  - `CLOSING`
  - `REVERSAL`
- Updated `journals` table with a `type` column (default `'operational'`). Existing journals remain fully compatible.
- `FinancialService::reverseJournal()` automatically tags generated reversing journals with `JournalType::REVERSAL`.

### 1.5 Strict Domain Exceptions
Replaced generic exceptions with domain-specific exceptions extending `RuntimeException`:
- `FinancialConfigurationException`
- `CrossOrganizationException`
- `AccountHierarchyException`
- `FiscalPeriodClosedException`
- `JournalImbalanceException`
- `JournalImmutableException`

## 2. Invariants & Security Guarantees
1. **Mathematical Balance**: Total Debits == Total Credits strictly validated using `bcadd`/`bccomp` at 4 decimal places.
2. **Double-Entry Immutability**: Posted journals and entries cannot be modified or deleted. Modifications trigger `JournalImmutableException`. Reversals generate atomic inverse journals.
3. **Period Locking**: Posting into closed or nonexistent fiscal periods is rejected with `FiscalPeriodClosedException`.
4. **Tenant Isolation**:
   - Accounts and Fiscal Periods are bounded by `OrganizationScope`.
   - Journals are bounded by `BusinessUnitScope`.
   - Cross-BU and Cross-Organization transactions are strictly blocked.
5. **Event Idempotency**: Payment listeners use `ProcessedEvent` to ensure repeated or retried domain events never duplicate journal postings.

## 3. Deferred Capabilities (Future Phase 4+)
The following features were intentionally NOT implemented in Core to avoid scope creep and maintain generic neutrality:
1. **Bank Statement Import & Reconciliation**: Out of scope for Core GL; deferred to Phase 4 Treasury/Cash Management.
2. **AccountBalance Projection Tables**: In-memory and on-the-fly summation across `JournalEntry` remains performant for foundational volume. Aggregate roll-up tables deferred until scale requires pre-aggregation.
3. **Tax Filing / Government Submissions**: Country-specific VAT return workflows and electronic filing systems deferred to localized business extensions.
4. **Financial Dashboards & UI**: No front-end components or dashboards were added to Core.
