Compare commits

...

14 Commits

Author SHA1 Message Date
vchikalkin
29f9e79867 add prefix _ to column names 2023-04-21 11:11:23 +03:00
vchikalkin
6adb1be0cf process/leasing-object: add selectConfiguration validation 2023-04-21 11:05:47 +03:00
vchikalkin
4d9cdf79a4 calculate: fix output validation 2023-04-21 10:59:48 +03:00
vchikalkin
5432536b2e fix prepared-values 2023-04-21 10:19:33 +03:00
vchikalkin
2097b28870 bfabdba: setTimeout for restart reaction 2023-04-21 09:47:33 +03:00
vchikalkin
b7f0a3e6cf unlimited: add new results values 2023-04-20 18:20:11 +03:00
vchikalkin
9f0c126ffb вывод столбцов для unlimited 2023-04-20 18:01:10 +03:00
vchikalkin
94e053c38d fix nsibBase 2023-04-20 17:47:37 +03:00
vchikalkin
f040cec7d2 fix preparedValues 2023-04-20 17:45:14 +03:00
vchikalkin
956180c52b fix loanRate 2023-04-20 16:21:53 +03:00
vchikalkin
8e2e9167fc calculate: pass payment sums to preparedPayments 2023-04-20 14:13:16 +03:00
vchikalkin
b38f25a039 extend payments table for unlimited 2023-04-20 13:48:44 +03:00
vchikalkin
6c3b93c914 Отключить реакцию на фильтрацию списка Методов расчета CalcType и отображать всегда все 3 значения списка (Irr? Сумма, Маржа) 2023-04-19 23:46:58 +03:00
vchikalkin
cc1f07d9e4 options: add graphType индивидуальный график 2023-04-19 23:45:39 +03:00
28 changed files with 352 additions and 97 deletions

View File

@ -1,4 +1,4 @@
import { usePaymentValue } from './hooks'; import { usePaymentSum, usePaymentValue } from './hooks';
import { useRowStatus } from '@/stores/tables/payments/hooks'; import { useRowStatus } from '@/stores/tables/payments/hooks';
import { observer } from 'mobx-react-lite'; import { observer } from 'mobx-react-lite';
import type { ComponentType } from 'react'; import type { ComponentType } from 'react';
@ -11,3 +11,12 @@ export function buildValueComponent<T>(index: number, Component: ComponentType<T
return <Component setValue={setValue} status={status} value={value} {...props} />; return <Component setValue={setValue} status={status} value={value} {...props} />;
}); });
} }
export function buildSumComponent<T>(index: number, Component: ComponentType<T>) {
return observer((props: T) => {
const [value, setValue] = usePaymentSum(index);
const status = useRowStatus(index);
return <Component setValue={setValue} status={status} value={value} {...props} />;
});
}

View File

@ -1,14 +1,22 @@
/* eslint-disable canonical/sort-keys */ /* eslint-disable canonical/sort-keys */
import { buildValueComponent } from './builders'; import { buildSumComponent, buildValueComponent } from './builders';
import type { ColumnsType } from 'antd/lib/table'; import type { ColumnsType } from 'antd/lib/table';
import { parser } from 'tools/number';
import { InputNumber } from 'ui/elements'; import { InputNumber } from 'ui/elements';
import { createFormatter } from 'ui/elements/InputNumber';
type Payment = { type Payment = {
key: number; key: number;
num: number; num: number;
paymentRelation: number; paymentRelation: number;
paymentSum: number;
}; };
const formatter = createFormatter({
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
export const columns: ColumnsType<Payment> = [ export const columns: ColumnsType<Payment> = [
{ {
key: 'num', key: 'num',
@ -27,4 +35,14 @@ export const columns: ColumnsType<Payment> = [
return <Component max={100} min={0} precision={payment.num === 0 ? 4 : 2} step={1} />; return <Component max={100} min={0} precision={payment.num === 0 ? 4 : 2} step={1} />;
}, },
}, },
{
key: 'paymentSum',
dataIndex: 'paymentSum',
title: 'Сумма',
render: (_value, payment) => {
const Component = buildSumComponent(payment.num, InputNumber);
return <Component min={0} precision={2} step={1000} formatter={formatter} parser={parser} />;
},
},
]; ];

View File

@ -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 { useEffect, useState } from 'react';
import { useDebouncedCallback } from 'use-debounce'; import { useDebouncedCallback } from 'use-debounce';
@ -20,3 +20,22 @@ export function usePaymentValue(index) {
return [value, setValue]; 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];
}

