TorbatYar/frontend/lib/voucher-balance.ts
Mortezakoohjani 8caed2cfd2 Fix live voucher balance totals and show system-posted vouchers in the list.
RHF was caching 0/0 via useMemo on in-place form arrays; MoneyInput now drives Controller. Voucher list exposes source filters for manual vs automatic GL docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-26 18:22:40 +03:30

47 lines
1.9 KiB
TypeScript

/** Live voucher line balance helpers — Rial integers, zero tolerance. */
import { toRialInteger } from "@/lib/utils";
export type BalanceLine = { debit?: string; credit?: string };
export function sumVoucherLines(lines: BalanceLine[] | undefined) {
let debit = 0;
let credit = 0;
(lines ?? []).forEach((line, index) => {
const d = Number(toRialInteger(line.debit) || "0");
const c = Number(toRialInteger(line.credit) || "0");
debit += Number.isFinite(d) ? d : 0;
credit += Number.isFinite(c) ? c : 0;
void index;
});
const difference = debit - credit;
const hasAmount = debit > 0 || credit > 0;
return {
debit,
credit,
difference,
hasAmount,
// Empty 0/0 is not "balanced" for UX — only real equal totals count.
isBalanced: difference === 0 && hasAmount && (lines?.length ?? 0) >= 2,
};
}
export function unbalancedMessage(debit: number, credit: number): string {
const diff = Math.abs(debit - credit);
if (debit > credit) {
return `سند نامتوازن است: جمع بدهکار ${debit.toLocaleString("fa-IR")} و بستانکار ${credit.toLocaleString("fa-IR")} — بدهکار ${diff.toLocaleString("fa-IR")} ریال بیشتر است.`;
}
return `سند نامتوازن است: جمع بدهکار ${debit.toLocaleString("fa-IR")} و بستانکار ${credit.toLocaleString("fa-IR")} — بستانکار ${diff.toLocaleString("fa-IR")} ریال بیشتر است.`;
}
export function lineBothSidesError(debit: string, credit: string): string | null {
const d = Number(toRialInteger(debit) || "0");
const c = Number(toRialInteger(credit) || "0");
if (d > 0 && c > 0) {
return "در یک ردیف نمی‌توان همزمان بدهکار و بستانکار داشت";
}
if (d === 0 && c === 0) {
return "حداقل یکی از بدهکار یا بستانکار باید مقدار داشته باشد";
}
return null;
}