Skip to main content

SendLoanOfferCommand

Overview​

Sends a loan offer through the configured cmdBankLingoSendLoanOfferLetter command chain and records the action in the loan approval history. It is normally called after the loan reaches FullyApproved and before disbursement.

Command Structure​

{
"cmd": "SendLoanOfferCommand",
"data": "JSON string containing loanRequestId, comment, and loanPurpose"
}

Parameters​

ParameterTypeRequiredDescription
loanRequestIdlongYesLoan application (LoanQuote) ID
commentstringNoNote written to the approval history after successful delivery
loanPurposestringNoBackward-compatible fallback for legacy loan rows. New loan requests use the purpose persisted on LoanQuote.

Command-chain context​

Before executing cmdBankLingoSendLoanOfferLetter, the command loads the customer, address, guarantors, branch hierarchy, deductions, and persisted repayment schedules. The object is serialized with camel-case property names and supplied to the chain as context.

The following example documents the complete context contract:

{
"requestedAmount": 500000.00,
"approvedAmount": 450000.00,
"totalDeductions": 5000.00,
"netDisbursementAmount": 445000.00,
"loanRequest": {
"id": 110,
"userId": 27,
"loanAmount": 450000.00,
"applicantEmail": "customer@example.com",
"applicantName": "Jane Customer",
"loanPurpose": "Business expansion"
},
"currency": "NGN",
"loanQuote": {
"loanAmount": 450000.00,
"loanProductCode": "PR-1",
"loanTenor": 6,
"interestRate": 4.0,
"repaymentAmount": 78000.00,
"displayName": "Payroll Loan",
"currencyCode": "NGN",
"requestedAmount": 500000.00,
"approvedAmount": 450000.00,
"totalDeductions": 5000.00,
"netDisbursementAmount": 445000.00
},
"guarantors": [
{
"id": 15,
"loanQuoteId": 110,
"name": "John Guarantor",
"emailAddress": "guarantor@example.com",
"mobileNumber": "08000000000",
"address": "Lagos",
"homeAddress": "Home address",
"officeAddress": "Office address",
"designation": "Manager",
"relationship": "Colleague",
"verificationStatus": 1,
"verificationComment": "Verified",
"dateOfBirth": "1985-04-10T00:00:00"
}
],
"deductions": [
{
"id": 9,
"code": "PROC_FEE",
"name": "Processing fee",
"deduction": 1.0,
"calculatedAmount": 5000.00,
"deductionCalculation": 0,
"deductionCalculationDesc": "Percentage",
"createdAt": "2026-09-23T10:00:00Z",
"createdBy": "loan.officer"
}
],
"schedule": [
{
"id": 501,
"installmentNumber": 1,
"paymentNumber": 1,
"dueDate": "2026-10-31T00:00:00",
"principalAmount": 75000.00,
"principal": 75000.00,
"interestAmount": 3000.00,
"interest": 3000.00,
"totalDue": 78000.00,
"total": 78000.00,
"outstandingBalance": 375000.00,
"status": "Pending",
"paidDate": null,
"amountPaid": null
}
],
"repaymentSchedule": {
"loanQuoteId": 110,
"hasSchedule": true,
"totalInstallments": 6,
"totalAmountDue": 468000.00,
"totalAmountPaid": 0.00,
"outstandingAmount": 468000.00
},
"settlementDetails": {
"id": 801,
"loanQuoteId": 110,
"isConfigured": true,
"loanAccountReference": "0110",
"settlementOption": 1,
"settlementOptionDescription": "Direct Settlement Account",
"providerCode": "EMTBO",
"providerName": "Empire Trust (Bank One)",
"virtualAccountNumber": null,
"accountNumber": "1100360574",
"createdAt": "2026-09-23T10:00:00Z",
"updatedAt": "2026-09-23T11:00:00Z"
},
"disbursementDetails": {
"id": 901,
"loanQuoteId": 110,
"isConfigured": true,
"bankId": 12,
"bankCode": "000013",
"bankName": "Example Bank",
"accountNumber": "0123456789",
"accountName": "Jane Customer",
"providerCode": "BANKLINGO",
"currencyCode": "NGN",
"transactionReference": "DISB-110",
"providerMessage": "Pending",
"disbursementMode": 2,
"disbursementModeDescription": "Bank Transfer",
"disbursementState": 1,
"disbursementStateDescription": "Pending Disbursement",
"disbursementAmount": 450000.00,
"disbursementFee": 0.00,
"disbursementDate": "2026-09-25T00:00:00",
"disbursedById": 27,
"thirdPartySettlementAccount": null,
"thirdPartySettlementBank": null,
"thirdPartySettlementBankCode": null,
"thirdPartySettlementReference": null,
"createdAt": "2026-09-23T10:00:00Z",
"updatedAt": "2026-09-23T11:00:00Z"
},
"product": {
"code": "PR-1",
"name": "Payroll Loan",
"currencyCode": "NGN"
},
"customerAddress": {
"id": 31,
"addressLine1": "10 Example Street",
"addressLine2": "Ikeja",
"city": "Lagos",
"state": "Lagos",
"country": "Nigeria",
"postalCode": "100001"
},
"userDetail": {
"id": 27,
"emailAddress": "customer@example.com",
"displayName": "Jane Customer",
"firstName": "Jane",
"lastName": "Customer",
"mobileNumber": "08000000000",
"mobileCountryCode": "+234"
}
}

