validate saleBonus using zod
This commit is contained in:
parent
5748bb9ffd
commit
91899164c0
@ -25,12 +25,12 @@ const AlertWrapper = styled(Box)`
|
||||
|
||||
function getElementsErrors($calculation) {
|
||||
return Object.values($calculation.$validation).map((validation) => {
|
||||
const elementErrors = validation.getMessages();
|
||||
const elementErrors = validation.getErrors();
|
||||
const elementTitle = validation.params.err_title;
|
||||
|
||||
return elementErrors.map((error) => (
|
||||
return elementErrors.map(({ key, message }) => (
|
||||
<AlertWrapper>
|
||||
<Alert type="error" showIcon message={Message(elementTitle, error)} />
|
||||
<Alert key={key} type="error" showIcon message={Message(elementTitle, message)} />
|
||||
</AlertWrapper>
|
||||
));
|
||||
});
|
||||
@ -38,18 +38,22 @@ function getElementsErrors($calculation) {
|
||||
|
||||
function getPaymentsTableErrors($tables) {
|
||||
const { payments } = $tables;
|
||||
const messages = payments.validation.getMessages();
|
||||
const errors = payments.validation.getErrors();
|
||||
const title = payments.validation.params.err_title;
|
||||
|
||||
return messages.map((text) => <Alert type="error" showIcon message={Message(title, text)} />);
|
||||
return errors.map(({ key, message }) => (
|
||||
<Alert key={key} type="error" showIcon message={Message(title, message)} />
|
||||
));
|
||||
}
|
||||
|
||||
function getInsuranceTableErrors($tables) {
|
||||
const { insurance } = $tables;
|
||||
const messages = insurance.validation.getMessages();
|
||||
const errors = insurance.validation.getErrors();
|
||||
const title = insurance.validation.params.err_title;
|
||||
|
||||
return messages.map((text) => <Alert type="error" showIcon message={Message(title, text)} />);
|
||||
return errors.map(({ key, message }) => (
|
||||
<Alert key={key} type="error" showIcon message={Message(title, message)} />
|
||||
));
|
||||
}
|
||||
|
||||
const Errors = observer(() => {
|
||||
|
||||
@ -1,40 +1,40 @@
|
||||
import * as addProduct from '@/process/add-product';
|
||||
// import * as addProduct from '@/process/add-product';
|
||||
import * as bonuses from '@/process/bonuses';
|
||||
import * as calculate from '@/process/calculate';
|
||||
import * as configurator from '@/process/configurator';
|
||||
import * as createKP from '@/process/create-kp';
|
||||
import * as fingap from '@/process/fingap';
|
||||
import * as gibdd from '@/process/gibdd';
|
||||
// import * as calculate from '@/process/calculate';
|
||||
// import * as configurator from '@/process/configurator';
|
||||
// import * as createKP from '@/process/create-kp';
|
||||
// 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 leadOpportunity from '@/process/lead-opportunity';
|
||||
import * as leasingObject from '@/process/leasing-object';
|
||||
import * as leasingWithoutKasko from '@/process/leasing-without-kasko';
|
||||
import * as loadKP from '@/process/load-kp';
|
||||
import * as payments from '@/process/payments';
|
||||
import * as price from '@/process/price';
|
||||
import * as subsidy from '@/process/subsidy';
|
||||
import * as subsidyImportProgram from '@/process/subsidy-import-program';
|
||||
import * as supplierAgent from '@/process/supplier-agent';
|
||||
import * as usedPl from '@/process/used-pl';
|
||||
// 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';
|
||||
// import * as loadKP from '@/process/load-kp';
|
||||
// import * as payments from '@/process/payments';
|
||||
// import * as price from '@/process/price';
|
||||
// import * as subsidy from '@/process/subsidy';
|
||||
// import * as subsidyImportProgram from '@/process/subsidy-import-program';
|
||||
// import * as supplierAgent from '@/process/supplier-agent';
|
||||
// import * as usedPl from '@/process/used-pl';
|
||||
|
||||
export default function useReactions() {
|
||||
useProcess(leadOpportunity);
|
||||
useProcess(loadKP);
|
||||
useProcess(calculate);
|
||||
useProcess(supplierAgent);
|
||||
useProcess(price);
|
||||
useProcess(fingap);
|
||||
useProcess(leasingWithoutKasko);
|
||||
useProcess(subsidy);
|
||||
useProcess(leasingObject);
|
||||
useProcess(configurator);
|
||||
useProcess(createKP);
|
||||
// useProcess(leadOpportunity);
|
||||
// useProcess(loadKP);
|
||||
// useProcess(calculate);
|
||||
// useProcess(supplierAgent);
|
||||
// useProcess(price);
|
||||
// useProcess(fingap);
|
||||
// useProcess(leasingWithoutKasko);
|
||||
// useProcess(subsidy);
|
||||
// useProcess(leasingObject);
|
||||
// useProcess(configurator);
|
||||
// useProcess(createKP);
|
||||
useProcess(bonuses);
|
||||
useProcess(usedPl);
|
||||
useProcess(subsidyImportProgram);
|
||||
useProcess(payments);
|
||||
useProcess(gibdd);
|
||||
useProcess(addProduct);
|
||||
useProcess(insurance);
|
||||
// useProcess(usedPl);
|
||||
// useProcess(subsidyImportProgram);
|
||||
// useProcess(payments);
|
||||
// useProcess(gibdd);
|
||||
// useProcess(addProduct);
|
||||
// useProcess(insurance);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import type { ProcessContext } from '../../../types';
|
||||
import type { ProcessContext } from '../../types';
|
||||
import { getUser } from '@/api/user/query';
|
||||
import type { ElementsTypes } from '@/Components/Calculation/config/map/values';
|
||||
import { STALE_TIME } from '@/constants/request';
|
||||
@ -1,6 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import type { ProcessContext } from '../../types';
|
||||
import helper from './lib/helper';
|
||||
import helper from '../lib/helper';
|
||||
import { makeDisposable } from '@/../../packages/tools';
|
||||
import * as CRMTypes from '@/graphql/crm.types';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
@ -1,23 +1,32 @@
|
||||
import helper from './lib/helper';
|
||||
import { createValidationSchema } from '../validation';
|
||||
import type { Elements } from '@/Components/Calculation/config/map/values';
|
||||
import type { ProcessContext } from '@/process/types';
|
||||
import ValidationHelper from '@/stores/validation/helper';
|
||||
import { reaction } from 'mobx';
|
||||
import { round } from 'tools';
|
||||
import { uid } from 'radash';
|
||||
|
||||
const key = uid(7);
|
||||
|
||||
export default function reactions(context: ProcessContext) {
|
||||
const { store } = context;
|
||||
const { $calculation } = store;
|
||||
const { getCoefficient } = helper(context);
|
||||
const validationSchema = createValidationSchema(context);
|
||||
|
||||
const helper = new ValidationHelper();
|
||||
reaction(
|
||||
() => $calculation.$values.getValues(['product', 'saleBonus']),
|
||||
async ({ product: productId, saleBonus }) => {
|
||||
const coefficient = await getCoefficient(productId);
|
||||
const maxBonus = (coefficient?.evo_sot_coefficient || 0) * 100;
|
||||
async (values) => {
|
||||
helper.removeErrors();
|
||||
const validationResult = await validationSchema.safeParseAsync(values);
|
||||
|
||||
$calculation.element('tbxSaleBonus').validate({
|
||||
invalid: round(saleBonus, 2) > round(maxBonus, 2),
|
||||
message: 'Размер бонуса МПЛ не может быть выше установленного по СОТ',
|
||||
});
|
||||
if (!validationResult.success) {
|
||||
validationResult.error.errors.forEach(({ path, message }) => {
|
||||
(path as Elements[]).forEach((elementName) => {
|
||||
const removeError = $calculation.element(elementName).setError({ key, message });
|
||||
if (removeError) helper.add(removeError);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
24
apps/web/process/bonuses/validation.ts
Normal file
24
apps/web/process/bonuses/validation.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import type { ProcessContext } from '../types';
|
||||
import helper from './lib/helper';
|
||||
import ValuesSchema from '@/config/schema/values';
|
||||
import { round } from 'tools';
|
||||
import { z } from 'zod';
|
||||
|
||||
export function createValidationSchema(context: ProcessContext) {
|
||||
const { getCoefficient } = helper(context);
|
||||
|
||||
return ValuesSchema.pick({ product: true, saleBonus: true }).superRefine(
|
||||
async ({ product, saleBonus }, ctx) => {
|
||||
const coefficient = await getCoefficient(product);
|
||||
const maxBonus = (coefficient?.evo_sot_coefficient || 0) * 100;
|
||||
|
||||
if (round(saleBonus, 2) > round(maxBonus, 2)) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: 'Размер бонуса МПЛ не может быть выше установленного по СОТ',
|
||||
path: ['tbxSaleBonus'],
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -21,6 +21,7 @@ export default function reactions({ store }: ProcessContext) {
|
||||
const hasElementsErrors = Object.values($calculation.$validation).some(
|
||||
(validation) => validation.hasErrors
|
||||
);
|
||||
|
||||
const hasPaymentsErrors = $tables.payments.validation.hasErrors;
|
||||
const hasInsuranceErrors = $tables.insurance.validation.hasErrors;
|
||||
const hasFingapErrors = $tables.fingap.validation.hasErrors;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import type { RemoveError, ValidationParams } from '../validation/types';
|
||||
import type { ValidationParams } from '../validation/types';
|
||||
import OptionsStore from './options';
|
||||
import StatusStore from './statuses';
|
||||
import ValuesStore from './values';
|
||||
@ -56,6 +56,10 @@ export default class CalculationStore {
|
||||
return this.$values.getValue(valueName) as Values.ElementsTypes[E];
|
||||
},
|
||||
|
||||
removeError: (params: Pick<ValidationParams, 'key'>) => {
|
||||
this.$validation[elementName]?.removeError(params);
|
||||
},
|
||||
|
||||
reset: () => {
|
||||
const valueName = getValueName(elementName);
|
||||
this.$values.resetValue(valueName);
|
||||
@ -80,6 +84,12 @@ export default class CalculationStore {
|
||||
return this.element(elementName);
|
||||
},
|
||||
|
||||
setError: (params: ValidationParams) => {
|
||||
if (!this.$validation[elementName]) this.createElementValidation(elementName);
|
||||
|
||||
return this.$validation[elementName]?.setError(params);
|
||||
},
|
||||
|
||||
setOptions: (options: Array<BaseOption<Values.ElementsTypes[E]>>) => {
|
||||
this.$options.setOptions(elementName, options);
|
||||
|
||||
@ -98,20 +108,5 @@ export default class CalculationStore {
|
||||
|
||||
return this.element(elementName);
|
||||
},
|
||||
|
||||
validate: ({ invalid, message, silent, helper }: ValidationParams) => {
|
||||
if (!this.$validation[elementName]) this.createElementValidation(elementName);
|
||||
|
||||
let removeError: RemoveError | undefined;
|
||||
|
||||
if (invalid) {
|
||||
removeError = this.$validation[elementName]?.addError(message, silent);
|
||||
if (helper && removeError) helper.add(removeError);
|
||||
} else {
|
||||
this.$validation[elementName]?.removeError(message);
|
||||
}
|
||||
|
||||
return removeError;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@ -2,9 +2,8 @@ import { useStore } from '@/stores/hooks';
|
||||
|
||||
export function useValidation(elementName) {
|
||||
const { $calculation } = useStore();
|
||||
const messages = $calculation.$validation[elementName]?.getMessages();
|
||||
|
||||
if (messages?.length) {
|
||||
const hasErrors = $calculation.$validation?.[elementName]?.hasErrors;
|
||||
if (hasErrors) {
|
||||
return {
|
||||
help: 'Некорректные данные',
|
||||
isValid: false,
|
||||
|
||||
@ -1,32 +1,38 @@
|
||||
import type { RemoveError, ValidationConfig } from './types';
|
||||
import type { RemoveError, ValidationConfig, ValidationError, ValidationParams } from './types';
|
||||
import { makeAutoObservable } from 'mobx';
|
||||
import notification from 'ui/elements/notification';
|
||||
|
||||
export default class Validation {
|
||||
private params: ValidationConfig;
|
||||
private messages: Set<string>;
|
||||
private errors: Set<ValidationError>;
|
||||
|
||||
constructor(config: ValidationConfig) {
|
||||
this.params = config;
|
||||
this.messages = new Set();
|
||||
this.errors = new Set();
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
|
||||
public get hasErrors() {
|
||||
return this.messages.size > 0;
|
||||
return this.errors.size > 0;
|
||||
}
|
||||
|
||||
public getMessages() {
|
||||
return [...this.messages];
|
||||
public getErrors() {
|
||||
return [...this.errors];
|
||||
}
|
||||
|
||||
public removeError = (message: string) => {
|
||||
this.messages.delete(message);
|
||||
if (this.messages.size === 0) notification.close(this.params.err_key);
|
||||
public removeError = ({ key }: Pick<ValidationError, 'key'>) => {
|
||||
const error = [...this.errors].find((x) => x.key === key);
|
||||
if (error) this.errors.delete(error);
|
||||
if (this.errors.size === 0) notification.close(this.params.err_key);
|
||||
};
|
||||
|
||||
public addError = (message: string, silent?: boolean) => {
|
||||
if (!silent && !this.messages.has(message)) {
|
||||
public setError = ({ key, message, silent }: ValidationParams) => {
|
||||
const error = [...this.errors].find((x) => x.key === key);
|
||||
if (error) this.removeError({ key });
|
||||
|
||||
this.errors.add({ key, message });
|
||||
|
||||
if (!silent) {
|
||||
notification.error({
|
||||
description: message,
|
||||
key: this.params.err_key,
|
||||
@ -34,13 +40,11 @@ export default class Validation {
|
||||
});
|
||||
}
|
||||
|
||||
this.messages.add(message);
|
||||
|
||||
return (() => this.removeError(message)) as RemoveError;
|
||||
return (() => this.removeError({ key })) as RemoveError;
|
||||
};
|
||||
|
||||
public clearErrors = () => {
|
||||
this.messages.clear();
|
||||
this.errors.clear();
|
||||
notification.close(this.params.err_key);
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,15 +1,10 @@
|
||||
import type ValidationHelper from './helper';
|
||||
|
||||
export type ValidationConfig = {
|
||||
err_key: string;
|
||||
err_title: string;
|
||||
};
|
||||
|
||||
export type ValidationParams = {
|
||||
helper?: ValidationHelper;
|
||||
invalid: boolean;
|
||||
message: string;
|
||||
silent?: boolean;
|
||||
};
|
||||
export type ValidationError = { key: string; message: string };
|
||||
|
||||
export type ValidationParams = ValidationError & { silent?: boolean };
|
||||
|
||||
export type RemoveError = () => void;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user