merge release/calc-56_limitations-on-degression

This commit is contained in:
Chika 2021-03-16 18:25:12 +03:00
parent aa1e5da9be
commit bfd6f1d1f9
14 changed files with 332 additions and 173 deletions

View File

@ -58,9 +58,9 @@ const sections: ISection[] = [
{
elements: ['selectProduct'],
},
{
elements: ['selectClientRisk'],
},
// {
// elements: ['selectClientRisk'],
// },
// {
// elements: ['selectClientType' ],
// },
@ -94,8 +94,8 @@ const sections: ISection[] = [
title: 'Параметры графика платежей',
elements: [
'radioGraphType',
'selectSeasonType',
'tbxParmentsDecreasePercent',
// 'radioSeasonType',
// 'selectHighSeasonStart',
],
layout: {

View File

@ -49,7 +49,7 @@ const elementsComponents: TElements<Component> = {
tbxLeasingPeriod: InputNumber,
radioGraphType: Radio,
tbxParmentsDecreasePercent: InputNumber,
radioSeasonType: Radio,
selectSeasonType: Select,
selectHighSeasonStart: Select,
tbxComissionPerc: InputNumber,
tbxComissionRub: InputNumber,

View File

@ -135,8 +135,7 @@ const elementsProps: TElements<ElementProps> = {
min: '50',
max: '99',
},
radioSeasonType: {
style: 'button',
selectSeasonType: {
},
tbxComissionPerc: {
min: '0',

View File

@ -23,6 +23,7 @@ const elementsTables: StoreTables<ITableElement> = {
min: '0.01',
max: '100.00',
step: '1.00',
precision: 2,
// TODO: toFixed
//numeral.js
},

View File

@ -38,7 +38,7 @@ const elementsTitles: TElements<string> = {
radioBalanceHolder: 'Балансодержатель',
radioGraphType: 'Вид графика',
tbxParmentsDecreasePercent: 'Процент убывания платежей',
radioSeasonType: 'Тип сезонности',
selectSeasonType: 'Тип дегрессии/сезонности',
selectHighSeasonStart: 'С какого платежа начинается высокий сезон',
tbxComissionPerc: 'Комиссия, %',
tbxComissionRub: 'Комиссия, руб.',

View File

@ -42,7 +42,7 @@ export const elementsValues: TElements<ValuesNames> = {
radioBalanceHolder: 'balanceHolder',
radioGraphType: 'graphType',
tbxParmentsDecreasePercent: 'parmentsDecreasePercent',
radioSeasonType: 'seasonType',
selectSeasonType: 'seasonType',
selectHighSeasonStart: 'highSeasonStart',
tbxComissionPerc: 'comissionPerc',
tbxComissionRub: 'comissionRub',

View File

@ -56,7 +56,7 @@ const validateElements = () => {
});
};
const validateTables = () => {
const validateInsuranceTable = () => {
const tableInsurance = CalculationStore.tables.tableInsurance;
const kaskoRowIndex = tableInsurance.rows.findIndex(
@ -89,7 +89,112 @@ const validateTables = () => {
]);
};
const validatePaymentsTable = () => {
const { graphType } = CalculationStore.values;
const payments = CalculationStore.tables.tablePayments.rows;
switch (graphType) {
case 100000001: {
{
const areMiddleRowsEqual =
new Set(
payments
.slice(1, payments.length - 1)
.map(x => x.paymentRelation?.value),
).size === 1;
CalculationStore.setTableRows(
'tablePayments',
1,
)(
Array.from({ length: payments.length - 2 }, () => ({
paymentRelation: {
validation: areMiddleRowsEqual ? false : true,
},
})),
);
}
if (
!CalculationStore.tables.tablePayments.rows.some(
x => x.paymentRelation?.validation === false,
)
) {
const target_payments = payments
.slice(1, 4)
.map(x => x.paymentRelation?.value);
const min = Math.min.apply(Math, target_payments);
const max = Math.max.apply(Math, target_payments);
const areInvalidRows = max - min > 10;
CalculationStore.setTableRows(
'tablePayments',
1,
)(
Array.from({ length: 3 }, () => ({
paymentRelation: {
validation: areInvalidRows ? false : true,
},
})),
);
}
if (
!CalculationStore.tables.tablePayments.rows.some(
x => x.paymentRelation?.validation === false,
)
) {
const target_payments = payments
.slice(1, payments.length - 1)
.map(x => x.paymentRelation?.value);
let pairs_number = 0;
new Set(target_payments).forEach(set_v => {
let setValueCount = 0;
target_payments.forEach(target_v => {
if (target_v === set_v) {
setValueCount++;
}
});
if (setValueCount > 1) {
pairs_number++;
}
});
CalculationStore.setTableRows(
'tablePayments',
2,
)(
Array.from({ length: payments.length - 3 }, () => ({
paymentRelation: {
validation: pairs_number >= 2 ? true : false,
},
})),
);
}
break;
}
case 100000004: {
const areMiddleRowsEqual =
new Set(payments.slice(1, 4).map(x => x.paymentRelation?.value))
.size === 1;
CalculationStore.setTableRows(
'tablePayments',
1,
)(
Array.from({ length: 3 }, () => ({
paymentRelation: {
validation: areMiddleRowsEqual ? false : true,
},
})),
);
break;
}
}
};
export default () => {
validateElements();
validateTables();
validateInsuranceTable();
validatePaymentsTable();
};

View File

@ -734,10 +734,39 @@ const reactionEffects: IReactionEffect[] = [
},
effect: graphType => {
if (graphType) {
calculationStore.setValue('seasonType', null);
switch (graphType) {
case 100000001: {
calculationStore.setStatus(
'selectSeasonType',
ElementStatus.Default,
);
calculationStore.setFilter('selectSeasonType', options =>
options.filter(
x =>
x.value &&
typeof x.value === 'number' &&
[100000003, 100000004, 100000005, 100000006].includes(
x.value,
),
),
);
calculationStore.setStatus(
'tbxParmentsDecreasePercent',
ElementStatus.Disabled,
);
calculationStore.setStatus(
'selectHighSeasonStart',
ElementStatus.Disabled,
);
break;
}
case 100000002: {
calculationStore.setStatus(
'radioSeasonType',
'selectSeasonType',
ElementStatus.Disabled,
);
calculationStore.setStatus(
@ -753,9 +782,18 @@ const reactionEffects: IReactionEffect[] = [
case 100000003: {
calculationStore.setStatus(
'radioSeasonType',
'selectSeasonType',
ElementStatus.Default,
);
calculationStore.setFilter('selectSeasonType', options =>
options.filter(
x =>
x.value &&
typeof x.value === 'number' &&
[100000000, 100000001, 100000002].includes(x.value),
),
);
calculationStore.setStatus(
'tbxParmentsDecreasePercent',
ElementStatus.Disabled,
@ -769,7 +807,7 @@ const reactionEffects: IReactionEffect[] = [
default: {
calculationStore.setStatus(
'radioSeasonType',
'selectSeasonType',
ElementStatus.Disabled,
);
calculationStore.setStatus(
@ -826,19 +864,36 @@ const reactionEffects: IReactionEffect[] = [
effect: leasingPeriod => {
if (leasingPeriod) {
if (parseInt(leasingPeriod) < 12) {
calculationStore.setValue('insNSIB', null);
calculationStore.setStatus('selectInsNSIB', ElementStatus.Disabled);
} else {
calculationStore.setStatus('selectInsNSIB', ElementStatus.Default);
}
}
},
options: {
fireImmediately: true,
},
}),
calculationStore => ({
expression: () => {
const { leasingPeriod } = calculationStore.values;
return leasingPeriod;
},
effect: leasingPeriod => {
if (leasingPeriod) {
if (parseInt(leasingPeriod) < 13) {
calculationStore.setStatus(
'radioBalanceHolder',
ElementStatus.Disabled,
);
calculationStore.setValue('balanceHolder', 100000000);
calculationStore.setValue('insNSIB', null);
calculationStore.setStatus('selectInsNSIB', ElementStatus.Disabled);
} else {
calculationStore.setStatus(
'radioBalanceHolder',
ElementStatus.Default,
);
calculationStore.setStatus('selectInsNSIB', ElementStatus.Default);
}
}
},
@ -1678,7 +1733,10 @@ const reactionEffects: IReactionEffect[] = [
default:
case 100000000: {
calculationStore.setStatus('tbxIRR_Perc', ElementStatus.Default);
calculationStore.setStatus('tbxTotalPayments', ElementStatus.Disabled);
calculationStore.setStatus(
'tbxTotalPayments',
ElementStatus.Disabled,
);
break;
}
case 100000002: {

View File

@ -392,7 +392,7 @@ const elementsToDisable: (ElementsNames | TableNames)[] = [
'radioLastPaymentRule',
'radioGraphType',
'tbxParmentsDecreasePercent',
'radioSeasonType',
'selectSeasonType',
'selectHighSeasonStart',
'selectLeaseObjectType',
'cbxLeaseObjectUsed',

View File

@ -455,7 +455,6 @@ export default [
parmentsDecreasePercent,
seasonType,
highSeasonStart: highSeasonStartId,
lastPaymentPerc,
} = calculationStore.values;
const highSeasonStart = calculationStore.options.selectHighSeasonStart?.find(
@ -468,7 +467,6 @@ export default [
parmentsDecreasePercent,
seasonType,
highSeasonStart: parseInt(highSeasonStart?.name || '2'),
lastPaymentPerc,
};
},
effect: async (nextParams, prevParams) => {
@ -476,14 +474,13 @@ export default [
return;
}
const { firstPaymentPerc } = calculationStore.values;
const { firstPaymentPerc, lastPaymentPerc } = calculationStore.values;
const {
leasingPeriod,
graphType,
parmentsDecreasePercent,
seasonType,
highSeasonStart,
lastPaymentPerc,
} = nextParams;
const prevValues = toJS(calculationStore.tables.tablePayments.rows).map(
@ -514,22 +511,57 @@ export default [
}
case 100000001: {
const middleRows = Array.from({ length: leasingPeriod - 3 }, () => ({
paymentRelation: {
value: 100,
status: ElementStatus.Default,
},
}));
payments = [
...payments,
{
paymentRelation: {
value: 100,
status: ElementStatus.Disabled,
if (seasonType) {
const paymentsInStep = Math.ceil((leasingPeriod - 2) / 3);
const targetSeasonType = calculationStore.options?.selectSeasonType?.find(
x => x?.value === seasonType,
);
const steps: number[] = targetSeasonType && targetSeasonType.steps;
const middleRows = Array.from(
{ length: leasingPeriod - 2 },
(_v, i) => {
let value = steps[2];
if (i <= paymentsInStep * 2 - 1) {
value = steps[1];
}
if (i <= paymentsInStep - 1) {
value = steps[0];
}
return {
paymentRelation: {
value,
status: ElementStatus.Disabled,
},
};
},
},
...middleRows,
];
);
payments = [...payments, ...middleRows];
} else {
const middleRows = Array.from(
{ length: leasingPeriod - 3 },
() => ({
paymentRelation: {
value: 100,
status: ElementStatus.Default,
},
}),
);
payments = [
...payments,
{
paymentRelation: {
value: 100,
status: ElementStatus.Disabled,
},
},
...middleRows,
];
}
break;
}
@ -732,7 +764,10 @@ export default [
}
}
payments = [
calculationStore.setTableRows(
'tablePayments',
0,
)([
...payments,
{
paymentRelation: {
@ -740,9 +775,28 @@ export default [
status: ElementStatus.Disabled,
},
},
];
]);
},
options: {
fireImmediately: true,
},
}),
calculationStore.setTableRows('tablePayments', 0)(payments);
calculationStore => ({
expression: () => {
const { lastPaymentPerc, leasingPeriod } = calculationStore.values;
return { lastPaymentPerc, leasingPeriod };
},
effect: ({ lastPaymentPerc }) => {
calculationStore.setTableRow(
'tablePayments',
calculationStore.tables.tablePayments.rows.length - 1,
)({
paymentRelation: {
value: lastPaymentPerc,
status: ElementStatus.Disabled,
},
});
},
options: {
fireImmediately: true,

View File

@ -81,12 +81,11 @@ const initialOptions: TElements<IBaseOption[]> = {
},
],
radioSeasonType: [
selectSeasonType: [
{
name: '6/6',
value: 100000000,
},
{
name: '8/4',
value: 100000001,
@ -95,6 +94,26 @@ const initialOptions: TElements<IBaseOption[]> = {
name: '4/4/4',
value: 100000002,
},
{
name: '100.50.25',
value: 100000003,
steps: [100, 50, 25],
},
{
name: '100.30.10',
value: 100000004,
steps: [100, 30, 10],
},
{
name: '100.70.40',
value: 100000005,
steps: [100, 70, 40],
},
{
name: '100.7.3',
value: 100000006,
steps: [100, 7, 3],
},
],
selectHighSeasonStart: [

View File

@ -1,5 +1,5 @@
import { ITable } from 'core/types/Calculation/Store/tables';
import { toJS } from 'mobx';
import { isEqual } from 'lodash';
const tablePayments: ITable = {
rows: [
@ -7,87 +7,46 @@ const tablePayments: ITable = {
// paymentRelation: { value: 5 },
// },
],
callbacks: {
paymentRelation: ({
calculationStore,
tableName,
rowIndex,
value,
}) => {
const { graphType } = calculationStore.values;
if (graphType === 100000001) {
if (
rowIndex > 1 &&
rowIndex < calculationStore.tables[tableName].rows.length - 1
) {
calculationStore.setTableRows(
tableName,
rowIndex,
)(
Array.from(
{
length:
calculationStore.tables[tableName].rows.length - rowIndex - 1,
},
() => ({
paymentRelation: {
value,
},
}),
),
);
for (let i in calculationStore.tables[tableName].rows) {
const currRow =
calculationStore.tables[tableName].rows[parseInt(i)];
const prevRow =
calculationStore.tables[tableName].rows[parseInt(i) - 1];
if (
parseInt(i) > 1 &&
currRow &&
prevRow &&
currRow.paymentRelation?.value > prevRow.paymentRelation?.value
) {
calculationStore.setTableRow(
tableName,
parseInt(i),
)({
paymentRelation: {
validation: false,
},
});
} else {
calculationStore.setTableRow(
tableName,
parseInt(i),
)({
paymentRelation: {
validation: true,
},
});
}
}
const middleRows = toJS(calculationStore.tables[tableName].rows);
middleRows.splice(0, 1);
middleRows.splice(-1, 1);
callbacks: {
paymentRelation: ({ calculationStore, tableName, rowIndex, value }) => {
const rowLength = calculationStore.tables[tableName].rows.length;
const { graphType, seasonType } = calculationStore.values;
if (graphType === 100000001 && !seasonType) {
if (rowIndex > 1 && rowIndex < rowLength - 1) {
if (
middleRows.every(
x =>
x.paymentRelation?.value ===
middleRows[0].paymentRelation?.value,
)
) {
calculationStore.tables[tableName].rows[rowIndex].paymentRelation
?.value !==
calculationStore.tables[tableName].rows[rowIndex + 1]
.paymentRelation?.value
)
calculationStore.setTableRows(
tableName,
2,
rowIndex,
)(
Array.from({ length: middleRows.length - 1 }, (v, i) => ({
paymentRelation: {
validation: false,
Array.from(
{
length: rowLength - rowIndex - 1,
},
})),
(_v, i) => ({
paymentRelation: {
value,
},
}),
),
);
}
const prevRow = calculationStore.tables[tableName].rows[rowIndex - 1];
const isCurrentValueGreater = value > prevRow.paymentRelation?.value;
calculationStore.setTableRow(
tableName,
rowIndex,
)({
paymentRelation: {
validation: isCurrentValueGreater || value < 3 ? false : true,
},
});
}
}
@ -110,60 +69,23 @@ const tablePayments: ITable = {
if (graphType === 100000004) {
if (rowIndex > 0 && rowIndex < 4) {
for (let i in calculationStore.tables[tableName].rows) {
const currRow =
calculationStore.tables[tableName].rows[parseInt(i)];
const nextRow =
calculationStore.tables[tableName].rows[parseInt(i) + 1];
if (
parseInt(i) > 0 &&
parseInt(i) < 4 &&
currRow &&
nextRow &&
currRow.paymentRelation?.value > nextRow.paymentRelation?.value
) {
calculationStore.setTableRow(
tableName,
parseInt(i),
)({
paymentRelation: {
validation: false,
},
});
} else {
calculationStore.setTableRow(
tableName,
parseInt(i),
)({
paymentRelation: {
validation: true,
},
});
}
}
const middleRows = toJS(calculationStore.tables[tableName].rows);
middleRows.splice(0, 1);
middleRows.length = 3;
if (
middleRows.every(
x =>
x.paymentRelation?.value ===
middleRows[0].paymentRelation?.value,
)
) {
calculationStore.setTableRows(
tableName,
1,
)(
Array.from({ length: middleRows.length }, (v, i) => ({
paymentRelation: {
validation: false,
},
})),
);
}
const isCorrect3MiddleRows = isEqual(
calculationStore.tables[tableName].rows
.slice(1, 4)
.map(x => x.paymentRelation?.value)
.sort((a, b) => a - b),
calculationStore.tables[tableName].rows
.slice(1, 4)
.map(x => x.paymentRelation?.value),
);
calculationStore.setTableRow(
tableName,
rowIndex,
)({
paymentRelation: {
validation: isCorrect3MiddleRows ? true : false,
},
});
}
}
},

View File

@ -37,7 +37,7 @@ export type ElementsNames =
| 'radioBalanceHolder'
| 'radioGraphType'
| 'tbxParmentsDecreasePercent'
| 'radioSeasonType'
| 'selectSeasonType'
| 'selectHighSeasonStart'
| 'tbxComissionPerc'
| 'tbxComissionRub'

View File

@ -4,4 +4,5 @@ export type IBaseOption = {
*/
name?: string;
value?: string | number | boolean;
[prop: string]: any | any[];
};