/* eslint-disable sonarjs/cognitive-complexity */ /* eslint-disable complexity */ import { SEASONS_PERIOD_NUMBER, SEASONS_PERIODS } from './lib/seasons-constants'; import { selectHighSeasonStart } from '@/config/default-options'; import PaymentsSchema from '@/config/schema/payments'; import ValuesSchema from '@/config/schema/values'; import { MIN_LASTPAYMENT_NSIB, MIN_PAYMENT } from '@/constants/values'; import { counting, max, min, shift, sort } from 'radash'; import { areEqual, isSorted } from 'tools/array'; import { z } from 'zod'; export function createValidationSchema() { return ValuesSchema.pick({ graphType: true, highSeasonStart: true, insNSIB: true, lastPaymentRub: true, leasingPeriod: true, seasonType: true, }) .extend({ payments: PaymentsSchema, }) .superRefine( async ( { graphType, highSeasonStart, leasingPeriod, payments, seasonType, insNSIB, lastPaymentRub, }, ctx ) => { if (Boolean(insNSIB) && lastPaymentRub < MIN_LASTPAYMENT_NSIB) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: `Последний платеж не может быть меньше ${MIN_LASTPAYMENT_NSIB} руб. при наличии НСИБ, укажите большее значение`, path: ['tbxLastPaymentRub'], }); } { const targetPayments = payments.values.slice(1, leasingPeriod - 1); if (!targetPayments.every((payment) => payment >= MIN_PAYMENT)) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: `Минимальное значение платежа должно быть равно ${MIN_PAYMENT}`, path: ['payments'], }); } } switch (graphType) { // Дегрессия case 100_000_001: { if (!seasonType) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Не выбран тип дегрессии', path: ['payments', 'selectSeasonType'], }); break; } /** * при Дегрессии все значения не должны быть равны друг другу * + что при Легком старте 2,3 и 4 платежи не должны быть равны 100 */ { const targetPayments = payments.values.slice(1, leasingPeriod - 1); if (new Set(targetPayments).size === 1) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Платежи не должны быть равны друг другу', path: ['payments'], }); } } /** * Проверка на возрастание */ { const targetPayments = payments.values.slice(1, leasingPeriod - 1); for (let i = 2; i < targetPayments.length - 1; i += 1) { if (targetPayments[i] > targetPayments[i - 1]) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Платежи должны убывать', path: ['payments'], }); } } } /** * Если вид графика = Дегрессия И значения в "Соотношении платежей" у 2, 3 и 4 платежа отличаются друг от друга не более чем на 10 * (т.е. берем значения в этих полях, определяем максимальное и минимальное значение и смотрим на их разницу) * то не осуществлять Расчет графика и выводить ошибку "Нельзя осуществить расчет - указана очень жетская дегрессия. * На 2-4 платежах Соотношение платежа должен отличаться не более чем на 10%", * иначе осуществлять расчет */ { const targetPayments = payments.values.slice(1, 4); if ((max(targetPayments) || 0) - (min(targetPayments) || 0) > 10) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Указана очень жесткая дегрессия. На 2-4 платежах Соотношение платежа должен отличаться не более чем на 10%', path: ['payments'], }); } } /** * Если вид графика = Дегрессия И значения в "Соотношении платежей" для строк с 2 До "Срок лизинга-1" как минимум 2 раза по 2 платежа должны между собой быть равны * (т.е. берем значения "Соотношения платежей" для строк с 2 до "Срок лизинга-1" и делаем сводную таблицу - если кол-во одинаковых значение больше 2 встречаются 2 и более раза), * то осуществлять расчет, * иначе не осуществлять Расчет графика и выводить ошибку "Нельзя осуществить расчет - указана очень жетская дегрессия. Не менее чем у 4х платежей "Соотношение платежа" должно не отличаться между самой", */ { const targetPayments = payments.values.slice(1, leasingPeriod - 1); const counts = counting(targetPayments, (v) => v); if (Object.values(counts).filter((count) => count > 1).length < 2) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Указана очень жесткая дегрессия. Не менее чем у 4х платежей соотношение должно не отличаться между собой', path: ['payments'], }); } } break; } case 100_000_003: { if (leasingPeriod < 14) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'При сезонном виде графика срок лизинга должен быть больше 14 месяцев', path: ['payments', 'tbxLeasingPeriod'], }); } if (!seasonType) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Не выбран тип сезонности', path: ['payments', 'selectSeasonType'], }); break; } if (!highSeasonStart) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Не выбрано смещение сезонности', path: ['payments', 'selectHighSeasonStart'], }); break; } const seasons = payments.values.slice(1, SEASONS_PERIOD_NUMBER + 1); const highSeasonStartOption = selectHighSeasonStart.find( (x) => x.value === highSeasonStart ); if (highSeasonStartOption) { const shiftNumber = Number.parseInt(highSeasonStartOption.label, 10) - 2; const unshiftedSeasons = shift(seasons, -shiftNumber); const positions = SEASONS_PERIODS[seasonType]; const seasonsValues = positions.map((position) => unshiftedSeasons[position]); if (isSorted(seasonsValues)) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Сезонные платежи должны убывать', path: ['payments'], }); } } break; } // Легкий старт case 100_000_004: { const targetPayments = payments.values.slice(1, 4); const sortedPayments = sort(targetPayments, (x) => x); const areEqualPayments = new Set(targetPayments).size === 1; if (!areEqual(targetPayments, sortedPayments) || areEqualPayments) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: '2, 3, 4 платежи должны возрастать', path: ['payments'], }); } break; } default: { break; } } } ); }