diff --git a/apps/web/Components/Calculation/Form/Payments/PaymentsTable/builders.tsx b/apps/web/Components/Calculation/Form/Payments/PaymentsTable/builders.tsx index ead1e62..d03a5db 100644 --- a/apps/web/Components/Calculation/Form/Payments/PaymentsTable/builders.tsx +++ b/apps/web/Components/Calculation/Form/Payments/PaymentsTable/builders.tsx @@ -1,4 +1,4 @@ -import { usePaymentValue } from './hooks'; +import { usePaymentSum, usePaymentValue } from './hooks'; import { useRowStatus } from '@/stores/tables/payments/hooks'; import { observer } from 'mobx-react-lite'; import type { ComponentType } from 'react'; @@ -11,3 +11,12 @@ export function buildValueComponent(index: number, Component: ComponentType; }); } + +export function buildSumComponent(index: number, Component: ComponentType) { + return observer((props: T) => { + const [value, setValue] = usePaymentSum(index); + const status = useRowStatus(index); + + return ; + }); +} diff --git a/apps/web/Components/Calculation/Form/Payments/PaymentsTable/config.tsx b/apps/web/Components/Calculation/Form/Payments/PaymentsTable/config.tsx index 9664aa3..17b9761 100644 --- a/apps/web/Components/Calculation/Form/Payments/PaymentsTable/config.tsx +++ b/apps/web/Components/Calculation/Form/Payments/PaymentsTable/config.tsx @@ -1,14 +1,22 @@ /* eslint-disable canonical/sort-keys */ -import { buildValueComponent } from './builders'; +import { buildSumComponent, buildValueComponent } from './builders'; import type { ColumnsType } from 'antd/lib/table'; +import { parser } from 'tools/number'; import { InputNumber } from 'ui/elements'; +import { createFormatter } from 'ui/elements/InputNumber'; type Payment = { key: number; num: number; paymentRelation: number; + paymentSum: number; }; +const formatter = createFormatter({ + minimumFractionDigits: 2, + maximumFractionDigits: 2, +}); + export const columns: ColumnsType = [ { key: 'num', @@ -27,4 +35,14 @@ export const columns: ColumnsType = [ return ; }, }, + { + key: 'paymentSum', + dataIndex: 'paymentSum', + title: 'Сумма', + render: (_value, payment) => { + const Component = buildSumComponent(payment.num, InputNumber); + + return ; + }, + }, ]; diff --git a/apps/web/Components/Calculation/Form/Payments/PaymentsTable/hooks.js b/apps/web/Components/Calculation/Form/Payments/PaymentsTable/hooks.js index 0d7f308..e2f0e2c 100644 --- a/apps/web/Components/Calculation/Form/Payments/PaymentsTable/hooks.js +++ b/apps/web/Components/Calculation/Form/Payments/PaymentsTable/hooks.js @@ -1,4 +1,4 @@ -import { useRowValue } from '@/stores/tables/payments/hooks'; +import { useRowSum, useRowValue } from '@/stores/tables/payments/hooks'; import { useEffect, useState } from 'react'; import { useDebouncedCallback } from 'use-debounce'; @@ -20,3 +20,22 @@ export function usePaymentValue(index) { return [value, setValue]; } + +export function usePaymentSum(index) { + const [storeValue, setStoreValue] = useRowSum(index); + const [value, setValue] = useState(storeValue); + + const debouncedSetStoreValue = useDebouncedCallback(setStoreValue, 350, { maxWait: 1000 }); + + useEffect(() => { + if (storeValue !== value) { + debouncedSetStoreValue(value); + } + }, [value]); + + useEffect(() => { + setValue(storeValue); + }, [storeValue]); + + return [value, setValue]; +} diff --git a/apps/web/Components/Calculation/Form/Payments/PaymentsTable/index.jsx b/apps/web/Components/Calculation/Form/Payments/PaymentsTable/index.jsx index 863f52e..418fe6e 100644 --- a/apps/web/Components/Calculation/Form/Payments/PaymentsTable/index.jsx +++ b/apps/web/Components/Calculation/Form/Payments/PaymentsTable/index.jsx @@ -3,9 +3,12 @@ import { useStore } from '@/stores/hooks'; import { min } from '@/styles/mq'; import { computed } from 'mobx'; import { observer } from 'mobx-react-lite'; +import { createContext, useContext, useMemo, useState } from 'react'; import styled from 'styled-components'; +import { Segmented } from 'ui/antd'; import { Alert, Table } from 'ui/elements'; import { Box, Flex } from 'ui/grid'; +import { useDebouncedCallback } from 'use-debounce'; const Grid = styled(Flex)` flex-direction: column; @@ -47,6 +50,8 @@ const Validation = observer(() => { return null; }); +export const ModeContext = createContext('paymentRelation'); + const SPLIT_NUMBER = 12; function TablePart({ num }) { @@ -55,16 +60,25 @@ function TablePart({ num }) { const values = payments.values.slice(num * SPLIT_NUMBER, num * SPLIT_NUMBER + SPLIT_NUMBER); - const dataSource = values.map((value, index) => ({ + const dataSource = values.map((_, index) => ({ key: index + num * SPLIT_NUMBER, num: index + num * SPLIT_NUMBER, - paymentRelation: value, })); - return ( - - - + const mode = useContext(ModeContext); + + return useMemo( + () => ( + +
['num', mode].includes(x.key))} + dataSource={dataSource} + pagination={false} + /> + + ), + [dataSource, mode] ); } @@ -84,11 +98,36 @@ const TablesGroup = observer(() => { return {tables}; }); +function Mode({ setMode }) { + const { $process } = useStore(); + + if (!$process.has('Unlimited')) { + return false; + } + + return ( + setMode(value)} + /> + ); +} + export default function TablePayments() { + const [mode, setMode] = useState('paymentRelation'); + const debouncedSetMode = useDebouncedCallback(setMode, 300); + return ( - - + + + + + ); } diff --git a/apps/web/Components/Output/PaymentsTable/config.ts b/apps/web/Components/Output/PaymentsTable/config.ts index 0cba7bc..46bc8c5 100644 --- a/apps/web/Components/Output/PaymentsTable/config.ts +++ b/apps/web/Components/Output/PaymentsTable/config.ts @@ -36,4 +36,49 @@ export const columns: ColumnsType = [ currency: 'RUB', }).format, }, + { + key: '_piColumn', + dataIndex: '_piColumn', + title: 'PI Column', + render: Intl.NumberFormat('ru', { + style: 'currency', + currency: 'RUB', + }).format, + }, + { + key: '_cashflowMsfoWithCfColumn', + dataIndex: '_cashflowMsfoWithCfColumn', + title: 'CashflowMSFOWithCF Column', + render: Intl.NumberFormat('ru', { + style: 'currency', + currency: 'RUB', + }).format, + }, + { + key: '_creditPaymentColumn', + dataIndex: '_creditPaymentColumn', + title: 'CreditPayment Column', + render: Intl.NumberFormat('ru', { + style: 'currency', + currency: 'RUB', + }).format, + }, + { + key: '_cashflowMsfoColumn', + dataIndex: '_cashflowMsfoColumn', + title: 'CashflowMSFO Column', + render: Intl.NumberFormat('ru', { + style: 'currency', + currency: 'RUB', + }).format, + }, + { + key: '_interestColumn', + dataIndex: '_interestColumn', + title: 'Interest Column', + render: Intl.NumberFormat('ru', { + style: 'currency', + currency: 'RUB', + }).format, + }, ]; diff --git a/apps/web/Components/Output/PaymentsTable/index.jsx b/apps/web/Components/Output/PaymentsTable/index.jsx index afba73c..e053f01 100644 --- a/apps/web/Components/Output/PaymentsTable/index.jsx +++ b/apps/web/Components/Output/PaymentsTable/index.jsx @@ -1,3 +1,4 @@ +/* eslint-disable no-negated-condition */ import { columns } from './config'; import { MAX_LEASING_PERIOD } from '@/constants/values'; import { useStore } from '@/stores/hooks'; @@ -6,11 +7,13 @@ import { observer } from 'mobx-react-lite'; import { Table } from 'ui/elements'; const PaymentsTable = observer(() => { - const { $results } = useStore(); + const { $results, $process } = useStore(); + + const unlimited = $process.has('Unlimited'); return (
!x.key.includes('_')) : columns} dataSource={toJS($results.payments)} size="small" pagination={{ diff --git a/apps/web/Components/Output/Results/config.ts b/apps/web/Components/Output/Results/config.ts index 12f92e9..1194bf0 100644 --- a/apps/web/Components/Output/Results/config.ts +++ b/apps/web/Components/Output/Results/config.ts @@ -4,6 +4,12 @@ export const id = 'output'; export const title = 'Результаты'; export const titles: Record = { + _resultContractEconomy: 'Экономика', + _resultContractEconomyWithVAT: 'Экономика, с НДС', + _resultPi: 'PI', + _resultSumCredit: 'Сумма кредита', + _resultSumCreditPayment: 'Сумма платежей по кредиту', + _resultVatRecoverable: 'НДС к возмещению', resultAB_FL: 'АВ ФЛ, без НДФЛ.', resultAB_UL: 'АВ ЮЛ, с НДС.', resultBonusDopProd: 'Бонус МПЛ за доп.продукты, без НДФЛ', @@ -37,6 +43,12 @@ const percentFormatter = Intl.NumberFormat('ru', { }).format; export const formatters = { + _resultContractEconomy: moneyFormatter, + _resultContractEconomyWithVAT: moneyFormatter, + _resultPi: percentFormatter, + _resultSumCredit: moneyFormatter, + _resultSumCreditPayment: moneyFormatter, + _resultVatRecoverable: moneyFormatter, resultAB_FL: moneyFormatter, resultAB_UL: moneyFormatter, resultBonusDopProd: moneyFormatter, diff --git a/apps/web/Components/Output/Results/index.jsx b/apps/web/Components/Output/Results/index.jsx index b421a1e..44b930f 100644 --- a/apps/web/Components/Output/Results/index.jsx +++ b/apps/web/Components/Output/Results/index.jsx @@ -4,6 +4,7 @@ import { useStore } from '@/stores/hooks'; import { min } from '@/styles/mq'; import { toJS } from 'mobx'; import { observer } from 'mobx-react-lite'; +import { omit } from 'radash'; import styled from 'styled-components'; import { Text } from 'ui/elements'; import { Box } from 'ui/grid'; @@ -18,8 +19,16 @@ const Grid = styled(Box)` `; const Results = observer(() => { - const { $results } = useStore(); - const values = toJS($results.values); + const { $results, $process } = useStore(); + + const resultsValues = toJS($results.values); + // eslint-disable-next-line no-negated-condition + const values = !$process.has('Unlimited') + ? omit( + resultsValues, + Object.keys(resultsValues).filter((x) => x.includes('_')) + ) + : resultsValues; return ( diff --git a/apps/web/api/core/types/calculate.ts b/apps/web/api/core/types/calculate.ts index 72d500a..f38981a 100644 --- a/apps/web/api/core/types/calculate.ts +++ b/apps/web/api/core/types/calculate.ts @@ -217,6 +217,10 @@ const ColumnsSchema = z.object({ nominal: z.number(), values: z.number().array(), }), + cashflowMsfoWithCfColumn: z.object({ + sum: z.number(), + values: z.number().array(), + }), cashflowNpvColumn: z.object({ values: z.number().array(), }), @@ -240,6 +244,10 @@ const ColumnsSchema = z.object({ sum: z.number(), values: z.number().array(), }), + creditPaymentColumn: z.object({ + sum: z.number(), + values: z.number().array(), + }), creditVATColumn: z.object({ sum: z.number(), values: z.number().array(), @@ -351,6 +359,9 @@ const ColumnsSchema = z.object({ percentPaymentColumn: z.object({ values: z.number().array(), }), + piColumn: z.object({ + values: z.number().array(), + }), ratExpensesColumn: z.object({ sum: z.number(), values: z.number().array(), @@ -416,6 +427,10 @@ const ColumnsSchema = z.object({ sum: z.number(), values: z.number().array(), }), + vatRecoverableColumn: z.object({ + sum: z.number(), + values: z.number().array(), + }), }); export const ResponseCalculateSchema = z.object({ diff --git a/apps/web/config/default-options.ts b/apps/web/config/default-options.ts index 15f6026..f1f9570 100644 --- a/apps/web/config/default-options.ts +++ b/apps/web/config/default-options.ts @@ -68,6 +68,10 @@ export const radioGraphType = [ label: 'легкий старт', value: 100_000_004, }, + { + label: 'индивидуальный график', + value: 100_000_005, + }, ]; export const selectObjectCategoryTax = [ diff --git a/apps/web/config/schema/payments.ts b/apps/web/config/schema/payments.ts index 9ef49b5..13d1194 100644 --- a/apps/web/config/schema/payments.ts +++ b/apps/web/config/schema/payments.ts @@ -1,6 +1,7 @@ import { z } from 'zod'; const PaymentsSchema = z.object({ + sums: z.number().optional().array(), values: z.number().array(), }); diff --git a/apps/web/config/schema/results.ts b/apps/web/config/schema/results.ts index 326f70f..59f8ba7 100644 --- a/apps/web/config/schema/results.ts +++ b/apps/web/config/schema/results.ts @@ -1,6 +1,12 @@ import { z } from 'zod'; export const ResultValuesSchema = z.object({ + _resultContractEconomy: z.number(), + _resultContractEconomyWithVAT: z.number(), + _resultPi: z.number(), + _resultSumCredit: z.number(), + _resultSumCreditPayment: z.number(), + _resultVatRecoverable: z.number(), resultAB_FL: z.number(), resultAB_UL: z.number(), resultBonusDopProd: z.number(), @@ -23,6 +29,11 @@ export const ResultValuesSchema = z.object({ }); export const ResultPaymentSchema = z.object({ + _cashflowMsfoColumn: z.number(), + _cashflowMsfoWithCfColumn: z.number(), + _creditPaymentColumn: z.number(), + _interestColumn: z.number(), + _piColumn: z.number(), key: z.string(), ndsCompensation: z.number(), num: z.number(), diff --git a/apps/web/process/calculate/action.ts b/apps/web/process/calculate/action.ts index cb198b3..0cbb5a0 100644 --- a/apps/web/process/calculate/action.ts +++ b/apps/web/process/calculate/action.ts @@ -22,12 +22,13 @@ export async function action({ store, trpcClient }: ProcessContext) { osago: toJS($tables.insurance.row('osago').getValues()), }; - const payments = toJS($tables.payments.values); + const paymentRelations = toJS($tables.payments.values); + const paymentSums = toJS($tables.payments.sums); trpcClient.calculate .mutate({ insurance: { values: insurance }, - payments: { values: payments }, + payments: { sums: paymentSums, values: paymentRelations }, values, }) .then((res) => { diff --git a/apps/web/process/configurator/reactions/filters.ts b/apps/web/process/configurator/reactions/filters.ts index 5b708d9..7db5bf8 100644 --- a/apps/web/process/configurator/reactions/filters.ts +++ b/apps/web/process/configurator/reactions/filters.ts @@ -1,8 +1,10 @@ +/* eslint-disable sonarjs/cognitive-complexity */ import { radioCalcType, radioGraphType, selectSeasonType } from '@/config/default-options'; import * as CRMTypes from '@/graphql/crm.types'; import { SEASON_TYPES } from '@/process/payments/lib/seasons-constants'; import type { ProcessContext } from '@/process/types'; import { normalizeOptions } from '@/utils/entity'; +import { disposableReaction } from '@/utils/mobx'; import dayjs from 'dayjs'; import utc from 'dayjs/plugin/utc'; import { reaction } from 'mobx'; @@ -11,7 +13,7 @@ import { diff } from 'radash'; dayjs.extend(utc); export default function reactions({ store, apolloClient, user }: ProcessContext) { - const { $calculation } = store; + const { $calculation, $process } = store; reaction( () => $calculation.$values.getValues(['dealer', 'importProgram', 'product', 'subsidy']), @@ -20,7 +22,6 @@ export default function reactions({ store, apolloClient, user }: ProcessContext) subsidy: subsidyId, importProgram: importProgramId, dealer: dealerId, - // eslint-disable-next-line sonarjs/cognitive-complexity }) => { /** * #1 @@ -241,15 +242,21 @@ export default function reactions({ store, apolloClient, user }: ProcessContext) ({ evo_tarif } = data); } - if (evo_tarif?.evo_graphtype_exception?.length) { - const filteredGraphTypes = radioGraphType.filter( + let options = radioGraphType; + if (!$process.has('Unlimited')) { + options = options.filter((x) => x.value !== 100_000_005); + } + + if (!$process.has('Unlimited') && evo_tarif?.evo_graphtype_exception?.length) { + options = options.filter( (type) => !evo_tarif?.evo_graphtype_exception?.includes(type.value) ); - - $calculation.element('radioGraphType').setOptions(filteredGraphTypes); - } else { - $calculation.element('radioGraphType').resetOptions(); } + + $calculation.element('radioGraphType').setOptions(options); + }, + { + fireImmediately: true, } ); @@ -299,7 +306,8 @@ export default function reactions({ store, apolloClient, user }: ProcessContext) * radioCalcType фильтровать значения согласно списку * в поле "Доступные Методы расчета в калькуляторе" evo_calculation_method в selectProduct */ - reaction( + disposableReaction( + () => $process.has('Unlimited'), () => $calculation.element('selectProduct').getValue(), async (productId) => { const IRRCalcTypeOptions = radioCalcType.filter((x) => x.value === 100_000_000); diff --git a/apps/web/process/create-kp/action.ts b/apps/web/process/create-kp/action.ts index 47f0ce1..d4a40f6 100644 --- a/apps/web/process/create-kp/action.ts +++ b/apps/web/process/create-kp/action.ts @@ -25,13 +25,14 @@ export function action({ store, trpcClient, apolloClient }: ProcessContext) { const fingap = $tables.fingap.getSelectedRisks(); - const payments = toJS($tables.payments.values); + const paymentRelations = toJS($tables.payments.values); + const paymentSums = toJS($tables.payments.sums); trpcClient.createQuote .mutate({ fingap, insurance: { values: insurance }, - payments: { values: payments }, + payments: { sums: paymentSums, values: paymentRelations }, values, }) .then(async (res) => { diff --git a/apps/web/process/leasing-object/validation.ts b/apps/web/process/leasing-object/validation.ts index c6abbb3..beec27d 100644 --- a/apps/web/process/leasing-object/validation.ts +++ b/apps/web/process/leasing-object/validation.ts @@ -8,6 +8,7 @@ import { z } from 'zod'; export function createValidationSchema({ apolloClient }: ValidationContext) { return ValuesSchema.pick({ brand: true, + configuration: true, countSeats: true, engineType: true, engineVolume: true, @@ -30,6 +31,7 @@ export function createValidationSchema({ apolloClient }: ValidationContext) { brand, model, leaseObjectUseFor, + configuration, }, ctx ) => { @@ -57,6 +59,23 @@ export function createValidationSchema({ apolloClient }: ValidationContext) { }); } + if (model && !configuration) { + const { + data: { evo_equipments }, + } = await apolloClient.query({ + query: CRMTypes.GetConfigurationsDocument, + variables: { modelId: model }, + }); + + if (evo_equipments?.length) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: 'Не заполнено поле', + path: ['selectConfiguration'], + }); + } + } + if (!leaseObjectUseFor) { ctx.addIssue({ code: z.ZodIssueCode.custom, diff --git a/apps/web/process/load-kp/reactions.ts b/apps/web/process/load-kp/reactions.ts index 77cae89..ae02c0f 100644 --- a/apps/web/process/load-kp/reactions.ts +++ b/apps/web/process/load-kp/reactions.ts @@ -72,9 +72,7 @@ export function common({ store, trpcClient }: ProcessContext) { $calculation.element('selectQuote').resetValue(); }) .finally(() => { - setTimeout(() => { - $process.delete('LoadKP'); - }, 100); + $process.delete('LoadKP'); }); } ); diff --git a/apps/web/process/payments/get-kp-data.ts b/apps/web/process/payments/get-kp-data.ts index 69823ef..fb69233 100644 --- a/apps/web/process/payments/get-kp-data.ts +++ b/apps/web/process/payments/get-kp-data.ts @@ -79,6 +79,7 @@ export async function getKPData({ return { payments: { + sums: [], values: [ quote?.evo_first_payment_perc ?? 0, ...paymentsValues, diff --git a/apps/web/process/payments/reactions/common.ts b/apps/web/process/payments/reactions/common.ts index 419fa05..a9de31d 100644 --- a/apps/web/process/payments/reactions/common.ts +++ b/apps/web/process/payments/reactions/common.ts @@ -53,7 +53,7 @@ export default function reactions({ store }: ProcessContext) { }; }, ({ graphType, leasingPeriod }) => { - if (graphType === 100_000_000) { + if ([100_000_000, 100_000_005].includes(graphType)) { const middlePayments: Row[] = Array.from( { length: leasingPeriod - 2, diff --git a/apps/web/process/payments/validation.ts b/apps/web/process/payments/validation.ts index 5a5fc1f..c89aae6 100644 --- a/apps/web/process/payments/validation.ts +++ b/apps/web/process/payments/validation.ts @@ -19,7 +19,7 @@ export function createValidationSchema() { seasonType: true, }) .extend({ - payments: PaymentsSchema, + payments: PaymentsSchema.omit({ sums: true }), }) .superRefine( async ( diff --git a/apps/web/server/routers/calculate/lib/request.ts b/apps/web/server/routers/calculate/lib/request.ts index 15c7afb..222ae74 100644 --- a/apps/web/server/routers/calculate/lib/request.ts +++ b/apps/web/server/routers/calculate/lib/request.ts @@ -7,7 +7,7 @@ import helper from '@/process/calculate/lib/helper'; import { createCurrencyUtility } from '@/utils/currency'; import dayjs from 'dayjs'; import utc from 'dayjs/plugin/utc'; -import { max, sum } from 'radash'; +import { min, sum } from 'radash'; dayjs.extend(utc); @@ -33,16 +33,44 @@ export async function createRequestData({ const { RUB } = createCurrencyUtility({ apolloClient }); + let tracker: CRMTypes.GetAddProductTypeQuery['evo_addproduct_type'] = null; + + if (input.values.tracker) { + const { data } = await apolloClient.query({ + query: CRMTypes.GetAddProductTypeDocument, + variables: { addproductTypeId: input.values.tracker }, + }); + tracker = data.evo_addproduct_type; + } + + let telematic: CRMTypes.GetAddProductTypeQuery['evo_addproduct_type'] = null; + if (input.values.telematic) { + const { data } = await apolloClient.query({ + query: CRMTypes.GetAddProductTypeDocument, + variables: { addproductTypeId: input.values.telematic }, + }); + telematic = data.evo_addproduct_type; + } + const preparedPayments: CoreTypes.PreparedPayments = { - rows: payments.values.map((payment, index) => ({ - gpsBasePayment: 0, - gpsCostPayment: 0, - numberPayment: index + 1, - percentPayment: index === 0 ? 0 : payment, - sumPayment: 0, - tlmBasePayment: 0, - tlmCostPayment: 0, - })), + rows: payments.values.map((value, index) => { + const tracker_evo_planpayments = tracker?.evo_planpayments?.[index]; + const telematic_evo_planpayments = telematic?.evo_planpayments?.[index]; + + return { + gpsBasePayment: + (tracker_evo_planpayments?.evo_cost_price_telematics_withoutnds || 0) + + (tracker_evo_planpayments?.evo_cost_equipment_withoutnds || 0), + gpsCostPayment: tracker_evo_planpayments?.evo_cost_telematics_withoutnds || 0, + numberPayment: index + 1, + percentPayment: index === 0 ? 0 : value, + sumPayment: (payments.sums[index] ?? 0) / (1 + VAT), + tlmBasePayment: + (telematic_evo_planpayments?.evo_cost_price_telematics_withoutnds || 0) + + (telematic_evo_planpayments?.evo_cost_equipment_withoutnds || 0), + tlmCostPayment: telematic_evo_planpayments?.evo_cost_telematics_withoutnds || 0, + }; + }), }; const currentDate = dayjs().utc(false); @@ -389,7 +417,9 @@ export async function createRequestData({ (x) => x?.evo_sot_coefficient_typeidData?.evo_id === 'DIRECTOR_BONUS_NSIB' ); - return evo_coefficient?.evo_sot_coefficient || 0; + const nsibBrutto = await this.nsibBrutto(); + + return (evo_coefficient?.evo_sot_coefficient || 0) * nsibBrutto; }, async directorExtraBonus() { @@ -754,7 +784,7 @@ export async function createRequestData({ }, async loanRate() { - return values.creditRate; + return values.creditRate / 100; }, async loanRatePeriod() { @@ -809,9 +839,9 @@ export async function createRequestData({ }, async nmperInsurance() { - const { insured } = insurance.values.kasko; + const { insTerm } = insurance.values.kasko; - return insured === 100_000_001 ? values.leasingPeriod : 12; + return insTerm === 100_000_001 ? values.leasingPeriod : 12; }, async npvniDelta() { @@ -832,47 +862,16 @@ export async function createRequestData({ }, async nsBonus() { - const evo_coefficient = evo_coefficients?.find( - (x) => - x?.evo_job_titleid === systemuser?.evo_job_titleid && - x?.evo_sot_coefficient_typeidData?.evo_id === 'BONUS_NS_PR' - ); - - return evo_coefficient?.evo_sot_coefficient || 0; + return 0; }, async nsibBase() { - const discount = await this.discount(); const plPrice = await this.plPrice(); - const importProgramSum = await this.importProgramSum(); - const insuranceContract = await this.insuranceContract(); - const rats = await this.rats(); - const registration = await this.registration(); - const trackerCost = await this.trackerCost(); - const tLMCost = await this.tlmCost(); - const transportTaxGr = await this.transportTaxGr(); - const tlmCostPaymentSum = await this.tlmCostPaymentSum(); - const gpsCostPaymentSum = await this.gpsCostPaymentSum(); - const leasing0K = await this.leasing0K(); const firstPaymentSum = await this.firstPaymentSum(); - const value = - (plPrice - - importProgramSum + - (insuranceContract + - rats + - registration + - trackerCost + - tLMCost + - transportTaxGr + - tlmCostPaymentSum + - gpsCostPaymentSum) * - leasing0K - - firstPaymentSum - - (values.product === 'LEASING0' ? 0 : discount)) * - (1 + VAT); + const value = (plPrice - firstPaymentSum) * (1 + VAT); - return max([NSIB_MAX, value], (v) => v) ?? NSIB_MAX; + return min([NSIB_MAX, value]) ?? NSIB_MAX; }, async nsibBonus() { diff --git a/apps/web/server/routers/calculate/lib/transform.ts b/apps/web/server/routers/calculate/lib/transform.ts index e82bcd2..0b597ef 100644 --- a/apps/web/server/routers/calculate/lib/transform.ts +++ b/apps/web/server/routers/calculate/lib/transform.ts @@ -21,11 +21,16 @@ export function transformCalculateResults({ length: preparedValues.nmper, }, (_, i) => ({ + _cashflowMsfoColumn: columns?.cashflowMsfoColumn.values[i + 1] || 0, + _cashflowMsfoWithCfColumn: columns?.cashflowMsfoWithCfColumn.values[i + 1] || 0, + _creditPaymentColumn: columns?.creditPaymentColumn.values[i + 1] || 0, + _interestColumn: columns?.interestColumn.values[i + 1] || 0, + _piColumn: columns?.piColumn.values[i + 1] || 0, key: String(i + 1), - ndsCompensation: columns.vatColumn.values[i + 1], + ndsCompensation: columns?.vatColumn.values[i + 1] || 0, num: i + 1, - paymentSum: columns.sumWithVatColumn.values[i + 1], - redemptionAmount: columns.sumRepaymentColumn.values[i + 1], + paymentSum: columns?.sumWithVatColumn.values[i + 1] || 0, + redemptionAmount: columns?.sumRepaymentColumn.values[i + 1] || 0, }) ); @@ -34,6 +39,12 @@ export function transformCalculateResults({ resultPayments[0].ndsCompensation -= subsidySum - subsidySum / (1 + VAT); const resultValues: OutputData['resultValues'] = { + _resultContractEconomy: postValues.contractEconomy, + _resultContractEconomyWithVAT: postValues.contractEconomyWithVAT, + _resultPi: columns?.piColumn.values[0], + _resultSumCredit: columns?.sumCreditColumn.values[1], + _resultSumCreditPayment: columns?.creditPaymentColumn.values[0], + _resultVatRecoverable: columns?.vatRecoverableColumn.values[0], resultAB_FL: ((preparedValues.agentsSum + preparedValues.doubleAgentsSum) / ESN) * (1 - NDFL), resultAB_UL: (preparedValues.deliverySum + @@ -45,11 +56,11 @@ export function transformCalculateResults({ (columns?.npvBonusExpensesColumn?.values[1] / (1 + preparedValues?.salaryRate)) * (1 - NDFL) ), resultBonusMPL: Math.abs( - (columns.npvBonusExpensesColumn.values[2] / (1 + preparedValues.salaryRate)) * (1 - NDFL) + (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) + (columns?.extraBonusSumColumn.values[2] / (1 + preparedValues.salaryRate)) * (1 - NDFL) ), resultDopProdSum: preparedValues.rats + @@ -60,8 +71,8 @@ export function transformCalculateResults({ preparedValues.insuranceFinGAPNmper, resultFirstPayment: preparedValues.firstPaymentSum * (1 + VAT) - inputValues.subsidySum, resultFirstPaymentRiskPolicy: preparedValues?.firstPayment, - resultIRRGraphPerc: columns.sumColumn.irr, - resultIRRNominalPerc: columns.cashflowMsfoColumn.nominal, + resultIRRGraphPerc: columns?.sumColumn.irr, + resultIRRNominalPerc: columns?.cashflowMsfoColumn.nominal, resultInsKasko: preparedValues.insuranceKasko, resultInsOsago: preparedValues.insuranceOsago, resultLastPayment: last(columns?.sumWithVatColumn?.values) || 0, @@ -70,9 +81,9 @@ export function transformCalculateResults({ (preparedValues.ratBonus + preparedValues.nsBonus + preparedValues.nsibBonus) * preparedValues.marketRate * preparedValues.districtRate + - Math.abs(columns.npvBonusExpensesColumn.values[0]) + + Math.abs(columns?.npvBonusExpensesColumn.values[0]) + Math.abs( - columns.extraBonusSumColumn.values[0] + + columns?.extraBonusSumColumn.values[0] + preparedValues.importerSum + preparedValues.agentsSum + preparedValues.deliverySum + @@ -86,7 +97,7 @@ export function transformCalculateResults({ inputValues.importProgramSum, resultPriceUpPr: postValues.priceUP_Year_PR, resultTerm: preparedValues.nmper, - resultTotalGraphwithNDS: columns.sumWithVatColumn.values[0] - inputValues.subsidySum, + resultTotalGraphwithNDS: columns?.sumWithVatColumn.values[0] - inputValues.subsidySum, }; const values: OutputData['values'] = { diff --git a/apps/web/server/routers/quote/index.ts b/apps/web/server/routers/quote/index.ts index a6a6946..fae060b 100644 --- a/apps/web/server/routers/quote/index.ts +++ b/apps/web/server/routers/quote/index.ts @@ -46,7 +46,7 @@ const defaultInsurance = { }; const defaultFingap = { keys: [] }; -const defaultPayments = { values: [] }; +const defaultPayments = { values: [], sums: [] }; const { URL_CRM_DOWNLOADKP_BASE } = getUrls(); diff --git a/apps/web/stores/results/default-values.ts b/apps/web/stores/results/default-values.ts index fb61969..acadc9f 100644 --- a/apps/web/stores/results/default-values.ts +++ b/apps/web/stores/results/default-values.ts @@ -1,6 +1,12 @@ import type { ResultValues } from './types'; export const defaultResultsValues: ResultValues = { + _resultContractEconomy: 0, + _resultContractEconomyWithVAT: 0, + _resultPi: 0, + _resultSumCredit: 0, + _resultSumCreditPayment: 0, + _resultVatRecoverable: 0, resultAB_FL: 0, resultAB_UL: 0, resultBonusDopProd: 0, diff --git a/apps/web/stores/tables/payments/hooks.js b/apps/web/stores/tables/payments/hooks.js index 0e9c8f7..1186c9f 100644 --- a/apps/web/stores/tables/payments/hooks.js +++ b/apps/web/stores/tables/payments/hooks.js @@ -13,6 +13,18 @@ export function useRowValue(index) { return [storeValue, setStoreValue]; } +export function useRowSum(index) { + const { $tables } = useStore(); + + const storeValue = computed(() => $tables.payments.getSum(index)).get(); + + function setStoreValue(value) { + $tables.payments.setSum(index, value); + } + + return [storeValue, setStoreValue]; +} + export function useRowStatus(index) { const { $tables } = useStore(); diff --git a/apps/web/stores/tables/payments/index.ts b/apps/web/stores/tables/payments/index.ts index 5688f33..10ab103 100644 --- a/apps/web/stores/tables/payments/index.ts +++ b/apps/web/stores/tables/payments/index.ts @@ -10,6 +10,7 @@ export default class PaymentsTable { private root: RootStore; public validation: Validation; public values: IObservableArray; + public sums: IObservableArray; private statuses: IObservableArray; private overridedStatus: IObservableValue; @@ -23,6 +24,7 @@ export default class PaymentsTable { ); this.values = observable([]); + this.sums = observable([]); this.statuses = observable([]); this.overridedStatus = observable.box(undefined); @@ -36,6 +38,7 @@ export default class PaymentsTable { () => this.values.length, (length) => { this.statuses.length = length; + this.sums.length = length; } ); } @@ -52,6 +55,14 @@ export default class PaymentsTable { this.values[index] = value; }; + public getSum(index: number) { + return this.sums[index]; + } + + public setSum = (index: number, sum: number) => { + this.sums[index] = sum; + }; + public setValues = (values: number[]) => { this.values.replace(values); }; diff --git a/apps/web/utils/mobx.ts b/apps/web/utils/mobx.ts index 0319b68..c8a86d6 100644 --- a/apps/web/utils/mobx.ts +++ b/apps/web/utils/mobx.ts @@ -27,11 +27,13 @@ export function disposableReaction( if (disposer !== undefined) disposer(); cleanDisposer(); } else { - disposer = reaction( - expression, - effect, - reactionOpts ? omit(reactionOpts, ['fireImmediately']) : undefined - ); + setTimeout(() => { + disposer = reaction( + expression, + effect, + reactionOpts ? omit(reactionOpts, ['fireImmediately']) : undefined + ); + }, 100); } }); } diff --git a/packages/ui/antd/index.ts b/packages/ui/antd/index.ts new file mode 100644 index 0000000..a13a8f1 --- /dev/null +++ b/packages/ui/antd/index.ts @@ -0,0 +1 @@ +export * from 'antd';