- {dependencies && dependencies.length ? + {missingVariables && missingVariables.length ? 'Répondez aux questions !' - : value != null ? - value + '€' + : computedValue != null ? + computedValue + '€' : 'Non applicable' }
diff --git a/source/engine/expressions.js b/source/engine/expressions.js index 5cb9366ed..9a0a2e249 100644 --- a/source/engine/expressions.js +++ b/source/engine/expressions.js @@ -6,15 +6,17 @@ import {parentName, nameLeaf} from './rules' // composants des regexps let - vn = '[A-Za-z\\u00C0-\\u017F\\s]+', //variableName - sep = '\\s\\.\\s' + vp = '[A-Za-z\\u00C0-\\u017F\\s]+', // variable part + sep = '\\s\\.\\s', + vn = `(${vp}(?:${sep}${vp})*)` let expressionTests = { // 'negatedVariable': v => /!((?:[a-z0-9]|\s|_)+)/g.exec(v), // 'variableIsIncludedIn': v => /((?:[a-z0-9]|\s|_)+)⊂*/g.exec(v), - 'variableComparedToNumber': v => /([\w\s]+(?:\s\.\s[\w\s]+)*)\s([<>]=?)\s([0-9]+)/g.exec(v), + // 'variableComparedToNumber': v => /([\w\s]+(?:\s\.\s[\w\s]+)*)\s([<>]=?)\s([0-9]+)/g.exec(v), + 'variableComparedToNumber': v => new RegExp(`^${vn}\\s([<>]=?)\\s([0-9]+)$`, 'g').exec(v), 'variableEqualsString': v => /([\w\s]+(?:\s\.\s[\w\s]+)*)\s=\s([\w\s]+)/g.exec(v), - 'variable': v => new RegExp(`^(${vn}(?:${sep}${vn})*)$`, 'g').exec(v) + 'variable': v => new RegExp(`^${vn}$`, 'g').exec(v) } export let recognizeExpression = value => { @@ -29,6 +31,7 @@ export let recognizeExpression = value => { match = expressionTests['variableComparedToNumber'](value) if (match) { + let [, variableName, symbol, number] = match return [variableName, situation => eval(`situation("${variableName}") ${symbol} ${number}`)] // eslint-disable-line no-unused-vars } @@ -48,9 +51,9 @@ export let recognizeExpression = value => { // let yo = parentName(variableName), // ya = nameLeaf(variableName), // yi = situation(parentName(variableName)) - // debugger; - return removeDiacritics(situation(variableName)) == 'oui' || - removeDiacritics(situation(parentName(variableName))) == nameLeaf(variableName) + // debugger + return situation(variableName) == 'oui' || + situation(parentName(variableName)) == nameLeaf(variableName) }] } } diff --git a/source/engine/rules.js b/source/engine/rules.js index 090cfd21f..bea46d987 100644 --- a/source/engine/rules.js +++ b/source/engine/rules.js @@ -60,7 +60,7 @@ export let searchRules = searchInput => export let findRuleByDottedName = dottedName => do { let found = entityRules.find(rule => rule.dottedName == dottedName) - found || console.log('dottedName = ', dottedName, ' a déserté') + found } export let findGroup = R.pipe( diff --git a/source/engine/traverse.js b/source/engine/traverse.js index 42d3576d1..e015d4eb8 100644 --- a/source/engine/traverse.js +++ b/source/engine/traverse.js @@ -8,8 +8,10 @@ import {recognizeExpression} from './expressions' let selectedRules = rules.filter(rule => R.contains( enrichRule(rule).name, - ['CIF CDD', 'Fin de contrat'] - // ['CIF CDD'] + [ + 'CIF CDD', 'fin de contrat', + 'majoration chômage CDD' + ] ) ) @@ -18,11 +20,15 @@ let knownVariable = (situation, variableName) => typeof R.or( situation(parentName(variableName)) ) !== 'undefined' +let transformPercentage = s => + s.indexOf('%') > -1 ? + +s.replace('%', '') / 100 : + +s let deriveRule = situationGate => R.pipe( R.toPairs, // Reduce to [variables needed to compute that variable, computed variable value] - R.reduce(([variableNames, result], [key, value]) => { + R.reduce(({missingVariables, computedValue}, [key, value]) => { if (key === 'concerne') { let [variableName, evaluation] = recognizeExpression(value) // Si cette variable a été renseignée @@ -30,21 +36,19 @@ let deriveRule = situationGate => R.pipe( // Si l'expression n'est pas vraie... if (!evaluation(situationGate)) { // On court-circuite toute la variable, et on n'a besoin d'aucune information ! - return R.reduced([[]]) + return R.reduced({missingVariables: []}) } else { // Sinon, on continue - return [variableNames] + return {missingVariables} } // sinon on demande la valeur de cette variable - } else return [[...variableNames, variableName]] + } else return { missingVariables: [...missingVariables, variableName] } } if (key === 'non applicable si') { let conditions = value['l\'une de ces conditions'] let [subVariableNames, reduced] = R.reduce(([variableNames], expression) => { - let [variableName, evaluation] = recognizeExpression(expression) - if (knownVariable(situationGate, variableName)) { if (evaluation(situationGate)) { return R.reduced([[], true]) @@ -54,8 +58,9 @@ let deriveRule = situationGate => R.pipe( } return [[...variableNames, variableName]] }, [[], null])(conditions) - if (reduced) return R.reduced([[]]) - else return [variableNames.concat(subVariableNames)] + + if (reduced) return R.reduced({missingVariables: []}) + else return {missingVariables: [...missingVariables, ...subVariableNames]} } if (key === 'formule') { @@ -67,30 +72,49 @@ let deriveRule = situationGate => R.pipe( assietteValue = situationGate(assietteVariableName), unknownAssiette = assietteValue == undefined - if (unknownAssiette) { - return [[...variableNames, assietteVariableName]] - } else { - if (variableNames.length > 0) { - return [variableNames] - } - } - // Arrivés là, cette formule devrait être calculable ! + let {missingVariables: tauxMissingVariables = [], computedValue} = typeof taux !== 'string' ? + do { + let numericalLogic = taux['logique numérique'] + if (!numericalLogic) throw 'On ne sait pas pour l\'instant traiter ce mécanisme de taux' - // A propos du taux - if (typeof taux !== 'string' && typeof taux !== 'number') { - throw 'Oups, pas de taux compliqués s\'il-vous-plaît' + let treatNumericalLogic = numericalLogic => { + if (typeof numericalLogic == 'string') { + return new Object({computedValue: assietteValue * transformPercentage(numericalLogic)}) + } else { + return R.pipe( + R.toPairs(), + R.reduce(({missingVariables}, [expression, subLogic]) => { + let [variableName, evaluation] = recognizeExpression(expression) + if (knownVariable(situationGate, variableName)) { + if (evaluation(situationGate)) { + return R.reduced(treatNumericalLogic(subLogic)) + } else { + return {missingVariables} + } + } else return {missingVariables: [...missingVariables, variableName]} + }, {missingVariables: []}) + )(numericalLogic) + }} + treatNumericalLogic(numericalLogic) + } : ({computedValue: assietteValue * transformPercentage(taux)}) + + let formulaResult = { + missingVariables: [ + ...missingVariables, + ...(unknownAssiette ? [assietteVariableName] : []), + ...tauxMissingVariables + ], + computedValue } - let tauxValue = taux.indexOf('%') > -1 ? - +taux.replace('%', '') / 100 : - +taux - return R.reduced([null, assietteValue * tauxValue]) + return computedValue != null ? R.reduced(formulaResult) : formulaResult + } } - return [variableNames] - }, [[], null]) + return {missingVariables} + }, {missingVariables: []}) ) let analyseRule = situationGate => diff --git a/source/reducers.js b/source/reducers.js index 47dafe8f1..a9e64ffaf 100644 --- a/source/reducers.js +++ b/source/reducers.js @@ -52,7 +52,6 @@ export default reduceReducers( (state, action) => { if (action.type == STEP_ACTION || action.type == START_CONVERSATION) { let {newState, name} = action - console.log('action', action) // une étape vient d'être validée : on va changer son état let newSteps = R.pipe( R.map(step => step.name == name ? {...step, state: newState} : step), @@ -68,7 +67,7 @@ export default reduceReducers( ), missingVariables = R.pipe( - R.map( ({name, derived: [missingVariables]}) => + R.map( ({name, derived: {missingVariables}}) => (missingVariables || []).map(mv => [mv, name]) ), R.unnest, @@ -91,10 +90,11 @@ export default reduceReducers( [R.isNil, () => variables.map(dottedName => { let rule = findRuleByDottedName(dottedName) return Object.assign(constructStepMeta(rule), - rule.contrainte == 'nombre positif' ? + rule.contrainte == 'nombre positif' || + rule.contrainte == 'période' ? { component: Input, - defaultValue: 0, + defaultValue: 1, valueType: euro, attributes: { inputMode: 'numeric',