calculate pt.3: it's calculate!!!
This commit is contained in:
parent
f45ab7f3a9
commit
dbe6bdfe16
1
.env
1
.env
@ -9,6 +9,7 @@ USERS_SUPER=["akalinina","vchikalkin"]
|
||||
URL_GET_USER_DIRECT=
|
||||
URL_CRM_GRAPHQL_DIRECT=
|
||||
URL_CORE_FINGAP_DIRECT=
|
||||
URL_CORE_CALCULATE_DIRECT=
|
||||
URL_1C_TRANSTAX_DIRECT=
|
||||
|
||||
####### SERVER ########
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
/* eslint-disable canonical/sort-keys */
|
||||
import type { Payment } from './types';
|
||||
import type { ResultPayment } from '@/stores/results/types';
|
||||
import type { ColumnsType } from 'antd/lib/table';
|
||||
|
||||
export const columns: ColumnsType<Payment> = [
|
||||
export const columns: ColumnsType<ResultPayment> = [
|
||||
{
|
||||
key: 'num',
|
||||
dataIndex: 'num',
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
export type Payment = {
|
||||
key: string;
|
||||
ndsCompensation: string;
|
||||
num: number;
|
||||
paymentSum: string;
|
||||
redemptionAmount: string;
|
||||
};
|
||||
@ -1,9 +1,10 @@
|
||||
import type { Values } from '@/stores/results/types';
|
||||
import type { ResultValues } from '@/stores/results/types';
|
||||
import { moneyFormatter, percentFormatter } from 'tools';
|
||||
|
||||
export const id = 'output';
|
||||
export const title = 'Результаты';
|
||||
|
||||
export const titles: Record<Values, string> = {
|
||||
export const titles: Record<keyof ResultValues, string> = {
|
||||
resultAB_FL: 'АВ ФЛ, без НДФЛ.',
|
||||
resultAB_UL: 'АВ ЮЛ, с НДС.',
|
||||
resultBonusDopProd: 'Бонус МПЛ за доп.продукты, без НДФЛ',
|
||||
@ -18,55 +19,31 @@ export const titles: Record<Values, string> = {
|
||||
resultInsKasko: 'КАСКО, НС, ДГО в графике',
|
||||
resultInsOsago: 'ОСАГО в графике',
|
||||
resultLastPayment: 'Последний платеж',
|
||||
resultParticipationAmount: 'Сумма участия (для принятия решения)',
|
||||
resultPlPrice: 'Стоимость ПЛ с НДС',
|
||||
resultPriceUpPr: 'Удорожание, год',
|
||||
resultTerm: 'Срок, мес.',
|
||||
resultTotalGraphwithNDS: 'Итого по графику, с НДС',
|
||||
};
|
||||
|
||||
const moneyFormatters = Object.fromEntries(
|
||||
(
|
||||
[
|
||||
'resultTotalGraphwithNDS',
|
||||
'resultPlPrice',
|
||||
'resultInsKasko',
|
||||
'resultInsOsago',
|
||||
'resultDopProdSum',
|
||||
'resultFirstPayment',
|
||||
'resultLastPayment',
|
||||
'resultAB_FL',
|
||||
'resultAB_UL',
|
||||
'resultBonusMPL',
|
||||
'resultDopMPLLeasing',
|
||||
'resultBonusDopProd',
|
||||
'tbxSubsidySum',
|
||||
'resultBonusSafeFinance',
|
||||
'resultPriceUpPr',
|
||||
] as Values[]
|
||||
).map((a) => [
|
||||
a,
|
||||
Intl.NumberFormat('ru', {
|
||||
currency: 'RUB',
|
||||
style: 'currency',
|
||||
}).format,
|
||||
])
|
||||
);
|
||||
|
||||
const percentFormatters = Object.fromEntries(
|
||||
(['resultIRRGraphPerc', 'resultIRRNominalPerc', 'resultFirstPaymentRiskPolicy'] as Values[]).map(
|
||||
(a) => [
|
||||
a,
|
||||
Intl.NumberFormat('ru', {
|
||||
maximumFractionDigits: 2,
|
||||
minimumFractionDigits: 2,
|
||||
style: 'percent',
|
||||
}).format,
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
const defaultFormatters = {
|
||||
resultTerm: Intl.NumberFormat('ru').format,
|
||||
export const formatters = {
|
||||
resultAB_FL: moneyFormatter,
|
||||
resultAB_UL: moneyFormatter,
|
||||
resultBonusDopProd: moneyFormatter,
|
||||
resultBonusMPL: moneyFormatter,
|
||||
resultBonusSafeFinance: moneyFormatter,
|
||||
resultDopMPLLeasing: moneyFormatter,
|
||||
resultDopProdSum: moneyFormatter,
|
||||
resultFirstPayment: moneyFormatter,
|
||||
resultFirstPaymentRiskPolicy: percentFormatter,
|
||||
resultIRRGraphPerc: percentFormatter,
|
||||
resultIRRNominalPerc: percentFormatter,
|
||||
resultInsKasko: moneyFormatter,
|
||||
resultInsOsago: moneyFormatter,
|
||||
resultLastPayment: moneyFormatter,
|
||||
resultParticipationAmount: moneyFormatter,
|
||||
resultPlPrice: moneyFormatter,
|
||||
resultPriceUpPr: moneyFormatter,
|
||||
resultTerm: (v) => v,
|
||||
resultTotalGraphwithNDS: moneyFormatter,
|
||||
};
|
||||
|
||||
export const formatters = Object.assign(moneyFormatters, percentFormatters, defaultFormatters);
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import type { RequestFinGAP, ResponseFinGAP } from './types';
|
||||
import type { RequestCalculate, RequestFinGAP, ResponseCalculate, ResponseFinGAP } from './types';
|
||||
import getUrls from '@/config/urls';
|
||||
import type { QueryFunctionContext } from '@tanstack/react-query';
|
||||
import axios from 'axios';
|
||||
|
||||
const { URL_CORE_FINGAP } = getUrls();
|
||||
const { URL_CORE_FINGAP, URL_CORE_CALCULATE } = getUrls();
|
||||
|
||||
export async function calculateFinGAP(payload: RequestFinGAP, { signal }: QueryFunctionContext) {
|
||||
const { data } = await axios.post<ResponseFinGAP>(URL_CORE_FINGAP, payload, {
|
||||
@ -12,3 +12,11 @@ export async function calculateFinGAP(payload: RequestFinGAP, { signal }: QueryF
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function calculate(payload: RequestCalculate, { signal }: QueryFunctionContext) {
|
||||
const { data } = await axios.post<ResponseCalculate>(URL_CORE_CALCULATE, payload, {
|
||||
signal,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
425
apps/web/api/core/types/calculate.ts
Normal file
425
apps/web/api/core/types/calculate.ts
Normal file
@ -0,0 +1,425 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const PreparedValuesSchema = z.object({
|
||||
acceptSum: z.number(),
|
||||
agentsSum: z.number(),
|
||||
balanceHolder: z.number(),
|
||||
baseRatCost: z.number(),
|
||||
baseRegistration: z.number(),
|
||||
bonus: z.number(),
|
||||
bonusCoefficient: z.number(),
|
||||
bonusFinGAP: z.number(),
|
||||
bonusFix: z.number(),
|
||||
bonusNsPr: z.number(),
|
||||
bonusNsibPr: z.number(),
|
||||
bonusRatPr: z.number(),
|
||||
brandId: z.string().nullable(),
|
||||
brokerOfDeliverySum: z.number(),
|
||||
brokerSum: z.number(),
|
||||
calcDate: z.date(),
|
||||
calcType: z.number(),
|
||||
carCapacity: z.number(),
|
||||
carCarrying: z.number(),
|
||||
carSeats: z.number(),
|
||||
cityc: z.string(),
|
||||
comissionRub: z.number(),
|
||||
configurationId: z.string().nullable(),
|
||||
deliverySum: z.number(),
|
||||
deliveryTime: z.number(),
|
||||
deprecationTime: z.number(),
|
||||
directorBonus: z.number(),
|
||||
directorBonusFinGAP: z.number(),
|
||||
directorBonusFix: z.number(),
|
||||
directorBonusNsib: z.number(),
|
||||
directorExtraBonus: z.number(),
|
||||
discount: z.number(),
|
||||
districtRate: z.number(),
|
||||
doubleAgentsSum: z.number(),
|
||||
extraBonus: z.number(),
|
||||
financialDeptOfDeliverySum: z.number(),
|
||||
firstPayment: z.number(),
|
||||
firstPaymentAbs: z.number(),
|
||||
firstPaymentNdsAbs: z.number(),
|
||||
firstPaymentSum: z.number(),
|
||||
firstPaymentWithNdsAbs: z.number(),
|
||||
fuelCardSum: z.number(),
|
||||
gpsCostPaymentSum: z.number(),
|
||||
iRR_MSFO_Plan: z.number(),
|
||||
importProgramSum: z.number(),
|
||||
importerSum: z.number(),
|
||||
insuranceBonus: z.number(),
|
||||
insuranceBonusLoss: z.number(),
|
||||
insuranceContract: z.number(),
|
||||
insuranceEvoKasko: z.number(),
|
||||
insuranceFinGAP: z.number(),
|
||||
insuranceKasko: z.number(),
|
||||
insuranceKaskoNmper: z.number(),
|
||||
insuranceOsago: z.number(),
|
||||
irrExpected: z.number(),
|
||||
lastPayment: z.number(),
|
||||
lastPaymentFix: z.boolean(),
|
||||
lastPaymentSum: z.number(),
|
||||
leasing0K: z.number(),
|
||||
loanRate: z.number(),
|
||||
loanRatePeriod: z.number(),
|
||||
marketRate: z.number(),
|
||||
modelId: z.string().nullable(),
|
||||
motorVolume: z.number(),
|
||||
nmper: z.number(),
|
||||
nmperDeprecation: z.number(),
|
||||
nmperFinGAP: z.number(),
|
||||
nmperInsurance: z.number(),
|
||||
npvniDelta: z.number(),
|
||||
npvniExpected: z.number(),
|
||||
nsBonus: z.number(),
|
||||
nsibBase: z.number(),
|
||||
nsibBonus: z.number(),
|
||||
nsibBrutto: z.number(),
|
||||
nsibBruttoPr: z.number(),
|
||||
nsibNetto: z.number(),
|
||||
nsibNettoPr: z.number(),
|
||||
paymentDateNew: z.date().nullable(),
|
||||
plEngineType: z.number().nullable(),
|
||||
plPrice: z.number(),
|
||||
plPriceVAT: z.number(),
|
||||
plPriceWithVAT: z.number(),
|
||||
plTypeId: z.string().nullable(),
|
||||
plYear: z.number(),
|
||||
profitExpected: z.number(),
|
||||
ratBonus: z.number(),
|
||||
rats: z.number(),
|
||||
regionalDirectorBonus: z.number(),
|
||||
regionalDirectorBonusFinGAP: z.number(),
|
||||
regionalDirectorBonusFix: z.number(),
|
||||
regionalDirectorBonusNsib: z.number(),
|
||||
regionalDirectorExtraBonus: z.number(),
|
||||
registration: z.number(),
|
||||
repayment: z.number(),
|
||||
retroBonus: z.number(),
|
||||
salaryRate: z.number(),
|
||||
scheduleOfPayments: z.number(),
|
||||
subsidyPaymentNumber: z.number(),
|
||||
subsidySum: z.number(),
|
||||
supplierFinancing: z.boolean(),
|
||||
tLMCost: z.number(),
|
||||
tlmCostPaymentSum: z.number(),
|
||||
totalExpected: z.number(),
|
||||
trackerCost: z.number(),
|
||||
transIncludeGr: z.boolean(),
|
||||
transTax: z.number(),
|
||||
transportTaxGr: z.number(),
|
||||
transportTaxGrYear: z.number(),
|
||||
});
|
||||
|
||||
export type PreparedValues = z.infer<typeof PreparedValuesSchema>;
|
||||
|
||||
const PaymentRowSchema = z.object({
|
||||
gpsBasePayment: z.number(),
|
||||
gpsCostPayment: z.number(),
|
||||
numberPayment: z.number(),
|
||||
percentPayment: z.number(),
|
||||
sumPayment: z.number(),
|
||||
tlmBasePayment: z.number(),
|
||||
tlmCostPayment: z.number(),
|
||||
});
|
||||
|
||||
const PreparedPaymentSchema = z.object({
|
||||
rows: PaymentRowSchema.array(),
|
||||
});
|
||||
|
||||
export type PreparedPayments = z.infer<typeof PreparedPaymentSchema>;
|
||||
|
||||
const AdditionalDataSchema = z.object({
|
||||
maxAllAgencyPerc: z.number().nullable(),
|
||||
maxCashflowMSFONominal: z.number().nullable(),
|
||||
minCashflowMSFONominal: z.number().nullable(),
|
||||
});
|
||||
|
||||
export type AdditionalData = z.infer<typeof AdditionalDataSchema>;
|
||||
|
||||
export const CalculateRequestSchema = z.object({
|
||||
additionalData: AdditionalDataSchema,
|
||||
preparedPayments: PreparedPaymentSchema,
|
||||
preparedValues: PreparedValuesSchema,
|
||||
});
|
||||
|
||||
export type RequestCalculate = z.infer<typeof CalculateRequestSchema>;
|
||||
|
||||
const PostValuesSchema = z.object({
|
||||
baseCost: z.number(),
|
||||
bonusBase: z.number(),
|
||||
bonusResult: z.number(),
|
||||
contractEconomy: z.number(),
|
||||
contractEconomyWithVAT: z.number(),
|
||||
directorBonus: z.number(),
|
||||
directorExtraBonus: z.number(),
|
||||
npvni: z.number(),
|
||||
priceUP: z.number(),
|
||||
priceUP_PR: z.number(),
|
||||
priceUP_Year: z.number(),
|
||||
priceUP_Year_PR: z.number(),
|
||||
regionalDirectorBonus: z.number(),
|
||||
regionalDirectorExtraBonus: z.number(),
|
||||
});
|
||||
|
||||
const ColumnsSchema = z.object({
|
||||
acceptInsuranceColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
acceptKaskoColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
acceptOsagoColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
acceptSumColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
agentComissionExpensesColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
cashflowColumn: z.object({
|
||||
dates: z.array(z.string()),
|
||||
irr: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
cashflowLeasingColumn: z.object({
|
||||
dates: z.array(z.string()),
|
||||
irr: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
cashflowMsfoColumn: z.object({
|
||||
dates: z.array(z.string()),
|
||||
irr: z.number(),
|
||||
nominal: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
cashflowMsfoFinal2Column: z.object({
|
||||
dates: z.array(z.string()),
|
||||
irr: z.number(),
|
||||
nominal: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
cashflowMsfoFinalColumn: z.object({
|
||||
dates: z.array(z.string()),
|
||||
irr: z.number(),
|
||||
nominal: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
cashflowNpvColumn: z.object({
|
||||
values: z.number().array(),
|
||||
}),
|
||||
cashflowNpvFinal2Column: z.object({
|
||||
values: z.number().array(),
|
||||
}),
|
||||
cashflowNpvFinalColumn: z.object({
|
||||
values: z.number().array(),
|
||||
}),
|
||||
cashflowNsibColumn: z.object({
|
||||
dates: z.array(z.string()),
|
||||
irr: z.number(),
|
||||
nominal: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
comissionBonusExpensesColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
creditColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
creditVATColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
dateColumn: z.object({
|
||||
values: z.array(z.string()),
|
||||
}),
|
||||
dateTempColumn: z.object({
|
||||
values: z.array(z.string()),
|
||||
}),
|
||||
deprecationColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
deprecationLdColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
deprecationLpColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
directorBonusSumColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
evoKaskoNmperGrColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
expensesColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
extraBonusSumColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
finGAPNmperGrColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
gpsExpensesColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
gpsGrColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
insuranceBonusExpensesColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
interestColumn: z.object({
|
||||
values: z.number().array(),
|
||||
}),
|
||||
irrGrColumn: z.object({
|
||||
values: z.number().array(),
|
||||
}),
|
||||
kaskoBonusGrSumColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
kaskoNmperGrColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
negativeCashflowColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
niColumn: z.object({
|
||||
values: z.number().array(),
|
||||
}),
|
||||
npvBonusExpensesColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
npvColumn: z.object({
|
||||
dates: z.array(z.string()),
|
||||
irr: z.number(),
|
||||
nominal: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
npvFinal2Column: z.object({
|
||||
dates: z.array(z.string()),
|
||||
irr: z.number(),
|
||||
nominal: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
npvFinalColumn: z.object({
|
||||
dates: z.array(z.string()),
|
||||
irr: z.number(),
|
||||
nominal: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
npvWeightColumn: z.object({
|
||||
values: z.number().array(),
|
||||
}),
|
||||
nsibBruttoGrColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
nsibExpensesColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
percentPaymentColumn: z.object({
|
||||
values: z.number().array(),
|
||||
}),
|
||||
ratExpensesColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
registrExpensesColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
revenueColumn: z.object({
|
||||
values: z.number().array(),
|
||||
}),
|
||||
subsidyExpensesColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
sumColumn: z.object({
|
||||
dates: z.array(z.string()),
|
||||
irr: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
sumCreditColumn: z.object({
|
||||
values: z.number().array(),
|
||||
}),
|
||||
sumCurrentColumn: z.object({
|
||||
values: z.number().array(),
|
||||
}),
|
||||
sumCurrentInterestColumn: z.object({
|
||||
values: z.number().array(),
|
||||
}),
|
||||
sumCurrentNegativeColumn: z.object({
|
||||
values: z.number().array(),
|
||||
}),
|
||||
sumCurrentTlmColumn: z.object({
|
||||
values: z.number().array(),
|
||||
}),
|
||||
sumRepaymentColumn: z.object({
|
||||
values: z.number().array(),
|
||||
}),
|
||||
sumVATCreditColumn: z.object({
|
||||
values: z.number().array(),
|
||||
}),
|
||||
sumWithVatColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
taxColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
tlmExpensesColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
tlmGrColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
transExprensesColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
vatColumn: z.object({
|
||||
sum: z.number(),
|
||||
values: z.number().array(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const ResponseCalculateSchema = z.object({
|
||||
columns: ColumnsSchema,
|
||||
errors: z.string().array(),
|
||||
postValues: PostValuesSchema,
|
||||
preparedValues: PreparedValuesSchema.extend({
|
||||
insuranceFinGAPNmper: z.number(),
|
||||
niAtInception: z.number(),
|
||||
}),
|
||||
});
|
||||
|
||||
export type ResponseCalculate = z.infer<typeof ResponseCalculateSchema>;
|
||||
2
apps/web/api/core/types/index.ts
Normal file
2
apps/web/api/core/types/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './calculate';
|
||||
export * from './fingap';
|
||||
@ -5,6 +5,7 @@ const envSchema = z.object({
|
||||
COOKIE_TOKEN_NAME: z.string().optional().default('token'),
|
||||
PORT: z.string().optional(),
|
||||
URL_1C_TRANSTAX_DIRECT: z.string(),
|
||||
URL_CORE_CALCULATE_DIRECT: z.string(),
|
||||
URL_CORE_FINGAP_DIRECT: z.string(),
|
||||
URL_CRM_GRAPHQL_DIRECT: z.string(),
|
||||
URL_GET_USER_DIRECT: z.string(),
|
||||
|
||||
33
apps/web/config/schema/results.ts
Normal file
33
apps/web/config/schema/results.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const ResultValuesSchema = z.object({
|
||||
resultAB_FL: z.number(),
|
||||
resultAB_UL: z.number(),
|
||||
resultBonusDopProd: z.number(),
|
||||
resultBonusMPL: z.number(),
|
||||
resultBonusSafeFinance: z.number(),
|
||||
resultDopMPLLeasing: z.number(),
|
||||
resultDopProdSum: z.number(),
|
||||
resultFirstPayment: z.number(),
|
||||
resultFirstPaymentRiskPolicy: z.number(),
|
||||
resultIRRGraphPerc: z.number(),
|
||||
resultIRRNominalPerc: z.number(),
|
||||
resultInsKasko: z.number(),
|
||||
resultInsOsago: z.number(),
|
||||
resultLastPayment: z.number(),
|
||||
resultParticipationAmount: z.number(),
|
||||
resultPlPrice: z.number(),
|
||||
resultPriceUpPr: z.number(),
|
||||
resultTerm: z.number(),
|
||||
resultTotalGraphwithNDS: z.number(),
|
||||
});
|
||||
|
||||
export const ResultPaymentSchema = z.object({
|
||||
key: z.string(),
|
||||
ndsCompensation: z.number(),
|
||||
num: z.number(),
|
||||
paymentSum: z.number(),
|
||||
redemptionAmount: z.number(),
|
||||
});
|
||||
|
||||
export const ResultPaymentsSchema = ResultPaymentSchema.array();
|
||||
@ -11,6 +11,7 @@ const serverRuntimeConfigSchema = envSchema.pick({
|
||||
COOKIE_TOKEN_NAME: true,
|
||||
PORT: true,
|
||||
URL_1C_TRANSTAX_DIRECT: true,
|
||||
URL_CORE_CALCULATE_DIRECT: true,
|
||||
URL_CORE_FINGAP_DIRECT: true,
|
||||
URL_CRM_GRAPHQL_DIRECT: true,
|
||||
URL_GET_USER_DIRECT: true,
|
||||
|
||||
@ -14,6 +14,7 @@ function getUrls() {
|
||||
URL_GET_USER_DIRECT,
|
||||
URL_CORE_FINGAP_DIRECT,
|
||||
URL_1C_TRANSTAX_DIRECT,
|
||||
URL_CORE_CALCULATE_DIRECT,
|
||||
PORT,
|
||||
} = serverRuntimeConfigSchema.parse(serverRuntimeConfig);
|
||||
|
||||
@ -21,6 +22,7 @@ function getUrls() {
|
||||
BASE_PATH,
|
||||
PORT,
|
||||
URL_1C_TRANSTAX: URL_1C_TRANSTAX_DIRECT,
|
||||
URL_CORE_CALCULATE: URL_CORE_CALCULATE_DIRECT,
|
||||
URL_CORE_FINGAP: URL_CORE_FINGAP_DIRECT,
|
||||
URL_CRM_GRAPHQL: URL_CRM_GRAPHQL_DIRECT,
|
||||
URL_GET_USER: URL_GET_USER_DIRECT,
|
||||
@ -34,6 +36,7 @@ function getUrls() {
|
||||
return {
|
||||
BASE_PATH,
|
||||
URL_1C_TRANSTAX: withBasePath(urls.URL_1C_TRANSTAX_PROXY),
|
||||
URL_CORE_CALCULATE: withBasePath(urls.URL_CORE_CALCULATE_PROXY),
|
||||
URL_CORE_FINGAP: withBasePath(urls.URL_CORE_FINGAP_PROXY),
|
||||
URL_CRM_GRAPHQL: withBasePath(urls.URL_CRM_GRAPHQL_PROXY),
|
||||
URL_GET_USER: withBasePath(urls.URL_GET_USER_PROXY),
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
module.exports = {
|
||||
URL_1C_TRANSTAX_PROXY: '/api/1c/transtax',
|
||||
URL_CORE_CALCULATE_PROXY: '/api/core/calculate',
|
||||
URL_CORE_FINGAP_PROXY: '/api/core/fingap',
|
||||
URL_CRM_GRAPHQL_PROXY: '/api/graphql/crm',
|
||||
URL_GET_USER_PROXY: '/api/auth/user',
|
||||
|
||||
@ -11,3 +11,4 @@ export const MAX_MASS = 3500;
|
||||
export const MAX_VEHICLE_SEATS = 20;
|
||||
export const ESN = 1.3;
|
||||
export const NSIB_MAX = 5_000_000;
|
||||
export const NDFL = 0.13;
|
||||
|
||||
48
apps/web/process/calculate/action.js
Normal file
48
apps/web/process/calculate/action.js
Normal file
@ -0,0 +1,48 @@
|
||||
import { toJS } from 'mobx';
|
||||
import notification from 'ui/elements/notification';
|
||||
|
||||
const key = 'ACTION_CALCULATE';
|
||||
const message = 'Ошибка во время расчета графика';
|
||||
|
||||
/**
|
||||
* @param {import('../types').ProcessContext} context
|
||||
* @param {*} onCompleted
|
||||
*/
|
||||
export async function action({ store, trpcClient }) {
|
||||
const { $calculation, $tables, $results } = store;
|
||||
|
||||
$calculation.$status.setStatus('btnCalculate', 'Loading');
|
||||
$calculation.$status.setStatus('btnCreateKP', 'Loading');
|
||||
$results.clear();
|
||||
|
||||
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 res = await trpcClient.calculate.calculate.query({
|
||||
insurance: { values: insurance },
|
||||
payments: { values: payments },
|
||||
values,
|
||||
});
|
||||
|
||||
if (res.success === false) {
|
||||
notification.error({
|
||||
description: res.error,
|
||||
key,
|
||||
message,
|
||||
});
|
||||
} else {
|
||||
$results.setPayments(res.data.resultPayments);
|
||||
$results.setValues(res.data.resultValues);
|
||||
$calculation.$values.setValues(res.data.values);
|
||||
}
|
||||
|
||||
$calculation.$status.setStatus('btnCalculate', 'Default');
|
||||
$calculation.$status.setStatus('btnCreateKP', 'Default');
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
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,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
import type { ResultsValues } from './types';
|
||||
import type { ResultValues } from './types';
|
||||
|
||||
export const defaultResultsValues: ResultsValues = {
|
||||
export const defaultResultsValues: ResultValues = {
|
||||
resultAB_FL: 0,
|
||||
resultAB_UL: 0,
|
||||
resultBonusDopProd: 0,
|
||||
@ -15,6 +15,7 @@ export const defaultResultsValues: ResultsValues = {
|
||||
resultInsKasko: 0,
|
||||
resultInsOsago: 0,
|
||||
resultLastPayment: 0,
|
||||
resultParticipationAmount: 0,
|
||||
resultPlPrice: 0,
|
||||
resultPriceUpPr: 0,
|
||||
resultTerm: 0,
|
||||
|
||||
@ -1,28 +1,27 @@
|
||||
import { defaultResultsValues } from './default-values';
|
||||
import type { ResultsValues } from './types';
|
||||
import type { Payment } from '@/Components/Output/PaymentsTable/types';
|
||||
import type { ResultPayment, ResultValues } from './types';
|
||||
import type RootStore from '@/stores/root';
|
||||
import type { IObservableArray } from 'mobx';
|
||||
import { makeAutoObservable, observable } from 'mobx';
|
||||
|
||||
export default class Results {
|
||||
private root: RootStore;
|
||||
public payments: IObservableArray<Payment>;
|
||||
public values: ResultsValues;
|
||||
public payments: IObservableArray<ResultPayment>;
|
||||
public values: ResultValues;
|
||||
|
||||
constructor(rootStore: RootStore) {
|
||||
this.payments = observable<Payment>([]);
|
||||
this.payments = observable<ResultPayment>([]);
|
||||
this.values = defaultResultsValues;
|
||||
makeAutoObservable(this);
|
||||
|
||||
this.root = rootStore;
|
||||
}
|
||||
|
||||
public setPayments = (payments: Payment[]) => {
|
||||
public setPayments = (payments: ResultPayment[]) => {
|
||||
this.payments.replace(payments);
|
||||
};
|
||||
|
||||
public setValues = (values: ResultsValues) => {
|
||||
public setValues = (values: ResultValues) => {
|
||||
this.values = values;
|
||||
};
|
||||
|
||||
|
||||
@ -1,22 +1,12 @@
|
||||
export type ResultsValues = {
|
||||
resultAB_FL: number;
|
||||
resultAB_UL: number;
|
||||
resultBonusDopProd: number;
|
||||
resultBonusMPL: number;
|
||||
resultBonusSafeFinance: number;
|
||||
resultDopMPLLeasing: number;
|
||||
resultDopProdSum: number;
|
||||
resultFirstPayment: number;
|
||||
resultFirstPaymentRiskPolicy: number;
|
||||
resultIRRGraphPerc: number;
|
||||
resultIRRNominalPerc: number;
|
||||
resultInsKasko: number;
|
||||
resultInsOsago: number;
|
||||
resultLastPayment: number;
|
||||
resultPlPrice: number;
|
||||
resultPriceUpPr: number;
|
||||
resultTerm: number;
|
||||
resultTotalGraphwithNDS: number;
|
||||
};
|
||||
import type {
|
||||
ResultPaymentSchema,
|
||||
ResultPaymentsSchema,
|
||||
ResultValuesSchema,
|
||||
} from '@/config/schema/results';
|
||||
import type { z } from 'zod';
|
||||
|
||||
export type Values = keyof ResultsValues;
|
||||
export type ResultValues = z.infer<typeof ResultValuesSchema>;
|
||||
|
||||
export type ResultPayment = z.infer<typeof ResultPaymentSchema>;
|
||||
|
||||
export type ResultPayments = z.infer<typeof ResultPaymentsSchema>;
|
||||
|
||||
92
apps/web/trpc/routers/calculate/convert.ts
Normal file
92
apps/web/trpc/routers/calculate/convert.ts
Normal file
@ -0,0 +1,92 @@
|
||||
import type { CalculateInput, OutputData } from './types';
|
||||
import type { RequestCalculate, ResponseCalculate } from '@/api/core/types';
|
||||
import { ESN, NDFL, VAT } from '@/constants/values';
|
||||
import { last } from 'radash';
|
||||
|
||||
type Input = {
|
||||
calculateInput: CalculateInput;
|
||||
requestCalculate: RequestCalculate;
|
||||
responseCalculate: ResponseCalculate;
|
||||
};
|
||||
|
||||
export function convertCalculateResults({ responseCalculate, calculateInput }: Input): OutputData {
|
||||
const { values: inputValues } = calculateInput;
|
||||
const { postValues, columns, preparedValues } = responseCalculate;
|
||||
|
||||
const resultPayments: OutputData['resultPayments'] = Array.from(
|
||||
{
|
||||
length: preparedValues.nmper,
|
||||
},
|
||||
(_, i) => ({
|
||||
key: String(i + 1),
|
||||
ndsCompensation: columns.vatColumn.values[i + 1],
|
||||
num: i + 1,
|
||||
paymentSum: columns.sumWithVatColumn.values[i + 1],
|
||||
redemptionAmount: columns.sumRepaymentColumn.values[i + 1],
|
||||
})
|
||||
);
|
||||
|
||||
const resultValues: OutputData['resultValues'] = {
|
||||
resultAB_FL: ((preparedValues.agentsSum + preparedValues.doubleAgentsSum) / ESN) * (1 - NDFL),
|
||||
resultAB_UL:
|
||||
(preparedValues.deliverySum +
|
||||
preparedValues.brokerSum +
|
||||
preparedValues.brokerOfDeliverySum +
|
||||
preparedValues.financialDeptOfDeliverySum) *
|
||||
(1 + VAT),
|
||||
resultBonusDopProd: Math.abs(
|
||||
(columns?.npvBonusExpensesColumn?.values[1] / (1 + preparedValues?.salaryRate)) * (1 - NDFL)
|
||||
),
|
||||
resultBonusMPL: Math.abs(
|
||||
(columns.npvBonusExpensesColumn.values[2] / (1 + preparedValues.salaryRate)) * (1 - NDFL)
|
||||
),
|
||||
resultBonusSafeFinance: preparedValues?.bonusFinGAP * (1 - NDFL),
|
||||
resultDopMPLLeasing: Math.abs(
|
||||
(columns.extraBonusSumColumn.values[2] / (1 + preparedValues.salaryRate)) * (1 - NDFL)
|
||||
),
|
||||
resultDopProdSum: 0,
|
||||
// resultDopProdSum: preparedValues.rats +
|
||||
// preparedValues.registration +
|
||||
// preparedValues.trackerCost +
|
||||
// preparedValues.tLMCost +
|
||||
// preparedValues.nsibBrutto +
|
||||
// preparedValues.insuranceFinGAPNmper,
|
||||
resultFirstPayment: preparedValues.firstPaymentSum * (1 + VAT) - inputValues.subsidySum,
|
||||
resultFirstPaymentRiskPolicy: preparedValues?.firstPayment * 100,
|
||||
resultIRRGraphPerc: columns.sumColumn.irr * 100,
|
||||
resultIRRNominalPerc: columns.cashflowMsfoColumn.nominal * 100,
|
||||
resultInsKasko: preparedValues.insuranceKasko,
|
||||
resultInsOsago: preparedValues.insuranceOsago,
|
||||
resultLastPayment: preparedValues.lastPaymentSum * (1 + VAT),
|
||||
resultParticipationAmount:
|
||||
preparedValues.niAtInception +
|
||||
(preparedValues.ratBonus + preparedValues.nsBonus + preparedValues.nsibBonus) *
|
||||
preparedValues.marketRate *
|
||||
preparedValues.districtRate +
|
||||
Math.abs(columns.npvBonusExpensesColumn.values[0]) +
|
||||
Math.abs(
|
||||
columns.extraBonusSumColumn.values[0] +
|
||||
preparedValues.importerSum +
|
||||
preparedValues.agentsSum +
|
||||
preparedValues.deliverySum +
|
||||
preparedValues.brokerSum +
|
||||
preparedValues.brokerOfDeliverySum +
|
||||
preparedValues.financialDeptOfDeliverySum
|
||||
),
|
||||
resultPlPrice:
|
||||
preparedValues.plPriceWithVAT -
|
||||
inputValues.supplierDiscountRub -
|
||||
inputValues.importProgramSum,
|
||||
resultPriceUpPr: postValues.priceUP_Year_PR * 100,
|
||||
resultTerm: preparedValues.nmper,
|
||||
resultTotalGraphwithNDS: columns.sumWithVatColumn.values[0] - inputValues.subsidySum,
|
||||
};
|
||||
|
||||
const values: OutputData['values'] = {
|
||||
IRR_Perc: columns?.cashflowMsfoColumn?.nominal * 100,
|
||||
lastPaymentRub: last(columns?.sumWithVatColumn?.values) || 0,
|
||||
totalPayments: columns?.sumWithVatColumn?.values[0] - inputValues.subsidySum,
|
||||
};
|
||||
|
||||
return { resultPayments, resultValues, values };
|
||||
}
|
||||
@ -1,9 +1,12 @@
|
||||
import { user } from '../../middleware';
|
||||
import { t } from '../../server';
|
||||
import { convertCalculateResults } from './convert';
|
||||
import { getRequestData } from './request';
|
||||
import { CalculateInputSchema, CalculateOutputSchema } from './types';
|
||||
import { validate } from './validation';
|
||||
import { calculate } from '@/api/core/query';
|
||||
import initializeApollo from '@/apollo/client';
|
||||
import type { QueryFunctionContext } from '@tanstack/react-query';
|
||||
import { QueryClient } from '@tanstack/react-query';
|
||||
|
||||
const calculateRouter = t.router({
|
||||
@ -15,7 +18,7 @@ const calculateRouter = t.router({
|
||||
const apolloClient = initializeApollo();
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
const { success, error } = await validate({
|
||||
const validationResult = await validate({
|
||||
context: {
|
||||
apolloClient,
|
||||
queryClient,
|
||||
@ -23,10 +26,10 @@ const calculateRouter = t.router({
|
||||
input,
|
||||
});
|
||||
|
||||
if (!success) {
|
||||
if (validationResult.success === false) {
|
||||
return {
|
||||
error,
|
||||
success,
|
||||
error: validationResult.error,
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
@ -39,9 +42,28 @@ const calculateRouter = t.router({
|
||||
user: ctx.user,
|
||||
});
|
||||
|
||||
const request = (context: QueryFunctionContext) => calculate(payload, context);
|
||||
|
||||
const calculateResult = await queryClient.fetchQuery(['calculate'], request, {
|
||||
staleTime: 15_000,
|
||||
});
|
||||
|
||||
if (calculateResult.errors?.length > 0) {
|
||||
return {
|
||||
error: calculateResult.errors[0],
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
const result = convertCalculateResults({
|
||||
calculateInput: input,
|
||||
requestCalculate: payload,
|
||||
responseCalculate: calculateResult,
|
||||
});
|
||||
|
||||
return {
|
||||
error: undefined,
|
||||
success,
|
||||
data: result,
|
||||
success: true,
|
||||
};
|
||||
}),
|
||||
});
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
/* eslint-disable sonarjs/cognitive-complexity */
|
||||
import type * as Types from './types';
|
||||
import type { CalculateInput, Context } from './types';
|
||||
import type * as CoreTypes from '@/api/core/types';
|
||||
import type { User } from '@/api/user/types';
|
||||
import { ESN, NSIB_MAX, VAT } from '@/constants/values';
|
||||
import * as CRMTypes from '@/graphql/crm.types';
|
||||
@ -12,30 +13,30 @@ import { max, sum } from 'radash';
|
||||
dayjs.extend(utc);
|
||||
|
||||
type Input = {
|
||||
context: Types.Context;
|
||||
input: Types.CalculateInput;
|
||||
context: Context;
|
||||
input: CalculateInput;
|
||||
user: User;
|
||||
};
|
||||
|
||||
type PreparedValuesGetters = {
|
||||
[Key in keyof Types.PreparedValues]: () => Promise<Types.PreparedValues[Key]>;
|
||||
[Key in keyof CoreTypes.PreparedValues]: () => Promise<CoreTypes.PreparedValues[Key]>;
|
||||
};
|
||||
|
||||
type AdditionalDataGetters = {
|
||||
[Key in keyof Types.AdditionalData]: () => Promise<Types.AdditionalData[Key]>;
|
||||
[Key in keyof CoreTypes.AdditionalData]: () => Promise<CoreTypes.AdditionalData[Key]>;
|
||||
};
|
||||
|
||||
export async function getRequestData({
|
||||
context,
|
||||
input,
|
||||
user,
|
||||
}: Input): Promise<Types.CalculateRequest> {
|
||||
}: Input): Promise<CoreTypes.RequestCalculate> {
|
||||
const { apolloClient } = context;
|
||||
const { values, insurance, payments } = input;
|
||||
|
||||
const { RUB } = createCurrencyUtility({ apolloClient });
|
||||
|
||||
const preparedPayments: Types.CalculateRequest['preparedPayments'] = {
|
||||
const preparedPayments: CoreTypes.PreparedPayments = {
|
||||
rows: payments.values.map((payment, index) => ({
|
||||
gpsBasePayment: 0,
|
||||
gpsCostPayment: 0,
|
||||
@ -160,7 +161,7 @@ export async function getRequestData({
|
||||
variables: { addproductTypeId: values.technicalCard },
|
||||
});
|
||||
|
||||
return evo_addproduct_type?.evo_cost_service_provider_withoutnds ?? 0;
|
||||
return evo_addproduct_type?.evo_cost_service_provider_withoutnds || 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -175,7 +176,7 @@ export async function getRequestData({
|
||||
variables: { addproductTypeId: values.registration },
|
||||
});
|
||||
|
||||
return evo_addproduct_type?.evo_cost_service_provider_withoutnds ?? 0;
|
||||
return evo_addproduct_type?.evo_cost_service_provider_withoutnds || 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1000,7 +1001,7 @@ export async function getRequestData({
|
||||
variables: { addproductTypeId: values.technicalCard },
|
||||
});
|
||||
|
||||
return evo_addproduct_type?.evo_graph_price_withoutnds ?? 0;
|
||||
return evo_addproduct_type?.evo_graph_price_withoutnds || 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1060,7 +1061,7 @@ export async function getRequestData({
|
||||
variables: { addproductTypeId: values.registration },
|
||||
});
|
||||
|
||||
return evo_addproduct_type?.evo_graph_price_withoutnds ?? 0;
|
||||
return evo_addproduct_type?.evo_graph_price_withoutnds || 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1079,7 +1080,7 @@ export async function getRequestData({
|
||||
variables: { addproductTypeId: values.technicalCard },
|
||||
});
|
||||
|
||||
return evo_addproduct_type?.evo_retro_bonus_withoutnds ?? 0;
|
||||
return evo_addproduct_type?.evo_retro_bonus_withoutnds || 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1129,7 +1130,7 @@ export async function getRequestData({
|
||||
variables: { addproductTypeId: values.telematic },
|
||||
});
|
||||
|
||||
return evo_addproduct_type?.evo_graph_price_withoutnds ?? 0;
|
||||
return evo_addproduct_type?.evo_graph_price_withoutnds || 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1152,7 +1153,7 @@ export async function getRequestData({
|
||||
variables: { addproductTypeId: values.tracker },
|
||||
});
|
||||
|
||||
return evo_addproduct_type?.evo_graph_price_withoutnds ?? 0;
|
||||
return evo_addproduct_type?.evo_graph_price_withoutnds || 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1177,7 +1178,7 @@ export async function getRequestData({
|
||||
|
||||
const preparedValuesResult = await Promise.all(
|
||||
(Object.keys(preparedValuesGetters) as Array<keyof PreparedValuesGetters>).map(
|
||||
async <T extends keyof Types.PreparedValues>(key: T) => {
|
||||
async <T extends keyof CoreTypes.PreparedValues>(key: T) => {
|
||||
const value = await preparedValuesGetters[key]();
|
||||
|
||||
return { [key]: value };
|
||||
@ -1185,7 +1186,7 @@ export async function getRequestData({
|
||||
)
|
||||
);
|
||||
|
||||
const preparedValues = Object.assign({}, ...preparedValuesResult) as Types.PreparedValues;
|
||||
const preparedValues = Object.assign({}, ...preparedValuesResult) as CoreTypes.PreparedValues;
|
||||
|
||||
const { getIrr } = helper({ apolloClient });
|
||||
const irr = await getIrr(values);
|
||||
@ -1215,7 +1216,7 @@ export async function getRequestData({
|
||||
|
||||
const additionalDataResult = await Promise.all(
|
||||
(Object.keys(additionalDataGetters) as Array<keyof AdditionalDataGetters>).map(
|
||||
async <T extends keyof Types.AdditionalData>(key: T) => {
|
||||
async <T extends keyof CoreTypes.AdditionalData>(key: T) => {
|
||||
const value = await additionalDataGetters[key]();
|
||||
|
||||
return { [key]: value };
|
||||
@ -1223,7 +1224,7 @@ export async function getRequestData({
|
||||
)
|
||||
);
|
||||
|
||||
const additionalData = Object.assign({}, ...additionalDataResult) as Types.AdditionalData;
|
||||
const additionalData = Object.assign({}, ...additionalDataResult) as CoreTypes.AdditionalData;
|
||||
|
||||
return {
|
||||
additionalData,
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { InsuranceSchema } from '@/config/schema/insurance';
|
||||
import PaymentsSchema from '@/config/schema/payments';
|
||||
import { ResultPaymentsSchema, ResultValuesSchema } from '@/config/schema/results';
|
||||
import ValuesSchema from '@/config/schema/values';
|
||||
import type { ProcessContext } from '@/process/types';
|
||||
import { z } from 'zod';
|
||||
@ -16,154 +17,28 @@ export const CalculateInputSchema = z
|
||||
|
||||
export type CalculateInput = z.infer<typeof CalculateInputSchema>;
|
||||
|
||||
export const CalculateOutputSchema = z.object({
|
||||
error: z.string().optional(),
|
||||
success: z.boolean(),
|
||||
export const OutputDataSchema = z.object({
|
||||
resultPayments: ResultPaymentsSchema,
|
||||
resultValues: ResultValuesSchema,
|
||||
values: ValuesSchema.pick({
|
||||
IRR_Perc: true,
|
||||
lastPaymentRub: true,
|
||||
totalPayments: true,
|
||||
}),
|
||||
});
|
||||
|
||||
export type OutputData = z.infer<typeof OutputDataSchema>;
|
||||
|
||||
export const CalculateOutputSchema = z
|
||||
.object({
|
||||
data: OutputDataSchema,
|
||||
success: z.boolean(),
|
||||
})
|
||||
.or(
|
||||
z.object({
|
||||
error: z.string(),
|
||||
success: z.boolean(),
|
||||
})
|
||||
);
|
||||
|
||||
export type CalculateOutput = z.infer<typeof CalculateOutputSchema>;
|
||||
|
||||
export const PreparedValuesSchema = z.object({
|
||||
acceptSum: z.number(),
|
||||
agentsSum: z.number(),
|
||||
balanceHolder: z.number(),
|
||||
baseRatCost: z.number(),
|
||||
baseRegistration: z.number(),
|
||||
bonus: z.number(),
|
||||
bonusCoefficient: z.number(),
|
||||
bonusFinGAP: z.number(),
|
||||
bonusFix: z.number(),
|
||||
bonusNsPr: z.number(),
|
||||
bonusNsibPr: z.number(),
|
||||
bonusRatPr: z.number(),
|
||||
brandId: z.string().nullable(),
|
||||
brokerOfDeliverySum: z.number(),
|
||||
brokerSum: z.number(),
|
||||
calcDate: z.date(),
|
||||
calcType: z.number(),
|
||||
carCapacity: z.number(),
|
||||
carCarrying: z.number(),
|
||||
carSeats: z.number(),
|
||||
cityc: z.string(),
|
||||
comissionRub: z.number(),
|
||||
configurationId: z.string().nullable(),
|
||||
deliverySum: z.number(),
|
||||
deliveryTime: z.number(),
|
||||
deprecationTime: z.number(),
|
||||
directorBonus: z.number(),
|
||||
directorBonusFinGAP: z.number(),
|
||||
directorBonusFix: z.number(),
|
||||
directorBonusNsib: z.number(),
|
||||
directorExtraBonus: z.number(),
|
||||
discount: z.number(),
|
||||
districtRate: z.number(),
|
||||
doubleAgentsSum: z.number(),
|
||||
extraBonus: z.number(),
|
||||
financialDeptOfDeliverySum: z.number(),
|
||||
firstPayment: z.number(),
|
||||
firstPaymentAbs: z.number(),
|
||||
firstPaymentNdsAbs: z.number(),
|
||||
firstPaymentSum: z.number(),
|
||||
firstPaymentWithNdsAbs: z.number(),
|
||||
fuelCardSum: z.number(),
|
||||
gpsCostPaymentSum: z.number(),
|
||||
iRR_MSFO_Plan: z.number(),
|
||||
importProgramSum: z.number(),
|
||||
importerSum: z.number(),
|
||||
insuranceBonus: z.number(),
|
||||
insuranceBonusLoss: z.number(),
|
||||
insuranceContract: z.number(),
|
||||
insuranceEvoKasko: z.number(),
|
||||
insuranceFinGAP: z.number(),
|
||||
insuranceKasko: z.number(),
|
||||
insuranceKaskoNmper: z.number(),
|
||||
insuranceOsago: z.number(),
|
||||
irrExpected: z.number(),
|
||||
lastPayment: z.number(),
|
||||
lastPaymentFix: z.boolean(),
|
||||
lastPaymentSum: z.number(),
|
||||
leasing0K: z.number(),
|
||||
loanRate: z.number(),
|
||||
loanRatePeriod: z.number(),
|
||||
marketRate: z.number(),
|
||||
modelId: z.string().nullable(),
|
||||
motorVolume: z.number(),
|
||||
nmper: z.number(),
|
||||
nmperDeprecation: z.number(),
|
||||
nmperFinGAP: z.number(),
|
||||
nmperInsurance: z.number(),
|
||||
npvniDelta: z.number(),
|
||||
npvniExpected: z.number(),
|
||||
nsBonus: z.number(),
|
||||
nsibBase: z.number(),
|
||||
nsibBonus: z.number(),
|
||||
nsibBrutto: z.number(),
|
||||
nsibBruttoPr: z.number(),
|
||||
nsibNetto: z.number(),
|
||||
nsibNettoPr: z.number(),
|
||||
paymentDateNew: z.date().nullable(),
|
||||
plEngineType: z.number().nullable(),
|
||||
plPrice: z.number(),
|
||||
plPriceVAT: z.number(),
|
||||
plPriceWithVAT: z.number(),
|
||||
plTypeId: z.string().nullable(),
|
||||
plYear: z.number(),
|
||||
profitExpected: z.number(),
|
||||
ratBonus: z.number(),
|
||||
rats: z.number(),
|
||||
regionalDirectorBonus: z.number(),
|
||||
regionalDirectorBonusFinGAP: z.number(),
|
||||
regionalDirectorBonusFix: z.number(),
|
||||
regionalDirectorBonusNsib: z.number(),
|
||||
regionalDirectorExtraBonus: z.number(),
|
||||
registration: z.number(),
|
||||
repayment: z.number(),
|
||||
retroBonus: z.number(),
|
||||
salaryRate: z.number(),
|
||||
scheduleOfPayments: z.number(),
|
||||
subsidyPaymentNumber: z.number(),
|
||||
subsidySum: z.number(),
|
||||
supplierFinancing: z.boolean(),
|
||||
tLMCost: z.number(),
|
||||
tlmCostPaymentSum: z.number(),
|
||||
totalExpected: z.number(),
|
||||
trackerCost: z.number(),
|
||||
transIncludeGr: z.boolean(),
|
||||
transTax: z.number(),
|
||||
transportTaxGr: z.number(),
|
||||
transportTaxGrYear: z.number(),
|
||||
});
|
||||
|
||||
export type PreparedValues = z.infer<typeof PreparedValuesSchema>;
|
||||
|
||||
const PaymentRowSchema = z.object({
|
||||
gpsBasePayment: z.number(),
|
||||
gpsCostPayment: z.number(),
|
||||
numberPayment: z.number(),
|
||||
percentPayment: z.number(),
|
||||
sumPayment: z.number(),
|
||||
tlmBasePayment: z.number(),
|
||||
tlmCostPayment: z.number(),
|
||||
});
|
||||
|
||||
const PreparedPaymentSchema = z.object({
|
||||
rows: PaymentRowSchema.array(),
|
||||
});
|
||||
|
||||
export type PreparedPayments = z.infer<typeof PreparedPaymentSchema>;
|
||||
|
||||
const AdditionalDataSchema = z.object({
|
||||
maxAllAgencyPerc: z.number().nullable(),
|
||||
maxCashflowMSFONominal: z.number().nullable(),
|
||||
minCashflowMSFONominal: z.number().nullable(),
|
||||
});
|
||||
|
||||
export type AdditionalData = z.infer<typeof AdditionalDataSchema>;
|
||||
|
||||
export const CalculateRequestSchema = z.object({
|
||||
additionalData: AdditionalDataSchema,
|
||||
preparedPayments: PreparedPaymentSchema,
|
||||
preparedValues: PreparedValuesSchema,
|
||||
});
|
||||
|
||||
export type CalculateRequest = z.infer<typeof CalculateRequestSchema>;
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import type { CalculateInput, Context } 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';
|
||||
@ -10,7 +9,7 @@ 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 { z, ZodIssue } from 'zod';
|
||||
import type { ZodIssue } from 'zod';
|
||||
|
||||
const processes = [
|
||||
configurator,
|
||||
@ -36,20 +35,7 @@ function getMessage(errors: ZodIssue[]) {
|
||||
return `${title}: ${message}`;
|
||||
}
|
||||
|
||||
const ValidationOutputSchema = CalculateOutputSchema.pick({
|
||||
error: true,
|
||||
success: true,
|
||||
});
|
||||
|
||||
type ValidationOutput = z.infer<typeof ValidationOutputSchema>;
|
||||
|
||||
export async function validate({
|
||||
input,
|
||||
context,
|
||||
}: {
|
||||
context: Context;
|
||||
input: CalculateInput;
|
||||
}): Promise<ValidationOutput> {
|
||||
export async function validate({ input, context }: { context: Context; input: CalculateInput }) {
|
||||
for (const { createValidationSchema } of processes) {
|
||||
const validationSchema = createValidationSchema(context);
|
||||
const validationResult = await validationSchema.safeParseAsync({
|
||||
@ -67,5 +53,6 @@ export async function validate({
|
||||
|
||||
return {
|
||||
success: true,
|
||||
error: '',
|
||||
};
|
||||
}
|
||||
|
||||
@ -19,6 +19,17 @@ export const formatterExtra = (value?: number) =>
|
||||
minimumFractionDigits: 2,
|
||||
}).format(value || 0);
|
||||
|
||||
export const moneyFormatter = Intl.NumberFormat('ru', {
|
||||
currency: 'RUB',
|
||||
style: 'currency',
|
||||
}).format;
|
||||
|
||||
export const percentFormatter = Intl.NumberFormat('ru', {
|
||||
maximumFractionDigits: 2,
|
||||
minimumFractionDigits: 2,
|
||||
style: 'percent',
|
||||
}).format;
|
||||
|
||||
export function round(value: number, precision: number = 0) {
|
||||
return Number.parseFloat(value.toFixed(precision));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user