# Loan Reference Number Rules

This document defines the File Reference Number (`file_ref_no`) generation rules for every loan type in the LBDI CWAS system. Each loan type has its own section. All new loan modules must add their rules here before implementation.

---

## Structure Overview

Every loan reference number follows this segment pattern:

```
FR / {LoanCode} - {SizeCode} - {CurrencyCode} / {DisbursementPrefix} / {GlobalSeq} / {DailySeq} - {MON} - {DD} - {YY}
```

| Segment | Position | Description |
|---|---|---|
| `FR/` | 1 | Fixed prefix — File Reference |
| `{LoanCode}-` | 2 | Loan type identifier (e.g. `ML` = Mortgage Loan) |
| `{SizeCode}-` | 3 | Amount tier code |
| `{CurrencyCode}/` | 4 | Currency disbursement code |
| `{DisbursementPrefix}` | 5 | Currency disbursement path |
| `{GlobalSeq:04d}/` | 6 | Zero-padded 4-digit total record count for this loan type |
| `{DailySeq:03d}-` | 7 | Zero-padded 3-digit count of this loan type created today |
| `{MON}-{DD}-{YY}` | 8 | Application date (abbreviated month, day, 2-digit year) |

---

## 1. Mortgage Loans (`ML`)

**Module:** `app/Modules/MortgageLoans/`
**Model:** `app/Models/MortgageApplicationModel.php` — `generateFileRef(float $approvedAmount, string $approvedCurrency)`
**DB table:** `mortgage_applications`

### 1.1 Base Format

```
FR/ML-M-MC/LRD/0001/001-JAN-07-26
```

### 1.2 Segment Breakdown

| Seg | Label | Default | Rule | Override |
|---|---|---|---|---|
| 1 | Fixed prefix | `FR/` | — | — |
| 2 | Loan code | `ML-` | Always `ML` for Mortgage Loan | — |
| 3 | Size code | `M-` | `approved_amount > 300,000` | `BD-` |
| 4 | Currency code | `MC/` | `approved_currency = 'LRD'` | `SM/` |
| 5 | Disbursement prefix | `LRD/` | `approved_currency = 'USD'` | `USD/LRD/` |
| 6 | Global sequence | `{n:04d}/` | Total mortgage records in DB + 1 | — |
| 7 | Daily sequence | `{n:03d}-` | Mortgage records created today + 1 | — |
| 8 | Date | `{MON}-{DD}-{YY}` | Current date at time of creation | — |

### 1.3 Segment Rules Explained

**Segment 3 — Size Code:**
- `M-` → Standard mortgage (approved amount ≤ $300,000)
- `BD-` → Big Deal mortgage (approved amount > $300,000)

**Segment 4 — Currency Code:**
- `MC/` → Multi-Currency (approved currency is USD)
- `SM/` → Single-currency Monrovia Dollar (approved currency is LRD)

**Segment 5 — Disbursement Prefix:**
- `LRD/` → Disbursed in Liberian Dollars only
- `USD/LRD/` → Disbursed in USD (with LRD equivalent tracked)

### 1.4 All Combinations

| Approved Amount | Approved Currency | Generated Format |
|---|---|---|
| ≤ $300,000 | LRD | `FR/ML-M-SM/LRD/0001/001-JAN-07-26` |
| ≤ $300,000 | USD | `FR/ML-M-MC/USD/LRD/0001/001-JAN-07-26` |
| > $300,000 | LRD | `FR/ML-BD-SM/LRD/0001/001-JAN-07-26` |
| > $300,000 | USD | `FR/ML-BD-MC/USD/LRD/0001/001-JAN-07-26` |

### 1.5 Implementation

**Model method** (`MortgageApplicationModel::generateFileRef`):

