diff --git a/apps/web/Components/Calculation/builders/build-action.tsx b/apps/web/Components/Calculation/builders/build-action.tsx index 37df9e1..5b165b3 100644 --- a/apps/web/Components/Calculation/builders/build-action.tsx +++ b/apps/web/Components/Calculation/builders/build-action.tsx @@ -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( return observer((props: T) => { const status = useStatus(elementName); + const context = useProcessContext(); + return ( import(`process/${processName}/action`).then((module) => module.action())} + action={() => + import(`process/${processName}/action`).then((module) => module.action(context))} status={status} {...props} /> diff --git a/apps/web/config/schema/fingap.ts b/apps/web/config/schema/fingap.ts index 129130a..ca63baa 100644 --- a/apps/web/config/schema/fingap.ts +++ b/apps/web/config/schema/fingap.ts @@ -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(), +}); diff --git a/apps/web/config/schema/insurance.ts b/apps/web/config/schema/insurance.ts index 6aeda66..98b23ce 100644 --- a/apps/web/config/schema/insurance.ts +++ b/apps/web/config/schema/insurance.ts @@ -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, + }), +}); diff --git a/apps/web/config/schema/payments.ts b/apps/web/config/schema/payments.ts index bf6d566..9ef49b5 100644 --- a/apps/web/config/schema/payments.ts +++ b/apps/web/config/schema/payments.ts @@ -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; diff --git a/apps/web/config/schema/values.ts b/apps/web/config/schema/values.ts index 4c821a1..5ec7c04 100644 --- a/apps/web/config/schema/values.ts +++ b/apps/web/config/schema/values.ts @@ -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; diff --git a/apps/web/process/bonuses/index.ts b/apps/web/process/bonuses/index.ts index e05ea2d..2bcf57b 100644 --- a/apps/web/process/bonuses/index.ts +++ b/apps/web/process/bonuses/index.ts @@ -1,2 +1,3 @@ export * from './get-kp-data'; export * as reactions from './reactions'; +export * from './validation'; diff --git a/apps/web/process/bonuses/validation.ts b/apps/web/process/bonuses/validation.ts index 6727bda..564b9fc 100644 --- a/apps/web/process/bonuses/validation.ts +++ b/apps/web/process/bonuses/validation.ts @@ -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'], }); } diff --git a/apps/web/process/calculate/action.ts b/apps/web/process/calculate/action.ts index 6761e50..852f8b1 100644 --- a/apps/web/process/calculate/action.ts +++ b/apps/web/process/calculate/action.ts @@ -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, + }); + } +} diff --git a/apps/web/process/configurator/index.ts b/apps/web/process/configurator/index.ts index e05ea2d..2bcf57b 100644 --- a/apps/web/process/configurator/index.ts +++ b/apps/web/process/configurator/index.ts @@ -1,2 +1,3 @@ export * from './get-kp-data'; export * as reactions from './reactions'; +export * from './validation'; diff --git a/apps/web/process/gibdd/index.ts b/apps/web/process/gibdd/index.ts index e05ea2d..2bcf57b 100644 --- a/apps/web/process/gibdd/index.ts +++ b/apps/web/process/gibdd/index.ts @@ -1,2 +1,3 @@ export * from './get-kp-data'; export * as reactions from './reactions'; +export * from './validation'; diff --git a/apps/web/process/hooks.ts b/apps/web/process/hooks.ts index 00ba40a..d762148 100644 --- a/apps/web/process/hooks.ts +++ b/apps/web/process/hooks.ts @@ -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, + }; } diff --git a/apps/web/process/insurance/index.ts b/apps/web/process/insurance/index.ts index e05ea2d..2bcf57b 100644 --- a/apps/web/process/insurance/index.ts +++ b/apps/web/process/insurance/index.ts @@ -1,2 +1,3 @@ export * from './get-kp-data'; export * as reactions from './reactions'; +export * from './validation'; diff --git a/apps/web/process/insurance/reactions.ts b/apps/web/process/insurance/reactions.ts index b895532..52f9a86 100644 --- a/apps/web/process/insurance/reactions.ts +++ b/apps/web/process/insurance/reactions.ts @@ -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, }; diff --git a/apps/web/process/insurance/validation.ts b/apps/web/process/insurance/validation.ts index fd52ada..a2fabb4 100644 --- a/apps/web/process/insurance/validation.ts +++ b/apps/web/process/insurance/validation.ts @@ -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) { diff --git a/apps/web/process/leasing-object/index.ts b/apps/web/process/leasing-object/index.ts index e05ea2d..2bcf57b 100644 --- a/apps/web/process/leasing-object/index.ts +++ b/apps/web/process/leasing-object/index.ts @@ -1,2 +1,3 @@ export * from './get-kp-data'; export * as reactions from './reactions'; +export * from './validation'; diff --git a/apps/web/process/payments/index.ts b/apps/web/process/payments/index.ts index e05ea2d..2bcf57b 100644 --- a/apps/web/process/payments/index.ts +++ b/apps/web/process/payments/index.ts @@ -1,2 +1,3 @@ export * from './get-kp-data'; export * as reactions from './reactions'; +export * from './validation'; diff --git a/apps/web/process/price/index.ts b/apps/web/process/price/index.ts index e05ea2d..2bcf57b 100644 --- a/apps/web/process/price/index.ts +++ b/apps/web/process/price/index.ts @@ -1,2 +1,3 @@ export * from './get-kp-data'; export * as reactions from './reactions'; +export * from './validation'; diff --git a/apps/web/process/price/reactions/common.ts b/apps/web/process/price/reactions/common.ts index d393e3b..a7c53a4 100644 --- a/apps/web/process/price/reactions/common.ts +++ b/apps/web/process/price/reactions/common.ts @@ -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); } diff --git a/apps/web/process/recalc/index.ts b/apps/web/process/recalc/index.ts index 88c740a..4ea3be6 100644 --- a/apps/web/process/recalc/index.ts +++ b/apps/web/process/recalc/index.ts @@ -1 +1,2 @@ export * as reactions from './reactions'; +export * from './validation'; diff --git a/apps/web/process/supplier-agent/index.ts b/apps/web/process/supplier-agent/index.ts index e05ea2d..2bcf57b 100644 --- a/apps/web/process/supplier-agent/index.ts +++ b/apps/web/process/supplier-agent/index.ts @@ -1,2 +1,3 @@ export * from './get-kp-data'; export * as reactions from './reactions'; +export * from './validation'; diff --git a/apps/web/process/types.ts b/apps/web/process/types.ts index da05177..688d082 100644 --- a/apps/web/process/types.ts +++ b/apps/web/process/types.ts @@ -14,4 +14,4 @@ export type Process = { reactions: Record void>; }; -export type ValidationContext = Omit; +export type ValidationContext = Omit; diff --git a/apps/web/process/used-pl/index.ts b/apps/web/process/used-pl/index.ts index 88c740a..4ea3be6 100644 --- a/apps/web/process/used-pl/index.ts +++ b/apps/web/process/used-pl/index.ts @@ -1 +1,2 @@ export * as reactions from './reactions'; +export * from './validation'; diff --git a/apps/web/stores/calculation/values/index.ts b/apps/web/stores/calculation/values/index.ts index 0cb1711..60ae3f1 100644 --- a/apps/web/stores/calculation/values/index.ts +++ b/apps/web/stores/calculation/values/index.ts @@ -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 = (keys: K[]) => pick(this.values, keys); + public getValues = (keys?: K[]) => { + if (keys) return pick(this.values, keys); + + return toJS(this.values); + }; public setValues = (values: Partial) => { (Object.keys(values) as Array).forEach((valueName) => { diff --git a/apps/web/trpc/routers/calculate/index.ts b/apps/web/trpc/routers/calculate/index.ts new file mode 100644 index 0000000..409b208 --- /dev/null +++ b/apps/web/trpc/routers/calculate/index.ts @@ -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; diff --git a/apps/web/trpc/routers/calculate/types.ts b/apps/web/trpc/routers/calculate/types.ts new file mode 100644 index 0000000..47becc2 --- /dev/null +++ b/apps/web/trpc/routers/calculate/types.ts @@ -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(), +}); diff --git a/apps/web/trpc/routers/calculate/validation.ts b/apps/web/trpc/routers/calculate/validation.ts new file mode 100644 index 0000000..2fb2933 --- /dev/null +++ b/apps/web/trpc/routers/calculate/validation.ts @@ -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; +type ValidationInput = z.infer; + +export async function validate({ + input, + context, +}: { + context: ValidationContext; + input: ValidationInput; +}): Promise { + 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, + }; +} diff --git a/apps/web/trpc/routers/index.ts b/apps/web/trpc/routers/index.ts index 190e228..9b08557 100644 --- a/apps/web/trpc/routers/index.ts +++ b/apps/web/trpc/routers/index.ts @@ -1,7 +1,9 @@ import { t } from '../server'; +import calculateRouter from './calculate'; import quoteRouter from './quote'; const appRouter = t.router({ + calculate: calculateRouter, quote: quoteRouter, });