# Phase 7 — Accounting and Operational Finance Authorization

## Scope

Phase 7 applies the system-wide RBAC architecture to operational finance without changing the existing permission catalog.

Covered domains:

- financial accounts;
- capital injections;
- account transfers;
- accounting ledger access;
- expenses and recurring expenses;
- payroll;
- cash reconciliation and daily closing;
- fixed assets, depreciation and maintenance.

Phase 7 starts from the Phase 6 authorization baseline and keeps branch isolation independent from functional permissions.

## Permission catalog

No new canonical permissions are introduced in this phase. The catalog remains at **95 permissions**.

The existing permissions are already sufficiently granular:

- `accounts.view`
- `accounts.manage`
- `accounts.capital`
- `accounts.transfer`
- `accounting.view`
- `expenses.view`
- `expenses.create`
- `expenses.approve`
- `expenses.categories.manage`
- `expenses.recurring.manage`
- `payroll.view`
- `payroll.compensation.manage`
- `payroll.periods.create`
- `payroll.approve`
- `payroll.pay`
- `cash-closing.view`
- `cash-reconciliation.perform`
- `daily-closing.prepare`
- `daily-closing.confirm`
- `fixed-assets.view`
- `fixed-assets.manage`
- `fixed-assets.depreciate`
- `fixed-assets.maintenance`

Deprecated umbrella permissions remain untouched for compatibility. Phase 7 does not silently remove or repurpose them.

## Authorization model

Phase 7 follows the established two-dimensional authorization model:

1. Functional permission answers **what** the employee may do.
2. Record policy plus `BranchAccessService` answers **which branch-owned records** the employee may act on.

Sensitive record routes therefore retain their `permission:*` middleware and add a `can:*` policy check.

Super-administrator still receives functional authorization through the global `Gate::before` rule. Domain maker-checker rules remain inside services and therefore continue to apply even to a super-administrator.

## Record policies

### FinancialAccountPolicy

- `view` → `accounts.view` + accessible branch
- `manage` → `accounts.manage` + accessible branch
- `capital` → `accounts.capital` + accessible branch
- `transfer` → `accounts.transfer` + accessible branch

### ExpensePolicy

- `view` → `expenses.view` + accessible branch
- `decide` → `expenses.approve` + accessible branch

### RecurringExpensePolicy

- `view` → `expenses.view` + accessible branch
- `manage` → `expenses.recurring.manage` + accessible branch

### PayrollPeriodPolicy

- `view` → `payroll.view` + accessible branch
- `updateEntries` → `payroll.periods.create` + accessible branch
- `decide` → `payroll.approve` + accessible branch
- `pay` → `payroll.pay` + accessible branch

### DailyClosingPolicy

- `view` → `cash-closing.view` + accessible branch
- `confirm` → `daily-closing.confirm` + accessible branch

### FixedAssetPolicy

- `view` → `fixed-assets.view` + accessible branch
- `manage` → `fixed-assets.manage` + accessible branch
- `depreciate` → `fixed-assets.depreciate` + accessible branch
- `maintenance` → `fixed-assets.maintenance` + accessible branch

All Phase 7 policies are explicitly registered in `AppServiceProvider`.

## Route hardening

The following representative routes now enforce both functional permission and record policy:

- financial account show/update;
- expense show/receipt/decision;
- recurring expense edit/update;
- payroll period show, entry update, approval/rejection, payment and payslip access;
- daily closing show and manager confirmation;
- fixed asset show/update/depreciation/maintenance.

Create operations that receive a branch or account ID from the request body retain functional middleware and validate branch access before or inside the domain service.

## Financial account service boundary

`FinancialAccountingService` rechecks authorization for high-risk account operations:

- account creation requires `accounts.manage` and an accessible target branch;
- capital injection authorizes the `capital` ability on the selected account;
- transfer authorizes the `transfer` ability on both source and destination accounts.

Transfers continue to enforce active accounts, sufficient funds and same-business constraints.

Loan disbursement and loan payment posting helpers intentionally do **not** require accounting-management permissions. Those helpers remain subordinate to the Phase 6 loan/payment authorization boundary so cashier and loan roles do not gain or require unrelated account-management authority.

## Expense controls

Expense approval and rejection reauthorize the `decide` policy inside `ExpenseService`.

Existing financial controls remain authoritative:

- pending expense creation does not move cash;
- paid-from account must belong to the expense branch;
- insufficient funds abort the transaction atomically;
- approval posts matching account and accounting entries;
- double posting is rejected;
- when maker-checker is enabled, the employee who entered an expense cannot approve it.

Recurring expense processing remains background-safe: generation creates pending expenses only and never auto-pays them.

## Payroll controls

`PayrollService` now rechecks authorization for:

- compensation configuration;
- payroll-period creation;
- draft entry updates;
- approval/rejection;
- payment.

Payroll payment remains atomic and restricted to an active financial account in the payroll branch.

### Maker-checker

When maker-checker is enabled:

- the payroll preparer cannot approve the same payroll;
- the payroll preparer cannot pay the same payroll.

The second rule is added in Phase 7 so the prepare/approve/pay chain cannot collapse back onto the original maker. It is a service-layer rule and therefore cannot be bypassed by the super-administrator Gate shortcut.

## Cash reconciliation and daily closing

Phase 7 adds record-level policy protection for viewing and confirming a daily closing while retaining the mature domain workflow:

- reconciliation is branch/account constrained;
- all cash accounts must be reconciled before preparation;
- stale reconciliations are rejected;
- a prepared closing carries a financial snapshot fingerprint;
- ledger changes after preparation invalidate confirmation until refreshed;
- when maker-checker is enabled, the preparer cannot confirm the same closing;
- once manager-confirmed, the branch day is permanently closed to late financial posting.

These domain invariants remain in `DailyClosingService` rather than being reduced to permissions.

## Fixed assets

Fixed-asset record actions now receive policy enforcement in addition to existing functional permissions.

Existing financial safety remains unchanged:

- purchased assets must use an active account from the asset branch;
- insufficient account balance blocks acquisition;
- acquisition posts balanced asset/cash or asset/capital entries;
- depreciation is idempotent per asset/month and constrained by useful life and residual value;
- maintenance costs require an active same-branch account and sufficient funds;
- disposed assets cannot receive new depreciation or maintenance postings.

## Branch isolation

Phase 7 does not change branch-isolation architecture.

`BranchAccessService`, `BranchContext`, model scopes, controller validation and record policies continue to define branch visibility. Spatie Teams is not used for branch isolation.

A multi-branch employee receives the union of assigned branches. A user with no branch assignment receives no operational branch-owned data. Super-administrator retains system-wide branch visibility.

## Regression coverage

`Phase7OperationalFinanceAuthorizationTest` verifies:

- Phase 7 policies combine functional permissions with accessible branch scope;
- representative routes retain `permission:*` and add `can:*` middleware;
- high-risk finance services contain internal authorization/domain safeguards;
- a payroll preparer cannot pay the same payroll even when that user is super-administrator;
- the canonical permission catalog remains exactly 95 unique names.

Existing workflow suites continue to verify accounting reconciliation, expense atomicity, recurring expense idempotency, payroll ledger integrity, daily closing closed-book behavior and fixed-asset financial postings.

## Explicit exclusions

Phase 7 does not address unrelated authorization drift such as:

- report export being coupled to `reports.view`;
- global search being authentication-only;
- the task status route still using `tasks.view` despite `tasks.update-status` existing;
- later administrative/support modules outside operational finance.

Those items remain for subsequent authorization phases and must not be mixed into this branch.
