mirror of
https://github.com/HamzaSha1/zod-backend.git
synced 2026-03-10 18:41: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,11 +105,30 @@ export class TransactionNotificationListener {
|
|||||||
const amount = transaction.transactionAmount;
|
const amount = transaction.transactionAmount;
|
||||||
const merchant = transaction.merchantName || 'merchant';
|
const merchant = transaction.merchantName || 'merchant';
|
||||||
|
|
||||||
// Fetch account by reference number to get fresh balance (bypasses entity cache)
|
// For child top-up notifications, show card.limit (newAmount) instead of account balance
|
||||||
// This ensures we get the updated balance after the transaction
|
// card.limit represents the total spending limit on the card after the transfer
|
||||||
let balance = 0;
|
let balance = 0;
|
||||||
let accountCurrency: string | undefined;
|
let accountCurrency: string | undefined;
|
||||||
|
|
||||||
|
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 Top-Up Notification] Using card limit (newAmount) - limit: ${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 {
|
try {
|
||||||
// Reload card to get account reference
|
// Reload card to get account reference
|
||||||
const cardWithUpdatedBalance = await this.cardService.getCardById(card.id);
|
const cardWithUpdatedBalance = await this.cardService.getCardById(card.id);
|
||||||
@ -121,24 +140,25 @@ export class TransactionNotificationListener {
|
|||||||
balance = account.balance;
|
balance = account.balance;
|
||||||
accountCurrency = account.currency;
|
accountCurrency = account.currency;
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`[Child Notification] Fetched account by reference - balance: ${balance} ${accountCurrency}`
|
`[Child Spending Notification] Fetched account by reference - balance: ${balance} ${accountCurrency}`
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Fallback: use card's account balance
|
// Fallback: use card's account balance
|
||||||
balance = cardWithUpdatedBalance.account?.balance || card.account?.balance || 0;
|
balance = cardWithUpdatedBalance.account?.balance || card.account?.balance || 0;
|
||||||
accountCurrency = cardWithUpdatedBalance.account?.currency || card.account?.currency;
|
accountCurrency = cardWithUpdatedBalance.account?.currency || card.account?.currency;
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`[Child Notification] Using card account balance - balance: ${balance} ${accountCurrency}`
|
`[Child Spending Notification] Using card account balance - balance: ${balance} ${accountCurrency}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
this.logger.warn(
|
this.logger.warn(
|
||||||
`[Child Notification] Could not fetch account by reference: ${error?.message}. Using card account balance.`
|
`[Child Spending Notification] Could not fetch account by reference: ${error?.message}. Using card account balance.`
|
||||||
);
|
);
|
||||||
// Fallback: use card's account balance
|
// Fallback: use card's account balance
|
||||||
balance = card.account?.balance || 0;
|
balance = card.account?.balance || 0;
|
||||||
accountCurrency = card.account?.currency;
|
accountCurrency = card.account?.currency;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
const currency = getCurrency(
|
const currency = getCurrency(
|
||||||
accountCurrency,
|
accountCurrency,
|
||||||
transaction.transactionCurrency,
|
transaction.transactionCurrency,
|
||||||
@ -362,13 +382,16 @@ export class TransactionNotificationListener {
|
|||||||
const amount = transaction.transactionAmount;
|
const amount = transaction.transactionAmount;
|
||||||
|
|
||||||
// Fetch parent account by reference number to get fresh balance (bypasses entity cache)
|
// 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 parentAccountBalance = 0;
|
||||||
|
let parentAccountReservedBalance = 0;
|
||||||
let parentAccountCurrency: string | undefined;
|
let parentAccountCurrency: string | undefined;
|
||||||
|
let availableBalance = 0;
|
||||||
|
|
||||||
if (card.parentId) {
|
if (card.parentId) {
|
||||||
try {
|
try {
|
||||||
// Get parent's card to access their account reference
|
// 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);
|
const parentCard = await this.cardService.getCardByCustomerId(card.parentId);
|
||||||
if (parentCard?.account?.accountReference) {
|
if (parentCard?.account?.accountReference) {
|
||||||
// Fetch by reference number to get fresh balance from database
|
// Fetch by reference number to get fresh balance from database
|
||||||
@ -376,24 +399,28 @@ export class TransactionNotificationListener {
|
|||||||
parentCard.account.accountReference
|
parentCard.account.accountReference
|
||||||
);
|
);
|
||||||
parentAccountBalance = parentAccount.balance;
|
parentAccountBalance = parentAccount.balance;
|
||||||
|
parentAccountReservedBalance = parentAccount.reservedBalance;
|
||||||
|
availableBalance = parentAccountBalance - parentAccountReservedBalance;
|
||||||
parentAccountCurrency = parentAccount.currency;
|
parentAccountCurrency = parentAccount.currency;
|
||||||
this.logger.debug(
|
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 {
|
} else {
|
||||||
// Fallback: try by customer ID
|
// Fallback: try by customer ID
|
||||||
const parentAccount = await this.accountService.getAccountByCustomerId(card.parentId);
|
const parentAccount = await this.accountService.getAccountByCustomerId(card.parentId);
|
||||||
parentAccountBalance = parentAccount.balance;
|
parentAccountBalance = parentAccount.balance;
|
||||||
|
parentAccountReservedBalance = parentAccount.reservedBalance;
|
||||||
|
availableBalance = parentAccountBalance - parentAccountReservedBalance;
|
||||||
parentAccountCurrency = parentAccount.currency;
|
parentAccountCurrency = parentAccount.currency;
|
||||||
this.logger.debug(
|
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) {
|
} catch (error: any) {
|
||||||
this.logger.warn(
|
this.logger.warn(
|
||||||
`[Parent Top-Up] Could not fetch parent account for customer ${card.parentId}: ${error?.message}. Using child account balance as fallback.`
|
`[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;
|
parentAccountCurrency = card.account?.currency;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -407,32 +434,37 @@ export class TransactionNotificationListener {
|
|||||||
parentCard.account.accountReference
|
parentCard.account.accountReference
|
||||||
);
|
);
|
||||||
parentAccountBalance = parentAccount.balance;
|
parentAccountBalance = parentAccount.balance;
|
||||||
|
parentAccountReservedBalance = parentAccount.reservedBalance;
|
||||||
|
availableBalance = parentAccountBalance - parentAccountReservedBalance;
|
||||||
parentAccountCurrency = parentAccount.currency;
|
parentAccountCurrency = parentAccount.currency;
|
||||||
this.logger.debug(
|
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 {
|
} else {
|
||||||
const parentAccount = await this.accountService.getAccountByCustomerId(parentCustomer.id);
|
const parentAccount = await this.accountService.getAccountByCustomerId(parentCustomer.id);
|
||||||
parentAccountBalance = parentAccount.balance;
|
parentAccountBalance = parentAccount.balance;
|
||||||
|
parentAccountReservedBalance = parentAccount.reservedBalance;
|
||||||
|
availableBalance = parentAccountBalance - parentAccountReservedBalance;
|
||||||
parentAccountCurrency = parentAccount.currency;
|
parentAccountCurrency = parentAccount.currency;
|
||||||
this.logger.debug(
|
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) {
|
} catch (error: any) {
|
||||||
this.logger.warn(
|
this.logger.warn(
|
||||||
`[Parent Top-Up] Could not fetch parent account via customer: ${error?.message}. Using child account balance as fallback.`
|
`[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;
|
parentAccountCurrency = card.account?.currency;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
parentAccountBalance = card.account?.balance || 0;
|
availableBalance = card.account?.balance || 0;
|
||||||
parentAccountCurrency = card.account?.currency;
|
parentAccountCurrency = card.account?.currency;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const balance = parentAccountBalance;
|
// Use available_balance for parent notification (balance - reserved_balance)
|
||||||
|
const balance = availableBalance;
|
||||||
const accountCurrency = parentAccountCurrency;
|
const accountCurrency = parentAccountCurrency;
|
||||||
const currency = getCurrency(
|
const currency = getCurrency(
|
||||||
accountCurrency,
|
accountCurrency,
|
||||||
|
|||||||
Reference in New Issue
Block a user