From 54004173ae426c22255b7b03937def669c9f2261 Mon Sep 17 00:00:00 2001 From: vchikalkin Date: Tue, 7 Mar 2023 13:05:55 +0300 Subject: [PATCH] process/insurance: use new validation --- apps/web/config/process/default.ts | 4 +- apps/web/process/insurance/reactions.ts | 115 +++++++++------------- apps/web/process/insurance/validation.ts | 82 +++++++++++++++ apps/web/stores/tables/insurance/index.ts | 15 +-- 4 files changed, 135 insertions(+), 81 deletions(-) create mode 100644 apps/web/process/insurance/validation.ts diff --git a/apps/web/config/process/default.ts b/apps/web/config/process/default.ts index 4acd219..6284afa 100644 --- a/apps/web/config/process/default.ts +++ b/apps/web/config/process/default.ts @@ -6,7 +6,7 @@ import * as configurator from '@/process/configurator'; import * as fingap from '@/process/fingap'; import * as gibdd from '@/process/gibdd'; import { useProcess } from '@/process/hooks'; -// import * as insurance from '@/process/insurance'; +import * as insurance from '@/process/insurance'; // import * as leadOpportunity from '@/process/lead-opportunity'; // import * as leasingObject from '@/process/leasing-object'; // import * as leasingWithoutKasko from '@/process/leasing-without-kasko'; @@ -36,5 +36,5 @@ export default function useReactions() { useProcess(payments); useProcess(gibdd); // useProcess(addProduct); - // useProcess(insurance); + useProcess(insurance); } diff --git a/apps/web/process/insurance/reactions.ts b/apps/web/process/insurance/reactions.ts index 7f4a971..9aade9e 100644 --- a/apps/web/process/insurance/reactions.ts +++ b/apps/web/process/insurance/reactions.ts @@ -1,14 +1,16 @@ /* eslint-disable @typescript-eslint/naming-convention */ import type { ProcessContext } from '../types'; +import { createValidationSchema } from './validation'; import { normalizeOptions } from '@/../../packages/tools'; -import type * as Insurance from '@/Components/Calculation/Form/Insurance/InsuranceTable/types'; +import type { Elements } from '@/Components/Calculation/config/map/values'; import { selectLeaseObjectUseFor } from '@/config/default-options'; import * as CRMTypes from '@/graphql/crm.types'; import ValidationHelper from '@/stores/validation/helper'; -import { reaction } from 'mobx'; +import { comparer, reaction, toJS } from 'mobx'; +import { uid } from 'radash'; export function common({ store, apolloClient }: ProcessContext) { - const { $calculation, $tables } = store; + const { $calculation } = store; reaction( () => $calculation.element('selectGPSBrand').getValue(), @@ -113,75 +115,52 @@ export function common({ store, apolloClient }: ProcessContext) { ); } -export function validation({ store, apolloClient }: ProcessContext) { - const { $calculation, $tables } = store; +const key = uid(7); - { - const validationHelper = new ValidationHelper(); - reaction( - () => ({ - insTerm: $tables.insurance.row('kasko').getValue('insTerm'), - ...$calculation.$values.getValues(['leasingPeriod', 'recalcWithRevision', 'quote']), - }), - async ({ leasingPeriod, insTerm, recalcWithRevision, quote: quoteId }) => { - if (!quoteId) { - validationHelper.removeErrors(); +export function validation(context: ProcessContext) { + const { $calculation, $tables } = context.store; - return; - } + const validationSchema = createValidationSchema(context); + const helper = new ValidationHelper(); - const { - data: { quote }, - } = await apolloClient.query({ - query: CRMTypes.GetQuoteDocument, - variables: { quoteId }, - }); + reaction( + () => { + const values = $calculation.$values.getValues([ + 'leasingPeriod', + 'quote', + 'recalcWithRevision', + ]); - $tables.insurance.validate({ - helper: validationHelper, - invalid: - recalcWithRevision && - quote?.evo_one_year_insurance === true && - leasingPeriod > 15 && - insTerm === 100_000_001, - message: - 'Срок страхования КАСКО должен быть 12 месяцев, т.к. оформляется Однолетний полис', + return { + insurance: { + fingap: toJS($tables.insurance.row('fingap').getValues()), + kasko: toJS($tables.insurance.row('kasko').getValues()), + osago: toJS($tables.insurance.row('osago').getValues()), + }, + ...values, + }; + }, + async (values) => { + helper.removeErrors(); + const validationResult = await validationSchema.safeParseAsync(values); + + if (!validationResult.success) { + validationResult.error.errors.forEach(({ path, message }) => { + (path as Array).forEach((elementName) => { + if (elementName === 'insurance') { + const removeError = $tables.insurance.setError({ key, message }); + if (removeError) helper.add(removeError); + } else { + const removeError = $calculation.element(elementName).setError({ key, message }); + if (removeError) helper.add(removeError); + } + }); }); } - ); - } - - (['osago', 'kasko'] as Insurance.Keys[]).forEach((key) => { - const validationHelper = new ValidationHelper(); - reaction( - () => $tables.insurance.row(key).getValues(), - ({ insCost, insured, policyType, insuranceCompany, insTerm }) => { - validationHelper.removeErrors(); - - $tables.insurance.validate({ - helper: validationHelper, - invalid: insCost === 0 && insured === 100_000_001, - message: `Укажите стоимость ${policyType}, включаемую в график`, - }); - - $tables.insurance.validate({ - helper: validationHelper, - invalid: insCost > 0 && !insuranceCompany, - message: `Укажите страховую компанию ${policyType}`, - }); - - $tables.insurance.validate({ - helper: validationHelper, - invalid: insCost > 0 && !insTerm, - message: `Укажите срок страхования ${policyType}`, - }); - - $tables.insurance.validate({ - helper: validationHelper, - invalid: insCost > 0 && !insured, - message: `Укажите плательщика ${policyType}`, - }); - } - ); - }); + }, + { + delay: 50, + equals: comparer.structural, + } + ); } diff --git a/apps/web/process/insurance/validation.ts b/apps/web/process/insurance/validation.ts new file mode 100644 index 0000000..61f59ac --- /dev/null +++ b/apps/web/process/insurance/validation.ts @@ -0,0 +1,82 @@ +import type { ValidationContext } from '../types'; +import type * as Insurance from '@/Components/Calculation/Form/Insurance/InsuranceTable/types'; +import { RowSchema } from '@/config/schema/insurance'; +import ValuesSchema from '@/config/schema/values'; +import * as CRMTypes from '@/graphql/crm.types'; +import { z } from 'zod'; + +export function createValidationSchema({ apolloClient }: ValidationContext) { + return ValuesSchema.pick({ + leasingPeriod: true, + quote: true, + recalcWithRevision: true, + }) + .extend({ + insurance: z + .object({ + fingap: RowSchema, + kasko: RowSchema, + osago: RowSchema, + }) + .strict(), + }) + .superRefine(async ({ leasingPeriod, recalcWithRevision, quote: quoteId, insurance }, ctx) => { + if (quoteId) { + const { + data: { quote }, + } = await apolloClient.query({ + query: CRMTypes.GetQuoteDocument, + variables: { quoteId }, + }); + if ( + recalcWithRevision && + quote?.evo_one_year_insurance === true && + leasingPeriod > 15 && + insurance.kasko.insTerm === 100_000_001 + ) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: + 'Срок страхования КАСКО должен быть 12 месяцев, т.к. оформляется Однолетний полис', + path: ['insurance'], + }); + } + } + + (['osago', 'kasko'] as Insurance.Keys[]).forEach((key) => { + const { insCost, insured, policyType, insuranceCompany, insTerm } = insurance[key]; + + if (insCost === 0 && insured === 100_000_001) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: `Укажите стоимость ${policyType}, включаемую в график`, + path: ['insurance'], + }); + } + + if (insCost > 0 && !insuranceCompany) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: `Укажите страховую компанию ${policyType}`, + path: ['insurance'], + }); + } + + if (insCost > 0 && !insTerm) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: `Укажите срок страхования ${policyType}`, + path: ['insurance'], + }); + } + + if (insCost > 0 && !insured) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: `Укажите плательщика ${policyType}`, + path: ['insurance'], + }); + } + }); + }); +} diff --git a/apps/web/stores/tables/insurance/index.ts b/apps/web/stores/tables/insurance/index.ts index f66df2d..af7faaa 100644 --- a/apps/web/stores/tables/insurance/index.ts +++ b/apps/web/stores/tables/insurance/index.ts @@ -1,5 +1,5 @@ import Validation from '../../validation'; -import type { RemoveError, ValidationParams } from '../../validation/types'; +import type { ValidationParams } from '../../validation/types'; import type * as Insurance from '@/Components/Calculation/Form/Insurance/InsuranceTable/types'; import * as insuranceTableConfig from '@/config/tables/insurance-table'; import type RootStore from '@/stores/root'; @@ -40,17 +40,10 @@ export default class InsuranceTable { if (initialStatuses) this.statuses = initialStatuses; }; - public validate = ({ invalid, message, helper }: ValidationParams) => { - let removeError: RemoveError | undefined; + public setError = (params: ValidationParams) => this.validation.setError(params); - if (invalid) { - removeError = this.validation?.addError(message); - if (helper && removeError) helper.add(removeError); - } else { - this.validation?.removeError(message); - } - - return removeError; + public removeError = (params: Pick) => { + this.validation.removeError(params); }; public reset = () => {