View File

@ -3,9 +3,12 @@ import { useStore } from '@/stores/hooks';
import { min } from '@/styles/mq'; import { min } from '@/styles/mq';
import { computed } from 'mobx'; import { computed } from 'mobx';
import { observer } from 'mobx-react-lite'; import { observer } from 'mobx-react-lite';
import { createContext, useContext, useMemo, useState } from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import { Segmented } from 'ui/antd';
import { Alert, Table } from 'ui/elements'; import { Alert, Table } from 'ui/elements';
import { Box, Flex } from 'ui/grid'; import { Box, Flex } from 'ui/grid';
import { useDebouncedCallback } from 'use-debounce';
const Grid = styled(Flex)` const Grid = styled(Flex)`
flex-direction: column; flex-direction: column;
@ -47,6 +50,8 @@ const Validation = observer(() => {
return null; return null;
}); });
export const ModeContext = createContext('paymentRelation');
const SPLIT_NUMBER = 12; const SPLIT_NUMBER = 12;
function TablePart({ num }) { function TablePart({ num }) {
@ -55,16 +60,25 @@ function TablePart({ num }) {
const values = payments.values.slice(num * SPLIT_NUMBER, num * SPLIT_NUMBER + SPLIT_NUMBER); 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, key: index + num * SPLIT_NUMBER,
num: index + num * SPLIT_NUMBER, num: index + num * SPLIT_NUMBER,
paymentRelation: value,
})); }));
return ( const mode = useContext(ModeContext);
<TableWrapper>
<Table size="small" columns={columns} dataSource={dataSource} pagination={false} /> return useMemo(
</TableWrapper> () => (
<TableWrapper>
<Table
size="small"
columns={columns.filter((x) => ['num', mode].includes(x.key))}
dataSource={dataSource}
pagination={false}
/>
</TableWrapper>
),
[dataSource, mode]
); );
} }
@ -84,11 +98,36 @@ const TablesGroup = observer(() => {
return <TablesGroupGrid>{tables}</TablesGroupGrid>; return <TablesGroupGrid>{tables}</TablesGroupGrid>;
}); });
function Mode({ setMode }) {
const { $process } = useStore();
if (!$process.has('Unlimited')) {
return false;
}
return (
<Segmented
block
options={[
{ label: 'Процент', value: 'paymentRelation' },
{ label: 'Сумма', value: 'paymentSum' },
]}
onChange={(value) => setMode(value)}
/>
);
}
export default function TablePayments() { export default function TablePayments() {
const [mode, setMode] = useState('paymentRelation');
const debouncedSetMode = useDebouncedCallback(setMode, 300);
return ( return (
<Grid> <Grid>
<Validation /> <ModeContext.Provider value={mode}>
<TablesGroup /> <Validation />
<Mode setMode={debouncedSetMode} />
<TablesGroup />
</ModeContext.Provider>
</Grid> </Grid>
); );
} }

View File

@ -36,4 +36,49 @@ export const columns: ColumnsType<ResultPayment> = [
currency: 'RUB', currency: 'RUB',
}).format, }).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,
},
]; ];

View File

