From 1ffb97c2f6ee2e4fc0677c437e4693c2fd0a31d9 Mon Sep 17 00:00:00 2001 From: Maxime Quandalle Date: Mon, 19 Aug 2019 09:36:27 +0200 Subject: [PATCH] =?UTF-8?q?Renomme=20"d=C3=A9sactive"=20en=20"rend=20non?= =?UTF-8?q?=20applicable"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ajout de tests, amélioration de la doc --- source/components/RuleLink.js | 4 +-- source/components/rule/Algorithm.js | 31 +--------------------- source/components/rule/Rule.js | 16 ++++++++++-- source/engine/evaluateRule.js | 4 +-- source/engine/known-mecanisms.yaml | 4 +-- source/engine/parseRule.js | 33 +++++++++++++++++++----- source/engine/traverse.js | 31 ++++++++++------------ source/règles/base.yaml | 10 +++---- test/mécanismes/rend-non-applicable.yaml | 15 +++++++++++ 9 files changed, 80 insertions(+), 68 deletions(-) create mode 100644 test/mécanismes/rend-non-applicable.yaml diff --git a/source/components/RuleLink.js b/source/components/RuleLink.js index 0b2e82d8b..7e3b59059 100644 --- a/source/components/RuleLink.js +++ b/source/components/RuleLink.js @@ -1,13 +1,13 @@ /* @flow */ import withColours from 'Components/utils/withColours' import withSitePaths from 'Components/utils/withSitePaths' +import { encodeRuleName, nameLeaf } from 'Engine/rules' import { compose } from 'ramda' import React from 'react' import { Link } from 'react-router-dom' import './RuleLink.css' import type { Règle } from 'Types/RegleTypes' import type { ThemeColours } from 'Components/utils/withColours' -import { encodeRuleName } from 'Engine/rules' type Props = Règle & { sitePaths: Object, @@ -29,7 +29,7 @@ const RuleLink = ({ to={newPath} className="rule-link" style={{ color: colour, ...style }}> - {title} + {title || nameLeaf(dottedName)} ) } diff --git a/source/components/rule/Algorithm.js b/source/components/rule/Algorithm.js index 4796b8e76..bdbc7ddb9 100644 --- a/source/components/rule/Algorithm.js +++ b/source/components/rule/Algorithm.js @@ -1,11 +1,8 @@ import classNames from 'classnames' import { React, T } from 'Components' -import withSitePaths from 'Components/utils/withSitePaths' import { makeJsx } from 'Engine/evaluation' -import { encodeRuleName } from 'Engine/rules' import { any, compose, identity, path } from 'ramda' import { Trans, withTranslation } from 'react-i18next' -import { Link } from 'react-router-dom' import './Algorithm.css' // The showValues prop is passed as a context. It used to be delt in CSS (not(.showValues) display: none), both coexist right now import { ShowValuesProvider } from './ShowValuesContext' @@ -38,32 +35,6 @@ let Conditions = ({ ) : null } -let DisabledBy = withSitePaths(({ isDisabledBy, sitePaths }) => { - return ( - isDisabledBy.length > 0 && ( - <> -

Exception :

-

- Cette règle ne s'applique pas pour le{' '} - {isDisabledBy.map(r => ( - - {r.title || r.name} - - ))} -

- - ) - ) -}) - export default compose(withTranslation())( class Algorithm extends React.Component { render() { @@ -93,7 +64,7 @@ export default compose(withTranslation())( )} - + {makeJsx(rule['rendu non applicable'])} ) diff --git a/source/components/rule/Rule.js b/source/components/rule/Rule.js index 804551568..1118f206f 100644 --- a/source/components/rule/Rule.js +++ b/source/components/rule/Rule.js @@ -24,6 +24,7 @@ import { } from 'Selectors/analyseSelectors' import Animate from 'Ui/animate' import { AttachDictionary } from '../AttachDictionary' +import RuleLink from '../RuleLink' import { Markdown } from '../utils/markdown' import Algorithm from './Algorithm' import Examples from './Examples' @@ -62,7 +63,6 @@ export default compose( flatRule = findRuleByDottedName(flatRules, dottedName) let { type, name, title, description, question, ns, icon } = flatRule, namespaceRules = findRuleByNamespace(flatRules, dottedName) - let displayedRule = analysedExample || analysedRule return ( @@ -164,9 +164,21 @@ export default compose( rule={displayedRule} showValues={valuesToShow || currentExample} /> + {displayedRule['rend non applicable'] && ( +
+

Rend non applicable :

+
    + {displayedRule['rend non applicable'].map(ruleName => ( +
  • + +
  • + ))} +
+
+ )} {flatRule.note && (
-

Note:

+

Note :

)} diff --git a/source/engine/evaluateRule.js b/source/engine/evaluateRule.js index afc398fc0..e99891ce7 100644 --- a/source/engine/evaluateRule.js +++ b/source/engine/evaluateRule.js @@ -11,7 +11,7 @@ export default (cache, situationGate, parsedRules, node) => { 'parentDependency', 'non applicable si', 'applicable si', - 'désactivé' + 'rendu non applicable' ]), map(value => evaluateNode(cache, situationGate, parsedRules, value)) )(node), @@ -19,7 +19,7 @@ export default (cache, situationGate, parsedRules, node) => { parentDependency, 'non applicable si': notApplicable, 'applicable si': applicable, - désactivé: disabled + 'rendu non applicable': disabled } = evaluatedAttributes, isApplicable = val(parentDependency) === false || diff --git a/source/engine/known-mecanisms.yaml b/source/engine/known-mecanisms.yaml index c4f1c9f0a..6b0976b77 100644 --- a/source/engine/known-mecanisms.yaml +++ b/source/engine/known-mecanisms.yaml @@ -113,9 +113,9 @@ non applicable si: Peut être accompagnée du mécanisme 'applicable si'. -désactive: +rend non applicable: description: | - Permet de désactiver certaines règles pour la situation saisie. + Permet de désactiver l'application de certaines règles pour la situation saisie. > Ce mécanisme est utile pour encoder les régimes d'exceptions (par exemple le [régime des impatriés]()) sans avoir à modifier la définition des règles de base. diff --git a/source/engine/parseRule.js b/source/engine/parseRule.js index 63a3e2842..edb2e2903 100644 --- a/source/engine/parseRule.js +++ b/source/engine/parseRule.js @@ -1,11 +1,12 @@ import { ShowValuesConsumer } from 'Components/rule/ShowValuesContext' +import RuleLink from 'Components/RuleLink' import evaluate from 'Engine/evaluateRule' import { parse } from 'Engine/parse' import { evolve, map } from 'ramda' import React from 'react' import { evaluateNode, makeJsx, rewriteNode } from './evaluation' import { Node } from './mecanismViews/common' -import { findParentDependency } from './rules' +import { disambiguateRuleReference, findParentDependency } from './rules' export default (rules, rule, parsedRules) => { // if (rule.dottedName.includes('distance journalière')) @@ -64,6 +65,10 @@ export default (rules, rule, parsedRules) => { parsedRules ), 'applicable si': evolveCond('applicable si', rule, rules, parsedRules), + 'rend non applicable': nonApplicableRules => + nonApplicableRules.map(referenceName => { + return disambiguateRuleReference(rules, rule, referenceName) + }), // formule de calcul formule: value => { let evaluate = (cache, situationGate, parsedRules, node) => { @@ -117,14 +122,13 @@ export default (rules, rule, parsedRules) => { parsedRules[rule.dottedName] = { // Pas de propriété explanation et jsx ici car on est parti du (mauvais) principe que 'non applicable si' et 'formule' sont particuliers, alors qu'ils pourraient être rangé avec les autres mécanismes ...parsedRoot, - désactivé, evaluate, parsed: true, isDisabledBy: [], unit: rule.unit || parsedRoot.formule?.explanation?.unit } - const désactivé = { + parsedRules[rule.dottedName]['rendu non applicable'] = { evaluate: (cache, situation, parsedRules, node) => { const nodeValue = node.explanation.isDisabledBy .map(disablerNode => @@ -133,16 +137,31 @@ export default (rules, rule, parsedRules) => { .some(x => x.nodeValue === true) return rewriteNode(node, nodeValue, node.explanation, {}) }, - jsx: (nodeValue, explanation) => , + jsx: (nodeValue, { isDisabledBy }) => { + return ( + isDisabledBy.length > 0 && ( + <> +

Exception{isDisabledBy.length > 1 && 's'}

+

+ Cette règle ne s'applique pas pour :{' '} + {isDisabledBy.map((rule, i) => ( + <> + {i > 0 && ', '} + + + ))} +

+ + ) + ) + }, category: 'ruleProp', rulePropType: 'cond', - name: 'désactivé', + name: 'rendu non applicable', type: 'boolean', explanation: parsedRules[rule.dottedName] } - parsedRules[rule.dottedName]['désactivé'] = désactivé - return parsedRules[rule.dottedName] } diff --git a/source/engine/traverse.js b/source/engine/traverse.js index eea6afbf5..7bd57447f 100644 --- a/source/engine/traverse.js +++ b/source/engine/traverse.js @@ -1,13 +1,9 @@ -import { evaluateControls } from 'Engine/controls' -import parseRule from 'Engine/parseRule' -import { chain, path } from 'ramda' -import { evaluateNode } from './evaluation' -import { parseReference } from './parseReference' -import { - disambiguateRuleReference, - findRule, - findRuleByDottedName -} from './rules' +import { evaluateControls } from 'Engine/controls'; +import parseRule from 'Engine/parseRule'; +import { chain, path } from 'ramda'; +import { evaluateNode } from './evaluation'; +import { parseReference } from './parseReference'; +import { findRule, findRuleByDottedName, disambiguateRuleReference } from './rules'; /* Dans ce fichier, les règles YAML sont parsées. @@ -49,19 +45,18 @@ export let parseAll = flatRules => { /* First we parse each rule one by one. When a mechanism is encountered, it is recursively parsed. When a reference to a variable is encountered, a 'variable' node is created, we don't parse variables recursively. */ let parsedRules = {} - let disabledMapping = {} + + /* A rule `A` can disable a rule `B` using the rule `rend non applicable: B` in the definition of `A`. + We need to map these exonerations to be able to retreive them from `B` */ + let nonApplicableMapping = {} flatRules.forEach(rule => { const parsed = parseRule(flatRules, rule, parsedRules) - if (parsed['désactive']) { - disabledMapping[rule.dottedName] = parsed['désactive'].map( - referenceName => { - return disambiguateRuleReference(flatRules, rule, referenceName) - } - ) + if (parsed['rend non applicable']) { + nonApplicableMapping[rule.dottedName] = parsed['rend non applicable'] } }) - Object.entries(disabledMapping).forEach(([a, b]) => { + Object.entries(nonApplicableMapping).forEach(([a, b]) => { b.forEach(ruleName => { parsedRules[ruleName].isDisabledBy.push( parseReference(flatRules, parsedRules[ruleName], parsedRules)({ diff --git a/source/règles/base.yaml b/source/règles/base.yaml index fcaa85424..8bc3264f0 100644 --- a/source/règles/base.yaml +++ b/source/règles/base.yaml @@ -692,7 +692,7 @@ Certains dirigeants d'entreprise (c'est notamment le cas pour les SASU) sont considérés par la sécurité sociale comme assimilés aux salariés. Ils sont alors au régime général de la sécurité sociale, avec quelques contraintes cependant. Par exemple, ils ne cotisent pas au chômage, et n'y ont donc pas droit. question: Le salarié est-il considéré comme "assimilé salarié" ? par défaut: non - désactive: + rend non applicable: - chômage - réduction générale - AGS @@ -1763,7 +1763,7 @@ par défaut: non # L'association a but non lucratif ne paie pas d'IS de droit commun article 206 du Code général des impôts # -> pas de taxe ni contribution d'apprentissage - désactive: + rend non applicable: - contrat salarié . taxe d'apprentissage - espace: entreprise @@ -1964,7 +1964,7 @@ description: | Le statut de jeune entreprise innovante (JEI) a été créé par la loi de finances pour 2004 et permet aux PME de moins de 8 ans consacrant 15% au moins de leurs charges à de la Recherche et Développement de bénéficier de certaines exonérations. par défaut: non - désactive: + rend non applicable: - contrat salarié . réduction générale - espace: contrat salarié . statut JEI @@ -2731,7 +2731,7 @@ applicable si: toutes ces conditions: - - entreprise . effectif > 250 + - entreprise . effectif >= 250 - entreprise . ratio alternants < 5% période: flexible @@ -2829,7 +2829,7 @@ Les impatriés sont exonérés de cotisations retraite (régime de base et complémentaire) à condition de justifier d'une contribution minimale versée par ailleurs (par exemple dans une caisse de retraite ou un fond de pension étranger). Ils n’acquièrent aucun droit pendant la durée d’exonération. note: La durée d’application est fixée au maximum jusqu’au 31 décembre de la huitième année civile suivant la prise de fonctions dans l’entreprise d’accueil. - désactive: + rend non applicable: - vieillesse - retraite complémentaire - protection sociale . retraite . base diff --git a/test/mécanismes/rend-non-applicable.yaml b/test/mécanismes/rend-non-applicable.yaml new file mode 100644 index 000000000..2e1ee62cb --- /dev/null +++ b/test/mécanismes/rend-non-applicable.yaml @@ -0,0 +1,15 @@ +- nom: impôt + formule: 1000 + +- nom: exilé fiscal + rend non applicable: + - impôt + +- nom: contribution + formule: impôt + test: règle désactivé + exemples: + - nom: evasion fiscale + situation: + exilé fiscal: oui + valeur attendue: 0