2019-07-22 10:36:50 +00:00
import { decompose } from 'Engine/mecanisms/utils'
2019-08-26 15:37:05 +00:00
import variations from 'Engine/mecanisms/variations'
2019-11-28 11:03:23 +00:00
import { convertNodeToUnit } from 'Engine/nodeUnits'
import { inferUnit , isPercentUnit } from 'Engine/units'
2019-07-09 10:14:42 +00:00
import {
add ,
any ,
equals ,
evolve ,
is ,
map ,
max ,
mergeWith ,
min ,
path ,
pluck ,
reduce ,
subtract ,
toPairs
} from 'ramda'
import React from 'react'
import { Trans } from 'react-i18next'
import 'react-virtualized/styles.css'
2019-11-28 11:03:23 +00:00
import { typeWarning } from './error'
2019-07-09 10:14:42 +00:00
import {
collectNodeMissing ,
defaultNode ,
evaluateArray ,
evaluateNode ,
evaluateObject ,
makeJsx ,
mergeAllMissing ,
2019-09-10 14:58:26 +00:00
parseObject
2019-07-09 10:14:42 +00:00
} from './evaluation'
import Allègement from './mecanismViews/Allègement'
import { Node , SimpleRuleLink } from './mecanismViews/common'
import InversionNumérique from './mecanismViews/InversionNumérique'
import Product from './mecanismViews/Product'
import Somme from './mecanismViews/Somme'
import { disambiguateRuleReference , findRuleByDottedName } from './rules'
import { anyNull , val } from './traverse-common-functions'
import uniroot from './uniroot'
2019-11-28 11:03:23 +00:00
import { parseUnit } from './units'
2017-07-28 12:24:29 +00:00
2017-06-28 10:08:32 +00:00
export let mecanismOneOf = ( recurse , k , v ) => {
2018-02-15 17:12:04 +00:00
if ( ! is ( Array , v ) ) throw new Error ( 'should be array' )
2017-07-09 17:42:45 +00:00
2018-01-08 15:07:26 +00:00
let explanation = map ( recurse , v )
2017-07-09 17:42:45 +00:00
2017-10-24 16:25:31 +00:00
let jsx = ( nodeValue , explanation ) => (
2017-07-13 19:55:59 +00:00
< Node
2017-06-28 10:08:32 +00:00
classes = "mecanism conditions list"
2017-10-24 16:25:31 +00:00
name = "une de ces conditions"
2017-07-13 19:55:59 +00:00
value = { nodeValue }
2017-06-28 10:08:32 +00:00
child = {
< ul >
2017-10-24 16:25:31 +00:00
{ explanation . map ( item => (
< li key = { item . name || item . text } > { makeJsx ( item ) } < / l i >
) ) }
2017-06-28 10:08:32 +00:00
< / u l >
2017-06-28 07:31:37 +00:00
}
2017-06-28 10:08:32 +00:00
/ >
2017-10-24 16:25:31 +00:00
)
2017-07-13 19:55:59 +00:00
2017-12-12 19:10:22 +00:00
let evaluate = ( cache , situationGate , parsedRules , node ) => {
2018-01-03 15:54:19 +00:00
let evaluateOne = child =>
evaluateNode ( cache , situationGate , parsedRules , child ) ,
2018-01-08 15:07:26 +00:00
explanation = map ( evaluateOne , node . explanation ) ,
values = pluck ( 'nodeValue' , explanation ) ,
nodeValue = any ( equals ( true ) , values )
2017-10-24 16:25:31 +00:00
? true
2018-05-09 16:41:57 +00:00
: any ( equals ( null ) , values )
2018-11-15 15:21:53 +00:00
? null
: false ,
2018-04-13 09:44:49 +00:00
// Unlike most other array merges of missing variables this is a "flat" merge
// because "one of these conditions" tend to be several tests of the same variable
// (e.g. contract type is one of x, y, z)
2018-05-09 16:41:57 +00:00
missingVariables =
nodeValue == null
? reduce ( mergeWith ( max ) , { } , map ( collectNodeMissing , explanation ) )
: { }
2017-10-24 16:25:31 +00:00
2019-09-10 14:58:26 +00:00
return { ... node , nodeValue , explanation , missingVariables }
2017-08-18 15:21:43 +00:00
}
2017-07-13 19:55:59 +00:00
return {
2017-08-18 15:21:43 +00:00
evaluate ,
2017-07-13 19:55:59 +00:00
jsx ,
explanation ,
category : 'mecanism' ,
name : 'une de ces conditions' ,
type : 'boolean'
2017-06-28 10:08:32 +00:00
}
}
2017-10-24 16:25:31 +00:00
export let mecanismAllOf = ( recurse , k , v ) => {
2018-02-15 17:12:04 +00:00
if ( ! is ( Array , v ) ) throw new Error ( 'should be array' )
2017-07-09 17:42:45 +00:00
2018-01-08 15:07:26 +00:00
let explanation = map ( recurse , v )
2017-07-09 17:42:45 +00:00
2017-10-24 16:25:31 +00:00
let jsx = ( nodeValue , explanation ) => (
2017-07-13 19:55:59 +00:00
< Node
2017-07-09 17:42:45 +00:00
classes = "mecanism conditions list"
2017-10-24 16:25:31 +00:00
name = "toutes ces conditions"
2017-07-13 19:55:59 +00:00
value = { nodeValue }
2017-07-09 17:42:45 +00:00
child = {
< ul >
2017-10-24 16:25:31 +00:00
{ explanation . map ( item => (
< li key = { item . name || item . text } > { makeJsx ( item ) } < / l i >
) ) }
2017-07-09 17:42:45 +00:00
< / u l >
}
/ >
2017-10-24 16:25:31 +00:00
)
2017-07-13 19:55:59 +00:00
2017-12-12 19:10:22 +00:00
let evaluate = ( cache , situationGate , parsedRules , node ) => {
2018-01-03 15:54:19 +00:00
let evaluateOne = child =>
evaluateNode ( cache , situationGate , parsedRules , child ) ,
2018-01-08 15:07:26 +00:00
explanation = map ( evaluateOne , node . explanation ) ,
values = pluck ( 'nodeValue' , explanation ) ,
nodeValue = any ( equals ( false ) , values )
2017-10-24 16:30:44 +00:00
? false // court-circuit
2018-05-09 16:41:57 +00:00
: any ( equals ( null ) , values )
2018-11-15 15:21:53 +00:00
? null
: true ,
2018-04-12 13:43:02 +00:00
missingVariables = nodeValue == null ? mergeAllMissing ( explanation ) : { }
2017-10-24 16:30:44 +00:00
2019-09-10 14:58:26 +00:00
return { ... node , nodeValue , explanation , missingVariables }
2017-10-24 16:30:44 +00:00
}
2017-07-13 19:55:59 +00:00
return {
2017-10-24 16:30:44 +00:00
evaluate : evaluate ,
2017-07-13 19:55:59 +00:00
jsx ,
explanation ,
category : 'mecanism' ,
name : 'toutes ces conditions' ,
type : 'boolean'
2017-07-09 17:42:45 +00:00
}
2017-06-28 10:08:32 +00:00
}
2017-06-28 07:31:37 +00:00
2019-01-08 21:38:04 +00:00
export let findInversion = ( situationGate , parsedRules , v , dottedName ) => {
2017-11-20 12:16:18 +00:00
let inversions = v . avec
if ( ! inversions )
2018-02-15 17:12:04 +00:00
throw new Error (
"Une formule d'inversion doit préciser _avec_ quoi on peut inverser la variable"
)
2017-11-20 12:16:18 +00:00
/ *
Quelle variable d ' inversion possible a sa valeur renseignée dans la situation courante ?
Ex . s 'il nous est demandé de calculer le salaire de base, est-ce qu' un candidat à l ' inversion , comme
le salaire net , a été renseigné ?
* /
2019-01-10 17:47:39 +00:00
let candidates = inversions
. map ( i =>
disambiguateRuleReference (
2019-06-13 16:17:22 +00:00
Object . values ( parsedRules ) ,
parsedRules [ dottedName ] ,
2019-01-10 17:47:39 +00:00
i
)
2018-01-03 15:54:19 +00:00
)
2019-01-10 17:47:39 +00:00
. map ( name => {
let userInput = situationGate ( name ) != undefined
let rule = findRuleByDottedName ( parsedRules , name )
2019-06-13 16:17:22 +00:00
if ( ! userInput ) return null
2019-01-10 17:47:39 +00:00
return {
fixedObjectiveRule : rule ,
userInput ,
2019-06-13 16:17:22 +00:00
fixedObjectiveValue : situationGate ( name )
2019-01-10 17:47:39 +00:00
}
} ) ,
candidateWithUserInput = candidates . find ( c => c && c . userInput )
2017-11-20 12:16:18 +00:00
2019-01-10 17:47:39 +00:00
return (
candidateWithUserInput || candidates . find ( candidate => candidate != null )
)
2017-11-20 12:16:18 +00:00
}
2018-04-12 10:25:01 +00:00
let doInversion = ( oldCache , situationGate , parsedRules , v , dottedName ) => {
2017-11-20 12:16:18 +00:00
let inversion = findInversion ( situationGate , parsedRules , v , dottedName )
2019-01-08 21:38:04 +00:00
if ( ! inversion )
2018-01-03 15:54:19 +00:00
return {
2018-05-09 16:41:57 +00:00
missingVariables : { [ dottedName ] : 1 } ,
2018-01-03 15:54:19 +00:00
nodeValue : null
}
2019-06-13 16:17:22 +00:00
let { fixedObjectiveValue , fixedObjectiveRule } = inversion
2019-01-08 21:38:04 +00:00
2017-12-12 19:10:22 +00:00
let inversionCache = { }
let fx = x => {
2019-11-28 11:03:23 +00:00
inversionCache = {
2019-12-16 14:13:22 +00:00
_meta : oldCache . _meta
2019-11-28 11:03:23 +00:00
}
2019-04-09 15:07:17 +00:00
let v = evaluateNode (
2018-01-03 15:54:19 +00:00
inversionCache , // with an empty cache
2019-04-12 08:26:57 +00:00
n =>
dottedName === n
? x
: n === 'sys.filter'
? undefined
: situationGate ( n ) ,
2017-11-20 12:16:18 +00:00
parsedRules ,
fixedObjectiveRule
2018-04-10 15:16:27 +00:00
)
2019-04-09 15:07:17 +00:00
return v
2017-12-12 19:10:22 +00:00
}
2017-11-20 12:16:18 +00:00
// si fx renvoie null pour une valeur numérique standard, disons 1000, on peut
// considérer que l'inversion est impossible du fait de variables manquantes
// TODO fx peut être null pour certains x, et valide pour d'autres : on peut implémenter ici le court-circuit
2018-04-10 15:16:27 +00:00
let attempt = fx ( 1000 )
if ( attempt . nodeValue == null ) {
return attempt
}
2017-11-23 15:19:24 +00:00
2018-11-15 15:21:53 +00:00
let tolerance = 0.1 ,
2020-01-14 14:13:37 +00:00
// cette fonction détermine l'inverse d'une fonction sans faire trop d'itérations
2017-11-20 12:16:18 +00:00
nodeValue = uniroot (
2018-12-19 16:26:11 +00:00
x => {
let y = fx ( x )
2019-06-13 16:17:22 +00:00
return y . nodeValue - fixedObjectiveValue
2018-12-19 16:26:11 +00:00
} ,
2019-04-09 15:50:36 +00:00
0.1 ,
2017-11-20 12:16:18 +00:00
1000000000 ,
2018-11-15 15:21:53 +00:00
tolerance ,
10
2017-11-20 12:16:18 +00:00
)
2020-01-14 14:13:37 +00:00
// Si aucune des valeurs ne fonctionne, on test la valeur 0.
if ( nodeValue == null ) {
attempt = fx ( 0 )
if ( Math . abs ( attempt . nodeValue - fixedObjectiveValue ) < 0.1 ) {
nodeValue = 0
}
}
2017-11-20 12:16:18 +00:00
return {
nodeValue ,
2018-04-12 13:43:02 +00:00
missingVariables : { } ,
2019-01-30 17:53:57 +00:00
inversionCache ,
inversedWith : {
rule : fixedObjectiveRule ,
value : fixedObjectiveValue
}
2017-11-20 12:16:18 +00:00
}
}
export let mecanismInversion = dottedName => ( recurse , k , v ) => {
2017-12-12 19:10:22 +00:00
let evaluate = ( cache , situationGate , parsedRules , node ) => {
2017-11-20 12:16:18 +00:00
let inversion =
2018-05-09 16:41:57 +00:00
// avoid the inversion loop !
2018-04-10 11:44:15 +00:00
situationGate ( dottedName ) == undefined &&
2018-04-12 10:25:01 +00:00
doInversion ( cache , situationGate , parsedRules , v , dottedName ) ,
2018-04-27 09:52:41 +00:00
// TODO - ceci n'est pas vraiment satisfaisant
2020-01-14 14:13:37 +00:00
nodeValue =
situationGate ( dottedName ) != null
? Number . parseFloat ( situationGate ( dottedName ) )
: inversion . nodeValue ,
2018-04-12 13:43:02 +00:00
missingVariables = inversion . missingVariables
2019-12-16 14:13:22 +00:00
if ( nodeValue === undefined ) {
2019-11-28 11:03:23 +00:00
cache . _meta . inversionFail = {
2019-04-09 15:07:17 +00:00
given : inversion . inversedWith . rule . dottedName ,
estimated : dottedName
}
2019-12-16 14:13:22 +00:00
}
2019-09-10 14:58:26 +00:00
let evaluatedNode = {
... node ,
2019-01-30 17:53:57 +00:00
nodeValue ,
2019-09-10 14:58:26 +00:00
explanation : {
... node . explanation ,
inversedWith : inversion ? . inversedWith
} ,
2019-01-30 17:53:57 +00:00
missingVariables
2019-09-10 14:58:26 +00:00
}
2018-04-12 16:06:54 +00:00
// TODO - we need this so that ResultsGrid will work, but it's
// just not right
toPairs ( inversion . inversionCache ) . map ( ( [ k , v ] ) => ( cache [ k ] = v ) )
2017-12-12 19:10:22 +00:00
return evaluatedNode
2017-11-20 12:16:18 +00:00
}
return {
2018-02-06 16:02:13 +00:00
... v ,
2017-11-20 12:16:18 +00:00
evaluate ,
2019-07-09 10:14:42 +00:00
explanation : evolve ( { avec : map ( recurse ) } , v ) ,
2019-01-30 17:53:57 +00:00
jsx : InversionNumérique ,
2017-11-20 12:16:18 +00:00
category : 'mecanism' ,
2019-01-30 17:53:57 +00:00
name : 'inversion numérique' ,
2017-11-20 12:16:18 +00:00
type : 'numeric'
}
}
2017-10-24 16:25:31 +00:00
export let mecanismSum = ( recurse , k , v ) => {
2017-07-09 22:14:22 +00:00
let explanation = v . map ( recurse )
2017-06-28 10:08:32 +00:00
2018-01-08 15:07:26 +00:00
let evaluate = evaluateArray ( add , 0 )
2017-07-13 19:55:59 +00:00
return {
evaluate ,
2018-05-22 17:12:13 +00:00
// eslint-disable-next-line
2019-07-20 16:30:42 +00:00
jsx : ( nodeValue , explanation , _ , unit ) => (
< Somme nodeValue = { nodeValue } explanation = { explanation } unit = { unit } / >
2017-10-24 16:25:31 +00:00
) ,
2017-07-13 19:55:59 +00:00
explanation ,
category : 'mecanism' ,
name : 'somme' ,
2019-07-11 14:29:05 +00:00
type : 'numeric' ,
2019-12-05 23:15:15 +00:00
unit : inferUnit (
'+' ,
explanation . map ( r => r . unit )
)
2017-06-28 10:08:32 +00:00
}
}
2018-02-14 16:50:47 +00:00
export let mecanismReduction = ( recurse , k , v ) => {
let objectShape = {
assiette : false ,
2019-02-14 17:00:31 +00:00
abattement : defaultNode ( 0 ) ,
2019-05-21 13:41:47 +00:00
plafond : defaultNode ( Infinity ) ,
2019-02-14 17:00:31 +00:00
franchise : defaultNode ( 0 )
2018-02-14 16:50:47 +00:00
}
2019-11-28 11:03:23 +00:00
let effect = (
{ assiette , abattement , plafond , franchise , décote } ,
cache
) => {
2018-02-22 18:47:27 +00:00
let v _assiette = val ( assiette )
if ( v _assiette == null ) return null
2019-11-28 11:03:23 +00:00
if ( assiette . unit ) {
try {
franchise = convertNodeToUnit ( assiette . unit , franchise )
plafond = convertNodeToUnit ( assiette . unit , plafond )
if ( ! isPercentUnit ( abattement . unit ) ) {
abattement = convertNodeToUnit ( assiette . unit , abattement )
}
if ( décote ) {
décote . plafond = convertNodeToUnit ( assiette . unit , décote . plafond )
décote . taux = convertNodeToUnit ( parseUnit ( '' ) , décote . taux )
}
} catch ( e ) {
typeWarning (
cache . _meta . contextRule ,
"Impossible de convertir les unités de l'allègement entre elles" ,
e
)
}
}
2018-02-22 18:47:27 +00:00
let montantFranchiséDécoté =
val ( franchise ) && v _assiette < val ( franchise )
2018-02-14 16:50:47 +00:00
? 0
: décote
2019-09-11 08:04:19 +00:00
? ( function ( ) {
2019-05-21 13:41:47 +00:00
let plafondDécote = val ( décote . plafond ) ,
2018-11-15 15:21:53 +00:00
taux = val ( décote . taux )
2018-02-14 16:50:47 +00:00
2019-09-11 08:04:19 +00:00
return v _assiette > plafondDécote
2018-11-15 15:21:53 +00:00
? v _assiette
2019-05-21 13:41:47 +00:00
: max ( 0 , ( 1 + taux ) * v _assiette - taux * plafondDécote )
2019-09-11 08:04:19 +00:00
} ) ( )
2018-11-15 15:21:53 +00:00
: v _assiette
2019-11-28 11:03:23 +00:00
const nodeValue = abattement
2018-02-22 17:00:44 +00:00
? val ( abattement ) == null
2018-05-09 16:41:57 +00:00
? montantFranchiséDécoté === 0
? 0
: null
2019-11-28 11:03:23 +00:00
: isPercentUnit ( abattement . unit )
2018-11-15 15:21:53 +00:00
? max (
0 ,
2019-06-11 17:26:33 +00:00
montantFranchiséDécoté -
min ( val ( plafond ) , val ( abattement ) * montantFranchiséDécoté )
2018-11-15 15:21:53 +00:00
)
2019-05-21 13:41:47 +00:00
: max ( 0 , montantFranchiséDécoté - min ( val ( plafond ) , val ( abattement ) ) )
2018-02-22 17:00:44 +00:00
: montantFranchiséDécoté
2019-11-28 11:03:23 +00:00
return {
nodeValue ,
additionalExplanation : {
unit : assiette . unit ,
franchise ,
plafond ,
abattement
}
}
2018-02-14 16:50:47 +00:00
}
let base = parseObject ( recurse , objectShape , v ) ,
2018-02-15 14:40:10 +00:00
explanation = v . décote
? {
... base ,
décote : map ( recurse , v . décote )
2018-05-09 16:41:57 +00:00
}
2018-02-15 14:40:10 +00:00
: base ,
2018-02-14 16:50:47 +00:00
evaluate = evaluateObject ( objectShape , effect )
return {
evaluate ,
2018-02-21 12:46:38 +00:00
jsx : Allègement ,
2018-02-14 16:50:47 +00:00
explanation ,
category : 'mecanism' ,
name : 'allègement' ,
2019-09-06 14:23:26 +00:00
type : 'numeric' ,
unit : explanation ? . assiette ? . unit
2018-02-14 16:50:47 +00:00
}
}
2017-10-24 16:25:31 +00:00
export let mecanismProduct = ( recurse , k , v ) => {
if ( v . composantes ) {
//mécanisme de composantes. Voir known-mecanisms.md/composantes
return decompose ( recurse , k , v )
2017-06-29 06:51:40 +00:00
}
2017-07-30 11:51:22 +00:00
if ( v . variations ) {
2019-07-22 10:36:50 +00:00
return variations ( recurse , k , v , true )
2017-07-30 11:51:22 +00:00
}
2017-06-29 06:51:40 +00:00
2017-07-12 09:50:34 +00:00
let objectShape = {
2017-10-24 16:25:31 +00:00
assiette : false ,
2019-02-14 17:00:31 +00:00
taux : defaultNode ( 1 ) ,
facteur : defaultNode ( 1 ) ,
plafond : defaultNode ( Infinity )
2017-07-12 09:50:34 +00:00
}
2019-11-28 11:03:23 +00:00
let effect = ( { assiette , taux , facteur , plafond } , cache ) => {
if ( assiette . unit ) {
try {
plafond = convertNodeToUnit ( assiette . unit , plafond )
} catch ( e ) {
typeWarning (
cache . _meta . contextRule ,
"Impossible de convertir l'unité du plafond de la multiplication dans celle de l'assiette" ,
e
)
}
}
2017-10-24 16:25:31 +00:00
let mult = ( base , rate , facteur , plafond ) =>
Math . min ( base , plafond ) * rate * facteur
2019-11-28 11:03:23 +00:00
const unit = inferUnit (
'*' ,
[ assiette , taux , facteur ] . map ( el => el . unit )
)
const nodeValue =
val ( taux ) === 0 ||
val ( taux ) === false ||
val ( assiette ) === 0 ||
val ( facteur ) === 0
? 0
: anyNull ( [ taux , assiette , facteur , plafond ] )
? null
: mult ( val ( assiette ) , val ( taux ) , val ( facteur ) , val ( plafond ) )
2019-03-25 18:14:27 +00:00
return {
2019-11-28 11:03:23 +00:00
nodeValue ,
additionalExplanation : {
plafondActif : val ( assiette ) > val ( plafond ) ,
unit
}
2019-03-25 18:14:27 +00:00
}
2017-07-11 15:39:50 +00:00
}
2017-10-24 16:25:31 +00:00
let explanation = parseObject ( recurse , objectShape , v ) ,
evaluate = evaluateObject ( objectShape , effect )
2017-07-11 15:39:50 +00:00
2017-07-13 19:55:59 +00:00
return {
evaluate ,
2019-03-20 15:59:55 +00:00
jsx : Product ,
2017-07-13 19:55:59 +00:00
explanation ,
category : 'mecanism' ,
name : 'multiplication' ,
2019-07-11 14:29:05 +00:00
type : 'numeric' ,
2019-07-11 15:07:34 +00:00
unit : inferUnit (
'*' ,
[ explanation . assiette , explanation . taux , explanation . facteur ] . map (
el => el . unit
)
)
2017-06-28 10:08:32 +00:00
}
}
2017-10-24 16:25:31 +00:00
export let mecanismMax = ( recurse , k , v ) => {
2017-07-11 15:39:50 +00:00
let explanation = v . map ( recurse )
2017-06-28 10:08:32 +00:00
2018-01-08 15:07:26 +00:00
let evaluate = evaluateArray ( max , Number . NEGATIVE _INFINITY )
2017-07-13 19:55:59 +00:00
2017-10-24 16:25:31 +00:00
let jsx = ( nodeValue , explanation ) => (
2017-07-13 19:55:59 +00:00
< Node
2017-06-28 10:08:32 +00:00
classes = "mecanism list maximum"
name = "le maximum de"
2017-07-13 19:55:59 +00:00
value = { nodeValue }
2017-06-28 10:08:32 +00:00
child = {
< ul >
2017-10-24 16:25:31 +00:00
{ explanation . map ( ( item , i ) => (
< li key = { i } >
< div className = "description" > { v [ i ] . description } < / d i v >
{ makeJsx ( item ) }
< / l i >
) ) }
2017-06-28 10:08:32 +00:00
< / u l >
2017-06-28 07:31:37 +00:00
}
2017-06-28 10:08:32 +00:00
/ >
2017-10-24 16:25:31 +00:00
)
2017-07-13 19:55:59 +00:00
return {
evaluate ,
jsx ,
explanation ,
type : 'numeric' ,
category : 'mecanism' ,
2019-10-24 12:58:41 +00:00
name : 'le maximum de' ,
unit : explanation [ 0 ] . unit
2017-06-28 10:08:32 +00:00
}
}
2017-10-24 16:25:31 +00:00
export let mecanismMin = ( recurse , k , v ) => {
2017-07-30 21:50:36 +00:00
let explanation = v . map ( recurse )
2018-01-08 15:07:26 +00:00
let evaluate = evaluateArray ( min , Infinity )
2017-07-30 21:50:36 +00:00
2017-10-24 16:25:31 +00:00
let jsx = ( nodeValue , explanation ) => (
2017-07-30 21:50:36 +00:00
< Node
classes = "mecanism list minimum"
name = "le minimum de"
value = { nodeValue }
child = {
< ul >
2017-10-24 16:25:31 +00:00
{ explanation . map ( ( item , i ) => (
< li key = { i } >
< div className = "description" > { v [ i ] . description } < / d i v >
{ makeJsx ( item ) }
< / l i >
) ) }
2017-07-30 21:50:36 +00:00
< / u l >
}
/ >
2017-10-24 16:25:31 +00:00
)
2017-07-30 21:50:36 +00:00
return {
evaluate ,
jsx ,
explanation ,
type : 'numeric' ,
category : 'mecanism' ,
2019-06-19 09:54:47 +00:00
name : 'le minimum de' ,
unit : explanation [ 0 ] . unit
2017-07-30 21:50:36 +00:00
}
}
2017-10-24 16:25:31 +00:00
export let mecanismComplement = ( recurse , k , v ) => {
if ( v . composantes ) {
//mécanisme de composantes. Voir known-mecanisms.md/composantes
return decompose ( recurse , k , v )
2017-06-29 12:26:24 +00:00
}
2017-10-24 16:25:31 +00:00
let objectShape = { cible : false , montant : false }
let effect = ( { cible , montant } ) => {
2017-07-12 09:50:34 +00:00
let nulled = val ( cible ) == null
2018-01-08 15:07:26 +00:00
return nulled ? null : subtract ( val ( montant ) , min ( val ( cible ) , val ( montant ) ) )
2017-07-12 09:50:34 +00:00
}
2017-10-24 16:25:31 +00:00
let explanation = parseObject ( recurse , objectShape , v )
2017-06-29 12:26:24 +00:00
return {
2017-10-24 16:25:31 +00:00
evaluate : evaluateObject ( objectShape , effect ) ,
2017-07-12 09:50:34 +00:00
explanation ,
2017-06-29 12:26:24 +00:00
type : 'numeric' ,
category : 'mecanism' ,
name : 'complément pour atteindre' ,
2018-05-22 17:12:13 +00:00
// eslint-disable-next-line
2017-10-24 16:25:31 +00:00
jsx : ( nodeValue , explanation ) => (
< Node
classes = "mecanism list complement"
name = "complément"
value = { nodeValue }
child = {
< ul className = "properties" >
< li key = "cible" >
2018-05-09 16:41:57 +00:00
< span className = "key" >
< Trans > cible < / T r a n s > : { ' ' }
< / s p a n >
2017-10-24 16:25:31 +00:00
< span className = "value" > { makeJsx ( explanation . cible ) } < / s p a n >
< / l i >
< li key = "mini" >
2018-05-09 16:41:57 +00:00
< span className = "key" >
< Trans > montant à atteindre < / T r a n s > : { ' ' }
< / s p a n >
2017-10-24 16:25:31 +00:00
< span className = "value" > { makeJsx ( explanation . montant ) } < / s p a n >
< / l i >
< / u l >
}
/ >
)
2017-06-29 12:26:24 +00:00
}
}
2018-09-06 14:45:50 +00:00
export let mecanismSynchronisation = ( recurse , k , v ) => {
let evaluate = ( cache , situationGate , parsedRules , node ) => {
let APIExplanation = evaluateNode (
cache ,
situationGate ,
parsedRules ,
node . explanation . API
)
2018-09-06 16:33:12 +00:00
2019-04-08 09:56:56 +00:00
let valuePath = v . chemin . split ( ' . ' )
2018-09-06 14:45:50 +00:00
let nodeValue =
2019-04-08 09:56:56 +00:00
val ( APIExplanation ) == null ? null : path ( valuePath , val ( APIExplanation ) )
// If the API gave a non null value, then some of its props may be null (the API can be composed of multiple API, some failing). Then this prop will be set to the default value defined in the API's rule
let safeNodeValue =
nodeValue == null && val ( APIExplanation ) != null
? path ( valuePath , APIExplanation . explanation . defaultValue )
: nodeValue
2018-09-06 16:33:12 +00:00
let missingVariables =
val ( APIExplanation ) === null ? { [ APIExplanation . dottedName ] : 1 } : { }
2018-09-06 14:45:50 +00:00
let explanation = { ... v , API : APIExplanation }
2019-09-10 14:58:26 +00:00
return { ... node , nodeValue : safeNodeValue , explanation , missingVariables }
2018-09-06 14:45:50 +00:00
}
return {
explanation : { ... v , API : recurse ( v . API ) } ,
evaluate ,
2018-09-07 14:56:36 +00:00
jsx : function Synchronisation ( nodeValue , explanation ) {
return (
< p >
Obtenu à partir de la saisie < SimpleRuleLink rule = { explanation . API } / >
< / p >
)
} ,
2018-09-06 14:45:50 +00:00
category : 'mecanism' ,
name : 'synchronisation'
}
}
2017-10-24 16:25:31 +00:00
export let mecanismError = ( recurse , k , v ) => {
2018-02-15 17:12:04 +00:00
throw new Error ( "Le mécanisme '" + k + "' est inconnu !" + v )
2017-06-28 10:08:32 +00:00
}
2019-05-15 14:31:33 +00:00
export let mecanismOnePossibility = dottedName => ( recurse , k , v ) => ( {
2019-05-14 11:52:23 +00:00
... v ,
'une possibilité' : 'oui' ,
evaluate : ( cache , situationGate , parsedRules , node ) => ( {
... node ,
2019-05-15 14:31:33 +00:00
missingVariables : { [ dottedName ] : 1 }
2019-05-14 11:52:23 +00:00
} )
} )