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
| Aspect | Refinance | Reschedule | Payoff |
|---|---|---|---|
| Loan Accounts | 2 (old closed, new opened) | 1 (same loan modified) | 1 (closed) |
| Balance Transfer | Old → New loan | Preserved in same loan | Paid off |
| Schedule | Old closed, completely new | Old superseded, new active | All closed |
| Purpose | Better terms + additional funds | Payment relief | Complete settlement |
| Credit History | Fresh start | Preserved | Loan completed |
| Top-Up | YES (new > old balance) | NO | NO |
Refinance Types
- Rate Refinance: Same balance, better interest rate
- Cash-Out Refinance: New loan > old balance (extra cash to borrower)
- Consolidation Refinance: Multiple old loans → 1 new loan
- 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
| Parameter | Type | Required | Description |
|---|---|---|---|
accountEncodedKey | string | ✅ Yes | Existing loan account to refinance |
clientEncodedKey | string | ✅ Yes | Client/borrower encoded key |
newLoanProductKey | string | ✅ Yes | New loan product for refinanced loan |
newPrincipalAmount | decimal | ⌠No | New principal (defaults to outstanding balance + top-up) |
newTermMonths | int | ⌠No | New loan term in months |
newInterestRate | decimal | ⌠No | New interest rate (%) |
topUpAmount | decimal | ⌠No | Additional funds disbursed |
transactionDate | DateTime | ⌠No | Refinance date (defaults to today) |
notes | string | ⌠No | Refinance 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
ProcessLoanRefinanceAsyncwith 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: