PayoffBalance Module – RAG Knowledge Base

Chunk 1: Module Overview
Metadata: module=PayoffBalance, type=overview, location=CMH.HFA.Accounting.Orchestration/src/PayoffBalance, count=2, purpose=payoffCalculation, pattern=LambdaOrchestration
Purpose: Lambda-based orchestration for calculating real-time insurance policy payoff balances
Scope: Single Lambda function coordinating multiple downstream Lambda invocations to aggregate customer and invoice data
Integration Points: Invokes customer retrieval Lambda, invokes invoice retrieval Lambda, returns calculated payoff balance to caller
Key Concepts: policy payoff calculation, Lambda-to-Lambda invocation, installment balance aggregation, synchronous orchestration, balance reconciliation

Chunk 2: PayoffBalanceLambda Function
Metadata: component=PayoffBalanceLambda, type=Lambda, operation=GetPayoffBalance, deployment=serverless, invocationType=synchronous
Description: Orchestrator Lambda function calculating exact policy payoff by aggregating invoice balance and open installment adjustments
Input: PayoffBalanceRequest containing PolicyNumber (required), AccountSourceReference (optional)
Output: Decimal representing payoff balance, or -1 for customer/invoice not found
Lambda Configuration: 256 MB memory, 30-second timeout, basic execution role
Orchestration Pattern: Sequential Lambda invocations (customer retrieval → invoice retrieval → local calculation)

Chunk 3: Payoff Balance Calculation Formula
Metadata: operation=CalculatePayoff, formula=balanceMinusAdjustments, precision=decimal
Formula: Payoff Balance = Invoice Balance Amount - Sum(Open Installment Adjusted Amounts)
Components:

Invoice Balance Amount: Total outstanding (InvoiceBalanceAmountDecimal)
Open Installment Adjusted Amounts: Sum of AmountAdjusted for installments with InstallmentStatus="Open"
Example: $1200 - $200 - $150 = $850
Purpose: Accounts for partial payments or credits, provides exact full-settlement amount

Chunk 4: Customer Retrieval Step
Metadata: operation=GetCustomerAsync, invocationType=RequestResponse, environmentVariable=GET_CUSTOMER_FUNCTION_NAME, returnType=OracleCustomer
Process: Invokes Lambda to retrieve Oracle customer data
Input Payload: Serialized PayoffBalanceRequest JSON
Response Handling: Deserializes CustomerWrapper → extracts first account number → returns null if no customer or accounts
Error Scenarios: Returns null → -1 payoff balance

Chunk 5: Invoice Retrieval Step
Metadata: operation=GetInvoiceAsync, invocationType=RequestResponse, environmentVariable=GET_INVOICE_FUNCTION_NAME, returnType=OracleInvoiceWithInstallments
Process: Invokes Lambda to retrieve invoice with installment details
Input Payload: JSON containing PolicyNumber and AccountNumber
Response Handling: Deserializes OracleInvoiceWithInstallments, logs errors, returns null if function fails
Error Detection: Checks FunctionError property, logs errors, continues processing → returns null → -1 payoff

Chunk 6: PayoffBalanceRequest Model
Metadata: model=PayoffBalanceRequest, type=inputDTO, requiredFields=1
Properties:

AccountSourceReference: Optional
PolicyNumber: Required
Usage: Lambda input parameter, serialized for downstream Lambda invocations
Validation: PolicyNumber validated in Lambda logic
Purpose: Minimal input to initiate payoff workflow

Chunk 7: CustomerWrapper Model
Metadata: model=CustomerWrapper, type=responseDTO, purpose=deserialization
Structure: Single property Customer of type OracleCustomer
Purpose: Wraps OracleCustomer for deserialization, temporary wrapper for account number extraction

Chunk 8: OracleInvoiceWithInstallments Model
Metadata: model=OracleInvoiceWithInstallments, type=composite, includesInstallments=true
Structure: Invoice header data (InvoiceBalanceAmountDecimal, etc.) + Installments array
Installment Properties: InstallmentStatus (Open/Paid/Cancelled), AmountAdjusted (string → parsed via ParsedAmountAdjusted extension)
Filtering: Only InstallmentStatus="Open" included in payoff calculation