@ -1,3 +1,4 @@
/* eslint-disable no-negated-condition */
import { columns } from './config'; import { columns } from './config';
import { MAX_LEASING_PERIOD } from '@/constants/values'; import { MAX_LEASING_PERIOD } from '@/constants/values';
import { useStore } from '@/stores/hooks'; import { useStore } from '@/stores/hooks';
@ -6,11 +7,13 @@ import { observer } from 'mobx-react-lite';
import { Table } from 'ui/elements'; import { Table } from 'ui/elements';
const PaymentsTable = observer(() => { const PaymentsTable = observer(() => {
const { $results } = useStore(); const { $results, $process } = useStore();
const unlimited = $process.has('Unlimited');
return ( return (
<Table <Table
columns={columns} columns={!unlimited ? columns.filter((x) => !x.key.includes('_')) : columns}
dataSource={toJS($results.payments)} dataSource={toJS($results.payments)}
size="small" size="small"
pagination={{ pagination={{

View File

@ -4,6 +4,12 @@ export const id = 'output';
export const title = 'Результаты'; export const title = 'Результаты';
export const titles: Record<keyof ResultValues, string> = { export const titles: Record<keyof ResultValues, string> = {
_resultContractEconomy: 'Экономика',
_resultContractEconomyWithVAT: 'Экономика, с НДС',
_resultPi: 'PI',
_resultSumCredit: 'Сумма кредита',
_resultSumCreditPayment: 'Сумма платежей по кредиту',
_resultVatRecoverable: 'НДС к возмещению',
resultAB_FL: 'АВ ФЛ, без НДФЛ.', resultAB_FL: 'АВ ФЛ, без НДФЛ.',
resultAB_UL: 'АВ ЮЛ, с НДС.', resultAB_UL: 'АВ ЮЛ, с НДС.',
resultBonusDopProd: 'Бонус МПЛ за доп.продукты, без НДФЛ', resultBonusDopProd: 'Бонус МПЛ за доп.продукты, без НДФЛ',
@ -37,6 +43,12 @@ const percentFormatter = Intl.NumberFormat('ru', {
}).format; }).format;
export const formatters = { export const formatters = {
_resultContractEconomy: moneyFormatter,
_resultContractEconomyWithVAT: moneyFormatter,
_resultPi: percentFormatter,
_resultSumCredit: moneyFormatter,
_resultSumCreditPayment: moneyFormatter,
_resultVatRecoverable: moneyFormatter,
resultAB_FL: moneyFormatter, resultAB_FL: moneyFormatter,
resultAB_UL: moneyFormatter, resultAB_UL: moneyFormatter,
resultBonusDopProd: moneyFormatter, resultBonusDopProd: moneyFormatter,

View File

@ -4,6 +4,7 @@ import { useStore } from '@/stores/hooks';
import { min } from '@/styles/mq'; import { min } from '@/styles/mq';
import { toJS } from 'mobx'; import { toJS } from 'mobx';
import { observer } from 'mobx-react-lite'; import { observer } from 'mobx-react-lite';
import { omit } from 'radash';
import styled from 'styled-components'; import styled from 'styled-components';
import { Text } from 'ui/elements'; import { Text } from 'ui/elements';
import { Box } from 'ui/grid'; import { Box } from 'ui/grid';
@ -18,8 +19,16 @@ const Grid = styled(Box)`
`; `;
const Results = observer(() => { const Results = observer(() => {
const { $results } = useStore(); const { $results, $process } = useStore();
const values = toJS($results.values);
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 ( return (
<Grid> <Grid>

View File

@ -217,6 +217,10 @@ const ColumnsSchema = z.object({
nominal: z.number(), nominal: z.number(),
values: z.number().array(), values: z.number().array(),
}), }),
cashflowMsfoWithCfColumn: z.object({
sum: z.number(),
values: z.number().array(),
}),
cashflowNpvColumn: z.object({ cashflowNpvColumn: z.object({
values: z.number().array(), values: z.number().array(),
}), }),
@ -240,6 +244,10 @@ const ColumnsSchema = z.object({
sum: z.number(), sum: z.number(),
values: z.number().array(), values: z.number().array(),
}), }),
creditPaymentColumn: z.object({
sum: z.number(),
values: z.number().array(),
}),
creditVATColumn: z.object({ creditVATColumn: z.object({
sum: z.number(), sum: z.number(),
values: z.number().array(), values: z.number().array(),
@ -351,6 +359,9 @@ const ColumnsSchema = z.object({
percentPaymentColumn: z.object({ percentPaymentColumn: z.object({
values: z.number().array(), values: z.number().array(),
}), }),
piColumn: z.object({
values: z.number().array(),
}),
ratExpensesColumn: z.object({ ratExpensesColumn: z.object({
sum: z.number(), sum: z.number(),
values: z.number().array(), values: z.number().array(),
@ -416,6 +427,10 @@ const ColumnsSchema = z.object({
sum: z.number(), sum: z.number(),
values: z.number().array(), values: z.number().array(),
}), }),
vatRecoverableColumn: z.object({
sum: z.number(),
values: z.number().array(),
}),
}); });
export const ResponseCalculateSchema = z.object({ export const ResponseCalculateSchema = z.object({

View File

@ -68,6 +68,10 @@ export const radioGraphType = [
label: 'легкий старт', label: 'легкий старт',
value: 100_000_004, value: 100_000_004,
}, },
{
label: 'индивидуальный график',
value: 100_000_005,
},
]; ];
export const selectObjectCategoryTax = [ export const selectObjectCategoryTax = [

View File

@ -1,6 +1,7 @@
import { z } from 'zod'; import { z } from 'zod';
const PaymentsSchema = z.object({ const PaymentsSchema = z.object({
sums: z.number().optional().array(),
values: z.number().array(), values: z.number().array(),
}); });

View File

@ -1,6 +1,12 @@
import { z } from 'zod'; import { z } from 'zod';
export const ResultValuesSchema = z.object({ 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_FL: z.number(),
resultAB_UL: z.number(), resultAB_UL: z.number(),
resultBonusDopProd: z.number(), resultBonusDopProd: z.number(),
@ -23,6 +29,11 @@ export const ResultValuesSchema = z.object({
}); });
export const ResultPaymentSchema = 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(), key: z.string(),
ndsCompensation: z.number(), ndsCompensation: z.number(),
num: z.number(), num: z.number(),

View File

@ -22,12 +22,13 @@ export async function action({ store, trpcClient }: ProcessContext) {
osago: toJS($tables.insurance.row('osago').getValues()), 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 trpcClient.calculate
.mutate({ .mutate({
insurance: { values: insurance }, insurance: { values: insurance },
payments: { values: payments }, payments: { sums: paymentSums, values: paymentRelations },
values, values,
}) })
.then((res) => { .then((res) => {

View File

@ -1,8 +1,10 @@
/* eslint-disable sonarjs/cognitive-complexity */
import { radioCalcType, radioGraphType, selectSeasonType } from '@/config/default-options'; import { radioCalcType, radioGraphType, selectSeasonType } from '@/config/default-options';
import * as CRMTypes from '@/graphql/crm.types'; import * as CRMTypes from '@/graphql/crm.types';
import { SEASON_TYPES } from '@/process/payments/lib/seasons-constants'; import { SEASON_TYPES } from '@/process/payments/lib/seasons-constants';
import type { ProcessContext } from '@/process/types'; import type { ProcessContext } from '@/process/types';
import { normalizeOptions } from '@/utils/entity'; import { normalizeOptions } from '@/utils/entity';
import { disposableReaction } from '@/utils/mobx';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc'; import utc from 'dayjs/plugin/utc';
import { reaction } from 'mobx'; import { reaction } from 'mobx';
@ -11,7 +13,7 @@ import { diff } from 'radash';
dayjs.extend(utc); dayjs.extend(utc);
export default function reactions({ store, apolloClient, user }: ProcessContext) { export default function reactions({ store, apolloClient, user }: ProcessContext) {
const { $calculation } = store; const { $calculation, $process } = store;
reaction( reaction(
() => $calculation.$values.getValues(['dealer', 'importProgram', 'product', 'subsidy']), () => $calculation.$values.getValues(['dealer', 'importProgram', 'product', 'subsidy']),
@ -20,7 +22,6 @@ export default function reactions({ store, apolloClient, user }: ProcessContext)
subsidy: subsidyId, subsidy: subsidyId,
importProgram: importProgramId, importProgram: importProgramId,
dealer: dealerId, dealer: dealerId,
// eslint-disable-next-line sonarjs/cognitive-complexity
}) => { }) => {
/** /**
* #1 * #1
@ -241,15 +242,21 @@ export default function reactions({ store, apolloClient, user }: ProcessContext)
({ evo_tarif } = data); ({ evo_tarif } = data);
} }
if (evo_tarif?.evo_graphtype_exception?.length) { let options = radioGraphType;
const filteredGraphTypes = radioGraphType.filter( 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) (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 фильтровать значения согласно списку * radioCalcType фильтровать значения согласно списку
* в поле "Доступные Методы расчета в калькуляторе" evo_calculation_method в selectProduct * в поле "Доступные Методы расчета в калькуляторе" evo_calculation_method в selectProduct
*/ */
reaction( disposableReaction(
() => $process.has('Unlimited'),
() => $calculation.element('selectProduct').getValue(), () => $calculation.element('selectProduct').getValue(),
async (productId) => { async (productId) => {
const IRRCalcTypeOptions = radioCalcType.filter((x) => x.value === 100_000_000); const IRRCalcTypeOptions = radioCalcType.filter((x) => x.value === 100_000_000);

View File

@ -25,13 +25,14 @@ export function action({ store, trpcClient, apolloClient }: ProcessContext) {
const fingap = $tables.fingap.getSelectedRisks(); 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 trpcClient.createQuote
.mutate({ .mutate({
fingap, fingap,
insurance: { values: insurance }, insurance: { values: insurance },
payments: { values: payments }, payments: { sums: paymentSums, values: paymentRelations },
values, values,
}) })
.then(async (res) => { .then(async (res) => {

View File

@ -8,6 +8,7 @@ import { z } from 'zod';
export function createValidationSchema({ apolloClient }: ValidationContext) { export function createValidationSchema({ apolloClient }: ValidationContext) {
return ValuesSchema.pick({ return ValuesSchema.pick({
brand: true, brand: true,
configuration: true,
countSeats: true, countSeats: true,
engineType: true, engineType: true,
engineVolume: true, engineVolume: true,
@ -30,6 +31,7 @@ export function createValidationSchema({ apolloClient }: ValidationContext) {
brand, brand,
model, model,
leaseObjectUseFor, leaseObjectUseFor,
configuration,
}, },
ctx 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) { if (!leaseObjectUseFor) {
ctx.addIssue({ ctx.addIssue({
code: z.ZodIssueCode.custom, code: z.ZodIssueCode.custom,

View File

@ -72,9 +72,7 @@ export function common({ store, trpcClient }: ProcessContext) {
$calculation.element('selectQuote').resetValue(); $calculation.element('selectQuote').resetValue();
}) })
.finally(() => { .finally(() => {
setTimeout(() => { $process.delete('LoadKP');
$process.delete('LoadKP');
}, 100);
}); });
} }
); );

View File

@ -79,6 +79,7 @@ export async function getKPData({
return { return {
payments: { payments: {
sums: [],
values: [ values: [
quote?.evo_first_payment_perc ?? 0, quote?.evo_first_payment_perc ?? 0,
...paymentsValues, ...paymentsValues,

View File

@ -53,7 +53,7 @@ export default function reactions({ store }: ProcessContext) {
}; };
}, },
({ graphType, leasingPeriod }) => { ({ graphType, leasingPeriod }) => {
if (graphType === 100_000_000) { if ([100_000_000, 100_000_005].includes(graphType)) {
const middlePayments: Row[] = Array.from( const middlePayments: Row[] = Array.from(
{ {
length: leasingPeriod - 2, length: leasingPeriod - 2,

View File

@ -19,7 +19,7 @@ export function createValidationSchema() {
seasonType: true, seasonType: true,
}) })
.extend({ .extend({
payments: PaymentsSchema, payments: PaymentsSchema.omit({ sums: true }),
}) })
.superRefine( .superRefine(
async ( async (

View File

@ -7,7 +7,7 @@ import helper from '@/process/calculate/lib/helper';
import { createCurrencyUtility } from '@/utils/currency'; import { createCurrencyUtility } from '@/utils/currency';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc'; import utc from 'dayjs/plugin/utc';
import { max, sum } from 'radash'; import { min, sum } from 'radash';
dayjs.extend(utc); dayjs.extend(utc);
@ -33,16 +33,44 @@ export async function createRequestData({
const { RUB } = createCurrencyUtility({ apolloClient }); 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 = { const preparedPayments: CoreTypes.PreparedPayments = {
rows: payments.values.map((payment, index) => ({ rows: payments.values.map((value, index) => {
gpsBasePayment: 0, const tracker_evo_planpayments = tracker?.evo_planpayments?.[index];
gpsCostPayment: 0, const telematic_evo_planpayments = telematic?.evo_planpayments?.[index];
numberPayment: index + 1,
percentPayment: index === 0 ? 0 : payment, return {
sumPayment: 0, gpsBasePayment:
tlmBasePayment: 0, (tracker_evo_planpayments?.evo_cost_price_telematics_withoutnds || 0) +
tlmCostPayment: 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); const currentDate = dayjs().utc(false);
@ -389,7 +417,9 @@ export async function createRequestData({
(x) => x?.evo_sot_coefficient_typeidData?.evo_id === 'DIRECTOR_BONUS_NSIB' (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() { async directorExtraBonus() {
@ -754,7 +784,7 @@ export async function createRequestData({
}, },
async loanRate() { async loanRate() {
return values.creditRate; return values.creditRate / 100;
}, },
async loanRatePeriod() { async loanRatePeriod() {
@ -809,9 +839,9 @@ export async function createRequestData({
}, },
async nmperInsurance() { 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() { async npvniDelta() {
@ -832,47 +862,16 @@ export async function createRequestData({
}, },
async nsBonus() { async nsBonus() {
const evo_coefficient = evo_coefficients?.find( return 0;
(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;
}, },
async nsibBase() { async nsibBase() {
const discount = await this.discount();
const plPrice = await this.plPrice(); 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 firstPaymentSum = await this.firstPaymentSum();
const value = const value = (plPrice - firstPaymentSum) * (1 + VAT);
(plPrice -
importProgramSum +
(insuranceContract +
rats +
registration +
trackerCost +
tLMCost +
transportTaxGr +
tlmCostPaymentSum +
gpsCostPaymentSum) *
leasing0K -
firstPaymentSum -
(values.product === 'LEASING0' ? 0 : discount)) *
(1 + VAT);
return max([NSIB_MAX, value], (v) => v) ?? NSIB_MAX; return min([NSIB_MAX, value]) ?? NSIB_MAX;
}, },
async nsibBonus() { async nsibBonus() {

View File

@ -21,11 +21,16 @@ export function transformCalculateResults({
length: preparedValues.nmper, length: preparedValues.nmper,
}, },
(_, i) => ({ (_, 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), key: String(i + 1),
ndsCompensation: columns.vatColumn.values[i + 1], ndsCompensation: columns?.vatColumn.values[i + 1] || 0,
num: i + 1, num: i + 1,
paymentSum: columns.sumWithVatColumn.values[i + 1], paymentSum: columns?.sumWithVatColumn.values[i + 1] || 0,
redemptionAmount: columns.sumRepaymentColumn.values[i + 1], redemptionAmount: columns?.sumRepaymentColumn.values[i + 1] || 0,
}) })
); );
@ -34,6 +39,12 @@ export function transformCalculateResults({
resultPayments[0].ndsCompensation -= subsidySum - subsidySum / (1 + VAT); resultPayments[0].ndsCompensation -= subsidySum - subsidySum / (1 + VAT);
const resultValues: OutputData['resultValues'] = { 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_FL: ((preparedValues.agentsSum + preparedValues.doubleAgentsSum) / ESN) * (1 - NDFL),
resultAB_UL: resultAB_UL:
(preparedValues.deliverySum + (preparedValues.deliverySum +
@ -45,11 +56,11 @@ export function transformCalculateResults({
(columns?.npvBonusExpensesColumn?.values[1] / (1 + preparedValues?.salaryRate)) * (1 - NDFL) (columns?.npvBonusExpensesColumn?.values[1] / (1 + preparedValues?.salaryRate)) * (1 - NDFL)
), ),
resultBonusMPL: Math.abs( 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), resultBonusSafeFinance: preparedValues?.bonusFinGAP * (1 - NDFL),
resultDopMPLLeasing: Math.abs( resultDopMPLLeasing: Math.abs(
(columns.extraBonusSumColumn.values[2] / (1 + preparedValues.salaryRate)) * (1 - NDFL) (columns?.extraBonusSumColumn.values[2] / (1 + preparedValues.salaryRate)) * (1 - NDFL)
), ),
resultDopProdSum: resultDopProdSum:
preparedValues.rats + preparedValues.rats +
@ -60,8 +71,8 @@ export function transformCalculateResults({
preparedValues.insuranceFinGAPNmper, preparedValues.insuranceFinGAPNmper,
resultFirstPayment: preparedValues.firstPaymentSum * (1 + VAT) - inputValues.subsidySum, resultFirstPayment: preparedValues.firstPaymentSum * (1 + VAT) - inputValues.subsidySum,
resultFirstPaymentRiskPolicy: preparedValues?.firstPayment, resultFirstPaymentRiskPolicy: preparedValues?.firstPayment,
resultIRRGraphPerc: columns.sumColumn.irr, resultIRRGraphPerc: columns?.sumColumn.irr,
resultIRRNominalPerc: columns.cashflowMsfoColumn.nominal, resultIRRNominalPerc: columns?.cashflowMsfoColumn.nominal,
resultInsKasko: preparedValues.insuranceKasko, resultInsKasko: preparedValues.insuranceKasko,
resultInsOsago: preparedValues.insuranceOsago, resultInsOsago: preparedValues.insuranceOsago,
resultLastPayment: last(columns?.sumWithVatColumn?.values) || 0, resultLastPayment: last(columns?.sumWithVatColumn?.values) || 0,
@ -70,9 +81,9 @@ export function transformCalculateResults({
(preparedValues.ratBonus + preparedValues.nsBonus + preparedValues.nsibBonus) * (preparedValues.ratBonus + preparedValues.nsBonus + preparedValues.nsibBonus) *
preparedValues.marketRate * preparedValues.marketRate *
preparedValues.districtRate + preparedValues.districtRate +
Math.abs(columns.npvBonusExpensesColumn.values[0]) + Math.abs(columns?.npvBonusExpensesColumn.values[0]) +
Math.abs( Math.abs(
columns.extraBonusSumColumn.values[0] + columns?.extraBonusSumColumn.values[0] +
preparedValues.importerSum + preparedValues.importerSum +
preparedValues.agentsSum + preparedValues.agentsSum +
preparedValues.deliverySum + preparedValues.deliverySum +
@ -86,7 +97,7 @@ export function transformCalculateResults({
inputValues.importProgramSum, inputValues.importProgramSum,
resultPriceUpPr: postValues.priceUP_Year_PR, resultPriceUpPr: postValues.priceUP_Year_PR,
resultTerm: preparedValues.nmper, resultTerm: preparedValues.nmper,
resultTotalGraphwithNDS: columns.sumWithVatColumn.values[0] - inputValues.subsidySum, resultTotalGraphwithNDS: columns?.sumWithVatColumn.values[0] - inputValues.subsidySum,
}; };
const values: OutputData['values'] = { const values: OutputData['values'] = {

View File

@ -46,7 +46,7 @@ const defaultInsurance = {
}; };
const defaultFingap = { keys: [] }; const defaultFingap = { keys: [] };
const defaultPayments = { values: [] }; const defaultPayments = { values: [], sums: [] };
const { URL_CRM_DOWNLOADKP_BASE } = getUrls(); const { URL_CRM_DOWNLOADKP_BASE } = getUrls();

View File

@ -1,6 +1,12 @@
import type { ResultValues } from './types'; import type { ResultValues } from './types';
export const defaultResultsValues: ResultValues = { export const defaultResultsValues: ResultValues = {
_resultContractEconomy: 0,
_resultContractEconomyWithVAT: 0,
_resultPi: 0,
_resultSumCredit: 0,
_resultSumCreditPayment: 0,
_resultVatRecoverable: 0,
resultAB_FL: 0, resultAB_FL: 0,
resultAB_UL: 0, resultAB_UL: 0,
resultBonusDopProd: 0, resultBonusDopProd: 0,

View File

@ -13,6 +13,18 @@ export function useRowValue(index) {
return [storeValue, setStoreValue]; 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) { export function useRowStatus(index) {
const { $tables } = useStore(); const { $tables } = useStore();

View File

@ -10,6 +10,7 @@ export default class PaymentsTable {
private root: RootStore; private root: RootStore;
public validation: Validation; public validation: Validation;
public values: IObservableArray<number>; public values: IObservableArray<number>;
public sums: IObservableArray<number>;
private statuses: IObservableArray<Status>; private statuses: IObservableArray<Status>;
private overridedStatus: IObservableValue<Status | undefined>; private overridedStatus: IObservableValue<Status | undefined>;
@ -23,6 +24,7 @@ export default class PaymentsTable {
); );
this.values = observable<number>([]); this.values = observable<number>([]);
this.sums = observable<number>([]);
this.statuses = observable<Status>([]); this.statuses = observable<Status>([]);
this.overridedStatus = observable.box(undefined); this.overridedStatus = observable.box(undefined);
@ -36,6 +38,7 @@ export default class PaymentsTable {
() => this.values.length, () => this.values.length,
(length) => { (length) => {
this.statuses.length = length; this.statuses.length = length;
this.sums.length = length;
} }
); );
} }
@ -52,6 +55,14 @@ export default class PaymentsTable {
this.values[index] = value; 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[]) => { public setValues = (values: number[]) => {
this.values.replace(values); this.values.replace(values);
}; };

View File

@ -27,11 +27,13 @@ export function disposableReaction<T, FireImmediately extends boolean = false>(
if (disposer !== undefined) disposer(); if (disposer !== undefined) disposer();
cleanDisposer(); cleanDisposer();
} else { } else {
disposer = reaction( setTimeout(() => {
expression, disposer = reaction(
effect, expression,
reactionOpts ? omit(reactionOpts, ['fireImmediately']) : undefined effect,
); reactionOpts ? omit(reactionOpts, ['fireImmediately']) : undefined
);
}, 100);
} }
}); });
} }

View File

@ -0,0 +1 @@
export * from 'antd';