mirror of
https://github.com/HamzaSha1/zod-backend.git
synced 2026-03-10 15:11:46 +00:00
feat: refine transaction notification listener for improved balance calculations
- Updated TransactionNotificationListener to differentiate between child top-up and spending notifications, ensuring accurate balance retrieval. - Enhanced error handling and fallback mechanisms for both child and parent account balance fetching. - Improved logging to provide detailed insights into balance calculations, including available balance after accounting for reserved amounts.
This commit is contained in:
@ -105,39 +105,59 @@ export class TransactionNotificationListener {
|
||||
const amount = transaction.transactionAmount;
|
||||
const merchant = transaction.merchantName || 'merchant';
|
||||
|
||||
// Fetch account by reference number to get fresh balance (bypasses entity cache)
|
||||
// This ensures we get the updated balance after the transaction
|
||||
// For child top-up notifications, show card.limit (newAmount) instead of account balance
|
||||
// card.limit represents the total spending limit on the card after the transfer
|
||||
let balance = 0;
|
||||
let accountCurrency: string | undefined;
|
||||
|
||||
try {
|
||||
// Reload card to get account reference
|
||||
const cardWithUpdatedBalance = await this.cardService.getCardById(card.id);
|
||||
if (cardWithUpdatedBalance?.account?.accountReference) {
|
||||
// Fetch by reference number to get fresh balance from database
|
||||
const account = await this.accountService.getAccountByReferenceNumber(
|
||||
cardWithUpdatedBalance.account.accountReference
|
||||
);
|
||||
balance = account.balance;
|
||||
accountCurrency = account.currency;
|
||||
if (isTopUp) {
|
||||
// For top-up: show card limit (newAmount from transfer response)
|
||||
try {
|
||||
// Reload card to get updated limit
|
||||
const cardWithUpdatedLimit = await this.cardService.getCardById(card.id);
|
||||
balance = cardWithUpdatedLimit.limit || card.limit || 0;
|
||||
accountCurrency = cardWithUpdatedLimit.account?.currency || card.account?.currency;
|
||||
this.logger.debug(
|
||||
`[Child Notification] Fetched account by reference - balance: ${balance} ${accountCurrency}`
|
||||
`[Child Top-Up Notification] Using card limit (newAmount) - limit: ${balance} ${accountCurrency}`
|
||||
);
|
||||
} else {
|
||||
// Fallback: use card's account balance
|
||||
balance = cardWithUpdatedBalance.account?.balance || card.account?.balance || 0;
|
||||
accountCurrency = cardWithUpdatedBalance.account?.currency || card.account?.currency;
|
||||
this.logger.debug(
|
||||
`[Child Notification] Using card account balance - balance: ${balance} ${accountCurrency}`
|
||||
} catch (error: any) {
|
||||
this.logger.warn(
|
||||
`[Child Top-Up Notification] Could not reload card: ${error?.message}. Using card limit from event.`
|
||||
);
|
||||
balance = card.limit || 0;
|
||||
accountCurrency = card.account?.currency;
|
||||
}
|
||||
} else {
|
||||
// For spending: show account balance
|
||||
try {
|
||||
// Reload card to get account reference
|
||||
const cardWithUpdatedBalance = await this.cardService.getCardById(card.id);
|
||||
if (cardWithUpdatedBalance?.account?.accountReference) {
|
||||
// Fetch by reference number to get fresh balance from database
|
||||
const account = await this.accountService.getAccountByReferenceNumber(
|
||||
cardWithUpdatedBalance.account.accountReference
|
||||
);
|
||||
balance = account.balance;
|
||||
accountCurrency = account.currency;
|
||||
this.logger.debug(
|
||||
`[Child Spending Notification] Fetched account by reference - balance: ${balance} ${accountCurrency}`
|
||||
);
|
||||
} else {
|
||||
// Fallback: use card's account balance
|
||||
balance = cardWithUpdatedBalance.account?.balance || card.account?.balance || 0;
|
||||
accountCurrency = cardWithUpdatedBalance.account?.currency || card.account?.currency;
|
||||
this.logger.debug(
|
||||
`[Child Spending Notification] Using card account balance - balance: ${balance} ${accountCurrency}`
|
||||
);
|
||||
}
|
||||
} catch (error: any) {
|
||||
this.logger.warn(
|
||||
`[Child Spending Notification] Could not fetch account by reference: ${error?.message}. Using card account balance.`
|
||||
);
|
||||
// Fallback: use card's account balance
|
||||
balance = card.account?.balance || 0;
|
||||
accountCurrency = card.account?.currency;
|
||||
}
|
||||
} catch (error: any) {
|
||||
this.logger.warn(
|
||||
`[Child Notification] Could not fetch account by reference: ${error?.message}. Using card account balance.`
|
||||
);
|
||||
// Fallback: use card's account balance
|
||||
balance = card.account?.balance || 0;
|
||||
accountCurrency = card.account?.currency;
|
||||
}
|
||||
const currency = getCurrency(
|
||||
accountCurrency,
|
||||
@ -362,13 +382,16 @@ export class TransactionNotificationListener {
|
||||
const amount = transaction.transactionAmount;
|
||||
|
||||
// Fetch parent account by reference number to get fresh balance (bypasses entity cache)
|
||||
// This ensures we get the updated balance after the transfer
|
||||
// For parent notification, show available_balance = balance - reserved_balance
|
||||
let parentAccountBalance = 0;
|
||||
let parentAccountReservedBalance = 0;
|
||||
let parentAccountCurrency: string | undefined;
|
||||
let availableBalance = 0;
|
||||
|
||||
if (card.parentId) {
|
||||
try {
|
||||
// Get parent's card to access their account reference
|
||||
// card.parentId is the parent's CUSTOMER ID
|
||||
const parentCard = await this.cardService.getCardByCustomerId(card.parentId);
|
||||
if (parentCard?.account?.accountReference) {
|
||||
// Fetch by reference number to get fresh balance from database
|
||||
@ -376,24 +399,28 @@ export class TransactionNotificationListener {
|
||||
parentCard.account.accountReference
|
||||
);
|
||||
parentAccountBalance = parentAccount.balance;
|
||||
parentAccountReservedBalance = parentAccount.reservedBalance;
|
||||
availableBalance = parentAccountBalance - parentAccountReservedBalance;
|
||||
parentAccountCurrency = parentAccount.currency;
|
||||
this.logger.debug(
|
||||
`[Parent Top-Up] Fetched parent account by reference - balance: ${parentAccountBalance} ${parentAccountCurrency}`
|
||||
`[Parent Top-Up] Fetched parent account by reference - balance: ${parentAccountBalance}, reserved: ${parentAccountReservedBalance}, available: ${availableBalance} ${parentAccountCurrency}`
|
||||
);
|
||||
} else {
|
||||
// Fallback: try by customer ID
|
||||
const parentAccount = await this.accountService.getAccountByCustomerId(card.parentId);
|
||||
parentAccountBalance = parentAccount.balance;
|
||||
parentAccountReservedBalance = parentAccount.reservedBalance;
|
||||
availableBalance = parentAccountBalance - parentAccountReservedBalance;
|
||||
parentAccountCurrency = parentAccount.currency;
|
||||
this.logger.debug(
|
||||
`[Parent Top-Up] Fetched parent account by customer ID - balance: ${parentAccountBalance} ${parentAccountCurrency}`
|
||||
`[Parent Top-Up] Fetched parent account by customer ID - balance: ${parentAccountBalance}, reserved: ${parentAccountReservedBalance}, available: ${availableBalance} ${parentAccountCurrency}`
|
||||
);
|
||||
}
|
||||
} catch (error: any) {
|
||||
this.logger.warn(
|
||||
`[Parent Top-Up] Could not fetch parent account for customer ${card.parentId}: ${error?.message}. Using child account balance as fallback.`
|
||||
);
|
||||
parentAccountBalance = card.account?.balance || 0;
|
||||
availableBalance = card.account?.balance || 0;
|
||||
parentAccountCurrency = card.account?.currency;
|
||||
}
|
||||
} else {
|
||||
@ -407,32 +434,37 @@ export class TransactionNotificationListener {
|
||||
parentCard.account.accountReference
|
||||
);
|
||||
parentAccountBalance = parentAccount.balance;
|
||||
parentAccountReservedBalance = parentAccount.reservedBalance;
|
||||
availableBalance = parentAccountBalance - parentAccountReservedBalance;
|
||||
parentAccountCurrency = parentAccount.currency;
|
||||
this.logger.debug(
|
||||
`[Parent Top-Up] Fetched parent account via customer relation (by reference) - balance: ${parentAccountBalance} ${parentAccountCurrency}`
|
||||
`[Parent Top-Up] Fetched parent account via customer relation (by reference) - balance: ${parentAccountBalance}, reserved: ${parentAccountReservedBalance}, available: ${availableBalance} ${parentAccountCurrency}`
|
||||
);
|
||||
} else {
|
||||
const parentAccount = await this.accountService.getAccountByCustomerId(parentCustomer.id);
|
||||
parentAccountBalance = parentAccount.balance;
|
||||
parentAccountReservedBalance = parentAccount.reservedBalance;
|
||||
availableBalance = parentAccountBalance - parentAccountReservedBalance;
|
||||
parentAccountCurrency = parentAccount.currency;
|
||||
this.logger.debug(
|
||||
`[Parent Top-Up] Fetched parent account via customer relation - balance: ${parentAccountBalance} ${parentAccountCurrency}`
|
||||
`[Parent Top-Up] Fetched parent account via customer relation - balance: ${parentAccountBalance}, reserved: ${parentAccountReservedBalance}, available: ${availableBalance} ${parentAccountCurrency}`
|
||||
);
|
||||
}
|
||||
} catch (error: any) {
|
||||
this.logger.warn(
|
||||
`[Parent Top-Up] Could not fetch parent account via customer: ${error?.message}. Using child account balance as fallback.`
|
||||
);
|
||||
parentAccountBalance = card.account?.balance || 0;
|
||||
availableBalance = card.account?.balance || 0;
|
||||
parentAccountCurrency = card.account?.currency;
|
||||
}
|
||||
} else {
|
||||
parentAccountBalance = card.account?.balance || 0;
|
||||
availableBalance = card.account?.balance || 0;
|
||||
parentAccountCurrency = card.account?.currency;
|
||||
}
|
||||
}
|
||||
|
||||
const balance = parentAccountBalance;
|
||||
// Use available_balance for parent notification (balance - reserved_balance)
|
||||
const balance = availableBalance;
|
||||
const accountCurrency = parentAccountCurrency;
|
||||
const currency = getCurrency(
|
||||
accountCurrency,
|
||||
|
||||
Reference in New Issue
Block a user