Chunk 9: Not Found Handling
Metadata: errorHandling=notFound, returnValue=-1, semantic=specialIndicator
Not Found Scenarios: Customer null, Customer has no accounts, Invoice retrieval null
Return Value: -1 decimal indicates not found
Pattern: Sentinel value instead of exception
Use Case: Invalid policy, account not created, policy exists but no invoice

Chunk 10: Environment Variable Configuration
Metadata: configuration=environmentVariables, required=2, validation=startup
Variables:

GET_CUSTOMER_FUNCTION_NAME: Lambda name/ARN for customer retrieval
GET_INVOICE_FUNCTION_NAME: Lambda name/ARN for invoice retrieval
Validation: Throws InvalidOperationException if null/empty
Purpose: Environment-specific Lambda routing without hardcoding

Chunk 11: Lambda Invocation Pattern
Metadata: pattern=synchronousInvocation, sdk=AmazonLambdaClient, invocationType=RequestResponse
Client Creation: AmazonLambdaClient within using statement
Invocation Type: RequestResponse synchronous
Payload Handling: JSON serialization/deserialization
Error Detection: Checks FunctionError, checks null Payload
Use Case: Sequential dependency (invoice requires account number from customer)

Chunk 12: Installment Status Filtering
Metadata: filtering=installmentStatus, statusValue=Open, caseSensitivity=exact
Filter: InstallmentStatus == "Open" (case-sensitive)
Purpose: Exclude Paid/Cancelled installments
Aggregation: Sum filtered using ParsedAmountAdjusted()

Chunk 13: Amount Parsing Extension
Metadata: extension=ParsedAmountAdjusted, sourceType=string, targetType=decimal
Purpose: Convert AmountAdjusted string → decimal
Usage: Called on each open installment
Null Handling: Null collection → 0m
Error Handling: Assumes valid numeric strings

Chunk 14: Use Cases and Workflows
Metadata: type=useCases, consumers=multiple, timing=realTime
Use Cases:

Policy cancellation → refund/owed amount
Lender payoff quote → real-time settlement
Customer inquiry → balance inquiry
Refinancing → exact payoff to clear debt
Account settlement → prevent over/underpayment

Chunk 15: Architectural Characteristics
Metadata: architecture=microservices, coupling=loose, scalability=horizontal, statefulness=stateless
Microservices: Customer retrieval, invoice retrieval, payoff calculation separated
Benefits: Independent scaling, reusable Lambdas, isolated failure domains, separation of concerns
Trade-offs: Multiple cold starts, increased latency, higher cost, distributed failure points
Statefulness: Stateless, no caching

Chunk 16: Error Propagation Strategy
Metadata: errorHandling=gracefulDegradation, exceptionStrategy=minimal
Function Error Logging: Logs downstream errors, does not throw
Null Propagation: Null responses → -1 result
Environment Validation: Only throws exceptions
Rationale: Caller distinguishes not found vs other errors, enables graceful orchestration

Chunk 17: Performance Considerations
Metadata: performance=latency, coldStarts=3possible, invocationCount=3
Latency Sources: Cold start of PayoffBalance Lambda, customer Lambda, invoice Lambda, serial invocation, network round trips
Optimization: Parallel invocations, caching, direct DB/Oracle queries
Current Approach: Simplicity and reusability over performance; suitable for infrequent payoff queries

Chunk 18: Search Queries Supported
Metadata: type=queryPatterns, purpose=RAGRetrieval
Sample Queries:

"How do I calculate insurance policy payoff balance?"
"What Lambda calculates policy payoff amounts?"
"How are open installments factored into payoff?"
"What does -1 payoff balance mean?"
"How do I invoke customer retrieval from Lambda?"
"What environment variables are needed?"
"What is the formula for payoff balance?"
"How are invoice balance and installment adjustments combined?"
"What happens when customer is not found?"
"How does Lambda-to-Lambda invocation work?"
"Return type for policy/customer not found?"
"How are installment adjusted amounts parsed?"
"Use cases requiring real-time payoff calculation?"
"How does workflow handle downstream Lambda errors?"
"Difference between invoice balance and payoff balance?"
"How are open vs paid installments filtered?"
"Configuration required for payoff Lambda?"
"How does synchronous Lambda invocation work?"