From 6cfed47148f58f016b23928cb1a3d82d774ab43d Mon Sep 17 00:00:00 2001 From: JoakimSM Date: Wed, 16 Dec 2020 15:39:07 +0100 Subject: [PATCH] fix: DHIS2-5490 rules engine numeric value parsing --- .../programRuleActionsForEvent.test.js | 2 +- .../engine/converters/inputValueConverter.js | 35 ++++++++++++------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/core_modules/capture-core/rules/engine/__tests__/programRuleActionsForEvent.test.js b/src/core_modules/capture-core/rules/engine/__tests__/programRuleActionsForEvent.test.js index bc98cc7473..d24e7b3cef 100644 --- a/src/core_modules/capture-core/rules/engine/__tests__/programRuleActionsForEvent.test.js +++ b/src/core_modules/capture-core/rules/engine/__tests__/programRuleActionsForEvent.test.js @@ -409,7 +409,7 @@ describe('Event rules engine effects with functions and effects', () => { // these variables are shared between each test const constants = [{ id: 'Gfd3ppDfq8E', displayName: 'Commodity ordering overhead', value: 5 }, { id: 'bCqvfPR02Im', displayName: 'Pi', value: 3.14 }]; const dataElementsInProgram = { oZg33kd9taw: { id: 'oZg33kd9taw', valueType: 'TEXT', optionSetId: 'pC3N9N77UmT' }, SWfdB5lX0fk: { id: 'SWfdB5lX0fk', valueType: 'BOOLEAN' }, qrur9Dvnyt5: { id: 'qrur9Dvnyt5', valueType: 'INTEGER' }, GieVkTxp4HH: { id: 'GieVkTxp4HH', valueType: 'NUMBER' }, vV9UWAZohSf: { id: 'vV9UWAZohSf', valueType: 'INTEGER_POSITIVE' }, eMyVanycQSC: { id: 'eMyVanycQSC', valueType: 'DATE' }, K6uUAvq500H: { id: 'K6uUAvq500H', valueType: 'TEXT', optionSetId: 'eUZ79clX7y1' }, msodh3rEMJa: { id: 'msodh3rEMJa', valueType: 'DATE' }, S33cRBsnXPo: { id: 'S33cRBsnXPo', valueType: 'ORGANISATION_UNIT' }, fWIAEtYVEGk: { id: 'fWIAEtYVEGk', valueType: 'TEXT', optionSetId: 'iDFPKpFTiVw' }, ulD2zW0TIy2: { id: 'ulD2zW0TIy2', valueType: 'FILE_RESOURCE' } }; - const programRules = [{ id: 'CTzRoPyvf8v', condition: 'true', displayName: 'Testing the functions!', programId: 'eBAyeGv0exc', programRuleActions: [{ id: 'isP0uvT24jf', content: "d2:yearsBetween( '2010-01-28', V{event_date}) =", data: "d2:yearsBetween( '2010-01-28', V{event_date})", programRuleActionType: 'DISPLAYTEXT' }, { id: 'vQCRnX6w9pM', content: 'd2:oizp( -10000000 ) =', data: 'd2:oizp( -10000000 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'SYAL0GIDnxI', content: 'display age = ', data: '#{age}', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'Xa0tKyNk5YE', content: 'org_unit = ', data: 'V{orgunit_code}', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'JXssEpbJdO2', content: 'd2:right(#{age}, 3) = ', data: 'd2:right(#{age}, 3)', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'o0LLNIYsliy', content: "d2:monthsBetween( '2020-01-28', V{event_date}) = ", data: "d2:monthsBetween( '2020-01-28', V{event_date})", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'k07KnI11Sf4', content: 'd2:left(#{age}, 3) = ', data: 'd2:left(#{age}, 3)', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'OITs4nPfMQ3', content: "d2:split('these-are-testing-values', '-', 2) = ", data: "d2:split('these-are-testing-values', '-', 2)", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'EzkFLDtAxCR', content: 'd2:modulus( 12 , 100 ) = ', data: 'd2:modulus( 12 , 100 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'RCYEyOly0Mi', content: "d2:countIfValue( #{gender}, 'Male' ) = ", data: "d2:countIfValue( #{gender}, 'Male' )", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'bRnjbxIwIRd', content: 'd2:round( 12.5 ) = ', data: 'd2:round( 12.5 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'BuEcHNoD98P', content: 'd2:ceil(11.3) = ', data: 'd2:ceil(11.3)', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'Foc3PhzoAVr', content: 'd2:count(#{age}) = ', data: 'd2:count(#{age})', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'QpeF2WDjwIV', content: "d2:addDays( '2020-01-12', 5 ) = ", data: "d2:addDays( '2020-01-12', 5 )", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'WJTjezLR4cJ', content: "d2:weeksBetween('2020-01-28', V{event_date} ) = ", data: "d2:weeksBetween('2020-01-28', V{event_date} )", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'YnE4dNJVF2P', content: 'd2:zing( -2 ) = ', data: 'd2:zing( -2 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'bZsv2cUkbB7', content: 'd2:floor( 11.5 ) =', data: 'd2:floor( 11.5 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'J8RxAbHlnO3', content: 'd2:oizp( 10000000 ) = ', data: 'd2:oizp( 10000000 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'NT1wojA2RdT', content: "d2:concatenate( 'dh', 'is', 2, 'is', 'rocking') = ", data: "d2:concatenate( 'dh', 'is', 2, 'is', 'rocking')", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'aqfqAMbmWHM', content: "d2:daysBetween( '2020-01-28', V{event_date}) =", data: "d2:daysBetween( '2020-01-28', V{event_date})", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'NUGe7EUVouK', content: "d2:substring('hello dhis 2', 6, 10) = ", data: "d2:substring('hello dhis 2', 6, 10)", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'Ma6nCIGrBrd', content: "d2:length( 'dhis2 rocks' ) = ", data: "d2:length( 'dhis2 rocks' )", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'RRSDsxWiUMc', content: 'd2:round( 0 ) = ', data: 'd2:round( 0 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'QUe0Pks4ckc', content: 'd2:countIfValue( #{age}, 1 ) = ', data: 'd2:countIfValue( #{age}, 1 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'sHaE1YI0ur2', content: 'd2:zing( 1000 ) = ', data: 'd2:zing( 1000 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'EojHcBMpW7q', content: 'd2:hasValue( #{age} ) = ', data: 'd2:hasValue( #{age} )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }] }]; + const programRules = [{ id: 'CTzRoPyvf8v', condition: 'true', displayName: 'Testing the functions!', programId: 'eBAyeGv0exc', programRuleActions: [{ id: 'isP0uvT24jf', content: "d2:yearsBetween( '2010-01-28', V{event_date}) =", data: "d2:yearsBetween( '2010-01-28', V{event_date})", programRuleActionType: 'DISPLAYTEXT' }, { id: 'vQCRnX6w9pM', content: 'd2:oizp( -10000000 ) =', data: 'd2:oizp( -10000000 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'SYAL0GIDnxI', content: 'display age = ', data: 'd2:hasValue(#{age}) && #{age}', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'Xa0tKyNk5YE', content: 'org_unit = ', data: 'V{orgunit_code}', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'JXssEpbJdO2', content: 'd2:right(#{age}, 3) = ', data: 'd2:hasValue(#{age}) && d2:right(#{age}, 3)', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'o0LLNIYsliy', content: "d2:monthsBetween( '2020-01-28', V{event_date}) = ", data: "d2:monthsBetween( '2020-01-28', V{event_date})", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'k07KnI11Sf4', content: 'd2:left(#{age}, 3) = ', data: 'd2:hasValue(#{age}) && d2:left(#{age}, 3)', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'OITs4nPfMQ3', content: "d2:split('these-are-testing-values', '-', 2) = ", data: "d2:split('these-are-testing-values', '-', 2)", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'EzkFLDtAxCR', content: 'd2:modulus( 12 , 100 ) = ', data: 'd2:modulus( 12 , 100 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'RCYEyOly0Mi', content: "d2:countIfValue( #{gender}, 'Male' ) = ", data: "d2:countIfValue( #{gender}, 'Male' )", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'bRnjbxIwIRd', content: 'd2:round( 12.5 ) = ', data: 'd2:round( 12.5 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'BuEcHNoD98P', content: 'd2:ceil(11.3) = ', data: 'd2:ceil(11.3)', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'Foc3PhzoAVr', content: 'd2:count(#{age}) = ', data: 'd2:count(#{age})', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'QpeF2WDjwIV', content: "d2:addDays( '2020-01-12', 5 ) = ", data: "d2:addDays( '2020-01-12', 5 )", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'WJTjezLR4cJ', content: "d2:weeksBetween('2020-01-28', V{event_date} ) = ", data: "d2:weeksBetween('2020-01-28', V{event_date} )", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'YnE4dNJVF2P', content: 'd2:zing( -2 ) = ', data: 'd2:zing( -2 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'bZsv2cUkbB7', content: 'd2:floor( 11.5 ) =', data: 'd2:floor( 11.5 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'J8RxAbHlnO3', content: 'd2:oizp( 10000000 ) = ', data: 'd2:oizp( 10000000 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'NT1wojA2RdT', content: "d2:concatenate( 'dh', 'is', 2, 'is', 'rocking') = ", data: "d2:concatenate( 'dh', 'is', 2, 'is', 'rocking')", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'aqfqAMbmWHM', content: "d2:daysBetween( '2020-01-28', V{event_date}) =", data: "d2:daysBetween( '2020-01-28', V{event_date})", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'NUGe7EUVouK', content: "d2:substring('hello dhis 2', 6, 10) = ", data: "d2:substring('hello dhis 2', 6, 10)", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'Ma6nCIGrBrd', content: "d2:length( 'dhis2 rocks' ) = ", data: "d2:length( 'dhis2 rocks' )", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'RRSDsxWiUMc', content: 'd2:round( 0 ) = ', data: 'd2:round( 0 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'QUe0Pks4ckc', content: 'd2:countIfValue( #{age}, 1 ) = ', data: 'd2:countIfValue( #{age}, 1 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'sHaE1YI0ur2', content: 'd2:zing( 1000 ) = ', data: 'd2:zing( 1000 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'EojHcBMpW7q', content: 'd2:hasValue( #{age} ) = ', data: 'd2:hasValue( #{age} )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }] }]; const programRulesVariables = [{ id: 'RycV5uDi66i', dataElementId: 'qrur9Dvnyt5', displayName: 'age', programId: 'eBAyeGv0exc', programRuleVariableSourceType: 'DATAELEMENT_NEWEST_EVENT_PROGRAM', useNameForOptionSet: true }, { id: 'zINGRka3g9N', dataElementId: 'oZg33kd9taw', displayName: 'gender', programId: 'eBAyeGv0exc', programRuleVariableSourceType: 'DATAELEMENT_NEWEST_EVENT_PROGRAM', useNameForOptionSet: true }, { id: 'Zj7UnCAulEk.vV9UWAZohSf', displayName: 'Zj7UnCAulEk.vV9UWAZohSf', programRuleVariableSourceType: 'DATAELEMENT_CURRENT_EVENT', dataElementId: 'vV9UWAZohSf', programId: 'eBAyeGv0exc' }, { id: 'Zj7UnCAulEk.GieVkTxp4HH', displayName: 'Zj7UnCAulEk.GieVkTxp4HH', programRuleVariableSourceType: 'DATAELEMENT_CURRENT_EVENT', dataElementId: 'GieVkTxp4HH', programId: 'eBAyeGv0exc' }, { id: 'Zj7UnCAulEk.GieVkTxp4HH', displayName: 'Zj7UnCAulEk.GieVkTxp4HH', programRuleVariableSourceType: 'DATAELEMENT_CURRENT_EVENT', dataElementId: 'GieVkTxp4HH', programId: 'eBAyeGv0exc' }]; const orgUnit = { id: 'DiszpKrYNg8', name: 'Ngelehun CHC', code: 'OU_559' }; const optionSet = { pC3N9N77UmT: { id: 'pC3N9N77UmT', displayName: 'Gender', version: 0, valueType: 'TEXT', options: [{ id: 'rBvjJYbMCVx', displayName: 'Male', code: 'Male', translations: [] }, { id: 'Mnp3oXrpAbK', displayName: 'Female', code: 'Female', translations: [] }] } }; diff --git a/src/core_modules/capture-core/rules/engine/converters/inputValueConverter.js b/src/core_modules/capture-core/rules/engine/converters/inputValueConverter.js index 04cbf8c62b..1935d5f245 100644 --- a/src/core_modules/capture-core/rules/engine/converters/inputValueConverter.js +++ b/src/core_modules/capture-core/rules/engine/converters/inputValueConverter.js @@ -1,6 +1,7 @@ // @flow /* eslint-disable class-methods-use-this */ -import { moment } from '../../../../capture-core-utils/moment'; +import { parseNumber } from 'capture-core-utils/parsers'; +import { moment } from 'capture-core-utils/moment'; import type { IConvertInputRulesValue } from '../rulesEngine.types'; const dateMomentFormat = 'YYYY-MM-DD'; @@ -51,28 +52,36 @@ class RulesValueConverter implements IConvertInputRulesValue { return value || ''; } - convertNumber(value: any): number | string { - return (value || value === 0) ? value : ''; + convertNumber(value: number | ''): number { + return value || 0; } - convertInteger(value: any): number | string { - return (value || value === 0) ? value : ''; + convertInteger(value: number | ''): number { + return value || 0; } - convertIntegerPositive(value: any): number | string { - return (value || value === 0) ? value : ''; + convertIntegerPositive(value: number | ''): number { + return value || 0; } - convertIntegerNegative(value: any): number | string { - return (value || value === 0) ? value : ''; + convertIntegerNegative(value: number | ''): number { + return value || 0; } - convertIntegerZeroOrPositive(value: any): number | string { - return (value || value === 0) ? value : ''; + convertIntegerZeroOrPositive(value: number | ''): number { + return value || 0; } - convertPercentage(value: any): number | string { - return (value || value === 0) ? value : ''; + convertPercentage(value: string): number { + if (!value) { + return 0; + } + const numberValue = parseNumber(value); + if (isNaN(numberValue)) { + return 0; + } + + return numberValue / 100; } convertUrl(value: any): string {