# Loan Fee Payment Tracking Documentation

## Purpose

This document describes the new registration fee and LAF payment tracking flow for LendCore. It explains the database changes, backend behavior, user experience, admin/officer views, and M-Pesa integration used to collect loan fees before disbursement.

## Summary

Loan requests now separate:
- `Loan Repayable` — principal plus interest.
- `Registration Fee` — one-time onboarding fee.
- `LAF Fee` — loan access fee.
- `Total Payable` — full loan repayment obligation including interest and any existing fee components.

The system now requires the borrower to pay registration and LAF fees together after admin approval and before the loan can be disbursed.

## Database Changes

A migration was added:
- `database/migrations/2026_05_12_210000_add_fee_payment_tracking_to_loans_table.php`

New loan columns:
- `registration_fee_paid` (decimal)
- `laf_fee_paid` (decimal)
- `fee_payment_completed_at` (timestamp)

These columns record how much of each fee has been paid and when the fee payment was completed.

## Model Changes

`app/Models/Loan.php`
- Added `registration_fee_paid`, `laf_fee_paid`, and `fee_payment_completed_at` to `$fillable` and `$casts`.
- Added helper accessors:
  - `fees_paid` — returns true when both fees are fully paid.
  - `fee_payment_due` — returns the combined remaining registration + LAF balance.

The loan accessor `total_loan_repayable` remains defined as `amount + interest`.

## Loan Fee Payment Flow

### When it occurs

- Only approved loans can receive the combined registration + LAF payment.
- The payment is captured before any disbursement.
- Loan disbursement is blocked until `fee_payment_due` is zero.

### User-facing flow

Updated file:
- `resources/views/user/loans/show.blade.php`

Behavior:
- Approved loans show a fee breakdown.
- If fees are unpaid, the user sees:
  - `Registration Fee`
  - `LAF Fee`
  - `Total Fee Due`
- A single form is presented to pay both fees via STK Push.
- The form submits to `POST /loans/{loan}/pay-fees`.

### Route

New route in `routes/web.php`:
- `Route::post('/loans/{loan}/pay-fees', [UserLoanController::class, 'processFeePayment'])->name('user.loans.pay-fees.submit');`

### Payment handling

`app/Http/Controllers/Web/LoanController.php`
- Added `processFeePayment()`.
- Creates a pending payment transaction.
- Initiates M-Pesa STK Push with a loan reference `LN-{loan_id}`.
- Stores `checkout_request_id` and callback metadata in the pending transaction.

### Phone format
- Uses `2547XXXXXXXX` format for STK Push requests, aligned with existing repayment handling.

## M-Pesa Callback Integration

Updated file:
- `app/Http/Controllers/Api/MpesaCallbackController.php`

Behavior:
- `c2bConfirmation()` now maps loan references starting with `LN-` to loan fee payments.
- If the loan is approved and still has fee balance, the callback records the payment via `RepaymentService::recordFeePayment()`.
- If the loan has no fee balance or the callback maps differently, previous repayment handling remains unchanged.

## Backend Locking

Updated file:
- `app/Services/LoanService.php`

Behavior:
- `disburseLoan()` now throws an exception when `fee_payment_due > 0`.
- `manualDisburseLoan()` also blocks disbursement until fees are paid.
- This ensures loans cannot move to B2C disbursement or manual disbursement while fees remain unpaid.

## Admin Experience

Updated file:
- `resources/views/admin/loans/show.blade.php`

Behavior:
- Displays `Registration Fee Paid` and `LAF Fee Paid`.
- Shows `Fee Payment Status` clearly.
- If fees remain due, admin disbursement controls are hidden and the loan is flagged as not ready.
- If fees are paid, the loan is shown as ready for disbursement.

## Officer Experience

Updated file:
- `resources/views/officer/loans/show.blade.php`

Behavior:
- Adds fee fields to the officer loan detail page:
  - `Registration Fee`
  - `LAF Fee`
  - `Fee Payment Due`

This gives officers visibility into whether a loan is ready for further action.

## Notes

- The fee payment flow uses a single combined payment for registration + LAF.
- The user must pay the full due amount, not a partial amount.
- The system tracks both fee balances separately but enforces completion only when both are paid.
- Once fees are paid, `fee_payment_completed_at` is set.

## Reconciliation Script

A helper script was added to fix loans where the M-Pesa fee payment transaction completed but the loan fee tracking fields were not updated.

File added:
- `reconcile_fee_payments.php`

Usage:

```bash
php reconcile_fee_payments.php
```

## Run migration

To apply the new database fields:

```bash
php artisan migrate
```

## Files changed

- `database/migrations/2026_05_12_210000_add_fee_payment_tracking_to_loans_table.php`
- `app/Models/Loan.php`
- `app/Services/LoanService.php`
- `app/Services/RepaymentService.php`
- `app/Http/Controllers/Web/LoanController.php`
- `app/Http/Controllers/Api/MpesaCallbackController.php`
- `routes/web.php`
- `resources/views/user/loans/show.blade.php`
- `resources/views/admin/loans/show.blade.php`
- `resources/views/officer/loans/show.blade.php`

## Intended behavior

After admin approval:
1. User visits loan detail page.
2. User pays combined registration + LAF fee via STK Push.
3. M-Pesa callback confirms payment.
4. Loan fee state updates to paid.
5. Admin sees the loan as ready for disbursement.
6. Admin can complete B2C or manual disbursement.
