Compare commits

...

15 Commits

Author SHA1 Message Date
vchikalkin
e9a4612262 fix: Нельзя включать новые риски Safe Finance после рассмотрения предложения на КК 2024-05-14 11:04:15 +03:00
vchikalkin
d4b0ae503f fix: Нельзя увеличивать бонус МПЛ после рассмотрения предложения на КК 2024-05-14 10:43:03 +03:00
vchikalkin
1dd23ea03d добавили проверку fingap.insured === 100_000_001 в проверку на новые риски 2024-05-14 10:34:33 +03:00
vchikalkin
746166a59d fix: Нельзя включать новые риски Safe Finance после рассмотрения предложения на КК 2024-05-14 10:15:01 +03:00
vchikalkin
c57fc73fdc Validation.jsx: simplify code 2024-05-13 18:09:52 +03:00
vchikalkin
c82144dc7e fix show fingap alerts 2024-05-13 18:08:00 +03:00
vchikalkin
870d7b373b fix quote?.evo_committee_quote check 2024-05-13 14:20:44 +03:00
vchikalkin
7797325f8c По итогам расчета графика платежей перед выводм результата расчета заложить валидацию
если Пересчете без пересмотра recalcWithRevision = True и если в Предложении selectQuote в поле "КП по итогам КК" = Да

и значение из итогов расчета npvBonusExpensesColumn (3я строка)/ (1 + PreparedValue.SalaryRate) больше значения суммы в полях Сумма бонуса МПЛ за лизинг, руб. quote.evo_leasing_bonus_summ + Сумма бонуса МПЛ за РАТ, руб quote.evo_card_bonus_summ + Сумма бонуса МПЛ за НСИБ, руб. quote.evo_nsib_bonus_summ из Предложения , которое указано в Предложении selectQuote в поле Одобренное КА quote.evo_accept_quoteid, больше 100,

то выводить сообщение "Нельзя увеличивать бонус МПЛ после рассмотрения предложения на КК"
2024-05-08 14:03:27 +03:00
vchikalkin
009c9fb5dd На изменение Плательщик insuredFinGAP в строке SafeFinance в таблице страхования добавить проверку:
если Пересчете без пересмотра recalcWithRevision = True и если в Предложении selectQuote в поле "КП по итогам КК" = Да

и значение insuredFinGAP = 100 000 001 Лизингодатель и в поле Плательщик ФинGAP  evo_fingap_payer значение не равно 100 000 001 Лизингодатель из Предложения , которое указано в Предложении selectQuote в поле Одобренное КА quote.evo_accept_quoteid,

то выводить сообщение "Нельзя включать в график SafeFinance после рассмотрения предложения на КК"

На изменение Плательщик insuredOSAGO  в строке ОСАГО в таблице страхования добавить проверку:

если Пересчете без пересмотра recalcWithRevision = True и если в Предложении selectQuote в поле "КП по итогам КК" = Да

и значение insuredOSAGO = 100 000 001 Лизингодатель и в поле Плательщик ОСАГО evo_osago_payer значение не равно 100 000 001 Лизингодатель из Предложения , которое указано в Предложении selectQuote в поле Одобренное КА quote.evo_accept_quoteid,

то выводить сообщение "Нельзя включать в график ОСАГО после рассмотрения предложения на КК"

На изменение Плательщик insuredKASKO  в строке КАСКО в таблице страхования добавить проверку:

если Пересчете без пересмотра recalcWithRevision = True и если в Предложении selectQuote в поле "КП по итогам КК" = Да

и значение insuredKASKO  = 100 000 001 Лизингодатель и в поле Плательщик КАСКО evo_kasko_payer значение не равно 100 000 001 Лизингодатель из Предложения , которое указано в Предложении selectQuote в поле Одобренное КА quote.evo_accept_quoteid,

то выводить сообщение "Нельзя включать в график КАСКО после рассмотрения предложения на КК"
2024-05-08 13:22:32 +03:00
vchikalkin
464e3cba8d На изменение Суммы за 1-й период inscostFinGAP в строке SafeFinance в таблице страхования добавить проверку:
если Пересчете без пересмотра recalcWithRevision = True и если в Предложении selectQuote в поле "КП по итогам КК" = Да

и выбранные риски SafeFinance по Типу доп.продукта evo_addproduct_typeid содержатся в связанных Рисках по продукту evo_product_risk с Предложением , которое указано в Предложении selectQuote в поле Одобренное КА quote.evo_accept_quoteid,

