export type SalaryShiftSettings = { enabled: boolean; categoryNames: string[]; dayThreshold: number; }; export function bookingMonth(bookingDate?: string): string | undefined { if (!bookingDate) return undefined; return bookingDate.slice(0, 7); } export function computeEffectiveMonth( bookingDate: string | undefined, assignedMonth: string | undefined, ): string | undefined { if (assignedMonth) return assignedMonth; return bookingMonth(bookingDate); } export function addMonthsToMonthKey(monthKey: string, months: number): string { const [yearStr, monthStr] = monthKey.split("-"); const date = new Date(Number(yearStr), Number(monthStr) - 1 + months, 1); const y = date.getFullYear(); const m = String(date.getMonth() + 1).padStart(2, "0"); return `${y}-${m}`; } export function getDayFromDate(dateStr: string): number { return Number(dateStr.slice(8, 10)); } export function applySalaryShiftRule( bookingDate: string | undefined, amount: number, categoryName: string | undefined, salaryShift: SalaryShiftSettings, existingAssignedMonth?: string, ): string | undefined { if (existingAssignedMonth) return existingAssignedMonth; if (!salaryShift.enabled || !bookingDate || amount <= 0 || !categoryName) { return undefined; } if (!salaryShift.categoryNames.includes(categoryName)) { return undefined; } const day = getDayFromDate(bookingDate); if (day < salaryShift.dayThreshold) { return undefined; } const booking = bookingMonth(bookingDate); if (!booking) return undefined; return addMonthsToMonthKey(booking, 1); } export function resolveAssignedAndEffective( bookingDate: string | undefined, amount: number, categoryName: string | undefined, salaryShift: SalaryShiftSettings, manualAssignedMonth?: string, ): { assignedMonth?: string; effectiveMonth?: string } { const assignedMonth = manualAssignedMonth ?? applySalaryShiftRule(bookingDate, amount, categoryName, salaryShift); const effectiveMonth = computeEffectiveMonth(bookingDate, assignedMonth); return { assignedMonth, effectiveMonth }; } export function monthKeyFromBasis( tx: { bookingDate?: string; effectiveMonth?: string }, basis: "effective" | "booking", ): string | undefined { if (basis === "effective") { return tx.effectiveMonth ?? bookingMonth(tx.bookingDate); } return bookingMonth(tx.bookingDate); }