480 lines
14 KiB
TypeScript

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';
import { MIN_PAYMENT } from '@/constants/values';
import type { ProcessContext } from '@/process/types';
import type { Row } from '@/stores/tables/payments/types';
import { comparer, reaction, toJS } from 'mobx';
import { shift } from 'radash';
import { difference } from 'tools/array';
import { makeDisposable } from 'tools/mobx';
const {
generateSeasonPaymentsRows,
generateSeasons,
generateSeasonsPayments,
getPositionIndex,
getSeasonsValues,
} = seasonsTools;
const { DEFAULT_SEASONS_VALUES, FORBIDDEN_HIGH_SEASON_START, SEASONS_PERIOD_NUMBER } =
seasonsConstants;
export default function reactions({ store }: ProcessContext) {
const { $calculation, $tables, $process } = store;
reaction(
() => $calculation.element('tbxFirstPaymentPerc').getValue(),
(firstPaymentPerc) => {
$tables.payments.setValue(0, firstPaymentPerc);
}
);
reaction(
() => $calculation.element('tbxLastPaymentPerc').getValue(),
(lastPaymentPerc) => {
const paymentsLength = $tables.payments.values.length;
$tables.payments.setValue(paymentsLength - 1, lastPaymentPerc);
}
);
/**
* Аннуитет
*/
reaction(
() => {
const graphType = $calculation.element('radioGraphType').getValue();
const leasingPeriod = $calculation.element('tbxLeasingPeriod').getValue();
return {
graphType,
leasingPeriod,
};
},
({ graphType, leasingPeriod }) => {
if (graphType === 100_000_000) {
const middlePayments: Row[] = Array.from(
{
length: leasingPeriod - 2,
},
() => ({
status: 'Disabled',
value: 100,
})
);
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));
}
},
{
fireImmediately: true,
}
);
/**
* Равноубывающий
*/
reaction(
() => {
const graphType = $calculation.element('radioGraphType').getValue();
const leasingPeriod = $calculation.element('tbxLeasingPeriod').getValue();
const parmentsDecreasePercent = $calculation.element('tbxParmentsDecreasePercent').getValue();
return {
graphType,
leasingPeriod,
parmentsDecreasePercent,
};
},
({ graphType, leasingPeriod, parmentsDecreasePercent }) => {
if (graphType === 100_000_002) {
const middlePayments: Row[] = Array.from(
{
length: leasingPeriod - 2,
},
(_, k) => {
let payment = 100 * (parmentsDecreasePercent / 100) ** k;
if (payment < MIN_PAYMENT) payment = MIN_PAYMENT;
return {
status: 'Disabled',
value: Number(payment.toFixed(2)),
};
}
);
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));
}
}
);
/**
* Легкий старт
*/
reaction(
() => {
const graphType = $calculation.element('radioGraphType').getValue();
const leasingPeriod = $calculation.element('tbxLeasingPeriod').getValue();
return {
graphType,
leasingPeriod,
};
},
({ graphType, leasingPeriod }) => {
if (graphType === 100_000_004) {
const editablePayments: Row[] = [
{
status: 'Default',
value: 25,
},
{
status: 'Default',
value: 50,
},
{
status: 'Default',
value: 75,
},
];
const payments: Row[] = Array.from(
{
length: leasingPeriod - 5,
},
() => ({
status: 'Disabled',
value: 100,
})
);
const firstPaymentPerc = $calculation.element('tbxFirstPaymentPerc').getValue();
const lastPaymentPerc = $calculation.element('tbxLastPaymentPerc').getValue();
const rows: Row[] = [
{
status: 'Disabled',
value: firstPaymentPerc,
},
...editablePayments,
...payments,
{
status: 'Disabled',
value: lastPaymentPerc,
},
];
if (!$process.has('LoadKP')) {
$tables.payments.setValues(rows.map((row) => row.value));
}
$tables.payments.setStatuses(rows.map((row) => row.status));
}
}
);
// /**
// * Дегрессия
// */
// reaction(
// () => {
// const graphType = $calculation.element('radioGraphType').getValue();
// return graphType;
// },
// (graphType) => {
// if (!graphType) {
// $calculation.element('selectSeasonType').resetOptions();
// return;
// }
// if (graphType === 100_000_001 || graphType === 100_000_003) {
// const allowedSeasonTypes = SEASON_TYPES[graphType];
// const selectSeasonTypeOptions = selectSeasonType.filter((option) =>
// allowedSeasonTypes.includes(option.value)
// );
// $calculation.element('selectSeasonType').setOptions(selectSeasonTypeOptions);
// } else {
// $calculation.element('selectSeasonType').resetOptions();
// }
// }
// );
makeDisposable(
() =>
reaction(
() => $calculation.$values.getValues(['leasingPeriod', 'seasonType']),
({ seasonType, leasingPeriod }) => {
const middlePayments: Row[] = degressionTools.generateDegressionRows({
leasingPeriod,
seasonType,
});
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(
() =>
reaction(
() => toJS($tables.payments.values),
(nextPayments, prevPayments) => {
const graphType = $calculation.element('radioGraphType').getValue();
const degressionType = $calculation.element('selectSeasonType').getValue();
if (graphType === 100_000_001 && degressionType === 100_000_007) {
const changes = difference(nextPayments, prevPayments);
if (!changes?.length || changes.length > 1) return;
const [changeIndex] = changes;
const value = nextPayments[changeIndex];
const payments = nextPayments.slice(1, -1).map((payment, i) => {
if (i <= changeIndex - 2) return payment;
return value;
});
const firstPaymentPerc = $calculation.element('tbxFirstPaymentPerc').getValue();
const lastPaymentPerc = $calculation.element('tbxLastPaymentPerc').getValue();
$tables.payments.setValues([firstPaymentPerc, ...payments, lastPaymentPerc]);
}
},
{
delay: 50,
equals: comparer.structural,
}
),
() => $process.has('LoadKP')
);
/**
* Сезонный
*/
reaction(
() => {
const graphType = $calculation.element('radioGraphType').getValue();
return {
graphType,
};
},
({ graphType }) => {
if (graphType !== 100_000_003) return;
const seasonType = $calculation.element('selectSeasonType').getValue();
const highSeasonStart = $calculation.element('selectHighSeasonStart').getValue();
if (!seasonType || !highSeasonStart) {
$tables.payments.setValues([]);
}
}
);
reaction(
() => $calculation.element('selectSeasonType').getValue(),
(seasonType) => {
const graphType = $calculation.element('radioGraphType').getValue();
if (graphType !== 100_000_003) return;
if (!seasonType) {
$calculation.element('selectHighSeasonStart').reset();
return;
}
const highSeasonStartOptions = selectHighSeasonStart.filter(
(option) => !FORBIDDEN_HIGH_SEASON_START[seasonType].includes(option.label)
);
$calculation.element('selectHighSeasonStart').setOptions(highSeasonStartOptions);
}
);
reaction(
() => {
const seasonType = $calculation.element('selectSeasonType').getValue();
const highSeasonStartOption = $calculation.element('selectHighSeasonStart').getOption();
const leasingPeriod = $calculation.element('tbxLeasingPeriod').getValue();
return {
highSeasonStartOption,
leasingPeriod,
seasonType,
};
},
({ seasonType, highSeasonStartOption, leasingPeriod }) => {
const graphType = $calculation.element('radioGraphType').getValue();
if (graphType !== 100_000_003) return;
if (!seasonType || !highSeasonStartOption) {
$tables.payments.setValues([]);
return;
}
const seasons = generateSeasons(seasonType, DEFAULT_SEASONS_VALUES);
const shiftNumber = Number.parseInt(highSeasonStartOption.label, 10) - 2;
const payments = generateSeasonsPayments(leasingPeriod, shift(seasons, shiftNumber));
const middlePayments: Row[] = generateSeasonPaymentsRows(seasonType, shiftNumber, payments);
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));
}
);
makeDisposable(
() =>
reaction(
() => {
const payments = toJS($tables.payments.values);
return payments.slice(1, SEASONS_PERIOD_NUMBER + 1);
},
(nextSeasons, prevSeasons) => {
const graphType = $calculation.element('radioGraphType').getValue();
if (graphType !== 100_000_003) return;
const seasonType = $calculation.element('selectSeasonType').getValue();
const highSeasonStartOption = $calculation.element('selectHighSeasonStart').getOption();
if (!seasonType || !highSeasonStartOption) return;
const shiftNumber = Number.parseInt(highSeasonStartOption.label, 10) - 2;
const unshiftedNextSeasons = shift(nextSeasons, -shiftNumber);
const unshiftedPrevSeasons = shift(prevSeasons, -shiftNumber);
const changes = difference(unshiftedNextSeasons, unshiftedPrevSeasons);
if (changes === null || changes.length > 1) return;
const [changeIndex] = changes;
const positionIndex = getPositionIndex(seasonType, changeIndex);
const values = getSeasonsValues(seasonType, unshiftedNextSeasons);
values[positionIndex] = unshiftedNextSeasons[changeIndex];
const seasons = generateSeasons(seasonType, values);
const leasingPeriod = $calculation.element('tbxLeasingPeriod').getValue();
const payments = generateSeasonsPayments(leasingPeriod, shift(seasons, shiftNumber));
const rows: Row[] = generateSeasonPaymentsRows(seasonType, shiftNumber, payments);
const firstPaymentPerc = $calculation.element('tbxFirstPaymentPerc').getValue();
const lastPaymentPerc = $calculation.element('tbxLastPaymentPerc').getValue();
$tables.payments.setRows([
{
status: 'Disabled',
value: firstPaymentPerc,
},
...rows,
{
status: 'Disabled',
value: lastPaymentPerc,
},
]);
},
{
delay: 50,
equals: comparer.structural,
}
),
() => $process.has('LoadKP')
);
makeDisposable(
() =>
reaction(
() => $calculation.element('radioGraphType').getValue(),
() => {
$calculation.element('selectSeasonType').resetValue();
$calculation.element('selectHighSeasonStart').resetValue();
$calculation.element('tbxParmentsDecreasePercent').resetValue();
}
),
() => $process.has('LoadKP')
);
}