то выводить сообщение "Нельзя включать новые риски SafeFinance после рассмотрения предложения на КК"
2024-05-08 13:01:56 +03:00
vchikalkin
d9c3c7e2a5 На изменение параметра На кого регистрация ТС objectRegistration добавить проверку:
если Пересчете без пересмотра recalcWithRevision = True и если в Предложении selectQuote в поле "КП по итогам КК" = Да

и На кого регистрация ТС objectRegistration  не равно значение в поле Регистрируется на (по итогам проверки УЭБ) quote.evo_db_accept_registration из Предложения , которое указано в Предложении selectQuote в поле Одобренное КА quote.evo_accept_quoteid,

то выводить сообщение "Нельзя менять регистрацию после рассмотрения предложения на КК"
2024-05-08 12:29:36 +03:00
vchikalkin
63462becc5 На изменение параметра НСИБ insNSIB добавить проверку:
если Пересчете без пересмотра recalcWithRevision = True и если в Предложении selectQuote в поле "КП по итогам КК" = Да

и НСИБ insNSIB содержит значение, а  в Предложении selectQuote, в поле Одобренное КА quote.evo_accept_quoteid указана запись Предложение, у которой в поле НСИБ quote.evo_nsib значение = Нет,

то выводить сообщение "Нельзя включать в график НСИБ после рассмотрения предложения на КК"

На изменение параметра Карта техпомощи technicalCard добавить проверку:

если Пересчете без пересмотра recalcWithRevision = True и если в Предложении selectQuote в поле "КП по итогам КК" = Да

и Карта техпомощи technicalCard содержит значение, а  в Предложении selectQuote, в поле Одобренное КА quote.evo_accept_quoteid указана запись Предложение, у которой в связанных Типах доп.продуктов evo_addproduct_type отсутствует запись, у которой Тип продукта evo_product_type = Карта тех.помощи 100 000 000,

то выводить сообщение "Нельзя включать в график карту тех.помощи после рассмотрения предложения на КК"
2024-05-08 12:27:44 +03:00
vchikalkin
ba22659578 На изменение параметра Мощность л.с. leaseObjectMotorPower добавить проверку:
если Пересчете без пересмотра recalcWithRevision = True и если в Предложении selectQuote в поле "КП по итогам КК" = Да

и текущее значение Мощность л.с. leaseObjectMotorPower минус Мощность л.с. quote.evo_power из Предложения , которое указано в Предложении selectQuote в поле Одобренное КА quote.evo_accept_quoteid, больше 10 по модулю,

то выводить сообщение "Нельзя корректировать мощность более чем на 10 л.с. после рассмотрения предложения на КК"

На изменение параметра Объем двигателя engineVolume добавить проверку:

если Пересчете без пересмотра recalcWithRevision = True и если в Предложении selectQuote в поле "КП по итогам КК" = Да

и текущее значение Объем двигателя engineVolume  минус Объем двигателя, л quote.evo_engine_volume из Предложения , которое указано в Предложении selectQuote в поле Одобренное КА quote.evo_accept_quoteid, больше 0.1 по модулю,

то выводить сообщение "Нельзя корректировать объем двигателя более чем на 0.1 л после рассмотрения предложения на КК"
2024-05-08 12:18:01 +03:00
vchikalkin
af5c9cb061 На изменение параметра IRR tbxIRR_Perc добавить проверку:
если Пересчете без пересмотра recalcWithRevision = True и если в Предложении selectQuote в поле "КП по итогам КК" = Да

и текущее значение IRR tbxIRR_Perc минус "IRR МСФО (номинал), %" quote.evo_msfo_irr для из Предложения , которое указано в Предложении selectQuote в поле Одобренное КА quote.evo_accept_quoteid, больше 0.1,

то выводить сообщение "Нельзя увеличивать IRR после рассмотрения предложения на КК"
2024-05-08 12:03:55 +03:00
vchikalkin
47807b7bda Закрыть на редактирование поля при Пересчете без пересмотра recalcWithRevision = True и если в Предложении selectQuote в поле "КП по итогам КК" = Да
Срок поставки* radioDeliveryTime
Цель использования*  selectLeaseObjectUseFor
Тип двигателя selectEngineType
Децентрализованное страхование cbxInsDecentral
2024-05-08 11:55:34 +03:00
9 changed files with 520 additions and 256 deletions

