исключила 1-3 кв для проверки
This commit is contained in:
parent
e11661a26b
commit
df6ea39194
@ -33,13 +33,25 @@ const bookingLessBalanceByColumn = new Map(
|
|||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//Бронь <= Остаток после брони для листов КВП и Опер 4 формы
|
||||||
|
const bookingLessBalance4From = [
|
||||||
|
["data.q4.booking", "data.q4.residual_after_booking"],
|
||||||
|
];
|
||||||
|
|
||||||
|
const bookingLessBalance4FormByColumn = new Map(
|
||||||
|
bookingLessBalance.flatMap(([bookingKey, balanceKey]) => [
|
||||||
|
[bookingKey, { bookingKey, balanceKey }],
|
||||||
|
[balanceKey, { bookingKey, balanceKey }],
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
//Перенос в фонд экономии <= Всего
|
//Перенос в фонд экономии <= Всего
|
||||||
const transferLessTotal = [
|
const transferLessTotal = [
|
||||||
["data.q1.transfer_econ", "data.q1.total"],
|
["data.q1.transfer_econ", "data.q1.total"],
|
||||||
["data.q2.transfer_econ", "data.q2.total"],
|
["data.q2.transfer_econ", "data.q2.total"],
|
||||||
["data.q3.transfer_econ", "data.q3.total"],
|
["data.q3.transfer_econ", "data.q3.total"],
|
||||||
["data.q4.transfer_econ", "data.q4.total"],
|
["data.q4.transfer_econ", "data.q4.total"],
|
||||||
]
|
];
|
||||||
const transferLessTotalByColumn = new Map(
|
const transferLessTotalByColumn = new Map(
|
||||||
transferLessTotal.flatMap(([transferKey, totalKey]) => [
|
transferLessTotal.flatMap(([transferKey, totalKey]) => [
|
||||||
[transferKey, { transferKey: transferKey, totalKey: totalKey }],
|
[transferKey, { transferKey: transferKey, totalKey: totalKey }],
|
||||||
@ -47,6 +59,15 @@ const transferLessTotalByColumn = new Map(
|
|||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Область действия всех правил. Пары можно добавлять, удалять и изменять.
|
||||||
|
const bookingLessBalanceRuleScope = {
|
||||||
|
includedScopes: [],
|
||||||
|
excludedScopes: [
|
||||||
|
{ formType: "FORM_4", sheetName: "AHR" },
|
||||||
|
{ formType: "FORM_4", sheetName: "OPER" },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
export const validationRules = [
|
export const validationRules = [
|
||||||
{
|
{
|
||||||
id: "remaining-booking",
|
id: "remaining-booking",
|
||||||
@ -72,6 +93,7 @@ export const validationRules = [
|
|||||||
Number(value) !== 0,
|
Number(value) !== 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
...bookingLessBalanceRuleScope,
|
||||||
id: "booking-less-balance",
|
id: "booking-less-balance",
|
||||||
columnKeys: bookingLessBalance.flat(),
|
columnKeys: bookingLessBalance.flat(),
|
||||||
errorColumnKeys: bookingLessBalance.map(([bookingKey]) => bookingKey),
|
errorColumnKeys: bookingLessBalance.map(([bookingKey]) => bookingKey),
|
||||||
@ -80,8 +102,41 @@ export const validationRules = [
|
|||||||
const pair = bookingLessBalanceByColumn.get(columnKey);
|
const pair = bookingLessBalanceByColumn.get(columnKey);
|
||||||
if (!pair) return false;
|
if (!pair) return false;
|
||||||
|
|
||||||
const booking = pair.bookingKey.split(".").reduce((value, key) => value?.[key], row);
|
const booking = pair.bookingKey
|
||||||
const balance = pair.balanceKey.split(".").reduce((value, key) => value?.[key], row);
|
.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: "booking-less-balance-4-form",
|
||||||
|
columnKeys: bookingLessBalance4From.flat(),
|
||||||
|
errorColumnKeys: bookingLessBalance4From.map(([bookingKey]) => bookingKey),
|
||||||
|
message: "Сумма бронирования превышает остаток после бронирования",
|
||||||
|
isInvalid: (_value, row, columnKey) => {
|
||||||
|
const pair = bookingLessBalance4FormByColumn.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 (
|
return (
|
||||||
booking !== null &&
|
booking !== null &&
|
||||||
@ -105,8 +160,12 @@ export const validationRules = [
|
|||||||
const pair = transferLessTotalByColumn.get(columnKey);
|
const pair = transferLessTotalByColumn.get(columnKey);
|
||||||
if (!pair) return false;
|
if (!pair) return false;
|
||||||
|
|
||||||
const transfer = pair.transferKey.split(".").reduce((value, key) => value?.[key], row);
|
const transfer = pair.transferKey
|
||||||
const total = pair.totalKey.split(".").reduce((value, key) => value?.[key], row);
|
.split(".")
|
||||||
|
.reduce((value, key) => value?.[key], row);
|
||||||
|
const total = pair.totalKey
|
||||||
|
.split(".")
|
||||||
|
.reduce((value, key) => value?.[key], row);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
transfer !== null &&
|
transfer !== null &&
|
||||||
|
|||||||
@ -1,30 +1,34 @@
|
|||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { validationRules } from '../constants/validation';
|
import { validationRules } from '../constants/validation';
|
||||||
import { buildColumnHeaderPaths, collectInvalidErrors } from '../utils/validationUtils';
|
import { buildColumnHeaderPaths, collectInvalidErrors, isValidationRuleEnabled } from '../utils/validationUtils';
|
||||||
|
|
||||||
export const useValidationRules = (data = [], columns = []) => {
|
export const useValidationRules = (data = [], columns = [], formType, sheetName) => {
|
||||||
const headerPaths = useMemo(() => buildColumnHeaderPaths(columns), [columns]);
|
const headerPaths = useMemo(() => buildColumnHeaderPaths(columns), [columns]);
|
||||||
|
const activeRules = useMemo(
|
||||||
|
() => validationRules.filter((rule) => isValidationRuleEnabled(rule, { formType, sheetName })),
|
||||||
|
[formType, sheetName],
|
||||||
|
);
|
||||||
|
|
||||||
const errors = useMemo(() => {
|
const errors = useMemo(() => {
|
||||||
const result = [];
|
const result = [];
|
||||||
const seen = new Set();
|
const seen = new Set();
|
||||||
|
|
||||||
for (const rule of validationRules) {
|
for (const rule of activeRules) {
|
||||||
collectInvalidErrors(data, rule, headerPaths, result, seen);
|
collectInvalidErrors(data, rule, headerPaths, result, seen);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}, [data, headerPaths]);
|
}, [activeRules, data, headerPaths]);
|
||||||
|
|
||||||
const isCellInvalid = useCallback(
|
const isCellInvalid = useCallback(
|
||||||
(columnId, value, row) =>
|
(columnId, value, row) =>
|
||||||
validationRules.some(
|
activeRules.some(
|
||||||
(rule) =>
|
(rule) =>
|
||||||
rule.columnKeys.includes(columnId) &&
|
rule.columnKeys.includes(columnId) &&
|
||||||
(!rule.appliesToRow || rule.appliesToRow(row)) &&
|
(!rule.appliesToRow || rule.appliesToRow(row)) &&
|
||||||
rule.isInvalid(value, row, columnId),
|
rule.isInvalid(value, row, columnId),
|
||||||
),
|
),
|
||||||
[],
|
[activeRules],
|
||||||
);
|
);
|
||||||
|
|
||||||
return { errors, isCellInvalid };
|
return { errors, isCellInvalid };
|
||||||
|
|||||||
@ -1,6 +1,21 @@
|
|||||||
// Достаёт вложенное поле из объекта строки таблицы
|
// Достаёт вложенное поле из объекта строки таблицы
|
||||||
export const getValueByPath = (row, path) => path.split('.').reduce((value, key) => value?.[key], row);
|
export const getValueByPath = (row, path) => path.split('.').reduce((value, key) => value?.[key], row);
|
||||||
|
|
||||||
|
const matchesValidationScope = (scope, { formType, sheetName }) =>
|
||||||
|
(!scope.formType || scope.formType === formType) &&
|
||||||
|
(!scope.sheetName || scope.sheetName === sheetName);
|
||||||
|
|
||||||
|
// Пустой includedScopes означает «работает везде»; исключения приоритетнее.
|
||||||
|
export const isValidationRuleEnabled = (rule, context = {}) => {
|
||||||
|
const includedScopes = rule.includedScopes || [];
|
||||||
|
const excludedScopes = rule.excludedScopes || [];
|
||||||
|
|
||||||
|
if (excludedScopes.some((scope) => matchesValidationScope(scope, context))) return false;
|
||||||
|
if (includedScopes.length && !includedScopes.some((scope) => matchesValidationScope(scope, context))) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
// Строит пути заголовков колонок
|
// Строит пути заголовков колонок
|
||||||
export const buildColumnHeaderPaths = (columns = [], path = [], map = {}) => {
|
export const buildColumnHeaderPaths = (columns = [], path = [], map = {}) => {
|
||||||
for (const column of columns) {
|
for (const column of columns) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user