# Step 12 — Arrears and Penalties — Implementation Report

**Status:** COMPLETED  
**Verified:** 12 August 2026

## What was implemented

- Automated overdue-loan management for active loans with persisted arrears state.
- Required arrears buckets:
  - 1–7 days
  - 8–30 days
  - 31–60 days
  - 61–90 days
  - 90+ days
- Branch-scoped arrears queue showing:
  - Customer
  - Phone
  - Branch
  - Loan officer
  - Overdue principal
  - Overdue interest
  - Overdue fees
  - Overdue penalties
  - Total overdue
  - Days overdue
  - Arrears bucket
  - Linked collateral
- Loan-level arrears workspace showing current total outstanding balances, overdue installment details, penalty history, collateral and collection history.
- Penalty types:
  - Fixed
  - Percentage
  - Daily percentage
  - Weekly percentage
- Loan applications now snapshot the product's late-payment penalty type and value onto the loan so later product edits cannot rewrite an existing borrower's terms.
- Existing loans are backfilled with their current product penalty terms when the Step 12 migration runs.
- Generated loan contracts now use the penalty terms frozen on the loan rather than the live product configuration.
- Percentage penalty calculations use the unpaid scheduled principal + interest + fees for the overdue installment as their base.
- Previously assessed penalties are excluded from the percentage base, so penalties never compound on penalties.
- Fixed and simple percentage penalties are assessed once, on the first overdue day.
- Daily percentage penalties are assessed once for each overdue day.
- Weekly percentage penalties are assessed on overdue days 1, 8, 15 and so on.
- Historical/catch-up assessment reconstructs the unpaid scheduled base using payment allocations that existed before each penalty effective date.
- Deterministic period keys plus a database unique constraint prevent duplicate penalty assessment.
- Penalty assessment creates permanent `loan_penalty_charges` records.
- Assessed penalties increase installment penalty due/remaining and loan penalty/total outstanding balances.
- Assessed penalties create customer-statement debit entries and statement running balances are recalculated chronologically.
- Existing payment accounting continues to recognize penalty income when penalties are actually collected.
- Loan payments perform penalty catch-up before allocating incoming money, preventing missed scheduler runs from bypassing already-due penalties.
- Payment allocation remains penalty → fees → interest → principal.
- Arrears state is refreshed immediately after payment instead of waiting until the next nightly job.
- Fully paid installments are removed from arrears state and overdue installment statuses are kept current.
- Collection follow-up records support:
  - Called
  - SMS
  - Visit
  - Promise to Pay
  - Guarantor Contacted
  - Demand Notice
  - Other
- Follow-ups permanently store the loan, customer, branch, action, timestamp, notes, employee and optional promise date.
- Promise to Pay requires a promise date.
- Collection follow-up creation is audit logged.
- No update/delete route exists for penalty charges or collection follow-up history.
- Backend branch isolation is enforced for arrears lists, details and follow-up posting.
- Dedicated permissions were added for arrears viewing and collection follow-up recording.
- Penalty assessment is system-controlled; branch staff cannot manually fabricate or delete penalty charges.
- `loans:update-overdue` performs duplicate-safe overdue and penalty processing for all active loans.
- The overdue processor is scheduled daily at 00:05 in the application timezone with overlap protection, before the repayment reminder dispatcher.

## Database changes

### `loans`

Added:

- `late_payment_penalty_type`
- `late_payment_penalty_value`
- `overdue_principal`
- `overdue_interest`
- `overdue_fees`
- `overdue_penalties`
- `total_overdue`
- `days_overdue`
- `arrears_bucket`
- `arrears_updated_at`

### `loan_penalty_charges`

Stores permanent assessed penalty events including:

- Loan
- Installment
- Branch
- Effective date
- Deterministic period key
- Penalty type/value
- Calculation base
- Amount
- Days overdue
- Source

The installment + period key is unique to prevent duplicate charging.

### `collection_follow_ups`

Stores permanent debt-collection actions including:

- Loan
- Customer
- Branch
- Action type
- Action time
- Notes
- Promise date
- Employee

## Main files created

- `database/migrations/2026_08_12_130000_create_arrears_penalties_workflow.php`
- `app/Models/LoanPenaltyCharge.php`
- `app/Models/CollectionFollowUp.php`
- `app/Services/CustomerStatementBalanceService.php`
- `app/Services/LoanPenaltyService.php`
- `app/Services/OverdueLoanService.php`
- `app/Http/Controllers/ArrearsController.php`
- `app/Console/Commands/UpdateLoanArrears.php`
- `routes/arrears.php`
- `resources/views/arrears/index.blade.php`
- `resources/views/arrears/show.blade.php`
- `tests/Feature/ArrearsPenaltyWorkflowTest.php`
- `tests/Feature/LoanPenaltyContractSnapshotTest.php`

## Main files modified

- `app/Models/Loan.php`
- `app/Models/LoanInstallment.php`
- `app/Services/LoanApplicationService.php`
- `app/Services/LoanPaymentService.php`
- `app/Services/LoanContractPdfService.php`
- `database/seeders/RolePermissionSeeder.php`
- `routes/console.php`
- `routes/web.php`
- `resources/views/layouts/partials/sidebar.blade.php`

## Routes/endpoints added

- `GET /arrears` — branch-scoped arrears queue
- `GET /arrears/{loan}` — arrears/collection workspace
- `POST /arrears/{loan}/follow-ups` — record a collection action

## Commands and scheduling

Manual processing:

```bash
php artisan loans:update-overdue
```

Historical/test processing:

```bash
php artisan loans:update-overdue --date=YYYY-MM-DD
```

Scheduler:

- Daily at `00:05`
- Application timezone
- `withoutOverlapping()`
- Runs before the Step 11 reminder dispatcher

Production still requires the normal Laravel scheduler runner, for example a system cron invoking `php artisan schedule:run` every minute.

## Permissions

Added:

- `arrears.view`
- `arrears.follow-up`

Operational grants:

- Branch Administrator: view + follow-up
- Branch Manager: view + follow-up
- Loan Officer: view + follow-up
- Loan Inspector: view
- Accountant: view
- Debt Collector: view + follow-up
- Auditor: view
- Super Administrator: all through the existing super-admin permission bypass

## Automated coverage

Step 12 tests verify:

- Fixed penalties.
- Percentage penalties.
- Daily percentage penalties.
- Weekly percentage penalties.
- Penalties do not compound on penalties.
- Duplicate scheduler reruns do not create duplicate charges.
- Exact bucket boundaries for all five arrears buckets.
- Customer-statement penalty balance updates.
- Payment-time catch-up when the scheduled overdue job has not run.
- Penalty-first payment allocation and accounting integration.
- Immediate arrears refresh after payment.
- Branch isolation for arrears lists/details/follow-ups.
- Required promise dates for Promise to Pay.
- Permanent collection follow-up and audit records.
- Loan penalty-term snapshots are insulated from later product edits.
- Contract PDFs use frozen loan penalty terms.
- Nightly scheduler registration and timing.
- Arrears list/detail UI rendering.

## Verification result

On the audited Step 12 implementation head before this documentation commit:

- **99 tests passed**
- **834 assertions passed**
- Fresh migrations passed.
- All seeders passed.
- All previously implemented modules remained green.

A final CI run is required for the documentation head before merge, following the repository's normal merge gate.

## Remaining for Step 12

None.

Step 13 — Loan Top-Up remains intentionally unimplemented and is the next roadmap phase.
