From 4305c4b75f0b7f0ae4526641bd48b1c2b3a72703 Mon Sep 17 00:00:00 2001 From: Abdalhamid Alhamad Date: Tue, 20 Jan 2026 14:40:16 +0300 Subject: [PATCH] fix the messages --- .../money-request-notification.listener.ts | 31 +++- .../transaction-notification.listener.ts | 137 ++++++++++++------ src/i18n/ar/app.json | 16 +- src/i18n/en/app.json | 16 +- 4 files changed, 138 insertions(+), 62 deletions(-) diff --git a/src/common/modules/notification/listeners/money-request-notification.listener.ts b/src/common/modules/notification/listeners/money-request-notification.listener.ts index 8d90f17..7f40ea7 100644 --- a/src/common/modules/notification/listeners/money-request-notification.listener.ts +++ b/src/common/modules/notification/listeners/money-request-notification.listener.ts @@ -139,14 +139,39 @@ export class MoneyRequestNotificationListener { const currency = getCurrency(accountCurrency, null, 'SAR'); const formattedAmount = formatCurrencyAmount(amount, currency); + const locale = this.getUserLocale(parentUser); + this.logger.debug( - `Notifying parent (user ${parentUser.id}): ${childName} requested ${formattedAmount} ${currency} - ${reason}` + `Notifying parent (user ${parentUser.id}): ${childName} requested ${formattedAmount} ${currency} for ${reason}` ); + let title: string; + let message: string; + + try { + title = this.i18n.t('app.NOTIFICATION.MONEY_REQUEST_CREATED_TITLE', { lang: locale }); + message = this.i18n.t('app.NOTIFICATION.MONEY_REQUEST_CREATED_MESSAGE', { + lang: locale, + args: { + childName: childName, + amount: formattedAmount, + currency: currency, + reason: reason, + }, + }); + } catch (i18nError: any) { + this.logger.error( + `[MoneyRequestNotificationListener] i18n error for parent ${parentUser.id}: ${i18nError?.message || 'Unknown i18n error'}. Falling back to English.`, + i18nError?.stack + ); + title = 'Money Request'; + message = `${childName} has requested ${formattedAmount} ${currency} for ${reason}.`; + } + await this.notificationFactory.send({ userId: parentUser.id, - title: 'Money Request', - message: `${childName} requested ${formattedAmount} ${currency}. Reason: ${reason}`, + title, + message, scope: NotificationScope.MONEY_REQUEST_CREATED, preferences: this.getUserPreferences(parentUser), data: { diff --git a/src/common/modules/notification/listeners/transaction-notification.listener.ts b/src/common/modules/notification/listeners/transaction-notification.listener.ts index 45a44ea..b671bce 100644 --- a/src/common/modules/notification/listeners/transaction-notification.listener.ts +++ b/src/common/modules/notification/listeners/transaction-notification.listener.ts @@ -180,32 +180,31 @@ export class TransactionNotificationListener { ? this.i18n.t('app.NOTIFICATION.CHILD_TOP_UP_TITLE', { lang: locale }) : this.i18n.t('app.NOTIFICATION.CHILD_SPENDING_TITLE', { lang: locale }); - message = isTopUp - ? this.i18n.t('app.NOTIFICATION.CHILD_TOP_UP_MESSAGE', { - lang: locale, - args: { - amount: formattedAmount, - currency: currency, - balance: formattedBalance, - }, - }) - : this.i18n.t('app.NOTIFICATION.CHILD_SPENDING_MESSAGE', { - lang: locale, - args: { - amount: formattedAmount, - currency: currency, - merchant: merchant, - balance: formattedBalance, - }, - }); + message = isTopUp + ? this.i18n.t('app.NOTIFICATION.CHILD_TOP_UP_MESSAGE', { + lang: locale, + args: { + amount: formattedAmount, + currency: currency, + balance: formattedBalance, + }, + }) + : this.i18n.t('app.NOTIFICATION.CHILD_SPENDING_MESSAGE', { + lang: locale, + args: { + amount: formattedAmount, + currency: currency, + merchant: merchant, + }, + }); } 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 ${formattedAmount} ${currency}. Total balance: ${formattedBalance} ${currency}` - : `You spent ${formattedAmount} ${currency} at ${merchant}. Balance: ${formattedBalance} ${currency}`; + title = isTopUp ? 'Funds Credited' : 'Purchase Successful'; + message = isTopUp + ? `${formattedAmount} ${currency} has been added to your card. Total balance: ${formattedBalance} ${currency}` + : `You spent ${formattedAmount} ${currency} at ${merchant}`; } this.logger.debug( @@ -263,29 +262,80 @@ export class TransactionNotificationListener { const amount = transaction.transactionAmount; const merchant = transaction.merchantName || 'a merchant'; - // Get parent's account balance (not child's balance) - reload to get fresh balance + // Get parent's available balance (balance - reserved_balance) - reload to get fresh balance let parentAccountBalance = 0; + let parentAccountReservedBalance = 0; let parentAccountCurrency: string | undefined; + let availableBalance = 0; + try { if (card.parentId) { - // Always reload parent account to get fresh balance after transaction - const parentAccount = await this.accountService.getAccountByCustomerId(card.parentId); - parentAccountBalance = parentAccount.balance; - parentAccountCurrency = parentAccount.currency; - this.logger.debug(`Fetched parent account balance: ${parentAccountBalance}, currency: ${parentAccountCurrency}`); + // Get parent's card to access their account reference + const parentCard = await this.cardService.getCardByCustomerId(card.parentId); + if (parentCard?.account?.accountReference) { + // Fetch by reference number to get fresh balance from database + const parentAccount = await this.accountService.getAccountByReferenceNumber( + parentCard.account.accountReference + ); + parentAccountBalance = parentAccount.balance; + parentAccountReservedBalance = parentAccount.reservedBalance; + availableBalance = parentAccountBalance - parentAccountReservedBalance; + parentAccountCurrency = parentAccount.currency; + this.logger.debug( + `[Parent Spending] 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 Spending] Fetched parent account by customer ID - balance: ${parentAccountBalance}, reserved: ${parentAccountReservedBalance}, available: ${availableBalance} ${parentAccountCurrency}` + ); + } } else { const parentCustomer = customer?.junior?.guardian?.customer; - if (parentCustomer?.cards?.[0]?.account) { - // Reload to get fresh balance - const parentAccount = await this.accountService.getAccountByCustomerId(parentCustomer.id); - parentAccountBalance = parentAccount.balance; - parentAccountCurrency = parentAccount.currency; - this.logger.debug(`Fetched parent account balance via customer: ${parentAccountBalance}, currency: ${parentAccountCurrency}`); + if (parentCustomer?.id) { + try { + const parentCard = await this.cardService.getCardByCustomerId(parentCustomer.id); + if (parentCard?.account?.accountReference) { + const parentAccount = await this.accountService.getAccountByReferenceNumber( + parentCard.account.accountReference + ); + parentAccountBalance = parentAccount.balance; + parentAccountReservedBalance = parentAccount.reservedBalance; + availableBalance = parentAccountBalance - parentAccountReservedBalance; + parentAccountCurrency = parentAccount.currency; + this.logger.debug( + `[Parent Spending] 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 Spending] Fetched parent account via customer relation - balance: ${parentAccountBalance}, reserved: ${parentAccountReservedBalance}, available: ${availableBalance} ${parentAccountCurrency}` + ); + } + } catch (error: any) { + this.logger.warn( + `[Parent Spending] Could not fetch parent account via customer: ${error?.message}. Using child account balance as fallback.` + ); + availableBalance = card.account?.balance || 0; + parentAccountCurrency = card.account?.currency; + } + } else { + availableBalance = card.account?.balance || 0; + parentAccountCurrency = card.account?.currency; } } } catch (error: any) { - this.logger.warn(`Could not fetch parent account for parent notification: ${error?.message}, using child account balance as fallback`); - parentAccountBalance = card.account?.balance || 0; + this.logger.warn(`[Parent Spending] Could not fetch parent account: ${error?.message}, using child account balance as fallback`); + availableBalance = card.account?.balance || 0; parentAccountCurrency = card.account?.currency; } @@ -297,11 +347,12 @@ export class TransactionNotificationListener { ); this.logger.debug( - `[Parent Spending Notification] Parent account currency: ${parentAccountCurrency}, Account currency: ${accountCurrency}, Transaction currency: ${transaction.transactionCurrency}, Final currency: ${currency}, Parent balance: ${parentAccountBalance}, Amount: ${amount}` + `[Parent Spending Notification] Parent account currency: ${parentAccountCurrency}, Account currency: ${accountCurrency}, Transaction currency: ${transaction.transactionCurrency}, Final currency: ${currency}, Parent available balance: ${availableBalance}, Amount: ${amount}` ); const formattedAmount = formatCurrencyAmount(amount, currency); - const formattedBalance = formatCurrencyAmount(parentAccountBalance, currency); + // Use available balance for parent spending notification + const formattedBalance = formatCurrencyAmount(availableBalance, currency); this.logger.debug( `Notifying parent (user ${parentUser.id}): ${childName} spent ${formattedAmount} ${currency} at ${merchant}` @@ -325,8 +376,8 @@ export class TransactionNotificationListener { } 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 ${formattedAmount} ${currency} at ${merchant}. Balance: ${formattedBalance} ${currency}`; + title = 'Spending Alert'; + message = `${childName} spent ${formattedAmount} ${currency} at ${merchant}. Remaining balance: ${formattedBalance} ${currency}`; } await this.notificationFactory.send({ @@ -479,7 +530,7 @@ export class TransactionNotificationListener { const formattedBalance = formatCurrencyAmount(balance, currency); this.logger.debug( - `Notifying parent (user ${parentUser.id}): Transferred ${formattedAmount} ${currency} to ${childName}, parent balance: ${formattedBalance} ${currency}` + `Notifying parent (user ${parentUser.id}): Transferred ${formattedAmount} ${currency} to ${childName}, child balance: ${formattedBalance} ${currency}` ); let title: string; @@ -499,8 +550,8 @@ export class TransactionNotificationListener { } 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 ${formattedAmount} ${currency} to ${childName}. Balance: ${formattedBalance} ${currency}`; + title = 'Transfer Completed'; + message = `${formattedAmount} ${currency} has been transferred to ${childName}'s card. ${childName}'s balance is ${formattedBalance} ${currency}`; } await this.notificationFactory.send({ diff --git a/src/i18n/ar/app.json b/src/i18n/ar/app.json index 1aa02f2..9d8f147 100644 --- a/src/i18n/ar/app.json +++ b/src/i18n/ar/app.json @@ -112,17 +112,17 @@ "NOT_FOUND": "لم يتم العثور على البطاقة." }, "NOTIFICATION": { - "CHILD_TOP_UP_TITLE": "تم شحن البطاقة", - "CHILD_TOP_UP_MESSAGE": "لقد استلمت {amount} {currency}. الرصيد الإجمالي: {balance} {currency}", + "CHILD_TOP_UP_TITLE": "تم إضافة الأموال", + "CHILD_TOP_UP_MESSAGE": "تم إضافة {amount} {currency} إلى بطاقتك. الرصيد الإجمالي: {balance} {currency}", "CHILD_SPENDING_TITLE": "تمت العملية بنجاح", - "CHILD_SPENDING_MESSAGE": "لقد أنفقت {amount} {currency} في {merchant}. الرصيد: {balance} {currency}", - "PARENT_TOP_UP_TITLE": "تأكيد الشحن", - "PARENT_TOP_UP_MESSAGE": "لقد قمت بتحويل {amount} {currency} إلى {childName}. الرصيد: {balance} {currency}", - "PARENT_SPENDING_TITLE": "تنبيه إنفاق الطفل", - "PARENT_SPENDING_MESSAGE": "أنفق {childName} {amount} {currency} في {merchant}. الرصيد: {balance} {currency}", + "CHILD_SPENDING_MESSAGE": "لقد أنفقت {amount} {currency} في {merchant}", + "PARENT_TOP_UP_TITLE": "اكتمل التحويل", + "PARENT_TOP_UP_MESSAGE": "تم تحويل {amount} {currency} إلى بطاقة {childName}. رصيد {childName} هو {balance} {currency}", + "PARENT_SPENDING_TITLE": "تنبيه الإنفاق", + "PARENT_SPENDING_MESSAGE": "أنفق {childName} {amount} {currency} في {merchant}. الرصيد المتبقي: {balance} {currency}", "YOUR_CHILD": "طفلك", "MONEY_REQUEST_CREATED_TITLE": "طلب مال", - "MONEY_REQUEST_CREATED_MESSAGE": "طلب {childName} مبلغ {amount} {currency}. السبب: {reason}", + "MONEY_REQUEST_CREATED_MESSAGE": "طلب {childName} مبلغ {amount} {currency} لـ {reason}.", "MONEY_REQUEST_APPROVED_TITLE": "تمت الموافقة على طلب المال", "MONEY_REQUEST_APPROVED_MESSAGE": "تمت الموافقة على طلبك بمبلغ {amount} {currency}. تمت إضافة المال إلى حسابك.", "MONEY_REQUEST_DECLINED_TITLE": "تم رفض طلب المال", diff --git a/src/i18n/en/app.json b/src/i18n/en/app.json index 790baa7..46b8a24 100644 --- a/src/i18n/en/app.json +++ b/src/i18n/en/app.json @@ -111,17 +111,17 @@ "NOT_FOUND": "The card was not found." }, "NOTIFICATION": { - "CHILD_TOP_UP_TITLE": "Card Topped Up", - "CHILD_TOP_UP_MESSAGE": "You received {amount} {currency}. Total balance: {balance} {currency}", + "CHILD_TOP_UP_TITLE": "Funds Credited", + "CHILD_TOP_UP_MESSAGE": "{amount} {currency} has been added to your card. Total balance: {balance} {currency}", "CHILD_SPENDING_TITLE": "Purchase Successful", - "CHILD_SPENDING_MESSAGE": "You spent {amount} {currency} at {merchant}. Balance: {balance} {currency}", - "PARENT_TOP_UP_TITLE": "Top-Up Confirmation", - "PARENT_TOP_UP_MESSAGE": "You transferred {amount} {currency} to {childName}. Balance: {balance} {currency}", - "PARENT_SPENDING_TITLE": "Child Spending Alert", - "PARENT_SPENDING_MESSAGE": "{childName} spent {amount} {currency} at {merchant}. Balance: {balance} {currency}", + "CHILD_SPENDING_MESSAGE": "You spent {amount} {currency} at {merchant}", + "PARENT_TOP_UP_TITLE": "Transfer Completed", + "PARENT_TOP_UP_MESSAGE": "{amount} {currency} has been transferred to {childName}'s card. {childName}'s balance is {balance} {currency}", + "PARENT_SPENDING_TITLE": "Spending Alert", + "PARENT_SPENDING_MESSAGE": "{childName} spent {amount} {currency} at {merchant}. Remaining balance: {balance} {currency}", "YOUR_CHILD": "Your child", "MONEY_REQUEST_CREATED_TITLE": "Money Request", - "MONEY_REQUEST_CREATED_MESSAGE": "{childName} requested {amount} {currency}. Reason: {reason}", + "MONEY_REQUEST_CREATED_MESSAGE": "{childName} has requested {amount} {currency} for {reason}.", "MONEY_REQUEST_APPROVED_TITLE": "Money Request Approved", "MONEY_REQUEST_APPROVED_MESSAGE": "Your request for {amount} {currency} has been approved. The money has been added to your account.", "MONEY_REQUEST_DECLINED_TITLE": "Money Request Declined",