Skip to main content

Loan Repayment via Teller

Customer repays loan installment via teller counter (Cash payment).

Overview

Loan repayment via teller allows customers to pay their loan obligations through cash presented at the teller counter. The transaction reduces the loan balances (Principal, Interest, Penalties, Fees) and increases the teller till balance.

Key Features:

  • Cash payment through teller
  • Payment allocation (Interest → Principal → Penalties → Fees)
  • Loan schedule tracking and updates
  • Till balance impact
  • Multiple schedule support (for restructured loans)
  • Approval workflow for early settlements
  • Concurrent transaction safety with impact tracking

Transaction Flow


Entities Impacted

Standard Repayment Scenario

Command: LoanRepaymentWithTellerCommand (BPMCore)

Payment: ₦15,000 allocated as:

  • Interest: ₦5,000
  • Principal: ₦10,000
ImpactedEntities:
[
{
entityType: "LoanAccount",
entityId: 54321,
fieldName: "InterestBalance",
oldValue: 50000.00,
newValue: 45000.00,
deltaAmount: -5000.00
},
{
entityType: "LoanAccount",
entityId: 54321,
fieldName: "PrincipalBalance",
oldValue: 500000.00,
newValue: 490000.00,
deltaAmount: -10000.00
},
{
entityType: "LoanSchedule",
entityId: 1001,
fieldName: "InterestPaid",
oldValue: 0.00,
newValue: 5000.00,
deltaAmount: +5000.00
},
{
entityType: "LoanSchedule",
entityId: 1001,
fieldName: "PrincipalPaid",
oldValue: 0.00,
newValue: 10000.00,
deltaAmount: +10000.00
},
{
entityType: "LoanSchedule",
entityId: 1001,
fieldName: "State",
oldValue: "ACTIVE",
newValue: "PAID",
deltaAmount: 0
},
{
entityType: "TellerTill",
entityId: 789,
fieldName: "CashBalance",
oldValue: 50000.00,
newValue: 65000.00,
deltaAmount: +15000.00
},
{
entityType: "TellerTill",
entityId: 789,
fieldName: "TransactionCount",
oldValue: 42,
newValue: 43,
deltaAmount: +1
},
{
entityType: "GLAccount",
entityKey: "1050-CASH-IN-TILL",
fieldName: "DebitAmount",
deltaAmount: +15000.00
},
{
entityType: "GLAccount",
entityKey: "3001-LOANS-RECEIVABLE",
fieldName: "CreditAmount",
deltaAmount: +10000.00
},
{
entityType: "GLAccount",
entityKey: "4001-INTEREST-INCOME",
fieldName: "CreditAmount",
deltaAmount: +5000.00
}
]
```text
### Repayment with Penalties & Fees

**Payment**: ₦20,000 allocated as:
- Interest: ₦5,000
- Principal: ₦10,000
- Penalty: ₦3,000
- Fees: ₦2,000

```typescript
ImpactedEntities:
[
// LoanAccount balances...
{
entityType: "LoanAccount",
entityId: 54321,
fieldName: "PenaltyBalance",
oldValue: 5000.00,
newValue: 2000.00,
deltaAmount: -3000.00
},
{
entityType: "LoanAccount",
entityId: 54321,
fieldName: "FeeBalance",
oldValue: 10000.00,
newValue: 8000.00,
deltaAmount: -2000.00
},
// LoanSchedule updates...
{
entityType: "LoanSchedule",
entityId: 1001,
fieldName: "PenaltyBalance",
oldValue: 3000.00,
newValue: 0.00,
deltaAmount: -3000.00
},
{
entityType: "LoanSchedule",
entityId: 1001,
fieldName: "FeeBalance",
oldValue: 2000.00,
newValue: 0.00,
deltaAmount: -2000.00
},
// Additional GL entries...
{
entityType: "GLAccount",
entityKey: "4002-PENALTY-INCOME",
fieldName: "CreditAmount",
deltaAmount: +3000.00
},
{
entityType: "GLAccount",
entityKey: "4003-FEE-INCOME",
fieldName: "CreditAmount",
deltaAmount: +2000.00
}
]
```text
---

## Implementation

### Loan Repayment with Teller Implementation

**BPMCore Command**: `LoanRepaymentWithTellerCommand`

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

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

## Payment Allocation Rules

### Allocation Order

Payments are allocated in the following priority:

1. **Interest** (oldest schedule first)
2. **Principal** (oldest schedule first)
3. **Penalties** (account-level)
4. **Fees** (account-level)

### Example Allocation

**Loan State**:
- Schedule 1 (Due Jan 15): Interest ₦5,000, Principal ₦10,000
- Schedule 2 (Due Feb 15): Interest ₦5,000, Principal ₦10,000
- Penalty Balance: ₦3,000
- Fee Balance: ₦2,000

**Payment**: ₦18,000

**Allocation**:

```text
1. Interest (Schedule 1): ₦5,000 → Remaining: ₦13,000
2. Interest (Schedule 2): ₦5,000 → Remaining: ₦8,000
3. Principal (Schedule 1): ₦8,000 → Remaining: ₦0

Result:
- Schedule 1: Interest PAID (₦5,000), Principal PARTIAL (₦8,000/₦10,000)
- Schedule 2: Interest PAID (₦5,000), Principal NOT PAID
- Penalties: ₦3,000 (unpaid)
- Fees: ₦2,000 (unpaid)
```text
---

## Validation Rules

### Till Validation

| Rule | Check | Error Message |
|------|-------|---------------|
| **Till Exists** | Till found by `TillId` or `EncodedKey` | "Till not found" |
| **Till State** | `TillAccountState == OPENED` | "Till {TillId} is not opened" |
| **Till Type** | `TillType == TellerTill` | "Invalid till type" |
| **Currency Match** | Till currency == Loan currency | "Currency mismatch" |
| **Maximum Balance** | `Balance + Amount <= MaximumBalance` (if Hard constraint) | "Transaction will exceed till maximum balance by {excess}" |

### Loan Validation

| Rule | Check | Error Message |
|------|-------|---------------|
| **Loan Exists** | Loan found by `AccountNumber` and `ClientEncodedKey` | "Loan account not found" |
| **Loan Active** | `LoanState == ACTIVE` | "Loan account is not active" |
| **Not Closed** | `LoanState != CLOSED` | "Loan account is closed" |
| **Not Written Off** | `LoanState != WRITTEN_OFF` | "Loan account has been written off" |
| **Active Schedules** | At least one active schedule exists | "No active loan schedules found" |
| **Amount Valid** | `Amount > 0` | "Payment amount must be greater than zero" |

---

## GL Account Postings

### Standard Repayment

| Account | Debit (Dr) | Credit (Cr) | Description |
|---------|------------|-------------|-------------|
| **Cash-in-Till Asset** | Amount | - | Increase till cash |
| **Loans Receivable Asset** | - | Principal | Reduce loan asset |
| **Interest Income** | - | Interest | Recognize interest revenue |
| **Penalty Income** | - | Penalty | Recognize penalty revenue |
| **Fee Income** | - | Fees | Recognize fee revenue |

**Example** (₦20,000 payment: ₦5K interest, ₦10K principal, ₦3K penalty, ₦2K fees):

```text
DR: 1050-Cash-in-Till ₦20,000
CR: 3001-Loans-Receivable ₦10,000
CR: 4001-Interest-Income ₦5,000
CR: 4002-Penalty-Income ₦3,000
CR: 4003-Fee-Income ₦2,000
```text
---

## Testing

### Test Scenario 1: Standard Installment Payment

**Setup**:
- Loan: ₦500,000 principal, ₦50,000 interest balance
- Schedule Due: Interest ₦5,000, Principal ₦10,000
- Payment: ₦15,000 (exact installment)

**Expected Results**:

```typescript
LoanAccount:
InterestBalance: 50000 → 45000 ✓
PrincipalBalance: 500000 → 490000 ✓

LoanSchedule:
InterestPaid: 0 → 5000 ✓
PrincipalPaid: 0 → 10000 ✓
State: ACTIVE → PAID ✓

TellerTill:
Balance: +15000 ✓
TransactionCount: +1 ✓

GLEntries:
DR: Cash-in-Till: ₦15,000 ✓
CR: Loans-Receivable: ₦10,000 ✓
CR: Interest-Income: ₦5,000 ✓
```text
### Test Scenario 2: Partial Payment

**Setup**:
- Schedule Due: Interest ₦5,000, Principal ₦10,000
- Payment: ₦8,000 (partial)

**Expected Results**:

```typescript
Allocation:
Interest: ₦5,000 (full) ✓
Principal: ₦3,000 (partial) ✓

