From ed80a94791682f603e9ad6e7b8b47480d62a97f5 Mon Sep 17 00:00:00 2001 From: vchikalkin Date: Mon, 22 Mar 2021 12:35:28 +0300 Subject: [PATCH] merge release/calc-18_season-graphs --- .../Calculation/Sections/sectionsList.ts | 2 +- .../actions/calculate/checkValidation.ts | 12 +- .../Effects/actions/calculate/validate.ts | 84 ++++++++-- .../Effects/reactions/otherReactions.ts | 2 + .../Effects/reactions/tablesReactions.ts | 144 ++++++++---------- .../CalculationStore/config/initialFilters.ts | 4 +- .../CalculationStore/config/initialOptions.ts | 17 ++- .../config/initialTables/tablePayments.ts | 77 ++++++++-- src/core/constants/values.js | 1 + src/core/tools/array.js | 12 ++ 10 files changed, 234 insertions(+), 121 deletions(-) diff --git a/src/client/Containers/Calculation/Sections/sectionsList.ts b/src/client/Containers/Calculation/Sections/sectionsList.ts index ab39676..a817ea7 100644 --- a/src/client/Containers/Calculation/Sections/sectionsList.ts +++ b/src/client/Containers/Calculation/Sections/sectionsList.ts @@ -96,7 +96,7 @@ const sections: ISection[] = [ 'radioGraphType', 'selectSeasonType', 'tbxParmentsDecreasePercent', - // 'selectHighSeasonStart', + 'selectHighSeasonStart', ], layout: { newLine: true, diff --git a/src/client/stores/CalculationStore/Effects/actions/calculate/checkValidation.ts b/src/client/stores/CalculationStore/Effects/actions/calculate/checkValidation.ts index e739ec7..d823d2e 100644 --- a/src/client/stores/CalculationStore/Effects/actions/calculate/checkValidation.ts +++ b/src/client/stores/CalculationStore/Effects/actions/calculate/checkValidation.ts @@ -1,6 +1,10 @@ -import elementsTitles, { tablesTitles } from 'client/Containers/Calculation/lib/elements/titles'; +import { TableNames } from 'core/types/Calculation/Store/tables'; +import elementsTitles, { + tablesTitles, +} from 'client/Containers/Calculation/lib/elements/titles'; import CalculationStore from 'client/stores/CalculationStore'; import { toJS } from 'mobx'; +import { omit } from 'lodash'; export default () => { let invalidElements: string[] = []; @@ -14,9 +18,11 @@ export default () => { let invalidTables: string[] = []; const { tables: storeTables } = CalculationStore; - const tables = toJS(storeTables); + const tables = omit(toJS(storeTables), tablesExclusion); Object.keys(tables).forEach(tableName => { if ( + !tables[tableName].rows || + tables[tableName].rows.length === 0 || tables[tableName].rows.some(row => Object.keys(row).some(propName => row[propName].validation === false), ) @@ -27,3 +33,5 @@ export default () => { return { invalidElements, invalidTables }; }; + +const tablesExclusion: TableNames[] = ['tableResults']; diff --git a/src/client/stores/CalculationStore/Effects/actions/calculate/validate.ts b/src/client/stores/CalculationStore/Effects/actions/calculate/validate.ts index e6c3525..243669b 100644 --- a/src/client/stores/CalculationStore/Effects/actions/calculate/validate.ts +++ b/src/client/stores/CalculationStore/Effects/actions/calculate/validate.ts @@ -1,6 +1,10 @@ import { elementsValues } from 'client/Containers/Calculation/lib/elements/values'; +import { shiftRight } from 'core/tools/array'; import { TElements } from 'core/types/Calculation/Store/elements'; +import { isEqual } from 'lodash'; import CalculationStore from '../../..'; +import valuesConstants from 'core/constants/values'; +const { PERIODS_NUMBER } = valuesConstants; const VALIDATIONS = { IS_NULL: valueName => @@ -27,6 +31,12 @@ const elementsValidations: TElements = { selectRegistration: VALIDATIONS.IS_NULL, selectLeaseObjectCategory: VALIDATIONS.IS_NULL, tbxLeasingPeriod: valueName => CalculationStore.getValue(valueName) < 7, + selectSeasonType: valueName => + CalculationStore.getValue('graphType') === 100000003 && + VALIDATIONS.IS_NULL(valueName), + selectHighSeasonStart: valueName => + CalculationStore.getValue('graphType') === 100000003 && + VALIDATIONS.IS_NULL(valueName), tbxLeaseObjectPrice: VALIDATIONS.LESS_OR_EQUALS_ZERO, tbxLastPaymentPerc: VALIDATIONS.IS_NULL, tbxLastPaymentRub: VALIDATIONS.IS_NULL, @@ -35,7 +45,7 @@ const elementsValidations: TElements = { tbxLeaseObjectCount: VALIDATIONS.LESS_OR_EQUALS_ZERO, selectQuote: valueName => CalculationStore.getValue('recalcWithRevision') === true && - !CalculationStore.getValue(valueName), + VALIDATIONS.IS_NULL(valueName), }; const validateElement = (elementName, condition) => { @@ -91,16 +101,15 @@ const validateInsuranceTable = () => { const validatePaymentsTable = () => { const { graphType } = CalculationStore.values; - const payments = CalculationStore.tables.tablePayments.rows; + const payments = CalculationStore.tables.tablePayments.rows.map( + x => x.paymentRelation?.value, + ); + switch (graphType) { case 100000001: { { const areMiddleRowsEqual = - new Set( - payments - .slice(1, payments.length - 1) - .map(x => x.paymentRelation?.value), - ).size === 1; + new Set(payments.slice(1, payments.length - 1)).size === 1; CalculationStore.setTableRows( 'tablePayments', @@ -119,9 +128,7 @@ const validatePaymentsTable = () => { x => x.paymentRelation?.validation === false, ) ) { - const target_payments = payments - .slice(1, 4) - .map(x => x.paymentRelation?.value); + const target_payments = payments.slice(1, 4); const min = Math.min.apply(Math, target_payments); const max = Math.max.apply(Math, target_payments); const areInvalidRows = max - min > 10; @@ -143,9 +150,7 @@ const validatePaymentsTable = () => { x => x.paymentRelation?.validation === false, ) ) { - const target_payments = payments - .slice(1, payments.length - 1) - .map(x => x.paymentRelation?.value); + const target_payments = payments.slice(1, payments.length - 1); let pairs_number = 0; new Set(target_payments).forEach(set_v => { let setValueCount = 0; @@ -173,10 +178,57 @@ const validatePaymentsTable = () => { break; } + + case 100000003: { + const { highSeasonStart: highSeasonStartId } = CalculationStore.values; + if (!highSeasonStartId) { + return; + } + const highSeasonStart = parseInt( + CalculationStore.options.selectHighSeasonStart?.find( + x => x.value === highSeasonStartId, + )?.name || '2', + ); + const shiftNumber = highSeasonStart - 2; + const middleRows = payments.slice(1, PERIODS_NUMBER + 1); + const unshiftedMiddleRows = shiftRight(middleRows, shiftNumber); + + const { seasonType } = CalculationStore.values; + if (!seasonType) { + return; + } + const seasonTypeOptions = CalculationStore.options.selectSeasonType?.find( + x => x.value === seasonType, + ); + const startPositions = + seasonTypeOptions && seasonTypeOptions.startPositions; + + let stepsValues = []; + for (let i = 0; i < startPositions.length; i++) { + const targetIndex = startPositions[i]; + //@ts-ignore + stepsValues.push(unshiftedMiddleRows[targetIndex]); + } + + const areCorrectSeasonPayments = isEqual( + stepsValues, + [...stepsValues].sort((a, b) => b - a), + ); + CalculationStore.setTableRows( + 'tablePayments', + 1, + )( + Array.from({ length: PERIODS_NUMBER }, () => ({ + paymentRelation: { + validation: areCorrectSeasonPayments, + }, + })), + ); + break; + } + case 100000004: { - const areMiddleRowsEqual = - new Set(payments.slice(1, 4).map(x => x.paymentRelation?.value)) - .size === 1; + const areMiddleRowsEqual = new Set(payments.slice(1, 4)).size === 1; CalculationStore.setTableRows( 'tablePayments', diff --git a/src/client/stores/CalculationStore/Effects/reactions/otherReactions.ts b/src/client/stores/CalculationStore/Effects/reactions/otherReactions.ts index 33a1f48..044a7a4 100644 --- a/src/client/stores/CalculationStore/Effects/reactions/otherReactions.ts +++ b/src/client/stores/CalculationStore/Effects/reactions/otherReactions.ts @@ -735,6 +735,8 @@ const reactionEffects: IReactionEffect[] = [ effect: graphType => { if (graphType) { calculationStore.setValue('seasonType', null); + calculationStore.setValue('highSeasonStart', null); + calculationStore.setValue('parmentsDecreasePercent', 50); switch (graphType) { case 100000001: { calculationStore.setStatus( diff --git a/src/client/stores/CalculationStore/Effects/reactions/tablesReactions.ts b/src/client/stores/CalculationStore/Effects/reactions/tablesReactions.ts index e51c895..d846153 100644 --- a/src/client/stores/CalculationStore/Effects/reactions/tablesReactions.ts +++ b/src/client/stores/CalculationStore/Effects/reactions/tablesReactions.ts @@ -5,6 +5,8 @@ import { Process } from 'core/types/Calculation/Store/process'; import { ITableCell, TableProps } from 'core/types/Calculation/Store/tables'; import { ElementStatus } from 'core/types/statuses'; import { toJS } from 'mobx'; +import valuesConstants from 'core/constants/values'; +const { PERIODS_NUMBER } = valuesConstants; export default [ (calculationStore, calculationProcess) => ({ @@ -516,19 +518,20 @@ export default [ const targetSeasonType = calculationStore.options?.selectSeasonType?.find( x => x?.value === seasonType, ); - const steps: number[] = targetSeasonType && targetSeasonType.steps; + const stepsValues: number[] = + targetSeasonType && targetSeasonType.stepsValues; const middleRows = Array.from( { length: leasingPeriod - 2 }, (_v, i) => { - let value = steps[2]; + let value = stepsValues[2]; if (i <= paymentsInStep * 2 - 1) { - value = steps[1]; + value = stepsValues[1]; } if (i <= paymentsInStep - 1) { - value = steps[0]; + value = stepsValues[0]; } return { @@ -540,7 +543,6 @@ export default [ }, ); payments = [...payments, ...middleRows]; - } else { const middleRows = Array.from( { length: leasingPeriod - 3 }, @@ -602,59 +604,56 @@ export default [ } case 100000003: { - let HIGH = 100, - MIDDLE = 75, - LOW = 50; + if (!seasonType) { + return; + } + const next_seasonType_option = calculationStore.options.selectSeasonType?.find( + x => x.value === seasonType, + ); + + const { + //@ts-ignore + startPositions: nextStartPositions, + //@ts-ignore + paymentsInStep: nextPaymentsInStep, + //@ts-ignore + stepsValues: nextStepsValues, + } = next_seasonType_option; + + let stepsValues: number[] = nextStepsValues; + + const { + seasonType: prevSeasonType, + highSeasonStart: prevHighSeasonStart, + } = prevParams; if ( - prevParams.graphType === nextParams.graphType - // && nextParams.graphType === 100000003 + prevParams.graphType === nextParams.graphType && + prevSeasonType === seasonType && + prevHighSeasonStart !== highSeasonStart ) { /** * FIND PREV HIGH, MIDDLE, LOW */ - const { - leasingPeriod: prevLeasingPeriod, - seasonType: prevSeasonType, - highSeasonStart: prevHighSeasonStart, - } = prevParams; - const prevPeriodsNumber = - prevLeasingPeriod <= 14 ? prevLeasingPeriod - 2 : 12; + //TODO: change 2 to variable from options selectHighSeasonStart const prevShiftNumber = prevHighSeasonStart - 2; - let middleRows = prevValues.slice(1, prevPeriodsNumber + 1); - if (middleRows.length < 12) { - middleRows = [ - ...middleRows, - ...Array.from({ length: 12 - middleRows.length }, v => 0), - ]; - } + let middleRows = prevValues.slice(1, PERIODS_NUMBER + 1); + + // prevent unnecessary running shiftRight if (prevShiftNumber > 0) middleRows = shiftRight(middleRows, prevShiftNumber); - switch (prevSeasonType) { - // 6/6 - case 100000000: { - HIGH = middleRows[0]; - LOW = middleRows[6]; - break; - } - // 8/4 - case 100000001: { - HIGH = middleRows[0]; - LOW = middleRows[8]; + const prev_seasonType_option = calculationStore.options.selectSeasonType?.find( + x => x.value === prevSeasonType, + ); + const prevStartPositions = + prev_seasonType_option && prev_seasonType_option.startPositions; - break; - } - // 4/4/4 - case 100000002: { - HIGH = middleRows[0]; - MIDDLE = middleRows[4]; - LOW = middleRows[8]; - break; - } - } + stepsValues = prevStartPositions.map( + startPosition => middleRows[startPosition], + ); /** */ } @@ -662,58 +661,36 @@ export default [ * GENERATE PERIODS */ - const { - leasingPeriod: nextLeasingPeriod, - seasonType: nextSeasonType, - highSeasonStart: nextHighSeasonStart, - } = nextParams; - - const nextPeriodsNumber = - nextLeasingPeriod <= 14 ? nextLeasingPeriod - 2 : 12; - const nextShiftNumber = nextHighSeasonStart - 2; + const nextShiftNumber = highSeasonStart - 2; let nextPeriods: number[] = []; - switch (nextSeasonType) { - // 6/6 - case 100000000: { - nextPeriods = Array.from({ length: 12 }, (v, i) => - i < 6 ? HIGH : LOW, - ); - break; + nextStartPositions.forEach((startPosition, i) => { + for ( + let j = startPosition; + j < startPosition + nextPaymentsInStep[i]; + j++ + ) { + nextPeriods[j] = stepsValues[i]; } - // 8/4 - case 100000001: { - nextPeriods = Array.from({ length: 12 }, (v, i) => - i < 8 ? HIGH : LOW, - ); - break; - } - // 4/4/4 - case 100000002: { - nextPeriods = Array.from( - { length: 12 }, - (v, i) => (i < 4 && HIGH) || (i < 8 && MIDDLE) || LOW, - ); - break; - } - } + }); + if (nextShiftNumber > 0) { nextPeriods = shift(nextPeriods, nextShiftNumber); } - nextPeriods.length = nextPeriodsNumber; + nextPeriods.length = PERIODS_NUMBER; const middleRows = Array.from( - { length: nextLeasingPeriod - 2 }, + { length: leasingPeriod - 2 }, (v, i) => { return { paymentRelation: { value: - nextPeriods[ - i - nextPeriodsNumber * Math.floor(i / nextPeriodsNumber) - ], + i < PERIODS_NUMBER && + // i - PERIODS_NUMBER * Math.floor(i / PERIODS_NUMBER) + nextPeriods[i], status: - i < nextPeriodsNumber + i < PERIODS_NUMBER ? ElementStatus.Default : ElementStatus.Disabled, }, @@ -767,6 +744,7 @@ export default [ calculationStore.setTableRows( 'tablePayments', 0, + true, )([ ...payments, { diff --git a/src/client/stores/CalculationStore/config/initialFilters.ts b/src/client/stores/CalculationStore/config/initialFilters.ts index f461ea4..6b7dc45 100644 --- a/src/client/stores/CalculationStore/config/initialFilters.ts +++ b/src/client/stores/CalculationStore/config/initialFilters.ts @@ -1,8 +1,6 @@ import { TElementFilter } from 'core/types/Calculation/Store/filters'; import { TElements } from 'core/types/Calculation/Store/elements'; -const initialFilters: TElements = { - radioGraphType: options => options.filter(x => x.value !== 100000003), -}; +const initialFilters: TElements = {}; export default initialFilters; diff --git a/src/client/stores/CalculationStore/config/initialOptions.ts b/src/client/stores/CalculationStore/config/initialOptions.ts index ce90491..920cd3f 100644 --- a/src/client/stores/CalculationStore/config/initialOptions.ts +++ b/src/client/stores/CalculationStore/config/initialOptions.ts @@ -85,34 +85,43 @@ const initialOptions: TElements = { { name: '6/6', value: 100000000, + startPositions: [0, 6], + paymentsInStep: [6, 6], + stepsValues: [100, 50], }, { name: '8/4', value: 100000001, + startPositions: [0, 8], + paymentsInStep: [8, 4], + stepsValues: [100, 50], }, { name: '4/4/4', value: 100000002, + startPositions: [0, 4, 8], + paymentsInStep: [4, 4, 4], + stepsValues: [100, 75, 50], }, { name: '100.50.25', value: 100000003, - steps: [100, 50, 25], + stepsValues: [100, 50, 25], }, { name: '100.30.10', value: 100000004, - steps: [100, 30, 10], + stepsValues: [100, 30, 10], }, { name: '100.70.40', value: 100000005, - steps: [100, 70, 40], + stepsValues: [100, 70, 40], }, { name: '100.7.3', value: 100000006, - steps: [100, 7, 3], + stepsValues: [100, 7, 3], }, ], diff --git a/src/client/stores/CalculationStore/config/initialTables/tablePayments.ts b/src/client/stores/CalculationStore/config/initialTables/tablePayments.ts index e6ba8f6..10c27b7 100644 --- a/src/client/stores/CalculationStore/config/initialTables/tablePayments.ts +++ b/src/client/stores/CalculationStore/config/initialTables/tablePayments.ts @@ -1,5 +1,8 @@ +import { rotateArrays } from 'core/tools/array'; import { ITable } from 'core/types/Calculation/Store/tables'; -import { isEqual } from 'lodash'; +import { inRange, isEqual } from 'lodash'; +import valuesConstants from 'core/constants/values'; +const { PERIODS_NUMBER } = valuesConstants; const tablePayments: ITable = { rows: [ @@ -52,17 +55,67 @@ const tablePayments: ITable = { if (graphType === 100000003) { const { leasingPeriod } = calculationStore.values; - const periodsNumber = leasingPeriod <= 14 ? leasingPeriod - 2 : 12; - if (rowIndex >= 1 && rowIndex <= periodsNumber) { - for (let i = rowIndex; i < leasingPeriod - 1; i += periodsNumber) { - calculationStore.setTableRow( - tableName, - i, - )({ - paymentRelation: { - value, - }, - }); + if (rowIndex >= 1 && rowIndex <= PERIODS_NUMBER) { + const { highSeasonStart } = calculationStore.values; + const highSeasonStartValue = parseInt( + calculationStore.options.selectHighSeasonStart?.find( + x => x.value === highSeasonStart, + )?.name || '2', + ), + shiftNumber = highSeasonStartValue - 2; + + const seasonTypeOptions = calculationStore.options.selectSeasonType?.find( + x => x.value === seasonType, + ); + const startPositions = + seasonTypeOptions && seasonTypeOptions.startPositions, + endPositions = + seasonTypeOptions && + seasonTypeOptions.paymentsInStep.map( + (x, i) => startPositions[i] + x, + ); + + const allBoundaries = rotateArrays(startPositions, endPositions); + + const withUnshift = n => n - shiftNumber; + const withShift = n => n + shiftNumber; + const withFirstPayment = n => n + 1; + let index; + for (let i = 0; i < allBoundaries.length; i++) { + const [min, max] = allBoundaries[i].map(x => withFirstPayment(x)); + let unshiftedRowIndex = withUnshift(rowIndex); + if (unshiftedRowIndex <= 0) { + unshiftedRowIndex += PERIODS_NUMBER; + } + + if (inRange(unshiftedRowIndex, min, max)) { + index = i; + break; + } + } + + const paymentsInStep = + seasonTypeOptions && seasonTypeOptions.paymentsInStep; + + for ( + let i = + withFirstPayment(withShift(allBoundaries[index][0])) - + PERIODS_NUMBER; + i < leasingPeriod - 1; + i += PERIODS_NUMBER + ) { + const targetStartPosition = i; + for ( + let j = targetStartPosition; + j < paymentsInStep[index] + targetStartPosition; + j++ + ) { + if (j > 0 && j < leasingPeriod - 1) + calculationStore.setTableRow( + tableName, + j, + )({ paymentRelation: { value } }); + } } } } diff --git a/src/core/constants/values.js b/src/core/constants/values.js index 1cf355b..2ae8799 100644 --- a/src/core/constants/values.js +++ b/src/core/constants/values.js @@ -7,4 +7,5 @@ export default { NDFL: 0.13, MAX_VEHICLE_MASS: 3500, MAX_VEHICLE_SEATS: 20, + PERIODS_NUMBER: 12, }; diff --git a/src/core/tools/array.js b/src/core/tools/array.js index ec9907f..82b8218 100644 --- a/src/core/tools/array.js +++ b/src/core/tools/array.js @@ -13,3 +13,15 @@ export function shiftRight(arr, n) { } return arr; } + +export function rotateArrays(...arrs) { + let res = []; + for (let i = 0; i < arrs[0].length; i++) { + let boundaries = []; + for (let arr of arrs) { + boundaries.push(arr[i]); + } + res.push(boundaries); + } + return res; +}