Repayment schedule contract​

  • schedule is ordered by installmentNumber.
  • paymentNumber, principal, interest, and total are template-friendly aliases for installmentNumber, principalAmount, interestAmount, and totalDue.
  • repaymentSchedule contains totals and a hasSchedule flag; it does not duplicate the installment array.
  • If no repayment schedule has been generated, schedule is [], hasSchedule is false, and all summary totals are zero.
  • Only plain context values are sent to the command engine. EF navigation properties and the LoanQuote back-reference are excluded.

Settlement and disbursement contracts​

  • UpdateLoanSettlementDetailsCommand persists settlement fields on [BPMLoanSelfService].[SelfServiceLoanCollectionInformation], linked by LoanQuoteId.
  • SetDisbursementDetailsCommand persists the beneficiary account, bank, mode, amount, state, and date on [BPMLoanSelfService].[SelfServiceDisbursementInformation], also linked by LoanQuoteId.
  • settlementDetails and disbursementDetails expose the most recently updated linked records as plain values to cmdBankLingoSendLoanOfferLetter.
  • settlementDetails.providerName is resolved from the configured virtual-account provider using providerCode.
  • disbursementDetails.bankName is resolved from the administration bank list using bankCode (matching either the internal or NIBSS bank code).
  • loanRequest.loanPurpose comes from the purpose persisted on LoanQuote; the command input remains only as a fallback for pre-migration records.
  • isConfigured distinguishes a pre-created/default record from details that have actually been configured.
  • If a linked record does not exist, its corresponding context property is null.
  • Offer letters are commonly sent before disbursement setup. In that sequence, disbursementDetails can exist with isConfigured: false and its initial account values; templates should check isConfigured before presenting the details as final.

Example document-template loop:

{{#schedule}}
{{paymentNumber}} | {{dueDate}} | {{principal}} | {{interest}} | {{total}}
{{/schedule}}

Processing sequence​

  1. Load the loan quote and related customer, address, guarantor, branch, schedule, settlement, and disbursement data.
  2. Calculate deductions, approved amount, and net disbursement amount.
  3. Build the complete command-chain context shown above.
  4. Resolve and execute cmdBankLingoSendLoanOfferLetter.
  5. Record the Send Offer Letter / Sent approval-history entry only when the configured chain succeeds.
  6. Return the command-chain response unchanged.

If the command chain is not configured, the command returns CONFIG_MISSING and includes the prepared context in the diagnostic response.

Lifecycle Position​

FullyApproved
|
SendLoanOfferCommand
|
SetDisbursementDetailsCommand
|
DisburseLoanRequestCommand