LoanSchedule:
InterestPaid: 0 → 5000 ✓
PrincipalPaid: 0 → 3000 ✓
State: ACTIVE (not fully paid) ✓
```text
### Test Scenario 3: Multiple Schedules

**Setup**:
- Schedule 1: Interest ₦5K, Principal ₦10K
- Schedule 2: Interest ₦5K, Principal ₦10K
- Payment: ₦25,000

**Expected Results**:

```typescript
Allocation:
Schedule 1 Interest: ₦5,000 ✓
Schedule 2 Interest: ₦5,000 ✓
Schedule 1 Principal: ₦10,000 ✓
Schedule 2 Principal: ₦5,000 (partial) ✓

Schedule 1: PAID ✓
Schedule 2: ACTIVE (partial payment) ✓
```text
### Test Scenario 4: Full Settlement with Penalties

**Setup**:
- Remaining Principal: ₦50,000
- Remaining Interest: ₦5,000
- Penalty Balance: ₦3,000
- Payment: ₦58,000 (full settlement)

**Expected Results**:

```typescript
LoanAccount:
PrincipalBalance: 50000 → 0 ✓
InterestBalance: 5000 → 0 ✓
PenaltyBalance: 3000 → 0 ✓
LoanState: ACTIVE → CLOSED ✓
ClosedDate: Set ✓

GLEntries:
DR: Cash-in-Till: ₦58,000 ✓
CR: Loans-Receivable: ₦50,000 ✓
CR: Interest-Income: ₦5,000 ✓
CR: Penalty-Income: ₦3,000 ✓

V2 API Commands

Architecture Overview

The V2 loan repayment with deposit command follows the Delegation Pattern:

  • V2 Facade: InitiateLoanRepaymentWithDepositCommand (BPMCore compatible)
  • V1 Implementation: Delegates to existing V1 LoanRepaymentWithDepositCommand with full business logic
  • BPM Integration: Accepts parameters via BpmUtil.GetPropertyValue()

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


InitiateLoanRepaymentWithDepositCommand

Purpose: Process loan repayment via cash deposit to teller till (no deposit account needed)

Command: InitiateLoanRepaymentWithDepositCommand

Delegation: → LoanRepaymentWithDepositCommand (V1 implementation)

BPM Parameters

{
"commandName": "InitiateLoanRepaymentWithDepositCommand",
"data": {
"accountEncodedKey": "string (mandatory)",
"clientEncodedKey": "string (mandatory)",
"paymentAmount": "decimal (mandatory)",
"tillId": "string (mandatory)",
"transactionDate": "DateTime (optional)",
"notes": "string (optional)"
}
}

Parameter Details

ParameterTypeRequiredDescription
accountEncodedKeystring✅ YesLoan account for repayment
clientEncodedKeystring✅ YesClient/borrower encoded key
paymentAmountdecimal✅ YesCash payment amount (must be > 0)
tillIdstring✅ YesTeller till ID receiving cash
transactionDateDateTime❌ NoPayment date (defaults to today)
notesstring❌ NoRepayment notes/remarks

Balance Impact

Loan Account: (same as regular repayment)

  • ✅ PrincipalBalance, InterestBalance, PenaltyBalance, FeesBalance reduced
  • ✅ Payment allocated across schedules (Penalty → Interest → Fees → Principal)

Teller Till:

Balance FieldChangeReason
TillBalance+paymentAmountCash received
TotalCashIn+paymentAmountTrack cash inflow

No Deposit Account Impact: Customer pays cash directly (no deposit account debit)

Example Response

{
"isSuccessful": true,
"transactionId": "TXN-LOAN-RPMT-TELLER-20251229-0001",
"transactionState": "SETTLED",
"message": "Loan repayment with cash deposit processed successfully",
"data": {
"loanAccountKey": "8a8080827f23loan017f23def456",
"paymentAmount": 50000.00,
"tillId": "TILL-001",
"allocation": {
"penaltyPaid": 2000.00,
"interestPaid": 15000.00,
"feesPaid": 1000.00,
"principalPaid": 32000.00
},
"tillBalance": {
"previousBalance": 500000.00,
"newBalance": 550000.00
},
"schedulesAffected": 2
}
}

Developer Resources

For API implementation details, see: