merge migration/fix-2
This commit is contained in:
parent
95040c5a10
commit
0d35042e41
@ -3,8 +3,8 @@ import { buildOptionComponent, buildValueComponent } from './builders';
|
||||
import type * as Insurance from './types';
|
||||
import { MAX_INSURANCE } from '@/constants/values';
|
||||
import type { ColumnsType } from 'antd/lib/table';
|
||||
import { formatter, parser } from 'tools/number';
|
||||
import InputNumber from 'ui/elements/InputNumber';
|
||||
import { parser } from 'tools/number';
|
||||
import InputNumber, { createFormatter } from 'ui/elements/InputNumber';
|
||||
import Select from 'ui/elements/Select';
|
||||
|
||||
export const columns: ColumnsType<Insurance.RowValues> = [
|
||||
@ -44,7 +44,7 @@ export const columns: ColumnsType<Insurance.RowValues> = [
|
||||
return (
|
||||
<Component
|
||||
addonAfter="₽"
|
||||
formatter={formatter}
|
||||
formatter={createFormatter({ minimumFractionDigits: 2, maximumFractionDigits: 2 })}
|
||||
max={MAX_INSURANCE}
|
||||
min={0}
|
||||
parser={parser}
|
||||
|
||||
@ -4,8 +4,11 @@ import CurrencyAddon from '../addons/currency-addon';
|
||||
import type { ElementsProps } from './elements-components';
|
||||
import { MAX_FRANCHISE, MAX_LEASING_PERIOD } from '@/constants/values';
|
||||
import dayjs from 'dayjs';
|
||||
import { formatter, formatterExtra, parser } from 'tools/number';
|
||||
import { parser } from 'tools/number';
|
||||
import { DownloadOutlined, PlusOutlined } from 'ui/elements/icons';
|
||||
import { createFormatter } from 'ui/elements/InputNumber';
|
||||
|
||||
const formatter = createFormatter({ minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||||
|
||||
const props: Partial<ElementsProps> = {
|
||||
tbxLeaseObjectPrice: {
|
||||
@ -77,7 +80,7 @@ const props: Partial<ElementsProps> = {
|
||||
max: 50,
|
||||
precision: 4,
|
||||
parser,
|
||||
formatter: formatterExtra,
|
||||
formatter: createFormatter({ minimumFractionDigits: 4, maximumFractionDigits: 4 }),
|
||||
addonAfter: '%',
|
||||
},
|
||||
tbxFirstPaymentRub: {
|
||||
@ -95,7 +98,7 @@ const props: Partial<ElementsProps> = {
|
||||
step: 1,
|
||||
precision: 6,
|
||||
parser,
|
||||
formatter: formatterExtra,
|
||||
formatter: createFormatter({ minimumFractionDigits: 6, maximumFractionDigits: 6 }),
|
||||
addonAfter: '%',
|
||||
},
|
||||
tbxLastPaymentRub: {
|
||||
@ -203,7 +206,7 @@ const props: Partial<ElementsProps> = {
|
||||
step: 0.5,
|
||||
precision: 4,
|
||||
parser,
|
||||
formatter: formatterExtra,
|
||||
formatter: createFormatter({ minimumFractionDigits: 4, maximumFractionDigits: 4 }),
|
||||
addonAfter: 'л',
|
||||
},
|
||||
tbxMaxMass: {
|
||||
@ -363,7 +366,7 @@ const props: Partial<ElementsProps> = {
|
||||
step: 0.0001,
|
||||
precision: 6,
|
||||
parser,
|
||||
formatter: formatterExtra,
|
||||
formatter: createFormatter({ minimumFractionDigits: 6, maximumFractionDigits: 6 }),
|
||||
addonAfter: '%',
|
||||
},
|
||||
linkDownloadKp: {
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import type { ResultValues } from '@/stores/results/types';
|
||||
import { moneyFormatter, percentFormatter } from 'tools';
|
||||
|
||||
export const id = 'output';
|
||||
export const title = 'Результаты';
|
||||
@ -26,6 +25,17 @@ export const titles: Record<keyof ResultValues, string> = {
|
||||
resultTotalGraphwithNDS: 'Итого по графику, с НДС',
|
||||
};
|
||||
|
||||
const moneyFormatter = Intl.NumberFormat('ru', {
|
||||
currency: 'RUB',
|
||||
style: 'currency',
|
||||
}).format;
|
||||
|
||||
const percentFormatter = Intl.NumberFormat('ru', {
|
||||
maximumFractionDigits: 2,
|
||||
minimumFractionDigits: 2,
|
||||
style: 'percent',
|
||||
}).format;
|
||||
|
||||
export const formatters = {
|
||||
resultAB_FL: moneyFormatter,
|
||||
resultAB_UL: moneyFormatter,
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
import helper from '../lib/helper';
|
||||
import type { ProcessContext } from '@/process/types';
|
||||
import { reaction } from 'mobx';
|
||||
import { formatter } from 'tools';
|
||||
|
||||
export const formatter = Intl.NumberFormat('ru', {
|
||||
minimumFractionDigits: 2,
|
||||
}).format;
|
||||
|
||||
export default function reactions({ store, apolloClient }: ProcessContext) {
|
||||
const { $calculation } = store;
|
||||
@ -27,7 +30,9 @@ export default function reactions({ store, apolloClient }: ProcessContext) {
|
||||
fireImmediately: true,
|
||||
}
|
||||
);
|
||||
|
||||
const { getIrr } = helper({ apolloClient });
|
||||
|
||||
reaction(
|
||||
() => $calculation.$values.getValues(['product', 'tarif', 'bonusCoefficient']),
|
||||
async (values) => {
|
||||
|
||||
@ -96,30 +96,31 @@ export function common({ store, apolloClient, queryClient }: ProcessContext) {
|
||||
typePTS,
|
||||
objectRegistration,
|
||||
}) => {
|
||||
if (objectRegistration === 100_000_001 && typePTS === 100_000_001) {
|
||||
$calculation.element('selectObjectCategoryTax').unblock();
|
||||
if (leaseObjectTypeId) {
|
||||
const {
|
||||
data: { evo_leasingobject_type },
|
||||
} = await apolloClient.query({
|
||||
query: CRMTypes.GetLeaseObjectTypeDocument,
|
||||
variables: { leaseObjectTypeId },
|
||||
});
|
||||
if (leaseObjectCategory && leaseObjectCategory === evo_leasingobject_type?.evo_category) {
|
||||
$calculation
|
||||
.element('selectObjectCategoryTax')
|
||||
.setOptions(
|
||||
selectObjectCategoryTax.filter((option) =>
|
||||
evo_leasingobject_type?.evo_category_tr?.includes(option.value)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$calculation.element('selectObjectCategoryTax').resetOptions();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$calculation.element('selectObjectCategoryTax').resetValue().block();
|
||||
if (!(objectRegistration === 100_000_001 && typePTS === 100_000_001) || !leaseObjectTypeId) {
|
||||
$calculation.element('selectObjectCategoryTax').resetOptions().resetValue().block();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
data: { evo_leasingobject_type },
|
||||
} = await apolloClient.query({
|
||||
query: CRMTypes.GetLeaseObjectTypeDocument,
|
||||
variables: { leaseObjectTypeId },
|
||||
});
|
||||
if (leaseObjectCategory && leaseObjectCategory === evo_leasingobject_type?.evo_category) {
|
||||
$calculation
|
||||
.element('selectObjectCategoryTax')
|
||||
.setOptions(
|
||||
selectObjectCategoryTax.filter((option) =>
|
||||
evo_leasingobject_type?.evo_category_tr?.includes(option.value)
|
||||
)
|
||||
)
|
||||
.unblock();
|
||||
}
|
||||
},
|
||||
{
|
||||
fireImmediately: true,
|
||||
}
|
||||
);
|
||||
|
||||
@ -226,6 +227,7 @@ export function common({ store, apolloClient, queryClient }: ProcessContext) {
|
||||
() => $process.has('LoadKP')
|
||||
);
|
||||
|
||||
// Не дышать на реакцию
|
||||
reaction(
|
||||
() =>
|
||||
$calculation.$values.getValues([
|
||||
@ -243,20 +245,18 @@ export function common({ store, apolloClient, queryClient }: ProcessContext) {
|
||||
typePTS,
|
||||
leaseObjectCategory,
|
||||
leaseObjectType,
|
||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||
}) => {
|
||||
if (!objectRegionRegistrationId || !regionRegistrationId) {
|
||||
$calculation.element('selectRegistration').resetValue();
|
||||
|
||||
return;
|
||||
}
|
||||
const currentDate = dayjs().utc(false).format('YYYY-MM-DD');
|
||||
|
||||
const {
|
||||
data: { evo_region },
|
||||
} = await apolloClient.query({
|
||||
query: CRMTypes.GetRegionDocument,
|
||||
variables: { regionId: objectRegionRegistrationId },
|
||||
});
|
||||
let evo_region: CRMTypes.GetRegionQuery['evo_region'];
|
||||
if (objectRegionRegistrationId) {
|
||||
const { data } = await apolloClient.query({
|
||||
query: CRMTypes.GetRegionDocument,
|
||||
variables: { regionId: objectRegionRegistrationId },
|
||||
});
|
||||
evo_region = data.evo_region;
|
||||
}
|
||||
|
||||
const {
|
||||
data: { evo_addproduct_types },
|
||||
@ -265,27 +265,50 @@ export function common({ store, apolloClient, queryClient }: ProcessContext) {
|
||||
variables: { currentDate },
|
||||
});
|
||||
|
||||
const options = evo_addproduct_types?.filter(
|
||||
(x) =>
|
||||
x?.evo_leasingobject_types?.find(
|
||||
const options = evo_addproduct_types?.filter((x) => {
|
||||
if (
|
||||
!x?.evo_leasingobject_types?.find(
|
||||
(evo_leasingobject_type) =>
|
||||
evo_leasingobject_type?.evo_leasingobject_typeid === leaseObjectType
|
||||
) &&
|
||||
x.evo_whom_register === objectRegistration &&
|
||||
Boolean(
|
||||
leaseObjectCategory === 100_000_001
|
||||
? x.evo_towtruck === true || x.evo_towtruck === false
|
||||
: x.evo_towtruck === false
|
||||
) &&
|
||||
x.evo_gibdd_region === (objectRegionRegistrationId === regionRegistrationId) &&
|
||||
Boolean(typePTS && x.evo_pts_type?.includes(typePTS)) &&
|
||||
Boolean(
|
||||
x.evo_accountid &&
|
||||
evo_region?.accounts?.some(
|
||||
(evo_region_account) => evo_region_account?.accountid === x.evo_accountid
|
||||
)
|
||||
)
|
||||
);
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!objectRegionRegistrationId && !regionRegistrationId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(x?.evo_whom_register === objectRegistration)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (leaseObjectCategory !== 100_000_001 && x?.evo_towtruck) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(x?.evo_gibdd_region === (objectRegionRegistrationId === regionRegistrationId))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
(typePTS &&
|
||||
(!x?.evo_pts_type ||
|
||||
x?.evo_pts_type.filter((evo_pts_type) => evo_pts_type > 0).length === 0)) ||
|
||||
(typePTS &&
|
||||
x?.evo_pts_type?.filter((evo_pts_type) => evo_pts_type > 0).includes(typePTS) === false)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!x?.evo_accountid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return evo_region?.accounts
|
||||
?.map((evo_region_account) => evo_region_account?.accountid)
|
||||
.includes(x.evo_accountid);
|
||||
});
|
||||
|
||||
$calculation.element('selectRegistration').setOptions(normalizeOptions(options));
|
||||
}
|
||||
@ -473,6 +496,22 @@ export function common({ store, apolloClient, queryClient }: ProcessContext) {
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
reaction(
|
||||
() => $calculation.element('radioObjectRegistration').getValue(),
|
||||
(objectRegistration) => {
|
||||
if (objectRegistration === 100_000_000) {
|
||||
$calculation.element('tbxVehicleTaxInYear').resetValue().block();
|
||||
$calculation.element('radioTypePTS').resetValue().block();
|
||||
} else {
|
||||
$calculation.element('tbxVehicleTaxInYear').unblock();
|
||||
$calculation.element('radioTypePTS').unblock();
|
||||
}
|
||||
},
|
||||
{
|
||||
fireImmediately: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const key = uid(7);
|
||||
|
||||
@ -8,6 +8,7 @@ import { gql } from '@apollo/client';
|
||||
|
||||
const { DEFAULT_FINGAP_ROW, DEFAULT_KASKO_ROW, DEFAULT_OSAGO_ROW } = insuranceTable;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const QUERY_GET_QUOTE_INSURANCE_DATA = gql`
|
||||
query GetQuoteInsuranceData($quoteId: Uuid!) {
|
||||
quote(quoteId: $quoteId) {
|
||||
@ -70,12 +71,12 @@ export async function getKPData({
|
||||
},
|
||||
values: {
|
||||
GPSBrand: quote?.evo_gps_brandid,
|
||||
GPSModel: quote?.evo_gps_modelid,
|
||||
insAgeDrivers: quote?.evo_age_drivers ?? defaultValues.insAgeDrivers,
|
||||
insDecentral: quote?.evo_insurance_decentral ?? defaultValues.insDecentral,
|
||||
insExpDrivers: quote?.evo_exp_drivers ?? defaultValues.insExpDrivers,
|
||||
insFranchise: quote?.evo_franchise ?? defaultValues.insFranchise,
|
||||
insUnlimitDrivers: quote?.evo_unlimit_drivers ?? defaultValues.insUnlimitDrivers,
|
||||
model: quote?.evo_gps_modelid,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -267,40 +267,25 @@ export default function reactions({ store, apolloClient }: ProcessContext) {
|
||||
);
|
||||
|
||||
reaction(
|
||||
() => $calculation.$values.getValues(['model', 'configuration']),
|
||||
async ({ model: modelId, configuration: configurationId }) => {
|
||||
$calculation.element('labelDepreciationGroup').resetValue();
|
||||
|
||||
if (configurationId) {
|
||||
const {
|
||||
data: { evo_equipment },
|
||||
} = await apolloClient.query({
|
||||
query: CRMTypes.GetConfigurationDocument,
|
||||
variables: { configurationId },
|
||||
});
|
||||
|
||||
if (evo_equipment?.evo_impairment_groupidData?.evo_name) {
|
||||
$calculation
|
||||
.element('labelDepreciationGroup')
|
||||
.setValue(evo_equipment?.evo_impairment_groupidData?.evo_name);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
() => $calculation.$values.getValues(['model']),
|
||||
async ({ model: modelId }) => {
|
||||
let evo_model: CRMTypes.GetModelQuery['evo_model'] = null;
|
||||
|
||||
if (modelId) {
|
||||
const {
|
||||
data: { evo_model },
|
||||
} = await apolloClient.query({
|
||||
const { data } = await apolloClient.query({
|
||||
query: CRMTypes.GetModelDocument,
|
||||
variables: { modelId },
|
||||
});
|
||||
|
||||
if (evo_model?.evo_impairment_groupidData?.evo_name) {
|
||||
$calculation
|
||||
.element('labelDepreciationGroup')
|
||||
.setValue(evo_model?.evo_impairment_groupidData?.evo_name);
|
||||
}
|
||||
evo_model = data.evo_model;
|
||||
}
|
||||
|
||||
if (evo_model?.evo_impairment_groupidData?.evo_name) {
|
||||
$calculation
|
||||
.element('labelDepreciationGroup')
|
||||
.setValue(evo_model?.evo_impairment_groupidData?.evo_name);
|
||||
} else {
|
||||
$calculation.element('labelDepreciationGroup').resetValue();
|
||||
}
|
||||
}
|
||||
);
|
||||
@ -429,7 +414,7 @@ export default function reactions({ store, apolloClient }: ProcessContext) {
|
||||
});
|
||||
|
||||
if (evo_leasingobject_type?.evo_id === '8') {
|
||||
$calculation.element('selectEngineType').resetValue().block();
|
||||
$calculation.element('selectEngineType').setValue(null).block();
|
||||
$calculation.element('tbxEngineVolume').resetValue().block();
|
||||
$calculation.element('tbxLeaseObjectMotorPower').resetValue().block();
|
||||
} else {
|
||||
|
||||
@ -9,8 +9,10 @@ export function common({ store, trpcClient }: ProcessContext) {
|
||||
const { $calculation, $process, $tables } = store;
|
||||
|
||||
reaction(
|
||||
() => $calculation.element('selectQuote').getOption(),
|
||||
(quote) => {
|
||||
() => $calculation.$values.getValue('quote'),
|
||||
() => {
|
||||
const quote = $calculation.element('selectQuote').getOption();
|
||||
|
||||
if (!quote || $process.has('LoadKP')) return;
|
||||
|
||||
$process.add('LoadKP');
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
import type { GetQuoteInputData, GetQuoteProcessData } from '../load-kp/types';
|
||||
import { generateDegressionRows } from './lib/degression-tools';
|
||||
import initializeApollo from '@/apollo/client';
|
||||
import defaultValues from '@/config/default-values';
|
||||
import * as CRMTypes from '@/graphql/crm.types';
|
||||
import { gql } from '@apollo/client';
|
||||
import { sort } from 'radash';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const QUERY_GET_QUOTE_PAYMENTS_DATA = gql`
|
||||
query GetQuotePaymentsData($quoteId: Uuid!) {
|
||||
quote(quoteId: $quoteId) {
|
||||
@ -27,6 +29,7 @@ const QUERY_GET_QUOTE_PAYMENTS_DATA = gql`
|
||||
}
|
||||
`;
|
||||
|
||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||
export async function getKPData({
|
||||
values: { quote: quoteId, recalcWithRevision },
|
||||
}: GetQuoteInputData): Promise<GetQuoteProcessData> {
|
||||
@ -45,7 +48,13 @@ export async function getKPData({
|
||||
? Math.min(quote?.evo_period ?? 0, quote?.evo_accept_period ?? 0)
|
||||
: quote?.evo_period ?? 0;
|
||||
|
||||
const graphType = quote?.evo_graph_type ?? defaultValues.graphType;
|
||||
const firstPaymentPerc = quote?.evo_first_payment_perc ?? defaultValues.firstPaymentPerc;
|
||||
const lastPaymentPerc = quote?.evo_last_payment_perc ?? defaultValues.lastPaymentPerc;
|
||||
const seasonType = quote?.evo_seasons_type;
|
||||
|
||||
let paymentsValues: number[] = [];
|
||||
|
||||
if (quote?.evo_graphs) {
|
||||
paymentsValues =
|
||||
sort(quote?.evo_graphs, (evo_graph) => Date.parse(evo_graph?.createdon ?? '0'))
|
||||
@ -55,6 +64,19 @@ export async function getKPData({
|
||||
.map((payment) => payment?.evo_payment_ratio || 0) || [];
|
||||
}
|
||||
|
||||
const isDegression =
|
||||
graphType === 100_000_001 &&
|
||||
seasonType !== null &&
|
||||
seasonType !== undefined &&
|
||||
seasonType !== 100_000_007;
|
||||
|
||||
if (recalcWithRevision && isDegression) {
|
||||
paymentsValues = generateDegressionRows({
|
||||
leasingPeriod,
|
||||
seasonType,
|
||||
}).map((x) => x.value);
|
||||
}
|
||||
|
||||
return {
|
||||
payments: {
|
||||
values: [
|
||||
@ -64,14 +86,14 @@ export async function getKPData({
|
||||
],
|
||||
},
|
||||
values: {
|
||||
firstPaymentPerc: quote?.evo_first_payment_perc ?? defaultValues.firstPaymentPerc,
|
||||
graphType: quote?.evo_graph_type ?? defaultValues.graphType,
|
||||
firstPaymentPerc,
|
||||
graphType,
|
||||
highSeasonStart: quote?.evo_high_season,
|
||||
lastPaymentPerc: quote?.evo_last_payment_perc ?? defaultValues.lastPaymentPerc,
|
||||
lastPaymentPerc,
|
||||
leasingPeriod,
|
||||
parmentsDecreasePercent:
|
||||
quote?.evo_payments_decrease_perc ?? defaultValues.parmentsDecreasePercent,
|
||||
seasonType: quote?.evo_seasons_type,
|
||||
seasonType,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
75
apps/web/process/payments/lib/degression-tools.ts
Normal file
75
apps/web/process/payments/lib/degression-tools.ts
Normal file
@ -0,0 +1,75 @@
|
||||
import type { CalculationValues } from '@/stores/calculation/values/types';
|
||||
import type { Row } from '@/stores/tables/payments/types';
|
||||
|
||||
const degressionSteps: { [key: number]: number[] } = {
|
||||
100_000_003: [100, 50, 25],
|
||||
100_000_004: [100, 30, 10],
|
||||
100_000_005: [100, 70, 40],
|
||||
100_000_006: [100, 7, 3],
|
||||
};
|
||||
|
||||
export function generateDegressionRows({
|
||||
seasonType: degressionType,
|
||||
leasingPeriod,
|
||||
}: Pick<CalculationValues, 'leasingPeriod' | 'seasonType'>) {
|
||||
let middlePayments: Row[] = [];
|
||||
|
||||
switch (degressionType) {
|
||||
case 100_000_007: {
|
||||
const editablePayments: Row[] = Array.from(
|
||||
{
|
||||
length: leasingPeriod - 3,
|
||||
},
|
||||
() => ({
|
||||
status: 'Default',
|
||||
value: 100,
|
||||
})
|
||||
);
|
||||
|
||||
middlePayments = [
|
||||
{
|
||||
status: 'Disabled',
|
||||
value: 100,
|
||||
},
|
||||
...editablePayments,
|
||||
];
|
||||
|
||||
break;
|
||||
}
|
||||
case 100_000_003:
|
||||
case 100_000_004:
|
||||
case 100_000_005:
|
||||
case 100_000_006: {
|
||||
const [step1, step2, step3] = degressionSteps[degressionType];
|
||||
const paymentsInStep = Math.ceil((leasingPeriod - 2) / 3);
|
||||
|
||||
middlePayments = Array.from(
|
||||
{
|
||||
length: leasingPeriod - 2,
|
||||
},
|
||||
(_v, i) => {
|
||||
let value = step3;
|
||||
|
||||
if (i <= paymentsInStep * 2 - 1) {
|
||||
value = step2;
|
||||
}
|
||||
|
||||
if (i <= paymentsInStep - 1) {
|
||||
value = step1;
|
||||
}
|
||||
|
||||
return {
|
||||
status: 'Disabled',
|
||||
value,
|
||||
};
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return middlePayments;
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
import * as degressionTools from '../lib/degression-tools';
|
||||
import * as seasonsConstants from '../lib/seasons-constants';
|
||||
import * as seasonsTools from '../lib/seasons-tools';
|
||||
import { selectHighSeasonStart } from '@/config/default-options';
|
||||
@ -244,108 +245,39 @@ export default function reactions({ store }: ProcessContext) {
|
||||
// }
|
||||
// );
|
||||
|
||||
const degressionSteps: { [key: number]: number[] } = {
|
||||
100_000_003: [100, 50, 25],
|
||||
100_000_004: [100, 30, 10],
|
||||
100_000_005: [100, 70, 40],
|
||||
100_000_006: [100, 7, 3],
|
||||
};
|
||||
makeDisposable(
|
||||
() =>
|
||||
reaction(
|
||||
() => $calculation.$values.getValues(['leasingPeriod', 'seasonType']),
|
||||
({ seasonType, leasingPeriod }) => {
|
||||
const middlePayments: Row[] = degressionTools.generateDegressionRows({
|
||||
leasingPeriod,
|
||||
seasonType,
|
||||
});
|
||||
|
||||
reaction(
|
||||
() => {
|
||||
const degressionType = $calculation.element('selectSeasonType').getValue();
|
||||
const leasingPeriod = $calculation.element('tbxLeasingPeriod').getValue();
|
||||
const graphType = $calculation.element('radioGraphType').getValue();
|
||||
const firstPaymentPerc = $calculation.element('tbxFirstPaymentPerc').getValue();
|
||||
const lastPaymentPerc = $calculation.element('tbxLastPaymentPerc').getValue();
|
||||
|
||||
return {
|
||||
degressionType,
|
||||
graphType,
|
||||
leasingPeriod,
|
||||
};
|
||||
},
|
||||
({ degressionType, leasingPeriod, graphType }) => {
|
||||
if (graphType === 100_000_001) {
|
||||
let middlePayments: Row[] = [];
|
||||
const rows: Row[] = [
|
||||
{
|
||||
status: 'Disabled',
|
||||
value: firstPaymentPerc,
|
||||
},
|
||||
...middlePayments,
|
||||
{
|
||||
status: 'Disabled',
|
||||
value: lastPaymentPerc,
|
||||
},
|
||||
];
|
||||
|
||||
switch (degressionType) {
|
||||
case 100_000_007: {
|
||||
const editablePayments: Row[] = Array.from(
|
||||
{
|
||||
length: leasingPeriod - 3,
|
||||
},
|
||||
() => ({
|
||||
status: 'Default',
|
||||
value: 100,
|
||||
})
|
||||
);
|
||||
|
||||
middlePayments = [
|
||||
{
|
||||
status: 'Disabled',
|
||||
value: 100,
|
||||
},
|
||||
...editablePayments,
|
||||
];
|
||||
|
||||
break;
|
||||
if (!$process.has('LoadKP')) {
|
||||
$tables.payments.setValues(rows.map((row) => row.value));
|
||||
}
|
||||
case 100_000_003:
|
||||
case 100_000_004:
|
||||
case 100_000_005:
|
||||
case 100_000_006: {
|
||||
const [step1, step2, step3] = degressionSteps[degressionType];
|
||||
const paymentsInStep = Math.ceil((leasingPeriod - 2) / 3);
|
||||
|
||||
middlePayments = Array.from(
|
||||
{
|
||||
length: leasingPeriod - 2,
|
||||
},
|
||||
(_v, i) => {
|
||||
let value = step3;
|
||||
|
||||
if (i <= paymentsInStep * 2 - 1) {
|
||||
value = step2;
|
||||
}
|
||||
|
||||
if (i <= paymentsInStep - 1) {
|
||||
value = step1;
|
||||
}
|
||||
|
||||
return {
|
||||
status: 'Disabled',
|
||||
value,
|
||||
};
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
$tables.payments.setStatuses(rows.map((row) => row.status));
|
||||
}
|
||||
|
||||
const firstPaymentPerc = $calculation.element('tbxFirstPaymentPerc').getValue();
|
||||
const lastPaymentPerc = $calculation.element('tbxLastPaymentPerc').getValue();
|
||||
|
||||
const rows: Row[] = [
|
||||
{
|
||||
status: 'Disabled',
|
||||
value: firstPaymentPerc,
|
||||
},
|
||||
...middlePayments,
|
||||
{
|
||||
status: 'Disabled',
|
||||
value: lastPaymentPerc,
|
||||
},
|
||||
];
|
||||
|
||||
if (!$process.has('LoadKP')) {
|
||||
$tables.payments.setValues(rows.map((row) => row.value));
|
||||
}
|
||||
|
||||
$tables.payments.setStatuses(rows.map((row) => row.status));
|
||||
}
|
||||
}
|
||||
),
|
||||
() => $calculation.element('radioGraphType').getValue() !== 100_000_001
|
||||
);
|
||||
|
||||
makeDisposable(
|
||||
@ -532,11 +464,16 @@ export default function reactions({ store }: ProcessContext) {
|
||||
() => $process.has('LoadKP')
|
||||
);
|
||||
|
||||
reaction(
|
||||
() => $calculation.element('radioGraphType').getValue(),
|
||||
() => {
|
||||
$calculation.element('selectSeasonType').resetValue();
|
||||
$calculation.element('selectHighSeasonStart').resetValue();
|
||||
}
|
||||
makeDisposable(
|
||||
() =>
|
||||
reaction(
|
||||
() => $calculation.element('radioGraphType').getValue(),
|
||||
() => {
|
||||
$calculation.element('selectSeasonType').resetValue();
|
||||
$calculation.element('selectHighSeasonStart').resetValue();
|
||||
$calculation.element('tbxParmentsDecreasePercent').resetValue();
|
||||
}
|
||||
),
|
||||
() => $process.has('LoadKP')
|
||||
);
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ import { VAT } from '@/constants/values';
|
||||
import * as CRMTypes from '@/graphql/crm.types';
|
||||
import type { ProcessContext } from '@/process/types';
|
||||
import { reaction } from 'mobx';
|
||||
import { makeDisposable } from 'tools';
|
||||
import { makeDisposable, round } from 'tools';
|
||||
|
||||
export default function reactions({ store, apolloClient }: ProcessContext) {
|
||||
const { $calculation, $process } = store;
|
||||
@ -40,9 +40,14 @@ export default function reactions({ store, apolloClient }: ProcessContext) {
|
||||
reaction(
|
||||
() => $calculation.$values.getValues(['leaseObjectPrice', 'supplierDiscountRub']),
|
||||
({ leaseObjectPrice, supplierDiscountRub }) => {
|
||||
$calculation
|
||||
.element('tbxSupplierDiscountPerc')
|
||||
.setValue((supplierDiscountRub / leaseObjectPrice) * 100);
|
||||
// NaN fix
|
||||
if (leaseObjectPrice === 0) {
|
||||
$calculation.element('tbxSupplierDiscountPerc').resetValue();
|
||||
} else {
|
||||
$calculation
|
||||
.element('tbxSupplierDiscountPerc')
|
||||
.setValue((supplierDiscountRub / leaseObjectPrice) * 100);
|
||||
}
|
||||
},
|
||||
{
|
||||
fireImmediately: true,
|
||||
@ -90,7 +95,7 @@ export default function reactions({ store, apolloClient }: ProcessContext) {
|
||||
.element('tbxLeaseObjectPriceWthtVAT')
|
||||
.setValue(leaseObjectPrice - VATInLeaseObjectPrice);
|
||||
} else {
|
||||
const priceWithVAT = leaseObjectPrice / (1 + VAT);
|
||||
const priceWithVAT = round(leaseObjectPrice / (1 + VAT), 2);
|
||||
const priceVAT = leaseObjectPrice - priceWithVAT;
|
||||
$calculation.element('tbxLeaseObjectPriceWthtVAT').setValue(priceWithVAT);
|
||||
$calculation.element('tbxVATInLeaseObjectPrice').setValue(priceVAT);
|
||||
@ -128,9 +133,15 @@ export default function reactions({ store, apolloClient }: ProcessContext) {
|
||||
);
|
||||
|
||||
reaction(
|
||||
() => $calculation.$values.getValues(['comissionPerc', 'plPriceRub']),
|
||||
({ plPriceRub, comissionPerc }) => {
|
||||
const rub = (comissionPerc * plPriceRub) / 100;
|
||||
() =>
|
||||
$calculation.$values.getValues([
|
||||
'comissionPerc',
|
||||
'plPriceRub',
|
||||
'addEquipmentPrice',
|
||||
'importProgramSum',
|
||||
]),
|
||||
({ plPriceRub, comissionPerc, addEquipmentPrice, importProgramSum }) => {
|
||||
const rub = (comissionPerc * (plPriceRub + addEquipmentPrice - importProgramSum)) / 100;
|
||||
$calculation.element('tbxComissionRub').setValue(rub);
|
||||
}
|
||||
);
|
||||
@ -140,8 +151,9 @@ export default function reactions({ store, apolloClient }: ProcessContext) {
|
||||
reaction(
|
||||
() => $calculation.element('tbxComissionRub').getValue(),
|
||||
(comissionRub) => {
|
||||
const { plPriceRub } = $calculation.$values.getValues();
|
||||
const perc = (comissionRub / plPriceRub) * 100;
|
||||
const { plPriceRub, addEquipmentPrice, importProgramSum } =
|
||||
$calculation.$values.getValues();
|
||||
const perc = (comissionRub / (plPriceRub + addEquipmentPrice - importProgramSum)) * 100;
|
||||
$calculation.element('tbxComissionPerc').setValue(perc);
|
||||
}
|
||||
),
|
||||
@ -157,28 +169,40 @@ export default function reactions({ store, apolloClient }: ProcessContext) {
|
||||
'lastPaymentPerc',
|
||||
'addEquipmentPrice',
|
||||
'importProgramSum',
|
||||
'lastPaymentRule',
|
||||
]),
|
||||
({ addEquipmentPrice, lastPaymentPerc, plPriceRub, importProgramSum }) => {
|
||||
({ addEquipmentPrice, lastPaymentPerc, plPriceRub, importProgramSum, lastPaymentRule }) => {
|
||||
if (lastPaymentRule === 100_000_000) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rub = (lastPaymentPerc * (plPriceRub + addEquipmentPrice - importProgramSum)) / 100;
|
||||
$calculation.element('tbxLastPaymentRub').setValue(rub);
|
||||
}
|
||||
),
|
||||
() => $calculation.element('radioLastPaymentRule').getValue() === 100_000_000
|
||||
() => $process.has('LoadKP')
|
||||
);
|
||||
|
||||
makeDisposable(
|
||||
() =>
|
||||
reaction(
|
||||
() => $calculation.element('tbxLastPaymentRub').getValue(),
|
||||
(lastPaymentRub) => {
|
||||
const { plPriceRub, addEquipmentPrice, importProgramSum } =
|
||||
$calculation.$values.getValues();
|
||||
() =>
|
||||
$calculation.$values.getValues([
|
||||
'plPriceRub',
|
||||
'lastPaymentRub',
|
||||
'addEquipmentPrice',
|
||||
'importProgramSum',
|
||||
'lastPaymentRule',
|
||||
]),
|
||||
({ lastPaymentRub, plPriceRub, addEquipmentPrice, importProgramSum, lastPaymentRule }) => {
|
||||
if (lastPaymentRule === 100_000_001) {
|
||||
return;
|
||||
}
|
||||
|
||||
const perc = (lastPaymentRub / (plPriceRub + addEquipmentPrice - importProgramSum)) * 100;
|
||||
$calculation.element('tbxLastPaymentPerc').setValue(perc);
|
||||
}
|
||||
),
|
||||
() =>
|
||||
$process.has('LoadKP') ||
|
||||
$calculation.element('radioLastPaymentRule').getValue() === 100_000_001
|
||||
() => $process.has('LoadKP')
|
||||
);
|
||||
}
|
||||
|
||||
@ -90,10 +90,8 @@ export function common({ store, apolloClient }: ProcessContext) {
|
||||
* иначе открыты для редактирования
|
||||
*/
|
||||
reaction(
|
||||
() => $calculation.$values.getValues(['recalcWithRevision', 'quote']),
|
||||
async ({ recalcWithRevision }) => {
|
||||
const productId = $calculation.element('selectProduct').getValue();
|
||||
|
||||
() => $calculation.$values.getValues(['recalcWithRevision', 'product']),
|
||||
async ({ recalcWithRevision, product: productId }) => {
|
||||
if (!productId) {
|
||||
$calculation.element('tbxFirstPaymentPerc').unblock();
|
||||
$calculation.element('tbxFirstPaymentRub').unblock();
|
||||
@ -184,25 +182,25 @@ export function common({ store, apolloClient }: ProcessContext) {
|
||||
reaction(
|
||||
() => $calculation.$values.getValues(['leaseObjectUsed', 'subsidy', 'product', 'dealer']),
|
||||
async ({ leaseObjectUsed, subsidy, product: productId, dealer: dealerId }) => {
|
||||
if (!productId || !dealerId) {
|
||||
$calculation.element('radioDeliveryTime').unblock();
|
||||
let evo_baseproduct: CRMTypes.GetProductQuery['evo_baseproduct'] = null;
|
||||
let dealer: CRMTypes.GetDealerQuery['dealer'] = null;
|
||||
|
||||
return;
|
||||
if (productId) {
|
||||
const { data } = await apolloClient.query({
|
||||
query: CRMTypes.GetProductDocument,
|
||||
variables: { productId },
|
||||
});
|
||||
|
||||
({ evo_baseproduct } = data);
|
||||
}
|
||||
|
||||
const {
|
||||
data: { evo_baseproduct },
|
||||
} = await apolloClient.query({
|
||||
query: CRMTypes.GetProductDocument,
|
||||
variables: { productId },
|
||||
});
|
||||
|
||||
const {
|
||||
data: { dealer },
|
||||
} = await apolloClient.query({
|
||||
query: CRMTypes.GetDealerDocument,
|
||||
variables: { dealerId },
|
||||
});
|
||||
if (dealerId) {
|
||||
const { data } = await apolloClient.query({
|
||||
query: CRMTypes.GetDealerDocument,
|
||||
variables: { dealerId },
|
||||
});
|
||||
({ dealer } = data);
|
||||
}
|
||||
|
||||
if (
|
||||
leaseObjectUsed ||
|
||||
|
||||
@ -48,12 +48,21 @@ export function createValidationSchema({ apolloClient }: ValidationContext) {
|
||||
}
|
||||
}
|
||||
|
||||
if (leaseObjectUsed && !mileage) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: 'Не заполнено поле',
|
||||
path: ['tbxMileage'],
|
||||
});
|
||||
if (leaseObjectUsed) {
|
||||
if (!mileage) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: 'Не заполнено поле',
|
||||
path: ['tbxMileage'],
|
||||
});
|
||||
}
|
||||
if (!vin) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: 'Не заполнено поле',
|
||||
path: ['tbxVIN'],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -71,10 +71,7 @@ export const quoteRouter = router({
|
||||
].map(({ getKPData }) => getKPData(input))
|
||||
);
|
||||
|
||||
const values = processData.reduce(
|
||||
(obj, data) => Object.assign(obj, data.values),
|
||||
defaultValues
|
||||
);
|
||||
const values = processData.reduce((obj, data) => ({ ...obj, ...data.values }), defaultValues);
|
||||
const payments = processData.find((x) => x.payments)?.payments ?? defaultPayments;
|
||||
const insurance = processData.find((x) => x.insurance)?.insurance ?? defaultInsurance;
|
||||
const fingap = processData.find((x) => x.fingap)?.fingap ?? defaultFingap;
|
||||
|
||||
@ -26,7 +26,7 @@ export default class ValuesStore {
|
||||
public setValues = (values: Partial<CalculationValues>) => {
|
||||
(Object.keys(values) as Array<keyof CalculationValues>).forEach((valueName) => {
|
||||
const value = values[valueName];
|
||||
if (value !== null && value !== undefined) {
|
||||
if (value !== undefined) {
|
||||
this.setValue(valueName, value);
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,34 +1,10 @@
|
||||
/* eslint-disable func-style */
|
||||
|
||||
export function parser(value?: string) {
|
||||
if (!value) return 0;
|
||||
|
||||
// eslint-disable-next-line unicorn/prefer-string-replace-all, require-unicode-regexp
|
||||
const normalized = value.replace(/\s/g, '').replaceAll(',', '.');
|
||||
const normalized = value.replaceAll(/\s/gu, '').replaceAll(',', '.');
|
||||
|
||||
return Number.parseFloat(normalized);
|
||||
}
|
||||
export const formatter = (value?: number) =>
|
||||
Intl.NumberFormat('ru', {
|
||||
minimumFractionDigits: 2,
|
||||
}).format(value || 0);
|
||||
|
||||
export const formatterExtra = (value?: number) =>
|
||||
Intl.NumberFormat('ru', {
|
||||
maximumFractionDigits: 6,
|
||||
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));
|
||||
|
||||
@ -38,3 +38,20 @@ function InputNumber({
|
||||
}
|
||||
|
||||
export default InputNumber as FC<InputNumberProps>;
|
||||
|
||||
export function createFormatter(options: Intl.NumberFormatOptions) {
|
||||
const format = Intl.NumberFormat('ru', options).format;
|
||||
const defaultFormat = Intl.NumberFormat('ru').format;
|
||||
|
||||
return ((value, { userTyping }) => {
|
||||
if (userTyping) {
|
||||
if (options.minimumFractionDigits && options.minimumFractionDigits <= 2) {
|
||||
return defaultFormat(value || 0);
|
||||
}
|
||||
|
||||
return value || 0;
|
||||
}
|
||||
|
||||
return format(value || 0);
|
||||
}) as NonNullable<InputNumberProps['formatter']>;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user