merge migration/fix-2

This commit is contained in:
vchikalkin 2023-04-10 11:58:50 +03:00
parent 95040c5a10
commit 0d35042e41
18 changed files with 375 additions and 275 deletions

View File

@ -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}

View File

@ -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: {

View File

@ -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,

View File

@ -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) => {

View File

@ -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);

View File

@ -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,
},
};
}

View File

@ -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 {

View File

@ -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');

View File

@ -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,
},
};
}

View 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;
}

View File

@ -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')
);
}

View File

@ -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')
);
}

View File

@ -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 ||

View File

@ -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'],
});
}
}
/**

View File

@ -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;

View File

@ -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);
}
});

View File

@ -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));

View File

@ -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']>;
}