From 19537e1d87b3b091c447306204320acc3620a71a Mon Sep 17 00:00:00 2001 From: Mael Date: Wed, 20 Feb 2019 11:57:35 +0100 Subject: [PATCH] =?UTF-8?q?:gear:=20un=20d=C3=A9but=20de=20propret=C3=A9?= =?UTF-8?q?=20dans=20les=20m=C3=A9canismes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit POC de mécanisme dznsnun style nouveau et dans un nouveau fichier. reste à abstraire la fonction v --- source/engine/mecanisms.js | 101 +----------------------------- source/engine/mecanisms/barème.js | 79 +++++++++++++++++++++++ source/engine/mecanisms/utils.js | 48 ++++++++++++++ source/engine/treat.js | 10 ++- 4 files changed, 137 insertions(+), 101 deletions(-) create mode 100644 source/engine/mecanisms/utils.js diff --git a/source/engine/mecanisms.js b/source/engine/mecanisms.js index d4383c6d3..28c25f270 100644 --- a/source/engine/mecanisms.js +++ b/source/engine/mecanisms.js @@ -42,7 +42,6 @@ import { evaluateNode, rewriteNode, evaluateArray, - evaluateArrayWithFilter, evaluateObject, parseObject, collectNodeMissing, @@ -64,55 +63,10 @@ import BarèmeContinu from './mecanismViews/BarèmeContinu' import InversionNumérique from './mecanismViews/InversionNumérique' import Variations from './mecanismViews/Variations' import Allègement from './mecanismViews/Allègement' -import Composantes from './mecanismViews/Composantes' -import { trancheValue } from './mecanisms/barème' import buildSelectionView from './mecanismViews/Selection' import uniroot from './uniroot' - -let decompose = (recurse, k, v) => { - let subProps = dissoc('composantes')(v), - explanation = v.composantes.map(c => ({ - ...recurse( - objOf(k, { - ...subProps, - ...dissoc('attributs')(c) - }) - ), - composante: c.nom ? { nom: c.nom } : c.attributs - })) - - let filter = situationGate => c => - !situationGate('sys.filter') || - !c.composante || - ((!c.composante['dû par'] || - c.composante['dû par'] == situationGate('sys.filter')) && - (!c.composante['impôt sur le revenu'] || - c.composante['impôt sur le revenu'] == situationGate('sys.filter'))) - - return { - explanation, - jsx: Composantes, - evaluate: evaluateArrayWithFilter(filter, add, 0), - category: 'mecanism', - name: 'composantes', - type: 'numeric' - } -} - -let devariateExplanation = (recurse, mecanismKey, v) => { - let fixedProps = dissoc('variations')(v), - explanation = v.variations.map(({ si, alors, sinon }) => ({ - consequence: recurse({ - [mecanismKey]: { - ...fixedProps, - ...(sinon || alors) - } - }), - condition: sinon ? undefined : recurse(si) - })) - - return explanation -} +import { decompose, devariateExplanation } from 'Engine/mecanisms/utils' +import { desugarScale } from 'Engine/mecanisms/barème' /* @devariate = true => This function will produce variations of a same mecanism (e.g. product) that share some common properties */ export let mecanismVariations = (recurse, k, v, devariate) => { @@ -726,16 +680,6 @@ export let mecanismProduct = (recurse, k, v) => { à: 1 ``` */ -let desugarScale = recurse => tranches => - tranches - .map(t => - has('en-dessous de')(t) - ? { ...t, de: 0, à: t['en-dessous de'] } - : has('au-dessus de')(t) - ? { ...t, de: t['au-dessus de'], à: Infinity } - : t - ) - .map(evolve({ taux: recurse })) export let mecanismLinearScale = (recurse, k, v) => { if (v.composantes) { @@ -782,47 +726,6 @@ export let mecanismLinearScale = (recurse, k, v) => { } } -export let mecanismScale = (recurse, k, v) => { - // Sous entendu : barème en taux marginaux. - if (v.composantes) { - //mécanisme de composantes. Voir known-mecanisms.md/composantes - return decompose(recurse, k, v) - } - if (v.variations) { - return mecanismVariations(recurse, k, v, true) - } - - let tranches = desugarScale(recurse)(v['tranches']), - objectShape = { - assiette: false, - multiplicateur: defaultNode(1) - } - - let effect = ({ assiette, multiplicateur: multiplicateur, tranches }) => { - let nulled = val(assiette) == null || val(multiplicateur) == null - - return nulled - ? null - : sum(tranches.map(trancheValue('marginal')(assiette, multiplicateur))) - } - - let explanation = { - ...parseObject(recurse, objectShape, v), - tranches - }, - evaluate = evaluateObject(objectShape, effect) - - return { - evaluate, - jsx: Barème('marginal'), - explanation, - category: 'mecanism', - name: 'barème', - barème: 'en taux marginaux', - type: 'numeric' - } -} - export let mecanismContinuousScale = (recurse, k, v) => { let objectShape = { assiette: false, diff --git a/source/engine/mecanisms/barème.js b/source/engine/mecanisms/barème.js index a9c82fd72..a06d8ac6e 100644 --- a/source/engine/mecanisms/barème.js +++ b/source/engine/mecanisms/barème.js @@ -1,4 +1,26 @@ import { val } from 'Engine/traverse-common-functions' +import { decompose } from 'Engine/mecanisms/utils' +import { mecanismVariations } from 'Engine/mecanisms' +import { has, evolve, sum } from 'ramda' +import { + defaultNode, + evaluateNode, + mergeMissing, + rewriteNode +} from 'Engine/evaluation' + +import Barème from 'Engine/mecanismViews/Barème' + +export let desugarScale = recurse => tranches => + tranches + .map(t => + has('en-dessous de')(t) + ? { ...t, de: 0, à: t['en-dessous de'] } + : has('au-dessus de')(t) + ? { ...t, de: t['au-dessus de'], à: Infinity } + : t + ) + .map(evolve({ taux: recurse })) export let trancheValue = barèmeType => (assiette, multiplicateur) => barèmeType === 'marginal' @@ -15,3 +37,60 @@ export let trancheValue = barèmeType => (assiette, multiplicateur) => ? val(assiette) * val(taux) : montant : 0 + +export default (recurse, k, v) => { + // Barème en taux marginaux. + + if (v.composantes) { + //mécanisme de composantes. Voir known-mecanisms.md/composantes + return decompose(recurse, k, v) + } + if (v.variations) { + return mecanismVariations(recurse, k, v, true) + } + + let tranches = desugarScale(recurse)(v['tranches']) + + let explanation = { + assiette: recurse(v['assiette']), + multiplicateur: + v['multiplicateur'] != null + ? recurse(v['multiplicateur']) + : defaultNode(1), + tranches + } + + let evaluate = (cache, situationGate, parsedRules, node) => { + let mv = {} + + let v = element => { + let evaluated = evaluateNode(cache, situationGate, parsedRules, element) + // automatically add missing variables when a variable is evaluated and thus needed in this mecanism's evaluation + mv = mergeMissing(mv, evaluated.missingVariables) + + return evaluated.nodeValue + }, + { assiette, multiplicateur } = node.explanation, + trancheValues = node.explanation.tranches.map( + ({ de: min, à: max, taux }) => + v(assiette) < min * v(multiplicateur) + ? 0 + : (Math.min(v(assiette), max * v(multiplicateur)) - + min * v(multiplicateur)) * + v(taux) + ), + nodeValue = sum(trancheValues) + + return rewriteNode(node, nodeValue, explanation, mv) + } + + return { + explanation, + evaluate, + jsx: () => null, + // jsx: Barème('marginal'), + category: 'mecanism', + name: 'barème', + barème: 'marginal' + } +} diff --git a/source/engine/mecanisms/utils.js b/source/engine/mecanisms/utils.js new file mode 100644 index 000000000..88362872a --- /dev/null +++ b/source/engine/mecanisms/utils.js @@ -0,0 +1,48 @@ +import Composantes from 'Engine/mecanismViews/Composantes' +import { add, dissoc, objOf } from 'ramda' +import { evaluateArrayWithFilter } from 'Engine/evaluation' + +export let decompose = (recurse, k, v) => { + let subProps = dissoc('composantes')(v), + explanation = v.composantes.map(c => ({ + ...recurse( + objOf(k, { + ...subProps, + ...dissoc('attributs')(c) + }) + ), + composante: c.nom ? { nom: c.nom } : c.attributs + })) + + let filter = situationGate => c => + !situationGate('sys.filter') || + !c.composante || + ((!c.composante['dû par'] || + c.composante['dû par'] == situationGate('sys.filter')) && + (!c.composante['impôt sur le revenu'] || + c.composante['impôt sur le revenu'] == situationGate('sys.filter'))) + + return { + explanation, + jsx: Composantes, + evaluate: evaluateArrayWithFilter(filter, add, 0), + category: 'mecanism', + name: 'composantes', + type: 'numeric' + } +} + +export let devariateExplanation = (recurse, mecanismKey, v) => { + let fixedProps = dissoc('variations')(v), + explanation = v.variations.map(({ si, alors, sinon }) => ({ + consequence: recurse({ + [mecanismKey]: { + ...fixedProps, + ...(sinon || alors) + } + }), + condition: sinon ? undefined : recurse(si) + })) + + return explanation +} diff --git a/source/engine/treat.js b/source/engine/treat.js index 41cbe6c66..cb471ce23 100644 --- a/source/engine/treat.js +++ b/source/engine/treat.js @@ -31,13 +31,19 @@ import { } from './treatVariable' import { treat } from './traverse' import knownMecanisms from './known-mecanisms.yaml' + +// This should be the new way to implement mecanisms +// In a specific file +// TODO import them automatically +// TODO convert the legacy functions to new files +import barème from 'Engine/mecanisms/barème.js' + import { mecanismOneOf, mecanismAllOf, mecanismNumericalSwitch, mecanismSum, mecanismProduct, - mecanismScale, mecanismLinearScale, mecanismContinuousScale, mecanismMax, @@ -251,7 +257,7 @@ export let treatObject = (rules, rule, treatOptions) => rawNode => { 'aiguillage numérique': mecanismNumericalSwitch, somme: mecanismSum, multiplication: mecanismProduct, - barème: mecanismScale, + barème, 'barème linéaire': mecanismLinearScale, 'barème continu': mecanismContinuousScale, 'le maximum de': mecanismMax,