Skip to main content

Loan Refinance Transaction

Overview

A Loan Refinance is a transaction where a borrower takes out a new loan to pay off an existing loan, typically to obtain better terms (lower interest rate, longer term, or additional funds). Unlike a reschedule which modifies the same loan, refinancing creates a completely new loan account that pays off the old one.

Key Characteristics

  • Purpose: Replace old loan with new loan offering better terms or additional funding
  • Transaction Type: REFN (Refinance)
  • Complexity: Very High - TWO loan transactions (old loan payoff + new loan disbursement)
  • Multi-Entity Impact: 2× LoanAccounts, 2× LoanSchedule sets, DepositAccount
  • Critical Requirement: Atomic execution (old loan closed AND new loan disbursed in single transaction)

Refinance vs Other Loan Transactions

AspectRefinanceReschedulePayoff
Loan Accounts2 (old closed, new opened)1 (same loan modified)1 (closed)
Balance TransferOld → New loanPreserved in same loanPaid off
ScheduleOld closed, completely newOld superseded, new activeAll closed
PurposeBetter terms + additional fundsPayment reliefComplete settlement
Credit HistoryFresh startPreservedLoan completed
Top-UpYES (new > old balance)NONO

Refinance Types

  1. Rate Refinance: Same balance, better interest rate
  2. Cash-Out Refinance: New loan > old balance (extra cash to borrower)
  3. Consolidation Refinance: Multiple old loans → 1 new loan
  4. Term Refinance: Extended/shortened term with new rate

Transaction Flow


Entities Impacted

Scenario 1: Cash-Out Refinance with Top-Up

Context:

  • Old Loan: NGN 3,000,000 principal, 24% interest, 36 months

    • 12 months paid, NGN 2,400,000 outstanding principal
    • Accrued interest: NGN 120,000
    • Prepayment penalty: 2% = NGN 48,000
    • Total Payoff: NGN 2,568,000
  • New Loan: NGN 3,500,000 principal, 18% interest, 48 months

    • To payoff old loan: NGN 2,568,000
    • Top-Up to customer: NGN 900,000 (NGN 3,500,000 - NGN 2,568,000 - NGN 32,000 fee)
    • Refinance fee: 1% of new loan = NGN 35,000 → Deducted = NGN 32,000 net

Calculation:

Old Loan Payoff = 2,400,000 (principal) + 120,000 (interest) + 48,000 (penalty) = 2,568,000
New Loan Amount = 3,500,000
Refinance Fee = 35,000
Top-Up to Customer = 3,500,000 - 2,568,000 - 35,000 = 897,000
```text
**Entities Impacted** (60+ ImpactedEntity records):

```typescript
{
transactionId: "REFN-001",
transactionType: "Loan Refinance",
refinanceDate: "2025-12-28",
impactedEntities: [

// 1-24: Old Loan Schedule Closure (24 outstanding schedules)
// Old Schedule 13 (example)
{
entityType: "LoanSchedule",
entityId: 313,
entityKey: "OLD-SCH-313",
fieldName: "State",
oldValue: "ACTIVE",
newValue: "CLOSED",
deltaAmount: 0
},
{
entityType: "LoanSchedule",
entityId: 313,
fieldName: "ClosureReason",
oldValue: null,
newValue: "Refinanced",
deltaAmount: 0
},
{
entityType: "LoanSchedule",
entityId: 313,
fieldName: "ClosedDate",
oldValue: null,
newValue: "2025-12-28",
deltaAmount: 0
},
// ... (23 more old schedules, each with 3 changes = 69 records)

// 25-32: Old LoanAccount Closure
{
entityType: "LoanAccount",
entityId: 201,
entityKey: "OLD-LOAN-201",
fieldName: "PrincipalBalance",
oldValue: 2400000.00,
newValue: 0.00,
deltaAmount: -2400000.00
},
{
entityType: "LoanAccount",
entityId: 201,
fieldName: "InterestBalance",
oldValue: 840000.00,
newValue: 0.00,
deltaAmount: -840000.00
},
{
entityType: "LoanAccount",
entityId: 201,
fieldName: "TotalPaid",
oldValue: 1200000.00,
newValue: 3768000.00, // +2,568,000 payoff
deltaAmount: +2568000.00
},
{
entityType: "LoanAccount",
entityId: 201,
fieldName: "PayoffAmount",
oldValue: 0.00,
newValue: 2568000.00,
deltaAmount: +2568000.00
},
{
entityType: "LoanAccount",
entityId: 201,
fieldName: "PayoffDate",
oldValue: null,
newValue: "2025-12-28",
deltaAmount: 0
},
{
entityType: "LoanAccount",
entityId: 201,
fieldName: "LoanState",
oldValue: "ACTIVE",
newValue: "CLOSED",
deltaAmount: 0
},
{
entityType: "LoanAccount",
entityId: 201,
fieldName: "ClosureReason",
oldValue: null,
newValue: "Refinanced",
deltaAmount: 0
},
{
entityType: "LoanAccount",
entityId: 201,
fieldName: "RefinancedByLoanId",
oldValue: null,
newValue: "301", // New loan ID
deltaAmount: 0
},

// 33-40: New LoanAccount Creation
{
entityType: "LoanAccount",
entityId: 301,
entityKey: "NEW-LOAN-301",
fieldName: "PrincipalAmount",
oldValue: null,
newValue: 3500000.00,
deltaAmount: +3500000.00
},
{
entityType: "LoanAccount",
entityId: 301,
fieldName: "PrincipalBalance",
oldValue: null,
newValue: 3500000.00,
deltaAmount: +3500000.00
},
{
entityType: "LoanAccount",
entityId: 301,
fieldName: "InterestRate",
oldValue: null,
newValue: 18.00,
deltaAmount: 0
},
{
entityType: "LoanAccount",
entityId: 301,
fieldName: "TermMonths",
oldValue: null,
newValue: 48,
deltaAmount: 0
},
{
entityType: "LoanAccount",
entityId: 301,
fieldName: "LoanState",
oldValue: null,
newValue: "ACTIVE",
deltaAmount: 0
},
{
entityType: "LoanAccount",
entityId: 301,
fieldName: "DisbursementDate",
oldValue: null,
newValue: "2025-12-28",
deltaAmount: 0
},
{
entityType: "LoanAccount",
entityId: 301,
fieldName: "RefinancesLoanId",
oldValue: null,
newValue: "201", // Old loan ID
deltaAmount: 0
},
{
entityType: "LoanAccount",
entityId: 301,
fieldName: "CreatedByTransactionId",
oldValue: null,
newValue: "REFN-001",
deltaAmount: 0
},

// 41-88: New Loan Schedule Creation (48 schedules)
// New Schedule 1 (example)
{
entityType: "LoanSchedule",
entityId: 501,
entityKey: "NEW-SCH-501",
fieldName: "ScheduleNumber",
oldValue: null,
newValue: "1",
deltaAmount: 0
},
{
entityType: "LoanSchedule",
entityId: 501,
fieldName: "DueDate",
oldValue: null,
newValue: "2026-01-28",
deltaAmount: 0
},
{
entityType: "LoanSchedule",
entityId: 501,
fieldName: "PrincipalDue",
oldValue: null,
newValue: 72917.00,
deltaAmount: +72917.00
},
{
entityType: "LoanSchedule",
entityId: 501,
fieldName: "InterestDue",
oldValue: null,
newValue: 52500.00,
deltaAmount: +52500.00
},
{
entityType: "LoanSchedule",
entityId: 501,
fieldName: "State",
oldValue: null,
newValue: "ACTIVE",
deltaAmount: 0
},
// ... (47 more new schedules, each with 5 changes = 235 records)

// 89-90: DepositAccount impacts (top-up credited)
{
entityType: "DepositAccount",
entityId: 501,
entityKey: "DEP-501",
fieldName: "BookBalance",
oldValue: 500000.00,
newValue: 1397000.00, // +897,000 top-up
deltaAmount: +897000.00
},
{
entityType: "DepositAccount",
entityId: 501,
fieldName: "AvailableBalance",
oldValue: 500000.00,
newValue: 1397000.00,
deltaAmount: +897000.00
},

// 91-96: GL Account impacts
{
entityType: "GLAccount",
entityKey: "1101-LOANS-TO-CUSTOMERS",
fieldName: "DebitAmount",
deltaAmount: +3500000.00 // DR: New loan asset
},
{
entityType: "GLAccount",
entityKey: "1101-LOANS-TO-CUSTOMERS",
fieldName: "CreditAmount",
deltaAmount: +2400000.00 // CR: Old loan principal removed
},
{
entityType: "GLAccount",
entityKey: "1105-INTEREST-RECEIVABLE",
fieldName: "CreditAmount",
deltaAmount: +120000.00 // CR: Old loan interest written off
},
{
entityType: "GLAccount",
entityKey: "4105-PREPAYMENT-PENALTY-INCOME",
fieldName: "CreditAmount",
deltaAmount: +48000.00 // CR: Penalty income
},
{
entityType: "GLAccount",
entityKey: "4107-REFINANCE-FEE-INCOME",
fieldName: "CreditAmount",
deltaAmount: +35000.00 // CR: Refinance fee income
},
{
entityType: "GLAccount",
entityKey: "2101-CUSTOMER-DEPOSITS",
fieldName: "CreditAmount",
deltaAmount: +897000.00 // CR: Top-up to customer
}
]
}
```text
**Net GL Effect**:

- Loans Asset: +3,500,000 (new) - 2,400,000 (old principal) = **+1,100,000** (net increase)
- Customer Deposits: +897,000 (top-up credited)
- Income: +48,000 (penalty) + 35,000 (fee) = **+83,000**

---

## Refinance Implementation

### Step 1: Calculate Refinance Terms

:::warning[Code Removed]
**Implementation details removed for security.**

Contact support for implementation guidance.
:::text
### Step 2: Execute Refinance (Atomic)

:::warning[Code Removed]
**Implementation details removed for security.**

Contact support for implementation guidance.
:::text
---

## Best Practices

### For Product Managers

1. **Refinance Policy**:
- Set minimum payment history (e.g., 12 months on-time)
- Define refinance eligibility criteria
- Set refinance fees (typically 1-2%)

2. **Top-Up Limits**:
- Maximum top-up: 30-50% of old loan balance
- Credit assessment required for top-up amount
- Consider debt-to-income ratio

3. **Rate Incentives**:
- Offer rate reductions for good payment history
- Competitive rates to retain customers
- Balance profitability with customer retention

### For Developers

1. **Atomic Execution**:
- Use database transactions (BEGIN/COMMIT/ROLLBACK)
- If new loan fails, rollback old loan closure
- Ensure data consistency across both loans

2. **Cross-Linking**:
- Link old loan → new loan (RefinancedByLoanId)
- Link new loan → old loan (RefinancesLoanId)
- Track in TransactionImpactRecord

3. **Impact Tracking**:
- Track EVERY old schedule closure
- Track EVERY new schedule creation
- Track both loan account changes

### For Bank Operations

1. **Approval Process**:
- Credit review for new loan amount (especially top-up)
- Verify customer eligibility
- Document refinance reason

2. **Customer Communication**:
- Clear explanation of new terms vs old terms
- Monthly savings calculation
- Top-up amount and when available

3. **Regulatory Reporting**:
- Report as new loan origination
- Close old loan with "Refinanced" reason
- Track refinance rate for portfolio analysis

---

## V2 API Commands

### Architecture Overview

The V2 loan refinance command follows the **Delegation Pattern**:

- **V2 Facade**: `InitiateLoanRefinanceCommand` (BPMCore compatible)
- **V1 Implementation**: Delegates to existing V1 `LoanRefinanceCommand` with full business logic
- **BPM Integration**: Accepts parameters via `BpmUtil.GetPropertyValue()`

**Implementation**: `CB.Administration.Api/Commands/BPMCore/Loans/AdministrationCoreLoanCommandHandlers.Transactions.cs`

---

### InitiateLoanRefinanceCommand

**Purpose**: Refinance existing loan with new terms (close old loan, create new loan)

**Command**: `InitiateLoanRefinanceCommand`

**Delegation**: → `LoanRefinanceCommand` (V1 implementation)

#### BPM Parameters

```json
{
"commandName": "InitiateLoanRefinanceCommand",
"data": {
"accountEncodedKey": "string (mandatory)",
"clientEncodedKey": "string (mandatory)",
"newLoanProductKey": "string (mandatory)",
"newPrincipalAmount": "decimal (optional)",
"newTermMonths": "int (optional)",
"newInterestRate": "decimal (optional)",
"topUpAmount": "decimal (optional)",
"transactionDate": "DateTime (optional)",
"notes": "string (optional)"
}
}

