From c58a7449d04e8ff7a136279c51f818ec0bdd424e Mon Sep 17 00:00:00 2001 From: Mael Date: Thu, 20 Sep 2018 17:14:11 +0200 Subject: [PATCH] =?UTF-8?q?Impl=C3=A9mentation=20plus=20puissante=20de=20l?= =?UTF-8?q?a=20d=C3=A9pendance=20parent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Elle est applicable à tous les parents calculables, et on fait attention à ne pas produire de boucles infinies. --- source/engine/rules.js | 9 +++++--- source/engine/traverse.js | 22 ++++++++++++-------- source/règles/base.yaml | 1 - test/real-rules.test.js | 2 +- test/traverse.test.js | 43 +++++++++++++++++++++++++++++++++++++-- 5 files changed, 62 insertions(+), 15 deletions(-) diff --git a/source/engine/rules.js b/source/engine/rules.js index 13c0749c1..a309c554a 100644 --- a/source/engine/rules.js +++ b/source/engine/rules.js @@ -53,8 +53,11 @@ export let enrichRule = (rule, sharedData = {}) => { defaultValue = rule['par défaut'], examples = rule['exemples'], icon = rule['icônes'], - booleanNamespace = - rule.question && (!rule.format || rule.format === 'booléen') + calculableNamespace = + rule.question || + rule['non applicable si'] || + rule['applicable si'] || + rule.formule return { ...rule, @@ -69,7 +72,7 @@ export let enrichRule = (rule, sharedData = {}) => { raw: rule, examples, icon, - booleanNamespace + calculableNamespace } } catch (e) { throw new Error('Problem enriching ' + JSON.stringify(rule)) diff --git a/source/engine/traverse.js b/source/engine/traverse.js index ec81f0386..19b8d1981 100644 --- a/source/engine/traverse.js +++ b/source/engine/traverse.js @@ -18,7 +18,8 @@ import { merge, keys, is, - T + T, + isEmpty } from 'ramda' import { Node } from './mecanismViews/common' import { @@ -164,14 +165,12 @@ export let treatRuleRoot = (rules, rule) => { return { ...evaluated, nodeValue, isApplicable, missingVariables } } - // A parent dependency means that one of a rule's parents is a boolean question - // When the question is resolved to false, then the whole branch under it is disactivate, non applicable + // A parent dependency means that one of a rule's parents is not just a namespace holder, it is calculable, so it can be false + // When it is resolved to false, then the whole branch under it is disactivate, non applicable // It lets those children omit parent applicability tests - let parentDependencies = ruleParents(rule.dottedName) - .reverse() - .map(joinName), + let parentDependencies = ruleParents(rule.dottedName).map(joinName), parentDependency = parentDependencies.find( - parent => rules.find(r => r.dottedName === parent)?.booleanNamespace + parent => rules.find(r => r.dottedName === parent)?.calculableNamespace ) let parsedRoot = evolve({ @@ -181,8 +180,15 @@ export let treatRuleRoot = (rules, rule) => { // condition d'applicabilité de la règle parentDependency: parent => { let evaluate = (cache, situationGate, parsedRules, node) => { + let cpd = cache.checkingParentDependencies || [] + if (cpd.includes(rule.dottedName)) + return rewriteNode(node, true, null, {}) + let explanation = evaluateNode( - cache, + { + ...cache, + checkingParentDependencies: [...cpd, rule.dottedName] + }, situationGate, parsedRules, node.explanation diff --git a/source/règles/base.yaml b/source/règles/base.yaml index 214652721..b42c1e24e 100644 --- a/source/règles/base.yaml +++ b/source/règles/base.yaml @@ -2356,7 +2356,6 @@ formule: entreprise . taxe sur les salaires / entreprise . effectif note: Cette implémentation de la taxe sur les salaires est spécifique aux associations à but non lucratif, elle est donc largement simplifiée. Plein d'autres organisations sont concernées, en fonction de la TVA qu'elles paient. Les associations y sont assujetties automatiquement. - exemples: - nom: non applicable par défaut situation: diff --git a/test/real-rules.test.js b/test/real-rules.test.js index d901ba813..1f8d72bfe 100644 --- a/test/real-rules.test.js +++ b/test/real-rules.test.js @@ -36,7 +36,7 @@ let parsedRules = parseAll(rules) describe('Tests des règles de notre base de règles', () => parsedRules.map(rule => { if (!rule.exemples) return null - describe(rule.name, () => { + describe(rule.dottedName, () => { let examples = runExamples(rule.exemples, rule) examples.map(example => it(example.nom + '', () => { diff --git a/test/traverse.test.js b/test/traverse.test.js index 8fc10dbfc..ff9f59b4c 100644 --- a/test/traverse.test.js +++ b/test/traverse.test.js @@ -507,14 +507,53 @@ describe('analyse with mecanisms', function() { }) describe('Implicit parent applicability', function() { - it('should make a variable non applicable if one parent is non applicable', function() { + it('should make a variable non applicable if one parent is input to false', function() { let rawRules = [ { nom: 'CDD', question: 'CDD ?' }, { nom: 'surcoût', formule: 10, espace: 'CDD' } ], rules = parseAll(rawRules.map(enrichRule)) expect( - analyse(rules, 'surcoût')(name => ({ CDD: false }[name])).targets[0] + analyse(rules, 'CDD . surcoût')(name => ({ CDD: false }[name])).targets[0] + ).to.have.property('nodeValue', 0) + }) + it('should make a variable non applicable if one parent is non applicable', function() { + let rawRules = [ + { nom: 'CDD', question: 'CDD ?', 'non applicable si': 'exception' }, + { nom: 'exception', question: 'Suivez-vous le lapin blanc ?' }, + { nom: 'surcoût', formule: 10, espace: 'CDD' } + ], + rules = parseAll(rawRules.map(enrichRule)) + expect( + analyse(rules, 'CDD . surcoût')(name => ({ exception: true }[name])) + .targets[0] + ).to.have.property('nodeValue', 0) + }) + it('should not go through eval loops from parent to children to parent', function() { + let rawRules = [ + { + nom: 'CDD', + question: 'CDD ?', + 'non applicable si': 'exception > 3' + }, + { + espace: 'CDD', + nom: 'surcoût', + formule: 'annuel / 12' + }, + { + espace: 'CDD . surcoût', + nom: 'annuel', + formule: 24 + }, + { + nom: 'exception', + formule: 'CDD . surcoût * 3' + } + ], + rules = parseAll(rawRules.map(enrichRule)) + expect( + analyse(rules, 'CDD . surcoût . annuel')(name => ({}[name])).targets[0] ).to.have.property('nodeValue', 0) }) })