⚙️ un début de propreté dans les mécanismes

POC de mécanisme dznsnun style nouveau et dans un nouveau fichier.

reste à abstraire la fonction v
indeps-catégorie-activité
Mael 2019-02-20 11:57:35 +01:00
parent 209694a4c6
commit 19537e1d87
4 changed files with 137 additions and 101 deletions

View File

@ -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,

View File

@ -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'
}
}

View File

@ -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
}

View File

@ -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,