calculate pt.1: add server validation

This commit is contained in:
vchikalkin 2023-03-16 19:42:10 +03:00
parent 9d45a7bff0
commit 8994cd8ec8
27 changed files with 393 additions and 208 deletions

View File

@ -1,4 +1,5 @@
import type { Elements } from '../config/map/actions';
import { useProcessContext } from '@/process/hooks';
import { useStatus } from '@/stores/calculation/statuses/hooks';
import { observer } from 'mobx-react-lite';
import type { ComponentType } from 'react';
@ -15,9 +16,12 @@ export default function buildAction<T>(
return observer((props: T) => {
const status = useStatus(elementName);
const context = useProcessContext();
return (
<Component
action={() => import(`process/${processName}/action`).then((module) => module.action())}
action={() =>
import(`process/${processName}/action`).then((module) => module.action(context))}
status={status}
{...props}
/>

View File

@ -1,14 +1,12 @@
import { z } from 'zod';
export const RiskSchema = z
.object({
calcType: z.number(),
key: z.string(),
keys: z.array(z.string()).optional(),
premium: z.number(),
premiumPerc: z.number(),
riskId: z.string(),
riskName: z.string(),
sum: z.number(),
})
.strict();
export const RiskSchema = z.object({
calcType: z.number(),
key: z.string(),
keys: z.array(z.string()).optional(),
premium: z.number(),
premiumPerc: z.number(),
riskId: z.string(),
riskName: z.string(),
sum: z.number(),
});

View File

@ -2,13 +2,19 @@ import { z } from 'zod';
export const KeysSchema = z.enum(['osago', 'kasko', 'fingap']);
export const RowSchema = z
.object({
insCost: z.number(),
insTerm: z.number().nullable(),
insuranceCompany: z.string().nullable(),
insured: z.number().nullable(),
key: KeysSchema,
policyType: z.string(),
})
.strict();
export const RowSchema = z.object({
insCost: z.number(),
insTerm: z.number().nullable(),
insuranceCompany: z.string().nullable(),
insured: z.number().nullable(),
key: KeysSchema,
policyType: z.string(),
});
export const InsuranceSchema = z.object({
values: z.object({
fingap: RowSchema,
kasko: RowSchema,
osago: RowSchema,
}),
});

View File

@ -1,9 +1,7 @@
import { z } from 'zod';
const PaymentsSchema = z
.object({
values: z.number().array(),
})
.strict();
const PaymentsSchema = z.object({
values: z.number().array(),
});
export default PaymentsSchema;

View File

@ -1,150 +1,148 @@
/* eslint-disable canonical/sort-keys */
import { z } from 'zod';
const ValuesSchema = z
.object({
addEquipmentPrice: z.number(),
balanceHolder: z.number().nullable(),
bonusCoefficient: z.number(),
brand: z.string().nullable(),
calcBroker: z.string().nullable(),
calcBrokerRewardCondition: z.string().nullable(),
calcBrokerRewardSum: z.number(),
calcDoubleAgent: z.string().nullable(),
calcDoubleAgentRewardCondition: z.string().nullable(),
calcDoubleAgentRewardSumm: z.number(),
calcFinDepartment: z.string().nullable(),
calcType: z.number().nullable(),
clientRisk: z.string().nullable(),
clientType: z.string().nullable(),
comissionPerc: z.number(),
comissionRub: z.number(),
configuration: z.string().nullable(),
costIncrease: z.boolean(),
countSeats: z.number(),
creditRate: z.number(),
dealer: z.string().nullable(),
dealerBroker: z.string().nullable(),
dealerBrokerRewardCondition: z.string().nullable(),
dealerBrokerRewardSumm: z.number(),
dealerPerson: z.string().nullable(),
dealerRewardCondition: z.string().nullable(),
dealerRewardSumm: z.number(),
deliveryTime: z.number().nullable(),
disableChecks: z.boolean(),
engineHours: z.number(),
engineType: z.number().nullable(),
engineVolume: z.number(),
finDepartmentRewardCondtion: z.string().nullable(),
finDepartmentRewardSumm: z.number(),
firstPaymentPerc: z.number(),
firstPaymentRub: z.number(),
fuelCard: z.string().nullable(),
fullPriceWithDiscount: z.boolean(),
GPSBrand: z.string().nullable(),
GPSModel: z.string().nullable(),
graphType: z.number().nullable(),
highSeasonStart: z.number().nullable(),
importerRewardPerc: z.number(),
importerRewardRub: z.number(),
importProgram: z.string().nullable(),
importProgramSum: z.number(),
indAgent: z.string().nullable(),
indAgentRewardCondition: z.string().nullable(),
indAgentRewardSumm: z.number(),
insAgeDrivers: z.number(),
insDecentral: z.boolean(),
insExpDrivers: z.number(),
insFranchise: z.number(),
insNSIB: z.string().nullable(),
insUnlimitDrivers: z.boolean(),
insurance: z.boolean(),
IRR_Perc: z.number(),
lastPaymentPerc: z.number(),
lastPaymentRedemption: z.boolean(),
lastPaymentRub: z.number(),
lastPaymentRule: z.number().nullable(),
lead: z.string().nullable(),
leaseObjectCategory: z.number().nullable(),
leaseObjectCount: z.number(),
leaseObjectMotorPower: z.number(),
leaseObjectPrice: z.number(),
leaseObjectPriceWthtVAT: z.number(),
leaseObjectType: z.string().nullable(),
leaseObjectUsed: z.boolean(),
leaseObjectUseFor: z.number().nullable(),
leaseObjectYear: z.number(),
leasingPeriod: z.number(),
leasingWithoutKasko: z.string().nullable(),
legalClientRegion: z.string().nullable(),
legalClientTown: z.string().nullable(),
maxMass: z.number(),
maxPriceChange: z.number(),
maxSpeed: z.number(),
mileage: z.number(),
minPriceChange: z.number(),
model: z.string().nullable(),
NSIB: z.boolean(),
objectCategoryTax: z.number().nullable(),
objectRegionRegistration: z.string().nullable(),
objectRegistration: z.number().nullable(),
objectTypeTax: z.number().nullable(),
opportunity: z.string().nullable(),
parmentsDecreasePercent: z.number(),
priceWithDiscount: z.boolean(),
product: z.string().nullable(),
quote: z.string().nullable(),
quoteContactGender: z.number().nullable(),
quoteName: z.string().nullable(),
quoteRedemptionGraph: z.boolean(),
rate: z.string().nullable(),
recalcWithRevision: z.boolean(),
redemptionPaymentSum: z.number(),
regionRegistration: z.string().nullable(),
registration: z.string().nullable(),
registrationQuote: z.boolean(),
requirementTelematic: z.number().nullable(),
saleBonus: z.number(),
seasonType: z.number().nullable(),
showFinGAP: z.boolean(),
subsidy: z.string().nullable(),
supplierCurrency: z.string().nullable(),
supplierDiscountPerc: z.number(),
supplierDiscountRub: z.number(),
tarif: z.string().nullable(),
technicalCard: z.string().nullable(),
technicalCardQuote: z.boolean(),
telematic: z.string().nullable(),
totalPayments: z.number(),
townRegistration: z.string().nullable(),
tracker: z.string().nullable(),
typePTS: z.number().nullable(),
VATInLeaseObjectPrice: z.number(),
vehicleTaxInLeasingPeriod: z.number(),
vehicleTaxInYear: z.number(),
withTrailer: z.boolean(),
vin: z.string().nullable(),
const ValuesSchema = z.object({
addEquipmentPrice: z.number(),
balanceHolder: z.number().nullable(),
bonusCoefficient: z.number(),
brand: z.string().nullable(),
calcBroker: z.string().nullable(),
calcBrokerRewardCondition: z.string().nullable(),
calcBrokerRewardSum: z.number(),
calcDoubleAgent: z.string().nullable(),
calcDoubleAgentRewardCondition: z.string().nullable(),
calcDoubleAgentRewardSumm: z.number(),
calcFinDepartment: z.string().nullable(),
calcType: z.number().nullable(),
clientRisk: z.string().nullable(),
clientType: z.string().nullable(),
comissionPerc: z.number(),
comissionRub: z.number(),
configuration: z.string().nullable(),
costIncrease: z.boolean(),
countSeats: z.number(),
creditRate: z.number(),
dealer: z.string().nullable(),
dealerBroker: z.string().nullable(),
dealerBrokerRewardCondition: z.string().nullable(),
dealerBrokerRewardSumm: z.number(),
dealerPerson: z.string().nullable(),
dealerRewardCondition: z.string().nullable(),
dealerRewardSumm: z.number(),
deliveryTime: z.number().nullable(),
disableChecks: z.boolean(),
engineHours: z.number(),
engineType: z.number().nullable(),
engineVolume: z.number(),
finDepartmentRewardCondtion: z.string().nullable(),
finDepartmentRewardSumm: z.number(),
firstPaymentPerc: z.number(),
firstPaymentRub: z.number(),
fuelCard: z.string().nullable(),
fullPriceWithDiscount: z.boolean(),
GPSBrand: z.string().nullable(),
GPSModel: z.string().nullable(),
graphType: z.number().nullable(),
highSeasonStart: z.number().nullable(),
importerRewardPerc: z.number(),
importerRewardRub: z.number(),
importProgram: z.string().nullable(),
importProgramSum: z.number(),
indAgent: z.string().nullable(),
indAgentRewardCondition: z.string().nullable(),
indAgentRewardSumm: z.number(),
insAgeDrivers: z.number(),
insDecentral: z.boolean(),
insExpDrivers: z.number(),
insFranchise: z.number(),
insNSIB: z.string().nullable(),
insUnlimitDrivers: z.boolean(),
insurance: z.boolean(),
IRR_Perc: z.number(),
lastPaymentPerc: z.number(),
lastPaymentRedemption: z.boolean(),
lastPaymentRub: z.number(),
lastPaymentRule: z.number().nullable(),
lead: z.string().nullable(),
leaseObjectCategory: z.number().nullable(),
leaseObjectCount: z.number(),
leaseObjectMotorPower: z.number(),
leaseObjectPrice: z.number(),
leaseObjectPriceWthtVAT: z.number(),
leaseObjectType: z.string().nullable(),
leaseObjectUsed: z.boolean(),
leaseObjectUseFor: z.number().nullable(),
leaseObjectYear: z.number(),
leasingPeriod: z.number(),
leasingWithoutKasko: z.string().nullable(),
legalClientRegion: z.string().nullable(),
legalClientTown: z.string().nullable(),
maxMass: z.number(),
maxPriceChange: z.number(),
maxSpeed: z.number(),
mileage: z.number(),
minPriceChange: z.number(),
model: z.string().nullable(),
NSIB: z.boolean(),
objectCategoryTax: z.number().nullable(),
objectRegionRegistration: z.string().nullable(),
objectRegistration: z.number().nullable(),
objectTypeTax: z.number().nullable(),
opportunity: z.string().nullable(),
parmentsDecreasePercent: z.number(),
priceWithDiscount: z.boolean(),
product: z.string().nullable(),
quote: z.string().nullable(),
quoteContactGender: z.number().nullable(),
quoteName: z.string().nullable(),
quoteRedemptionGraph: z.boolean(),
rate: z.string().nullable(),
recalcWithRevision: z.boolean(),
redemptionPaymentSum: z.number(),
regionRegistration: z.string().nullable(),
registration: z.string().nullable(),
registrationQuote: z.boolean(),
requirementTelematic: z.number().nullable(),
saleBonus: z.number(),
seasonType: z.number().nullable(),
showFinGAP: z.boolean(),
subsidy: z.string().nullable(),
supplierCurrency: z.string().nullable(),
supplierDiscountPerc: z.number(),
supplierDiscountRub: z.number(),
tarif: z.string().nullable(),
technicalCard: z.string().nullable(),
technicalCardQuote: z.boolean(),
telematic: z.string().nullable(),
totalPayments: z.number(),
townRegistration: z.string().nullable(),
tracker: z.string().nullable(),
typePTS: z.number().nullable(),
VATInLeaseObjectPrice: z.number(),
vehicleTaxInLeasingPeriod: z.number(),
vehicleTaxInYear: z.number(),
withTrailer: z.boolean(),
vin: z.string().nullable(),
/**
* Link Values
*/
kpUrl: z.string().nullable(),
leadUrl: z.string().nullable(),
opportunityUrl: z.string().nullable(),
quoteUrl: z.string().nullable(),
/**
* Link Values
*/
kpUrl: z.string().nullable(),
leadUrl: z.string().nullable(),
opportunityUrl: z.string().nullable(),
quoteUrl: z.string().nullable(),
/**
* Readonly Values
*/
depreciationGroup: z.string().nullable(),
discountRub: z.number(),
insKaskoPriceLeasePeriod: z.number(),
irrInfo: z.string().nullable(),
leaseObjectRiskName: z.string().nullable(),
plPriceRub: z.number(),
registrationDescription: z.string().nullable(),
subsidySum: z.number(),
})
.strict();
/**
* Readonly Values
*/
depreciationGroup: z.string().nullable(),
discountRub: z.number(),
insKaskoPriceLeasePeriod: z.number(),
irrInfo: z.string().nullable(),
leaseObjectRiskName: z.string().nullable(),
plPriceRub: z.number(),
registrationDescription: z.string().nullable(),
subsidySum: z.number(),
});
export default ValuesSchema;

View File

@ -1,2 +1,3 @@
export * from './get-kp-data';
export * as reactions from './reactions';
export * from './validation';

View File

@ -15,7 +15,7 @@ export function createValidationSchema(context: ValidationContext) {
if (round(saleBonus, 2) > round(maxBonus, 2)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Размер бонуса МПЛ не может быть выше установленного по СОТ',
message: 'Бонус не может быть выше установленного по СОТ',
path: ['tbxSaleBonus'],
});
}

View File

@ -1 +1,34 @@
export function action() {}
import type { ProcessContext } from '../types';
import { toJS } from 'mobx';
import notification from 'ui/elements/notification';
const key = 'ACTION_CALCULATE';
const message = 'Ошибка во время расчета графика';
export async function action({ store, trpcClient }: ProcessContext) {
const { $calculation, $tables } = store;
const values = $calculation.$values.getValues();
const insurance = {
fingap: toJS($tables.insurance.row('fingap').getValues()),
kasko: toJS($tables.insurance.row('kasko').getValues()),
osago: toJS($tables.insurance.row('osago').getValues()),
};
const payments = toJS($tables.payments.values);
const { error, success } = await trpcClient.calculate.calculate.query({
insurance: { values: insurance },
payments: { values: payments },
values,
});
if (!success) {
notification.error({
description: error,
key,
message,
});
}
}

View File

@ -1,2 +1,3 @@
export * from './get-kp-data';
export * as reactions from './reactions';
export * from './validation';

View File

@ -1,2 +1,3 @@
export * from './get-kp-data';
export * as reactions from './reactions';
export * from './validation';

View File

@ -1,21 +1,27 @@
import type { Process } from '@/process/types';
import type { Process, ProcessContext } from '@/process/types';
import { useStore } from '@/stores/hooks';
import { trpcPureClient } from '@/trpc/client';
import { useApolloClient } from '@apollo/client';
import { useQueryClient } from '@tanstack/react-query';
export function useProcess({ reactions }: Process) {
const context = useProcessContext();
Object.keys(reactions).forEach((name) => {
const injector = reactions[name];
injector(context);
});
}
export function useProcessContext(): ProcessContext {
const store = useStore();
const apolloClient = useApolloClient();
const queryClient = useQueryClient();
Object.keys(reactions).forEach((name) => {
const injector = reactions[name];
injector({
apolloClient,
queryClient,
store,
trpcClient: trpcPureClient,
});
});
return {
apolloClient,
queryClient,
store,
trpcClient: trpcPureClient,
};
}

View File

@ -1,2 +1,3 @@
export * from './get-kp-data';
export * as reactions from './reactions';
export * from './validation';

View File

@ -285,9 +285,11 @@ export function validation(context: ProcessContext) {
return {
insurance: {
fingap: toJS($tables.insurance.row('fingap').getValues()),
kasko: toJS($tables.insurance.row('kasko').getValues()),
osago: toJS($tables.insurance.row('osago').getValues()),
values: {
fingap: toJS($tables.insurance.row('fingap').getValues()),
kasko: toJS($tables.insurance.row('kasko').getValues()),
osago: toJS($tables.insurance.row('osago').getValues()),
},
},
...values,
};

View File

@ -1,19 +1,11 @@
/* eslint-disable zod/require-strict */
import type { ValidationContext } from '../types';
import type * as Insurance from '@/Components/Calculation/Form/Insurance/InsuranceTable/types';
import { RowSchema } from '@/config/schema/insurance';
import { InsuranceSchema } from '@/config/schema/insurance';
import ValuesSchema from '@/config/schema/values';
import * as CRMTypes from '@/graphql/crm.types';
import { z } from 'zod';
const InsuranceSchema = z.object({
insurance: z.object({
fingap: RowSchema,
kasko: RowSchema,
osago: RowSchema,
}),
});
export function createValidationSchema({ apolloClient }: ValidationContext) {
return ValuesSchema.pick({
insDecentral: true,
@ -22,7 +14,10 @@ export function createValidationSchema({ apolloClient }: ValidationContext) {
quote: true,
recalcWithRevision: true,
})
.merge(InsuranceSchema)
.extend({
insurance: InsuranceSchema,
})
.superRefine(
async (
{
@ -46,7 +41,7 @@ export function createValidationSchema({ apolloClient }: ValidationContext) {
recalcWithRevision &&
quote?.evo_one_year_insurance === true &&
leasingPeriod > 15 &&
insurance.kasko.insTerm === 100_000_001
insurance.values.kasko.insTerm === 100_000_001
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
@ -58,7 +53,7 @@ export function createValidationSchema({ apolloClient }: ValidationContext) {
}
(['osago', 'kasko'] as Insurance.Keys[]).forEach((key) => {
const { insCost, insured, policyType, insuranceCompany, insTerm } = insurance[key];
const { insCost, insured, policyType, insuranceCompany, insTerm } = insurance.values[key];
if (insured === 100_000_001 && insCost < 1000) {
ctx.addIssue({
@ -96,14 +91,14 @@ export function createValidationSchema({ apolloClient }: ValidationContext) {
if (
!leasingWithoutKasko &&
!insDecentral &&
insurance.osago.insuranceCompany &&
insurance.kasko.insuranceCompany !== insurance.osago.insuranceCompany
insurance.values.osago.insuranceCompany &&
insurance.values.kasko.insuranceCompany !== insurance.values.osago.insuranceCompany
) {
const {
data: { account },
} = await apolloClient.query({
query: CRMTypes.GetInsuranceCompanyDocument,
variables: { accountId: insurance.osago.insuranceCompany },
variables: { accountId: insurance.values.osago.insuranceCompany },
});
if (account?.evo_osago_with_kasko) {

View File

@ -1,2 +1,3 @@
export * from './get-kp-data';
export * as reactions from './reactions';
export * from './validation';

View File

@ -1,2 +1,3 @@
export * from './get-kp-data';
export * as reactions from './reactions';
export * from './validation';

View File

@ -1,2 +1,3 @@
export * from './get-kp-data';
export * as reactions from './reactions';
export * from './validation';

View File

@ -117,7 +117,8 @@ export default function reactions({ store, apolloClient }: ProcessContext) {
reaction(
() => $calculation.element('tbxFirstPaymentRub').getValue(),
(firstPaymentRub) => {
const { plPriceRub, addEquipmentPrice, importProgramSum } = $calculation.$values.values;
const { plPriceRub, addEquipmentPrice, importProgramSum } =
$calculation.$values.getValues();
const perc =
(firstPaymentRub / (plPriceRub + addEquipmentPrice - importProgramSum)) * 100;
$calculation.element('tbxFirstPaymentPerc').setValue(perc);
@ -139,7 +140,7 @@ export default function reactions({ store, apolloClient }: ProcessContext) {
reaction(
() => $calculation.element('tbxComissionRub').getValue(),
(comissionRub) => {
const { plPriceRub } = $calculation.$values.values;
const { plPriceRub } = $calculation.$values.getValues();
const perc = (comissionRub / plPriceRub) * 100;
$calculation.element('tbxComissionPerc').setValue(perc);
}
@ -170,7 +171,8 @@ export default function reactions({ store, apolloClient }: ProcessContext) {
reaction(
() => $calculation.element('tbxLastPaymentRub').getValue(),
(lastPaymentRub) => {
const { plPriceRub, addEquipmentPrice, importProgramSum } = $calculation.$values.values;
const { plPriceRub, addEquipmentPrice, importProgramSum } =
$calculation.$values.getValues();
const perc = (lastPaymentRub / (plPriceRub + addEquipmentPrice - importProgramSum)) * 100;
$calculation.element('tbxLastPaymentPerc').setValue(perc);
}

View File

@ -1 +1,2 @@
export * as reactions from './reactions';
export * from './validation';

View File

@ -1,2 +1,3 @@
export * from './get-kp-data';
export * as reactions from './reactions';
export * from './validation';

View File

@ -14,4 +14,4 @@ export type Process = {
reactions: Record<string, (context: ProcessContext) => void>;
};
export type ValidationContext = Omit<ProcessContext, 'store'>;
export type ValidationContext = Omit<ProcessContext, 'store' | 'trpcClient'>;

View File

@ -1 +1,2 @@
export * as reactions from './reactions';
export * from './validation';

View File

@ -1,12 +1,12 @@
import type RootStore from '../../root';
import type { CalculationValues, Values } from './types';
import defaultValues from '@/config/default-values';
import { makeAutoObservable } from 'mobx';
import { makeAutoObservable, toJS } from 'mobx';
import { pick } from 'radash';
export default class ValuesStore {
private root: RootStore;
public values = defaultValues;
private values = defaultValues;
constructor(rootStore: RootStore) {
makeAutoObservable(this);
@ -17,7 +17,11 @@ export default class ValuesStore {
this.values = { ...defaultValues, ...initialValues };
};
public getValues = <K extends keyof CalculationValues>(keys: K[]) => pick(this.values, keys);
public getValues = <K extends keyof CalculationValues>(keys?: K[]) => {
if (keys) return pick(this.values, keys);
return toJS(this.values);
};
public setValues = (values: Partial<CalculationValues>) => {
(Object.keys(values) as Array<keyof CalculationValues>).forEach((valueName) => {

View File

@ -0,0 +1,37 @@
import { t } from '../../server';
import { CalculateInputSchema, CalculateOutputSchema } from './types';
import { validate } from './validation';
import initializeApollo from '@/apollo/client';
import { QueryClient } from '@tanstack/react-query';
const calculateRouter = t.router({
calculate: t.procedure
.input(CalculateInputSchema)
.output(CalculateOutputSchema)
.query(async ({ input }) => {
const apolloClient = initializeApollo();
const queryClient = new QueryClient();
const { success, error } = await validate({
context: {
apolloClient,
queryClient,
},
input,
});
if (!success) {
return {
error,
success,
};
}
return {
error: undefined,
success,
};
}),
});
export default calculateRouter;

View File

@ -0,0 +1,17 @@
import { InsuranceSchema } from '@/config/schema/insurance';
import PaymentsSchema from '@/config/schema/payments';
import ValuesSchema from '@/config/schema/values';
import { z } from 'zod';
export const CalculateInputSchema = z
.object({
insurance: InsuranceSchema,
payments: PaymentsSchema,
values: ValuesSchema,
})
.strict();
export const CalculateOutputSchema = z.object({
error: z.string().optional(),
success: z.boolean(),
});

View File

@ -0,0 +1,73 @@
import type { CalculateInputSchema } from './types';
import { CalculateOutputSchema } from './types';
import elementsTitles from '@/Components/Calculation/config/elements-titles';
import type { Elements } from '@/Components/Calculation/config/map/values';
import * as bonuses from '@/process/bonuses';
import * as configurator from '@/process/configurator';
import * as gibdd from '@/process/gibdd';
import * as insuranceProcess from '@/process/insurance';
import * as leasingObject from '@/process/leasing-object';
import * as paymentsProcess from '@/process/payments';
import * as price from '@/process/price';
import * as supplierAgent from '@/process/supplier-agent';
import type { ValidationContext } from '@/process/types';
import type { z, ZodIssue } from 'zod';
const processes = [
configurator,
supplierAgent,
paymentsProcess,
price,
bonuses,
leasingObject,
gibdd,
insuranceProcess,
];
const titles = Object.assign(elementsTitles, {
insurance: 'Таблица страхования',
payments: 'Таблица платежей',
});
function getMessage(errors: ZodIssue[]) {
const elementName = errors?.at(0)?.path.at(0) as Elements;
const title = titles[elementName];
const message = errors?.at(0)?.message;
return `${title}: ${message}`;
}
const ValidationOutputSchema = CalculateOutputSchema.pick({
error: true,
success: true,
});
type ValidationOutput = z.infer<typeof ValidationOutputSchema>;
type ValidationInput = z.infer<typeof CalculateInputSchema>;
export async function validate({
input,
context,
}: {
context: ValidationContext;
input: ValidationInput;
}): Promise<ValidationOutput> {
for (const { createValidationSchema } of processes) {
const validationSchema = createValidationSchema(context);
const validationResult = await validationSchema.safeParseAsync({
...input.values,
insurance: input.insurance,
payments: input.payments,
});
if (validationResult.success === false) {
const error = getMessage(validationResult.error.errors);
return { error, success: false };
}
}
return {
success: true,
};
}

View File

@ -1,7 +1,9 @@
import { t } from '../server';
import calculateRouter from './calculate';
import quoteRouter from './quote';
const appRouter = t.router({
calculate: calculateRouter,
quote: quoteRouter,
});