Files
nademitex_server/src/common/utils/check-rass.ts
T
2026-10-29 15:37:44 +03:30

81 lines
2.1 KiB
TypeScript

export type CheckRassInput = {
amount: number;
dueDate: Date | string;
};
export type CheckRassResult = {
checkCount: number;
totalAmount: number;
nearestDueDate: string | null;
farthestDueDate: string | null;
rassDays: number;
rassDate: string | null;
};
import {
addDays,
calendarDayOf,
diffInDays,
tehranCalendarDay,
} from './tehran-time';
/** وضعیتی که فاکتور قیمت‌گذاری‌شده برای مشتری ارسال می‌شود. */
const INVOICE_ISSUED_STATUS = 'awaiting_settlement';
/**
* مبدأ راس چک، تاریخ صدور فاکتور است نه امروز و نه تاریخ ثبت پیش‌سفارش.
* اگر فاکتور دوباره ارسال شده باشد، آخرین صدور ملاک است.
*/
export function invoiceAnchorDate(
createdAt: Date,
history: { toStatus: string; changedAt: Date }[] = [],
): Date {
for (let i = history.length - 1; i >= 0; i -= 1) {
const row = history[i];
if (row?.toStatus === INVOICE_ISSUED_STATUS) return row.changedAt;
}
return createdAt;
}
export function calculateCheckRass(
checks: CheckRassInput[],
baseDate: Date,
): CheckRassResult {
if (checks.length === 0) {
return {
checkCount: 0,
totalAmount: 0,
nearestDueDate: null,
farthestDueDate: null,
rassDays: 0,
rassDate: null,
};
}
const base = tehranCalendarDay(baseDate);
let totalAmount = 0;
let weightedDays = 0;
const dueDates: Date[] = [];
for (const check of checks) {
const due = calendarDayOf(check.dueDate);
dueDates.push(due);
const days = Math.max(0, diffInDays(base, due));
totalAmount += check.amount;
weightedDays += check.amount * days;
}
const rassDays = totalAmount > 0 ? Math.round(weightedDays / totalAmount) : 0;
const rassDate = addDays(base, rassDays);
dueDates.sort((a, b) => a.getTime() - b.getTime());
return {
checkCount: checks.length,
totalAmount,
nearestDueDate: dueDates[0]?.toISOString() ?? null,
farthestDueDate: dueDates[dueDates.length - 1]?.toISOString() ?? null,
rassDays,
rassDate: rassDate.toISOString(),
};
}