# Loan Creation Module Update for Legacy Import

## Goal

Add a loan-level flag to distinguish loans created through the legacy CSV import flow from loans created through the normal application flow.

The intended behavior is:

- If a loan is created during a legacy CSV import, set `legacy_import = 1` (or `true`).
- If a loan is created normally through the app, set `legacy_import = 0` (or `false`).
- When `legacy_import = 1`, the loan’s paid amount should be treated as a fixed legacy value sourced directly from the CSV `Paid` field and should not be regenerated from repayment totals.

---

## Business Rule

### Rule 1: Legacy flag on creation

Add a boolean column on the `loans` table:

```php
legacy_import BOOLEAN NOT NULL DEFAULT false
```

or, if the app prefers integer storage:

```php
legacy_import TINYINT(1) NOT NULL DEFAULT 0
```

The value should be set at loan creation time:

- legacy CSV import: `1`
- regular app-created loan: `0`

### Rule 2: Paid amount for legacy-imported loans

If `legacy_import = true` for a specific loan, then:

- `amount_paid` (or equivalent paid value) should be hardcoded from the CSV `Paid` value that was imported for that loan.
- The system must not overwrite that value using the runtime sum of repayments for that loan.
- The validator and reconciliation logic must treat this as a fixed legacy snapshot unless explicit re-import/reset logic is triggered.

This means the import path should preserve the CSV source value as the authoritative paid value for that loan.

---

## Implementation Approach

### 1) Database migration

Create a migration to add the field:

```php
Schema::table('loans', function (Blueprint $table) {
    $table->boolean('legacy_import')->default(false)->after('status');
});
```

If the project uses `amount_paid` and related summary fields on the loan table, ensure those values remain compatible with the legacy import flow.

### 2) Model update

Add the cast to the `Loan` model:

```php
protected $casts = [
    'legacy_import' => 'boolean',
];
```

Also add a convenience method if needed:

```php
public function isLegacyImported(): bool
{
    return (bool) $this->legacy_import;
}
```

### 3) Legacy import service logic

When a loan is created in the legacy import flow, set:

```php
'legacy_import' => true,
```

For example, in the legacy import service path:

```php
$loan = Loan::create([
    'user_id' => $user->id,
    'amount' => $principal,
    'legacy_import' => true,
    'status' => 'active',
    // ...other fields
]);
```

If the loan already exists and is being updated through legacy import, ensure the flag remains true.

### 4) Paid logic for legacy-imported loans

This is the key part of the assignment.

When `legacy_import` is true, the paid amount should be derived from the original CSV `Paid` column and stored as the authoritative value for that loan.

In pseudo-logic:

```php
if ($loan->legacy_import) {
    $loan->amount_paid = $csvPaidValue;
    $loan->save();
} else {
    // normal runtime logic
    $loan->amount_paid = $loan->repayments()->sum('amount_paid');
}
```

or, if the app uses a dedicated reconciliation method:

```php
protected function reconcileLoanSummaryFromRepayments(Loan $loan, ?float $paid = null): void
{
    if ($loan->legacy_import && $paid !== null) {
        $loan->update([
            'amount_paid' => round((float) $paid, 2),
        ]);

        return;
    }

    $totalRepaid = (float) $loan->repayments()->sum('amount_paid');
    $loan->update([
        'amount_paid' => $totalRepaid,
    ]);
}
```

This ensures the CSV `Paid` value wins for legacy-imported loans.

---

## Important Rule

The legacy-import loan should not be treated as a normal dynamic repayment loan for summary fields like `amount_paid`.

Instead:

- `legacy_import = true` means the loan is a historical CSV-imported record.
- `Paid` from the legacy CSV is treated as the source of truth.
- subsequent automatic reconciliation based on `repayments()->sum('amount_paid')` must be bypassed for that loan.

This is important because the legacy import process is not a live repayment flow; it is a historical data ingestion process.

---

## Recommended Guardrails

### Option A: strict enforcement

If `legacy_import = true`, stop summary recomputation for `amount_paid` entirely unless an explicit admin action says to re-sync.

### Option B: CSV-sourced snapshot with explicit override

Store an additional value such as `legacy_import_paid_override` if you want to preserve the CSV figure separately from the runtime payment summary, while still exposing a computed value elsewhere.

This is safer if the project needs both:

- the original CSV paid value for historical reporting
- the runtime repayment summary for current operational logic

---

## Acceptance Criteria

1. New migration adds `legacy_import` to `loans` with default `0`.
2. Legacy import loan creation sets `legacy_import` to `1`.
3. Regular loan creation sets `legacy_import` to `0`.
4. A legacy-imported loan keeps `amount_paid` equal to the imported CSV `Paid` value.
5. Reconciliation logic does not override a legacy-imported loan's paid value from repayments.
6. Validation logic confirms that CSV `Paid` and DB paid match for all loans with `legacy_import = 1`.

---

## Suggested rollout order

1. Add the migration.
2. Update the `Loan` model and casts.
3. Update the legacy import service to set `legacy_import = true` during import.
4. Update reconciliation logic to short-circuit when `legacy_import` is true.
5. Add validation checks to confirm all `legacy_import` loans use CSV `Paid` as the paid baseline.
6. Run a focused dry run on a sample of imported records before broad enforcement.

---

## Final implementation intent

The project should treat the legacy import as a data-capture event, not a normal live loan repayment event. That means the imported CSV `Paid` value becomes the authoritative `amount_paid` for any loan created during the legacy import process when `legacy_import` is enabled.
