fix: format prices in notifications, change partial payment label, and add session holding notify API

This commit is contained in:
2026-08-21 20:17:30 +03:30
parent 6839685a21
commit 4c07ca2ae1
9 changed files with 145 additions and 14 deletions
+10
View File
@@ -44,6 +44,15 @@ const sumPaidTransactions = (transactions = []) => {
}, 0);
};
const formatPrice = (value) => {
if (value === null || value === undefined || value === '') return '';
const num = typeof value === 'number' ? value : Number(String(value).replace(/,/g, ''));
if (!Number.isNaN(num) && Number.isFinite(num)) {
return num.toLocaleString('en-US');
}
return String(value);
};
const remainingPayable = (payment = {}, transactions = []) => {
return Math.max(0, getPayableAmount(payment) - sumPaidTransactions(transactions));
};
@@ -53,6 +62,7 @@ module.exports = {
getPayableAmount,
normalizeDiscount,
sanitizeNotes,
formatPrice,
rialsToToman,
isPaidTransaction,
isCancelledTransaction,
+13 -1
View File
@@ -10,7 +10,8 @@ const {
rialsToToman,
isPaidTransaction,
sumPaidTransactions,
remainingPayable
remainingPayable,
formatPrice
} = require('./paymentAmount');
describe('payment amount helpers', () => {
@@ -40,6 +41,17 @@ describe('payment amount helpers', () => {
});
});
describe('formatPrice', () => {
it('formats numbers and numeric strings with decimal thousand separators', () => {
assert.equal(formatPrice(8000000), '8,000,000');
assert.equal(formatPrice('8000000'), '8,000,000');
assert.equal(formatPrice(500000), '500,000');
assert.equal(formatPrice(0), '0');
assert.equal(formatPrice(''), '');
assert.equal(formatPrice(null), '');
});
});
describe('rialsToToman', () => {
it('drops one zero so spreadsheet Rials become website Toman', () => {
assert.equal(rialsToToman(110_000_000), 11_000_000);
+11 -6
View File
@@ -175,11 +175,13 @@ const sendClassReminderSms = async (receiver, className, time, place = '', userI
});
};
const { formatPrice } = require('../paymentAmount');
const sendInvoiceCreatedSms = async (receiver, payload, userId = null) => {
const resolvedUserId = userId || await resolveUserIdByPhone(receiver);
const data = typeof payload === 'object' && payload !== null ? payload : { amount: payload };
const fullNameLabel = data.fullName || 'کارآموز';
const amountLabel = data.amount != null ? String(data.amount) : '';
const amountLabel = data.amount != null ? formatPrice(data.amount) : '';
const courseLabel = data.course || '-';
return sendTemplateSms({
@@ -203,6 +205,7 @@ const sendInvoiceCreatedSms = async (receiver, payload, userId = null) => {
const sendPaymentStatusChangedSms = async (receiver, payload, userId = null) => {
const data = payload || {};
const amountLabel = data.amount != null ? formatPrice(data.amount) : '';
return sendTemplateSms({
templateKey: 'paymentStatusChanged',
receiver,
@@ -213,7 +216,7 @@ const sendPaymentStatusChangedSms = async (receiver, payload, userId = null) =>
slotValues: {
fullName: data.fullName || 'کارآموز',
status: data.statusLabel || data.status || '-',
amount: data.amount != null ? String(data.amount) : '',
amount: amountLabel,
invoiceCode: data.invoiceCode || '',
course: data.course || '-'
}
@@ -222,16 +225,17 @@ const sendPaymentStatusChangedSms = async (receiver, payload, userId = null) =>
const sendPaymentReminderSms = async (receiver, payload, userId = null) => {
const data = payload || {};
const amountLabel = data.amount != null ? formatPrice(data.amount) : '-';
return sendTemplateSms({
templateKey: 'paymentReminder',
receiver,
userId,
subject: 'یادآوری سررسید پرداخت',
body: `یادآوری: مبلغ ${data.amount || '-'} تومان تا ${data.dueDate || '-'} سررسید دارد.`,
body: `یادآوری: مبلغ ${amountLabel} تومان تا ${data.dueDate || '-'} سررسید دارد.`,
relatedEvent: 'payment.reminder_due',
slotValues: {
fullName: data.fullName || 'کارآموز',
amount: data.amount != null ? String(data.amount) : '',
amount: data.amount != null ? formatPrice(data.amount) : '',
dueDate: data.dueDate || '',
invoiceCode: data.invoiceCode || '',
course: data.course || '-'
@@ -241,16 +245,17 @@ const sendPaymentReminderSms = async (receiver, payload, userId = null) => {
const sendTransactionRecordedSms = async (receiver, payload, userId = null) => {
const data = payload || {};
const amountLabel = data.amount != null ? formatPrice(data.amount) : '-';
return sendTemplateSms({
templateKey: 'transactionRecorded',
receiver,
userId,
subject: 'ثبت تراکنش',
body: `تراکنش به مبلغ ${data.amount || '-'} تومان ثبت شد.`,
body: `تراکنش به مبلغ ${amountLabel} تومان ثبت شد.`,
relatedEvent: 'payment.transaction_added',
slotValues: {
fullName: data.fullName || 'کارآموز',
amount: data.amount != null ? String(data.amount) : '',
amount: data.amount != null ? formatPrice(data.amount) : '',
invoiceCode: data.invoiceCode || '',
transactionCode: data.transactionCode || '',
receiptNumber: data.receiptNumber || ''