View File

@ -23,73 +23,34 @@ const AlertWrapper = styled(Box)`
margin: 0 0 5px 0;
`;
function getAlerts(errors, title, $process) {
return errors.map(({ key, message }) => (
<AlertWrapper>
<Alert
key={key}
type={$process.has('Unlimited') ? 'warning' : 'error'}
showIcon
message={Message(title, message)}
/>
</AlertWrapper>
));
}
function getElementsErrors({ $calculation, $process }) {
return Object.values($calculation.$validation).map((validation) => {
const elementErrors = validation.getErrors();
const elementTitle = validation.params.err_title;
return elementErrors.map(({ key, message }) => (
<AlertWrapper>
<Alert
key={key}
type={$process.has('Unlimited') ? 'warning' : 'error'}
showIcon
message={Message(elementTitle, message)}
/>
</AlertWrapper>
));
return getAlerts(elementErrors, elementTitle, $process);
});
}
function getPaymentsTableErrors({ $process, $tables }) {
const { payments } = $tables;
const errors = payments.validation.getErrors();
const title = payments.validation.params.err_title;
function getTableErrors(tableName, { $process, $tables }) {
const table = $tables[tableName];
const errors = table.validation.getErrors();
const title = table.validation.params.err_title;
return errors.map(({ key, message }) => (
<AlertWrapper>
<Alert
key={key}
type={$process.has('Unlimited') ? 'warning' : 'error'}
showIcon
message={Message(title, message)}
/>
</AlertWrapper>
));
}
function getInsuranceTableErrors({ $process, $tables }) {
const { insurance } = $tables;
const errors = insurance.validation.getErrors();
const title = insurance.validation.params.err_title;
return errors.map(({ key, message }) => (
<AlertWrapper>
<Alert
key={key}
type={$process.has('Unlimited') ? 'warning' : 'error'}
showIcon
message={Message(title, message)}
/>
</AlertWrapper>
));
}
function getFingapTableErrors({ $process, $tables }) {
const { fingap } = $tables;
const errors = fingap.validation.getErrors();
const title = fingap.validation.params.err_title;
return errors.map(({ key, message }) => (
<AlertWrapper>
<Alert
key={key}
type={$process.has('Unlimited') ? 'warning' : 'error'}
showIcon
message={Message(title, message)}
/>
</AlertWrapper>
));
return getAlerts(errors, title, $process);
}
const Errors = observer(() => {
@ -101,15 +62,16 @@ const Errors = observer(() => {
);
const hasPaymentsErrors = $tables.payments.validation.hasErrors;
const hasInsuranceErrors = $tables.insurance.validation.hasErrors;
const hasFingapErrors = $tables.fingap.validation.hasErrors;
if (!hasElementsErrors && !hasPaymentsErrors && !hasInsuranceErrors) {
if (!hasElementsErrors && !hasPaymentsErrors && !hasInsuranceErrors && !hasFingapErrors) {
return <Alert type="success" showIcon message="Ошибок нет 🙂" />;
}
const elementsErrors = getElementsErrors(store);
const paymentsErrors = getPaymentsTableErrors(store);
const insuranceErrors = getInsuranceTableErrors(store);
const fingapErrors = getFingapTableErrors(store);
const paymentsErrors = getTableErrors('payments', store);
const insuranceErrors = getTableErrors('insurance', store);
const fingapErrors = getTableErrors('fingap', store);
const errors = [...elementsErrors, ...paymentsErrors, ...insuranceErrors, ...fingapErrors];

View File

@ -110,6 +110,25 @@ query GetQuote($quoteId: Uuid!) {
evo_promotion
evo_sale_without_nds
link
evo_committee_quote
evo_msfo_irr
evo_accept_quoteid
evo_power
evo_engine_volume
evo_nsib
evo_addproduct_types {
evo_product_type
}
evo_db_accept_registration
evo_product_risks {
evo_addproduct_typeid
}
evo_fingap_payer
evo_osago_payer
evo_kasko_payer
evo_leasing_bonus_summ
evo_card_bonus_summ
evo_nsib_bonus_summ
}
}

View File

@ -2523,6 +2523,7 @@ type quote {
evo_coefficien_bonus_reducttion: Decimal
evo_comission_perc: Decimal
evo_comission_rub: Decimal
evo_committee_quote: Int
evo_contact_name: String
evo_cost_increace: Boolean
evo_cost_increase_perc: Decimal

File diff suppressed because one or more lines are too long

View File

@ -1,10 +1,11 @@
import type { ProcessContext } from '../types';
import { createValidationSchema } from './validation';
import type { Elements } from '@/Components/Calculation/config/map/values';
import * as CRMTypes from '@/graphql/crm.types';
import { createValidationReaction } from '@/process/tools';
import { reaction } from 'mobx';
export function common({ store }: ProcessContext) {
export function common({ store, apolloClient }: ProcessContext) {
const { $calculation, $tables } = store;
reaction(
@ -65,6 +66,7 @@ export function common({ store }: ProcessContext) {
// 'tbxLastPaymentRub',
'cbxPartialVAT',
];
reaction(
() => $calculation.element('cbxRecalcWithRevision').getValue(),
(recalcWithRevision) => {
@ -79,7 +81,53 @@ export function common({ store }: ProcessContext) {
}
}
);
}
{
/**
* Закрыть на редактирование поля при Пересчете без пересмотра recalcWithRevision = True и если в Предложении selectQuote в поле "КП по итогам КК" = Да
* Срок поставки* radioDeliveryTime
* Цель использования* selectLeaseObjectUseFor
* Тип двигателя selectEngineType
* Децентрализованное страхование cbxInsDecentral
*/
const elements: Elements[] = [
'radioDeliveryTime',
'selectLeaseObjectUseFor',
'selectEngineType',
'cbxInsDecentral',
];
reaction(
() => $calculation.$values.getValues(['recalcWithRevision', 'quote']),
async ({ recalcWithRevision, quote: quoteId }) => {
if (!recalcWithRevision || !quoteId) {
elements.forEach((elementName) => $calculation.$status.clearOverridedStatus(elementName));
return;
}
const {
data: { quote },
} = await apolloClient.query({
query: CRMTypes.GetQuoteDocument,
variables: {
quoteId,
},
});
if (quote?.evo_committee_quote === 100_000_000) {
elements.forEach((elementName) =>
$calculation.$status.overrideStatus(elementName, 'Disabled')
);
} else {
elements.forEach((elementName) => $calculation.$status.clearOverridedStatus(elementName));
}
}
);
}
{
const agents: Elements[] = [
'selectCalcBrokerRewardCondition',
'selectCalcDoubleAgentRewardCondition',

View File

@ -1,6 +1,9 @@
/* eslint-disable sonarjs/cognitive-complexity */
/* eslint-disable complexity */
import type { ValidationContext } from '../types';
import type { Elements } from '@/Components/Calculation/config/map/values';
import { FinGAPSchema } from '@/config/schema/fingap';
import { InsuranceSchema } from '@/config/schema/insurance';
import ValuesSchema from '@/config/schema/values';
import { MAX_MASS, VEHICLE_SEATS } from '@/constants/values';
import * as CRMTypes from '@/graphql/crm.types';
@ -8,221 +11,367 @@ import { z } from 'zod';
export function createValidationSchema({ apolloClient }: ValidationContext) {
return ValuesSchema.pick({
IRR_Perc: true,
addEquipmentPrice: true,
countSeats: true,
dealerPerson: true,
discountRub: true,
engineVolume: true,
firstPaymentPerc: true,
importProgramSum: true,
insNSIB: true,
lastPaymentPerc: true,
leaseObjectCategory: true,
leaseObjectCount: true,
leaseObjectMotorPower: true,
leaseObjectPriceWthtVAT: true,
leaseObjectUsed: true,
leaseObjectYear: true,
maxMass: true,
objectRegistration: true,
partialVAT: true,
plPriceRub: true,
product: true,
quote: true,
recalcWithRevision: true,
}).superRefine(
async (
{
addEquipmentPrice,
dealerPerson: dealerPersonId,
importProgramSum,
leaseObjectPriceWthtVAT,
leaseObjectUsed,
product: productId,
quote: quoteId,
recalcWithRevision,
discountRub,
plPriceRub,
firstPaymentPerc,
leaseObjectCount,
maxMass,
countSeats,
leaseObjectYear,
lastPaymentPerc,
leaseObjectCategory,
partialVAT,
},
ctx
) => {
if (!recalcWithRevision) {
return;
}
technicalCard: true,
})
.extend({
fingap: FinGAPSchema,
insurance: InsuranceSchema,
})
.superRefine(
async (
{
addEquipmentPrice,
dealerPerson: dealerPersonId,
importProgramSum,
leaseObjectPriceWthtVAT,
leaseObjectUsed,
product: productId,
quote: quoteId,
recalcWithRevision,
discountRub,
plPriceRub,
firstPaymentPerc,
leaseObjectCount,
maxMass,
countSeats,
leaseObjectYear,
lastPaymentPerc,
leaseObjectCategory,
partialVAT,
IRR_Perc,
leaseObjectMotorPower,
engineVolume,
insNSIB,
technicalCard,
objectRegistration,
fingap: fingapRisks,
insurance,
},
ctx
) => {
if (!recalcWithRevision) {
return;
}
if (!quoteId) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Не указано предложение, по которому осуществляется Пересчет без пересмотра',
path: ['selectQuote'],
});
}
if (dealerPersonId && quoteId && productId) {
const {
data: { account: dealerPerson },
} = await apolloClient.query({
query: CRMTypes.GetDealerPersonDocument,
variables: { dealerPersonId },
});
const {
data: { quote },
} = await apolloClient.query({
query: CRMTypes.GetQuoteDocument,
variables: { quoteId },
});
const maxCondition1 =
leaseObjectUsed === false &&
dealerPerson?.evo_supplier_type !== 100_000_001 &&
quote?.evo_max_price_change &&
!partialVAT &&
plPriceRub - discountRub + addEquipmentPrice - importProgramSum >
quote.evo_max_price_change;
const maxCondition2 =
leaseObjectUsed === false &&
dealerPerson?.evo_supplier_type !== 100_000_001 &&
quote?.evo_max_price_change &&
partialVAT &&
leaseObjectPriceWthtVAT >
quote.evo_max_price_change - (quote.evo_nds_in_price_supplier_currency || 0);
const maxCondition3 =
(leaseObjectUsed === true || dealerPerson?.evo_supplier_type === 100_000_001) &&
quote?.evo_supplier_currency_price &&
plPriceRub - discountRub + addEquipmentPrice - importProgramSum >
quote.evo_supplier_currency_price -
(quote.evo_discount_supplier_currency || 0) +
(quote.evo_equip_price || 0) -
(quote.evo_program_import_subsidy_sum || 0);
const minCondition1 =
!partialVAT &&
quote?.evo_min_change_price &&
plPriceRub - discountRub + addEquipmentPrice - importProgramSum <
quote.evo_min_change_price;
const minCondition2 =
partialVAT &&
quote?.evo_min_change_price &&
leaseObjectPriceWthtVAT <
quote.evo_min_change_price - (quote.evo_nds_in_price_supplier_currency || 0);
if (maxCondition1 || maxCondition2) {
if (!quoteId) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message:
'Указанная стоимость предмета лизинга больше возможного изменения стоимости предмета лизинга при пересчете без пересмотра. ' +
'Уменьшите стоимость предмета лизинга',
path: ['tbxLeaseObjectPrice'],
message: 'Не указано предложение, по которому осуществляется Пересчет без пересмотра',
path: ['selectQuote'],
});
} else if (maxCondition3) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message:
'При пересчете без пересмотра КП с ПЛ БУ или с непрофессиональным поставщиком недопустимо увеличение стоимости. Создайте новое КП и отправьте его на рассмотрение андеррайтингу для повторной проверки оценщиком.',
path: ['tbxLeaseObjectPrice'],
}
if (dealerPersonId && quoteId && productId) {
const {
data: { account: dealerPerson },
} = await apolloClient.query({
query: CRMTypes.GetDealerPersonDocument,
variables: { dealerPersonId },
});
} else if (minCondition1 || minCondition2) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message:
'Указанная стоимость предмета лизинга меньше возможного изменения стоимости предмета лизинга при пересчете без пересмотра. ' +
'Увеличьте стоимость предмета лизинга',
path: ['tbxLeaseObjectPrice'],
const {
data: { quote },
} = await apolloClient.query({
query: CRMTypes.GetQuoteDocument,
variables: { quoteId },
});
const maxCondition1 =
leaseObjectUsed === false &&
dealerPerson?.evo_supplier_type !== 100_000_001 &&
quote?.evo_max_price_change &&
!partialVAT &&
plPriceRub - discountRub + addEquipmentPrice - importProgramSum >
quote.evo_max_price_change;
const maxCondition2 =
leaseObjectUsed === false &&
dealerPerson?.evo_supplier_type !== 100_000_001 &&
quote?.evo_max_price_change &&
partialVAT &&
leaseObjectPriceWthtVAT >
quote.evo_max_price_change - (quote.evo_nds_in_price_supplier_currency || 0);
const maxCondition3 =
(leaseObjectUsed === true || dealerPerson?.evo_supplier_type === 100_000_001) &&
quote?.evo_supplier_currency_price &&
plPriceRub - discountRub + addEquipmentPrice - importProgramSum >
quote.evo_supplier_currency_price -
(quote.evo_discount_supplier_currency || 0) +
(quote.evo_equip_price || 0) -
(quote.evo_program_import_subsidy_sum || 0);
const minCondition1 =
!partialVAT &&
quote?.evo_min_change_price &&
plPriceRub - discountRub + addEquipmentPrice - importProgramSum <
quote.evo_min_change_price;
const minCondition2 =
partialVAT &&
quote?.evo_min_change_price &&
leaseObjectPriceWthtVAT <
quote.evo_min_change_price - (quote.evo_nds_in_price_supplier_currency || 0);
if (maxCondition1 || maxCondition2) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message:
'Указанная стоимость предмета лизинга больше возможного изменения стоимости предмета лизинга при пересчете без пересмотра. ' +
'Уменьшите стоимость предмета лизинга',
path: ['tbxLeaseObjectPrice'],
});
} else if (maxCondition3) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message:
'При пересчете без пересмотра КП с ПЛ БУ или с непрофессиональным поставщиком недопустимо увеличение стоимости. Создайте новое КП и отправьте его на рассмотрение андеррайтингу для повторной проверки оценщиком.',
path: ['tbxLeaseObjectPrice'],
});
} else if (minCondition1 || minCondition2) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message:
'Указанная стоимость предмета лизинга меньше возможного изменения стоимости предмета лизинга при пересчете без пересмотра. ' +
'Увеличьте стоимость предмета лизинга',
path: ['tbxLeaseObjectPrice'],
});
}
}
if (quoteId) {
const {
data: { quote },
} = await apolloClient.query({
query: CRMTypes.GetQuoteDocument,
variables: { quoteId },
});
if (
firstPaymentPerc <
(quote?.evo_approved_first_payment || 0) + (quote?.evo_percent_subsidy || 0)
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `Указанный первый платеж меньше одобренного ${quote?.evo_approved_first_payment}. При пересчете без пересмотра изменение первого платежа возможно только в большую сторону от одобренного значения`,
path: ['tbxFirstPaymentPerc'],
});
}
if (quote?.evo_recalc_limit && leaseObjectCount > quote.evo_recalc_limit) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Количество ПЛ превышает лимит пересчета без пересмотра',
path: ['tbxLeaseObjectCount'],
});
}
if (
quote?.evo_max_mass &&
((quote.evo_max_mass < MAX_MASS && maxMass >= MAX_MASS) ||
(quote?.evo_max_mass >= MAX_MASS && maxMass < MAX_MASS))
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message:
'Указанная разрешенная макс. масса выходит из утвержденного диапазона. Для изменения параметра требуется пересмотр сделки',
path: ['tbxMaxMass'],
});
}
if (
leaseObjectCategory === 100_000_003 &&
quote?.evo_seats &&
((quote.evo_seats < VEHICLE_SEATS && countSeats >= VEHICLE_SEATS) ||
(quote.evo_seats >= VEHICLE_SEATS && countSeats < VEHICLE_SEATS))
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message:
'Указанное кол-во мест выходит из утвержденного диапазона. Для изменения параметра требуется пересмотр сделки',
path: ['tbxCountSeats'],
});
}
if (quote?.evo_year && leaseObjectYear < quote.evo_year) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'При пересчете без пересмотра год выпуска нельзя уменьшать',
path: ['tbxLeaseObjectYear'],
});
}
if (
quote?.evo_last_payment_perc &&
lastPaymentPerc > 1 &&
lastPaymentPerc > quote.evo_last_payment_perc
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message:
'При пересчете без пересмотра последний платеж можно уменьшать или увеличивать до 1%',
path: ['tbxLastPaymentPerc'],
});
}
if (partialVAT !== quote?.evo_sale_without_nds) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Нельзя менять частичный НДС при пересчете без пересмотра',
path: ['selectProduct'],
});
}
if (quote?.evo_committee_quote === 100_000_000 && quote.evo_accept_quoteid) {
const {
data: { quote: accept_quote },
} = await apolloClient.query({
query: CRMTypes.GetQuoteDocument,
variables: { quoteId: quote.evo_accept_quoteid },
});
if (accept_quote?.evo_msfo_irr && IRR_Perc - accept_quote?.evo_msfo_irr > 0.1)
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Нельзя увеличивать IRR после рассмотрения предложения на КК',
path: ['tbxIRR_Perc'] as Elements[],
});
if (
accept_quote?.evo_power &&
Math.abs(leaseObjectMotorPower - accept_quote.evo_power) > 10
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message:
'Нельзя корректировать мощность более чем на 10 л.с. после рассмотрения предложения на КК',
path: ['tbxLeaseObjectMotorPower'] as Elements[],
});
}
if (
accept_quote?.evo_engine_volume &&
Math.abs(engineVolume - accept_quote.evo_engine_volume) > 0.1
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message:
'Нельзя корректировать объем двигателя более чем на 0.1 л после рассмотрения предложения на КК',
path: ['tbxEngineVolume'] as Elements[],
});
}
if (insNSIB && !accept_quote?.evo_nsib) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Нельзя включать в график НСИБ после рассмотрения предложения на КК',
path: ['selectInsNSIB'] as Elements[],
});
}
if (
technicalCard &&
!accept_quote?.evo_addproduct_types?.some((x) => x?.evo_product_type === 100_000_000)
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message:
'Нельзя включать в график карту тех.помощи после рассмотрения предложения на КК',
path: ['selectTechnicalCard'] as Elements[],
});
}
if (
objectRegistration &&
objectRegistration !== accept_quote?.evo_db_accept_registration
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Нельзя менять регистрацию после рассмотрения предложения на КК',
path: ['radioObjectRegistration'] as Elements[],
});
}
if (
insurance.values.fingap.insured === 100_000_001 &&
fingapRisks?.length > 0 &&
fingapRisks.some(
(fingapRisk) =>
!accept_quote?.evo_product_risks?.some(
(evo_product_risk) =>
fingapRisk.riskId === evo_product_risk?.evo_addproduct_typeid
)
)
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message:
'Нельзя включать новые риски Safe Finance после рассмотрения предложения на КК',
path: ['fingap'],
});
}
if (
insurance.values.fingap.insured === 100_000_001 &&
accept_quote?.evo_fingap_payer &&
insurance.values.fingap.insured !== accept_quote?.evo_fingap_payer
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message:
'Нельзя включать в график SafeFinance после рассмотрения предложения на КК',
path: ['insurance'],
});
}
if (
insurance.values.osago.insured === 100_000_001 &&
accept_quote?.evo_osago_payer &&
insurance.values.osago.insured !== accept_quote?.evo_osago_payer
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Нельзя включать в график ОСАГО после рассмотрения предложения на КК',
path: ['insurance'],
});
}
if (
insurance.values.kasko.insured === 100_000_001 &&
accept_quote?.evo_kasko_payer &&
insurance.values.kasko.insured !== accept_quote?.evo_kasko_payer
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Нельзя включать в график КАСКО после рассмотрения предложения на КК',
path: ['insurance'],
});
}
}
}
}
if (quoteId) {
const {
data: { quote },
} = await apolloClient.query({
query: CRMTypes.GetQuoteDocument,
variables: { quoteId },
});
if (
firstPaymentPerc <
(quote?.evo_approved_first_payment || 0) + (quote?.evo_percent_subsidy || 0)
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `Указанный первый платеж меньше одобренного ${quote?.evo_approved_first_payment}. При пересчете без пересмотра изменение первого платежа возможно только в большую сторону от одобренного значения`,
path: ['tbxFirstPaymentPerc'],
});
}
if (quote?.evo_recalc_limit && leaseObjectCount > quote.evo_recalc_limit) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Количество ПЛ превышает лимит пересчета без пересмотра',
path: ['tbxLeaseObjectCount'],
});
}
if (
quote?.evo_max_mass &&
((quote.evo_max_mass < MAX_MASS && maxMass >= MAX_MASS) ||
(quote?.evo_max_mass >= MAX_MASS && maxMass < MAX_MASS))
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message:
'Указанная разрешенная макс. масса выходит из утвержденного диапазона. Для изменения параметра требуется пересмотр сделки',
path: ['tbxMaxMass'],
});
}
if (
leaseObjectCategory === 100_000_003 &&
quote?.evo_seats &&
((quote.evo_seats < VEHICLE_SEATS && countSeats >= VEHICLE_SEATS) ||
(quote.evo_seats >= VEHICLE_SEATS && countSeats < VEHICLE_SEATS))
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message:
'Указанное кол-во мест выходит из утвержденного диапазона. Для изменения параметра требуется пересмотр сделки',
path: ['tbxCountSeats'],
});
}
if (quote?.evo_year && leaseObjectYear < quote.evo_year) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'При пересчете без пересмотра год выпуска нельзя уменьшать',
path: ['tbxLeaseObjectYear'],
});
}
if (
quote?.evo_last_payment_perc &&
lastPaymentPerc > 1 &&
lastPaymentPerc > quote.evo_last_payment_perc
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message:
'При пересчете без пересмотра последний платеж можно уменьшать или увеличивать до 1%',
path: ['tbxLastPaymentPerc'],
});
}
if (partialVAT !== quote?.evo_sale_without_nds) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Нельзя менять частичный НДС при пересчете без пересмотра',
path: ['selectProduct'],
});
}
}
}
);
);
}