```php
public function generateFileRef(float $approvedAmount = 0, string $approvedCurrency = 'LRD'): string
{
    $month = strtoupper(date('M'));
    $day   = date('d');
    $year  = date('y');

    $db = \Config\Database::connect();

    // Segment 6: global record count
    $globalSeq = (int) $db->table($this->table)->countAll() + 1;

    // Segment 7: records created today
    $dailySeq = (int) $db->table($this->table)
        ->where('DATE(created_at)', date('Y-m-d'))
        ->countAllResults() + 1;

    // Segment 3: M- (standard) or BD- (big deal)
    $s3 = $approvedAmount > 300000 ? 'BD-' : 'M-';

    // Segment 4: MC (USD) or SM (LRD)
    $s4 = $approvedCurrency === 'LRD' ? 'SM' : 'MC';

    // Segment 5: LRD/ or USD/LRD/
    $s5 = $approvedCurrency === 'USD' ? 'USD/LRD/' : 'LRD/';

    return sprintf('FR/ML-%s%s/%s%04d/%03d-%s-%s-%s',
        $s3, $s4, $s5,
        $globalSeq,
        $dailySeq,
        $month, $day, $year
    );
}
```

**Controller call** (`MortgageLoanController::store`):

```php
if (empty($post['file_ref_no'])) {
    $post['file_ref_no'] = $this->model->generateFileRef(
        (float) ($post['approved_amount']   ?? 0),
        $post['approved_currency'] ?? 'LRD'
    );
}
```

---

## 2. Apex (Employee Salary) Loans (`AL`)

**Module:** `app/Modules/ApexLoans/`
**Models:** `app/Models/ApexFacilityModel.php` — `generateFileRef()` · `app/Models/ApexLoanModel.php` — `generateSubLoanRef(int $facilityId)`
**DB tables:** `apex_facilities`, `apex_loans`

Apex Loans have **two distinct reference number types**: one for the corporate umbrella facility and one for each employee sub-loan.

### 2.1 Facility Reference Number

```
FR/AL-AF-MC/USD/LRD/0001/001-JAN-07-26
```

| Seg | Label | Value | Notes |
|---|---|---|---|
| 1 | Fixed prefix | `FR/` | — |
| 2 | Loan code | `AL-` | Apex Loan |
| 3 | Record type | `AF-` | Apex Facility (corporate umbrella) |
| 4 | Currency code | `MC/` | Always Multi-Currency (USD) |
| 5 | Disbursement prefix | `USD/LRD/` | Always USD with LRD tracking |
| 6 | Global seq | `{n:04d}/` | Total apex facilities in DB + 1 |
| 7 | Daily seq | `{n:03d}-` | Apex facilities created today + 1 |
| 8 | Date | `{MON}-{DD}-{YY}` | Creation date |

**Implementation** (`ApexFacilityModel::generateFileRef`):

```php
public function generateFileRef(): string
{
    $month = strtoupper(date('M'));
    $day   = date('d');
    $year  = date('y');

    $db = \Config\Database::connect();

    $globalSeq = (int) $db->table($this->table)->countAll() + 1;
    $dailySeq  = (int) $db->table($this->table)
        ->where('DATE(created_at)', date('Y-m-d'))
        ->countAllResults() + 1;

    return sprintf('FR/AL-AF-MC/USD/LRD/%04d/%03d-%s-%s-%s',
        $globalSeq, $dailySeq, $month, $day, $year);
}
```

### 2.2 Employee Sub-Loan Reference Number

```
FR/AL-SL-MC/USD/LRD/0001/001-JAN-07-26
```

| Seg | Label | Value | Notes |
|---|---|---|---|
| 1 | Fixed prefix | `FR/` | — |
| 2 | Loan code | `AL-` | Apex Loan |
| 3 | Record type | `SL-` | Sub-Loan (individual employee) |
| 4 | Currency code | `MC/` | Always Multi-Currency (USD) |
| 5 | Disbursement prefix | `USD/LRD/` | Always USD with LRD tracking |
| 6 | Global seq | `{n:04d}/` | Total apex sub-loans in DB + 1 |
| 7 | Facility seq | `{n:03d}-` | Sub-loans within this facility + 1 |
| 8 | Date | `{MON}-{DD}-{YY}` | Creation date |