Parameter Details

ParameterTypeRequiredDescription
accountEncodedKeystring✅ YesExisting loan account to refinance
clientEncodedKeystring✅ YesClient/borrower encoded key
newLoanProductKeystring✅ YesNew loan product for refinanced loan
newPrincipalAmountdecimal❌ NoNew principal (defaults to outstanding balance + top-up)
newTermMonthsint❌ NoNew loan term in months
newInterestRatedecimal❌ NoNew interest rate (%)
topUpAmountdecimal❌ NoAdditional funds disbursed
transactionDateDateTime❌ NoRefinance date (defaults to today)
notesstring❌ NoRefinance notes/remarks

Impact

Old Loan Account:

  • ✅ State → CLOSED (with "REFINANCED" reason)
  • ✅ Outstanding balance paid off from new loan

New Loan Account:

  • ✅ Created with new terms (principal, rate, term)
  • ✅ Principal = old outstanding + top-up amount
  • ✅ New schedules generated
  • ✅ Disbursed immediately

Example Response

{
"isSuccessful": true,
"transactionId": "TXN-LOAN-REFN-20251229-0001",
"transactionState": "SETTLED",
"message": "Loan refinanced successfully",
"data": {
"oldLoanAccountKey": "8a8080827f23loan017f23old456",
"newLoanAccountKey": "8a8080827f23loan017f23new789",
"oldOutstandingBalance": 400000.00,
"topUpAmount": 100000.00,
"newPrincipalAmount": 500000.00,
"newTermMonths": 48,
"newInterestRate": 16.5,
"oldLoanState": "CLOSED",
"newLoanState": "ACTIVE"
}
}

Implementation Checklist

Phase 1: Calculation

  • Implement CalculateRefinanceTermsAsync
  • Add top-up calculation
  • Calculate monthly savings
  • Unit tests (5+ scenarios)

Phase 2: Execution

  • Implement ProcessLoanRefinanceAsync with atomic execution
  • Add new loan creation logic
  • Add old loan closure logic
  • Add cross-linking
  • Integration tests

Phase 3: API

  • Create refinance calculation endpoint
  • Create refinance execution endpoint
  • Add validation rules
  • API tests

Phase 4: Testing

  • End-to-end tests (3+ scenarios)
  • Atomic transaction verification (rollback tests)
  • Production deployment

Developer Resources

For API implementation details, see:


Document Version: 1.0
Last Updated: December 28, 2025
Related Documents: