Files
gameno-api/utils/paymentAmount.js
T
kavehhn 5328f36f06 Add admin transaction cancellation without deleting history.
Cancelled transactions are excluded from paid totals and due-date
calculations while remaining visible for audit purposes.
2026-08-16 22:38:00 +03:30

63 lines
1.7 KiB
JavaScript

'use strict';
const NOTES_MAX_LENGTH = 5000;
const toNonNegativeNumber = (value) => {
const n = Number(value);
if (!Number.isFinite(n) || n < 0) return 0;
return n;
};
const normalizeDiscount = (discount, amount) => {
return Math.min(toNonNegativeNumber(discount), toNonNegativeNumber(amount));
};
const getPayableAmount = (payment = {}) => {
const amount = toNonNegativeNumber(payment.amount);
return amount - normalizeDiscount(payment.discount, amount);
};
const sanitizeNotes = (notes) => {
if (notes == null) return '';
return String(notes).trim().slice(0, NOTES_MAX_LENGTH);
};
const rialsToToman = (value) => Math.floor(toNonNegativeNumber(value) / 10);
const isCancelledTransaction = (trx = {}) => String(trx.status || '').toLowerCase() === 'cancelled';
const isPaidTransaction = (trx = {}) => {
if (isCancelledTransaction(trx)) return false;
const status = String(trx.status || '').toLowerCase();
if (status === 'pending') return false;
if (status === 'paid') return true;
return Boolean(trx.date);
};
const isActiveTransaction = (trx = {}) => !isCancelledTransaction(trx);
const sumPaidTransactions = (transactions = []) => {
if (!Array.isArray(transactions)) return 0;
return transactions.reduce((sum, trx) => {
if (!isPaidTransaction(trx)) return sum;
return sum + toNonNegativeNumber(trx.amount);
}, 0);
};
const remainingPayable = (payment = {}, transactions = []) => {
return Math.max(0, getPayableAmount(payment) - sumPaidTransactions(transactions));
};
module.exports = {
NOTES_MAX_LENGTH,
getPayableAmount,
normalizeDiscount,
sanitizeNotes,
rialsToToman,
isPaidTransaction,
isCancelledTransaction,
isActiveTransaction,
sumPaidTransactions,
remainingPayable
};