Merge pull request #79 from Zod-Alkhair/feature/notification-system-fcm-registration

feat: enhance transaction notification logging and error handling
This commit is contained in:
Majdalkilany0
2026-01-12 16:48:13 +03:00
committed by GitHub
3 changed files with 85 additions and 45 deletions

View File

@ -117,7 +117,10 @@ export class TransactionService {
isChildSpending: true, isChildSpending: true,
timestamp: new Date(), timestamp: new Date(),
}; };
console.log(`[TransactionService] Emitting TRANSACTION_CREATED event for transaction ${transaction.id}`);
this.eventEmitter.emit(NOTIFICATION_EVENTS.TRANSACTION_CREATED, event); this.eventEmitter.emit(NOTIFICATION_EVENTS.TRANSACTION_CREATED, event);
console.log(`[TransactionService] Event emitted successfully`);
return transaction; return transaction;
} }

View File

@ -128,7 +128,7 @@ export class MoneyRequestNotificationListener {
const child = moneyRequest?.junior; const child = moneyRequest?.junior;
const childUser = child?.customer?.user; const childUser = child?.customer?.user;
const childName = childUser?.firstName || 'Your child'; const childName = childUser?.firstName || 'Your child';
const amount = moneyRequest.amount; const amount = typeof moneyRequest.amount === 'string' ? parseFloat(moneyRequest.amount) : moneyRequest.amount;
const reason = moneyRequest.reason || 'No reason provided'; const reason = moneyRequest.reason || 'No reason provided';
this.logger.debug( this.logger.debug(
@ -175,7 +175,7 @@ export class MoneyRequestNotificationListener {
return; return;
} }
const amount = moneyRequest.amount; const amount = typeof moneyRequest.amount === 'string' ? parseFloat(moneyRequest.amount) : moneyRequest.amount;
this.logger.debug( this.logger.debug(
`Notifying child (user ${childUser.id}): Money request of $${amount} was approved` `Notifying child (user ${childUser.id}): Money request of $${amount} was approved`
@ -218,7 +218,7 @@ export class MoneyRequestNotificationListener {
return; return;
} }
const amount = moneyRequest.amount; const amount = typeof moneyRequest.amount === 'string' ? parseFloat(moneyRequest.amount) : moneyRequest.amount;
const reason = rejectionReason || 'No reason provided'; const reason = rejectionReason || 'No reason provided';
this.logger.debug( this.logger.debug(

View File

@ -41,12 +41,15 @@ export class TransactionNotificationListener {
@OnEvent(NOTIFICATION_EVENTS.TRANSACTION_CREATED) @OnEvent(NOTIFICATION_EVENTS.TRANSACTION_CREATED)
async handleTransactionCreated(event: ITransactionCreatedEvent): Promise<void> { async handleTransactionCreated(event: ITransactionCreatedEvent): Promise<void> {
try { try {
console.log(`[TransactionNotificationListener] Event received: ${NOTIFICATION_EVENTS.TRANSACTION_CREATED}`);
const { transaction, card, isTopUp, isChildSpending } = event; const { transaction, card, isTopUp, isChildSpending } = event;
this.logger.log( this.logger.log(
`Processing transaction notification for transaction ${transaction.id} - ` + `Processing transaction notification for transaction ${transaction.id} - ` +
`isTopUp: ${isTopUp}, isChildSpending: ${isChildSpending}` `isTopUp: ${isTopUp}, isChildSpending: ${isChildSpending}`
); );
console.log(`[TransactionNotificationListener] Transaction: ${transaction.id}, Card: ${card?.id}, isTopUp: ${isTopUp}, isChildSpending: ${isChildSpending}`);
await this.notifyTransactionOwner(transaction, card, isTopUp, isChildSpending); await this.notifyTransactionOwner(transaction, card, isTopUp, isChildSpending);
@ -62,6 +65,7 @@ export class TransactionNotificationListener {
`Transaction notification processed successfully for transaction ${transaction.id}` `Transaction notification processed successfully for transaction ${transaction.id}`
); );
} catch (error: any) { } catch (error: any) {
console.error(`[TransactionNotificationListener] ERROR:`, error);
this.logger.error( this.logger.error(
`Failed to process transaction notification: ${error?.message || 'Unknown error'}`, `Failed to process transaction notification: ${error?.message || 'Unknown error'}`,
error?.stack error?.stack
@ -96,28 +100,41 @@ export class TransactionNotificationListener {
const balance = card.account?.balance || 0; const balance = card.account?.balance || 0;
const currency = card.account?.currency || transaction.transactionCurrency || 'SAR'; const currency = card.account?.currency || transaction.transactionCurrency || 'SAR';
const title = isTopUp let title: string;
? this.i18n.t('app.NOTIFICATION.CHILD_TOP_UP_TITLE', { lang: locale }) let message: string;
: this.i18n.t('app.NOTIFICATION.CHILD_SPENDING_TITLE', { lang: locale });
try {
title = isTopUp
? this.i18n.t('app.NOTIFICATION.CHILD_TOP_UP_TITLE', { lang: locale })
: this.i18n.t('app.NOTIFICATION.CHILD_SPENDING_TITLE', { lang: locale });
const message = isTopUp message = isTopUp
? this.i18n.t('app.NOTIFICATION.CHILD_TOP_UP_MESSAGE', { ? this.i18n.t('app.NOTIFICATION.CHILD_TOP_UP_MESSAGE', {
lang: locale, lang: locale,
args: { args: {
amount: amount.toString(), amount: amount.toString(),
currency: currency, currency: currency,
balance: balance.toString(), balance: balance.toString(),
}, },
}) })
: this.i18n.t('app.NOTIFICATION.CHILD_SPENDING_MESSAGE', { : this.i18n.t('app.NOTIFICATION.CHILD_SPENDING_MESSAGE', {
lang: locale, lang: locale,
args: { args: {
amount: amount.toString(), amount: amount.toString(),
currency: currency, currency: currency,
merchant: merchant, merchant: merchant,
balance: balance.toString(), balance: balance.toString(),
}, },
}); });
} catch (i18nError: any) {
console.error(`[TransactionNotificationListener] i18n error:`, i18nError);
this.logger.error(`i18n translation failed: ${i18nError?.message}`, i18nError?.stack);
// Fallback to English without i18n
title = isTopUp ? 'Card Topped Up' : 'Purchase Successful';
message = isTopUp
? `You received ${amount} ${currency}. Total balance: ${balance} ${currency}`
: `You spent ${amount} ${currency} at ${merchant}. Balance: ${balance} ${currency}`;
}
this.logger.debug( this.logger.debug(
`Notifying transaction owner (user ${user.id}) - Amount: ${amount} ${currency}, Merchant: ${merchant}` `Notifying transaction owner (user ${user.id}) - Amount: ${amount} ${currency}, Merchant: ${merchant}`
@ -180,17 +197,27 @@ export class TransactionNotificationListener {
`Notifying parent (user ${parentUser.id}): ${childName} spent ${amount} ${currency} at ${merchant}` `Notifying parent (user ${parentUser.id}): ${childName} spent ${amount} ${currency} at ${merchant}`
); );
const title = this.i18n.t('app.NOTIFICATION.PARENT_SPENDING_TITLE', { lang: locale }); let title: string;
const message = this.i18n.t('app.NOTIFICATION.PARENT_SPENDING_MESSAGE', { let message: string;
lang: locale,
args: { try {
childName: childName, title = this.i18n.t('app.NOTIFICATION.PARENT_SPENDING_TITLE', { lang: locale });
amount: amount.toString(), message = this.i18n.t('app.NOTIFICATION.PARENT_SPENDING_MESSAGE', {
currency: currency, lang: locale,
merchant: merchant, args: {
balance: balance.toString(), childName: childName,
}, amount: amount.toString(),
}); currency: currency,
merchant: merchant,
balance: balance.toString(),
},
});
} catch (i18nError: any) {
console.error(`[TransactionNotificationListener] i18n error in parent spending:`, i18nError);
this.logger.error(`i18n translation failed: ${i18nError?.message}`, i18nError?.stack);
title = 'Child Spending Alert';
message = `${childName} spent ${amount} ${currency} at ${merchant}. Balance: ${balance} ${currency}`;
}
await this.notificationFactory.send({ await this.notificationFactory.send({
userId: parentUser.id, userId: parentUser.id,
@ -250,16 +277,26 @@ export class TransactionNotificationListener {
`Notifying parent (user ${parentUser.id}): Transferred ${amount} ${currency} to ${childName}` `Notifying parent (user ${parentUser.id}): Transferred ${amount} ${currency} to ${childName}`
); );
const title = this.i18n.t('app.NOTIFICATION.PARENT_TOP_UP_TITLE', { lang: locale }); let title: string;
const message = this.i18n.t('app.NOTIFICATION.PARENT_TOP_UP_MESSAGE', { let message: string;
lang: locale,
args: { try {
amount: amount.toString(), title = this.i18n.t('app.NOTIFICATION.PARENT_TOP_UP_TITLE', { lang: locale });
currency: currency, message = this.i18n.t('app.NOTIFICATION.PARENT_TOP_UP_MESSAGE', {
childName: childName, lang: locale,
balance: balance.toString(), args: {
}, amount: amount.toString(),
}); currency: currency,
childName: childName,
balance: balance.toString(),
},
});
} catch (i18nError: any) {
console.error(`[TransactionNotificationListener] i18n error in parent top-up:`, i18nError);
this.logger.error(`i18n translation failed: ${i18nError?.message}`, i18nError?.stack);
title = 'Top-Up Confirmation';
message = `You transferred ${amount} ${currency} to ${childName}. Balance: ${balance} ${currency}`;
}
await this.notificationFactory.send({ await this.notificationFactory.send({
userId: parentUser.id, userId: parentUser.id,