> **Note:** Segment 7 for sub-loans uses the **facility-scoped** count (loans under the same `facility_id`), not the daily global count. This gives each facility its own sequential loan numbering.

**Implementation** (`ApexLoanModel::generateSubLoanRef`):

```php
public function generateSubLoanRef(int $facilityId): string
{
    $month = strtoupper(date('M'));
    $day   = date('d');
    $year  = date('y');

    $db = \Config\Database::connect();

    // Global sequence across all apex sub-loans
    $globalSeq = (int) $db->table($this->table)->countAll() + 1;

    // Sequence within this specific facility
    $facilitySeq = (int) $db->table($this->table)
        ->where('facility_id', $facilityId)
        ->countAllResults() + 1;

    return sprintf('FR/AL-SL-MC/USD/LRD/%04d/%03d-%s-%s-%s',
        $globalSeq, $facilitySeq, $month, $day, $year);
}
```

### 2.3 Key Business Rules

- **Facility ref** is always USD (Apex facilities are USD-only, minimum $300k by contract).
- **Sub-loan ref** segment 7 tracks the count of loans within the specific corporate facility, giving each corporation its own numbered loan sequence.
- Both types are always `MC` (Multi-Currency) because USD is used with LRD equivalent tracking.
- The `AF` vs `SL` distinction in segment 3 allows instant visual identification of facility-level vs employee-level documents.

---

## 3. Personal Loans (`PL`)

> **Not yet implemented.** Reserved for future use.

Planned format:

```
FR/PL-{SizeCode}-{CurrencyCode}/{DisbursementPrefix}{GlobalSeq:04d}/{DailySeq:03d}-{MON}-{DD}-{YY}
```

Add rules here when the PersonalLoans module is built.

---

## 3. Vehicle Loans (`VL`)

> **Not yet implemented.** Reserved for future use.

Planned format:

```
FR/VL-{SizeCode}-{CurrencyCode}/{DisbursementPrefix}{GlobalSeq:04d}/{DailySeq:03d}-{MON}-{DD}-{YY}
```

Add rules here when the VehicleLoans module is built.

---

## 4. Business Loans (`BL`)

> **Not yet implemented.** Reserved for future use.

Planned format:

```
FR/BL-{SizeCode}-{CurrencyCode}/{DisbursementPrefix}{GlobalSeq:04d}/{DailySeq:03d}-{MON}-{DD}-{YY}
```

Add rules here when the BusinessLoans module is built.

---

## General Implementation Notes

1. **Always use the DB count, not a model-level query chain.** Use `\Config\Database::connect()` directly inside `generateFileRef()` so the global and daily counts do not interfere with any active query builder state.

2. **Global sequence counts all records in the table**, including soft-deleted or draft records, to guarantee uniqueness.

3. **Daily sequence resets each calendar day.** It counts records where `DATE(created_at) = CURDATE()`.

4. **Date is the creation date** (server time at the moment `store()` is called), not the `application_date` field entered by the user.

5. **The generated ref is stored immediately on `insert()`** and never regenerated. If a user provides their own `file_ref_no` in the form, the generated value is skipped entirely.

6. **Each loan type's `generateFileRef()` is a method on its own model.** The method signature must accept at minimum the parameters required to compute the conditional segments. Parameters that are not relevant to a particular loan type may be omitted.

7. **Loan code registry** — reserve codes here to prevent collisions:

| Code | Loan Type | Status |
|---|---|---|
| `ML` | Mortgage Loan | Active |
| `AL` | Apex (Employee Salary) Loan | Active |
| `PL` | Personal Loan | Reserved |
| `VL` | Vehicle Loan | Reserved |
| `BL` | Business Loan | Reserved |