View File

@ -1,4 +1,5 @@
import { router } from '../../trpc';
import { validateResults } from './lib/post-validation';
import { createRequestData } from './lib/request';
import { transformCalculateResults } from './lib/transform';
import { validate } from './lib/validation';
@ -52,6 +53,20 @@ export const calculateRouter = router({
const calculateResult = await calculate(requestData);
const postValidationResult = await validateResults({
calculateResult,
context: {
apolloClient,
queryClient,
user: ctx.user,
},
input,
});
if (postValidationResult.success === false) {
throw new HttpError(postValidationResult.message, 400);
}
const result = transformCalculateResults({
calculateInput: input,
requestCalculate: requestData,

View File

@ -0,0 +1,55 @@
import type { CalculateInput, Context } from '../types';
import type { ResponseCalculate } from '@/api/core/types';
import * as CRMTypes from '@/graphql/crm.types';
export async function validateResults({
input,
context,
calculateResult,
}: {
calculateResult: ResponseCalculate;
context: Context;
input: CalculateInput;
}) {
const { recalcWithRevision, quote: quoteId } = input.values;
if (recalcWithRevision && quoteId) {
const { apolloClient } = context;
const {
data: { quote },
} = await apolloClient.query({
query: CRMTypes.GetQuoteDocument,
variables: {
quoteId,
},
});
if (quote?.evo_committee_quote === 100_000_000 && quote.evo_accept_quoteid) {
const { preparedValues } = calculateResult;
const { npvBonusExpensesColumn } = calculateResult.columns;
const {
data: { quote: accept_quote },
} = await apolloClient.query({
query: CRMTypes.GetQuoteDocument,
variables: { quoteId: quote.evo_accept_quoteid },
});
if (
Math.abs(npvBonusExpensesColumn.values.at(2) || 0) / (1 + preparedValues.salaryRate) -
(accept_quote?.evo_leasing_bonus_summ || 0) >
100
) {
return {
message: 'Нельзя увеличивать бонус МПЛ после рассмотрения предложения на КК',
success: false,
};
}
}
}
return {
message: '',
success: true,
};
}

View File

@ -1,6 +1,7 @@
/* eslint-disable canonical/sort-keys */
import { protectedProcedure } from '../../procedure';
import { router } from '../../trpc';
import { validateResults } from '../calculate/lib/post-validation';
import { createRequestData } from '../calculate/lib/request';
import { transformCalculateResults } from '../calculate/lib/transform';
import { validate } from '../calculate/lib/validation';
@ -147,6 +148,20 @@ export const quoteRouter = router({
const calculateResult = await calculate(requestData);
const postValidationResult = await validateResults({
calculateResult,
context: {
apolloClient,
queryClient,
user: ctx.user,
},
input,
});
if (postValidationResult.success === false) {
throw new HttpError(postValidationResult.message, 400);
}
const requestCreateKP = compatRequestCreateKP({
domainName: user.domainName,
finGAP: input.fingap,