// Требование №1. Контроль превышения бронирования над сметой. const remainingBookingKeys = [ "data.q1.rem_booking", "data.q2.rem_booking", "data.q3.rem_booking", "data.q4.rem_booking", "data.q1.residual_after_booking", "data.q2.residual_after_booking", "data.q3.residual_after_booking", "data.q4.residual_after_booking", ]; // Требование №2. Контроль столбца «Текущие корректировки = 0». const zeroValueRequirementKeys = [ "data.q1.adj_current", "data.q2.adj_current", "data.q3.adj_current", "data.q4.adj_current", ]; //Бронь <= Остаток после брони const bookingLessBalance = [ ["data.q1.booking", "data.q1.residual_after_booking"], ["data.q2.booking", "data.q2.residual_after_booking"], ["data.q3.booking", "data.q3.residual_after_booking"], ["data.q4.booking", "data.q4.residual_after_booking"], ]; const bookingLessBalanceByColumn = new Map( bookingLessBalance.flatMap(([bookingKey, balanceKey]) => [ [bookingKey, { bookingKey, balanceKey }], [balanceKey, { bookingKey, balanceKey }], ]), ); //Перенос в фонд экономии <= Всего const transferLessTotal = [ ["data.q1.transfer_econ", "data.q1.total"], ["data.q2.transfer_econ", "data.q2.total"], ["data.q3.transfer_econ", "data.q3.total"], ["data.q4.transfer_econ", "data.q4.total"], ] const transferLessTotalByColumn = new Map( transferLessTotal.flatMap(([transferKey, totalKey]) => [ [transferKey, { transferKey: transferKey, totalKey: totalKey }], [totalKey, { transferKey: transferKey, totalKey: totalKey }], ]), ); export const validationRules = [ { id: "remaining-booking", columnKeys: remainingBookingKeys, message: "Сумма бронирования превышает сумму, предусмотренную сметой", isInvalid: (value) => value !== null && value !== undefined && value !== "" && Number.isFinite(Number(value)) && Number(value) < 0, }, { id: "current-adjustments-zero", columnKeys: zeroValueRequirementKeys, message: "Текущие корректировки должны быть равны 0", appliesToRow: (row) => row?.depth === 0 || row?.row_type === "ROOT", isInvalid: (value) => value !== null && value !== undefined && value !== "" && Number.isFinite(Number(value)) && Number(value) !== 0, }, { id: "booking-less-balance", columnKeys: bookingLessBalance.flat(), errorColumnKeys: bookingLessBalance.map(([bookingKey]) => bookingKey), message: "Сумма бронирования превышает остаток после бронирования", isInvalid: (_value, row, columnKey) => { const pair = bookingLessBalanceByColumn.get(columnKey); if (!pair) return false; const booking = pair.bookingKey.split(".").reduce((value, key) => value?.[key], row); const balance = pair.balanceKey.split(".").reduce((value, key) => value?.[key], row); return ( booking !== null && booking !== undefined && booking !== "" && balance !== null && balance !== undefined && balance !== "" && Number.isFinite(Number(booking)) && Number.isFinite(Number(balance)) && Number(booking) > Number(balance) ); }, }, { id: "transfer-less-total", columnKeys: transferLessTotal.flat(), errorColumnKeys: transferLessTotal.map(([transferKey]) => transferKey), message: "Перенос в фонд экономии превышает всего", isInvalid: (_value, row, columnKey) => { const pair = transferLessTotalByColumn.get(columnKey); if (!pair) return false; const transfer = pair.transferKey.split(".").reduce((value, key) => value?.[key], row); const total = pair.totalKey.split(".").reduce((value, key) => value?.[key], row); return ( transfer !== null && transfer !== undefined && transfer !== "" && total !== null && total !== undefined && total !== "" && Number.isFinite(Number(transfer)) && Number.isFinite(Number(total)) && Number(transfer) > Number(total) ); }, }, ];