2017-01-09 17:17:51 +00:00
import R from 'ramda'
2017-02-10 14:12:00 +00:00
import { rules , findRuleByName , parentName } from './rules'
2017-01-20 10:52:39 +00:00
import { recognizeExpression } from './expressions'
2017-01-09 17:17:51 +00:00
2017-01-19 15:27:27 +00:00
// L'objectif de la simulation : quelles règles voulons nous calculer ?
let selectedRules = rules . filter ( rule =>
2017-02-10 14:12:00 +00:00
R . contains ( rule . name ,
2017-02-07 19:10:04 +00:00
[
2017-02-10 14:12:00 +00:00
'CIF CDD' ,
'fin de contrat' ,
2017-02-07 19:10:04 +00:00
'majoration chômage CDD'
]
2017-01-19 15:27:27 +00:00
)
)
2017-01-09 17:17:51 +00:00
2017-02-10 14:12:00 +00:00
let knownVariable = ( situation , variableName ) => R . or (
2017-01-26 12:19:04 +00:00
situation ( variableName ) ,
2017-02-10 14:12:00 +00:00
situation ( parentName ( variableName ) ) // pour 'usage', 'motif' ( le parent de 'usage') = 'usage'
) != null
2017-01-10 18:22:44 +00:00
2017-02-07 19:10:04 +00:00
let transformPercentage = s =>
s . indexOf ( '%' ) > - 1 ?
+ s . replace ( '%' , '' ) / 100 :
+ s
2017-01-26 12:19:04 +00:00
2017-02-10 14:12:00 +00:00
let deriveRule = ( situationGate , rule ) => R . pipe (
2017-01-10 18:22:44 +00:00
R . toPairs ,
2017-02-07 19:10:04 +00:00
R . reduce ( ( { missingVariables , computedValue } , [ key , value ] ) => {
2017-01-17 09:04:34 +00:00
if ( key === 'concerne' ) {
2017-02-10 14:12:00 +00:00
let [ variableName , evaluation ] = recognizeExpression ( rule , value )
2017-01-10 18:22:44 +00:00
// Si cette variable a été renseignée
2017-01-26 12:19:04 +00:00
if ( knownVariable ( situationGate , variableName ) ) {
2017-01-10 18:22:44 +00:00
// Si l'expression n'est pas vraie...
2017-01-26 12:19:04 +00:00
if ( ! evaluation ( situationGate ) ) {
2017-01-10 18:22:44 +00:00
// On court-circuite toute la variable, et on n'a besoin d'aucune information !
2017-02-07 19:10:04 +00:00
return R . reduced ( { missingVariables : [ ] } )
2017-01-10 18:22:44 +00:00
} else {
// Sinon, on continue
2017-02-07 19:10:04 +00:00
return { missingVariables }
2017-01-10 18:22:44 +00:00
}
// sinon on demande la valeur de cette variable
2017-02-07 19:10:04 +00:00
} else return { missingVariables : [ ... missingVariables , variableName ] }
2017-01-10 18:22:44 +00:00
}
if ( key === 'non applicable si' ) {
let conditions = value [ 'l\'une de ces conditions' ]
let [ subVariableNames , reduced ] = R . reduce ( ( [ variableNames ] , expression ) => {
2017-02-10 14:12:00 +00:00
let [ variableName , evaluation ] = recognizeExpression ( rule , expression )
2017-01-26 12:19:04 +00:00
if ( knownVariable ( situationGate , variableName ) ) {
if ( evaluation ( situationGate ) ) {
2017-01-10 18:22:44 +00:00
return R . reduced ( [ [ ] , true ] )
2017-01-09 17:17:51 +00:00
} else {
2017-01-10 18:22:44 +00:00
return [ variableNames ]
2017-01-09 17:17:51 +00:00
}
}
return [ [ ... variableNames , variableName ] ]
2017-01-10 18:22:44 +00:00
} , [ [ ] , null ] ) ( conditions )
2017-02-07 19:10:04 +00:00
if ( reduced ) return R . reduced ( { missingVariables : [ ] } )
else return { missingVariables : [ ... missingVariables , ... subVariableNames ] }
2017-01-10 18:22:44 +00:00
}
2017-01-17 09:04:34 +00:00
if ( key === 'formule' ) {
if ( value [ 'linéaire' ] ) {
2017-01-10 18:22:44 +00:00
let { assiette , taux } = value [ 'linéaire' ]
// A propos de l'assiette
2017-02-10 14:12:00 +00:00
let [ assietteVariableName ] = recognizeExpression ( rule , assiette ) ,
2017-01-26 12:19:04 +00:00
assietteValue = situationGate ( assietteVariableName ) ,
2017-01-10 18:22:44 +00:00
unknownAssiette = assietteValue == undefined
// Arrivés là, cette formule devrait être calculable !
2017-02-07 19:10:04 +00:00
let { missingVariables : tauxMissingVariables = [ ] , computedValue } = typeof taux !== 'string' ?
do {
let numericalLogic = taux [ 'logique numérique' ]
if ( ! numericalLogic ) throw 'On ne sait pas pour l\'instant traiter ce mécanisme de taux'
let treatNumericalLogic = numericalLogic => {
if ( typeof numericalLogic == 'string' ) {
return new Object ( { computedValue : assietteValue * transformPercentage ( numericalLogic ) } )
} else {
return R . pipe (
R . toPairs ( ) ,
R . reduce ( ( { missingVariables } , [ expression , subLogic ] ) => {
2017-02-10 14:12:00 +00:00
let [ variableName , evaluation ] = recognizeExpression ( rule , expression )
2017-02-07 19:10:04 +00:00
if ( knownVariable ( situationGate , variableName ) ) {
if ( evaluation ( situationGate ) ) {
return R . reduced ( treatNumericalLogic ( subLogic ) )
} else {
return { missingVariables }
}
} else return { missingVariables : [ ... missingVariables , variableName ] }
} , { missingVariables : [ ] } )
) ( numericalLogic )
} }
treatNumericalLogic ( numericalLogic )
} : ( { computedValue : assietteValue * transformPercentage ( taux ) } )
let formulaResult = {
missingVariables : [
... missingVariables ,
... ( unknownAssiette ? [ assietteVariableName ] : [ ] ) ,
... tauxMissingVariables
] ,
computedValue
2017-01-10 18:22:44 +00:00
}
2017-01-09 17:17:51 +00:00
2017-02-07 19:10:04 +00:00
return computedValue != null ? R . reduced ( formulaResult ) : formulaResult
2017-01-10 18:22:44 +00:00
}
}
2017-01-09 17:17:51 +00:00
2017-02-07 19:10:04 +00:00
return { missingVariables }
2017-02-10 14:12:00 +00:00
} , { missingVariables : [ ] }
2017-01-10 18:22:44 +00:00
)
2017-02-10 14:12:00 +00:00
)
2017-01-09 17:17:51 +00:00
2017-02-10 14:12:00 +00:00
/ * A n a l y s e t h e s e t o f s e l e c t e d r u l e s , a n d a d d d e r i v e d i n f o r m a t i o n t o t h e m :
- do they need variables that are not present in the user situation ?
- if not , do they have a computed value or are they non applicable ?
* /
2017-01-26 12:19:04 +00:00
export let analyseSituation = situationGate =>
2017-02-10 14:12:00 +00:00
selectedRules . map ( rule =>
// how to express that better in Ramda ?
R . assoc (
'derived' ,
deriveRule ( situationGate , rule ) ( rule )
) ( rule )
)
2017-01-26 12:19:04 +00:00
2017-01-10 14:39:40 +00:00
export let variableType = name => {
2017-01-10 18:22:44 +00:00
if ( name == null ) return null
let found = findRuleByName ( name )
2017-01-10 14:39:40 +00:00
// tellement peu de variables pour l'instant
// que c'est très simpliste
2017-01-10 18:22:44 +00:00
if ( ! found ) return 'boolean'
let { rule , type } = found
if ( typeof rule . formule [ 'somme' ] !== 'undefined' ) return 'numeric'
2017-01-10 14:39:40 +00:00
}
2017-01-19 15:27:27 +00:00
/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Ce qui suit est la première tentative d ' écriture du principe du moteur et de la syntaxe * /
2017-01-09 17:17:51 +00:00
// let types = {
/ *
( expression ) :
| ( variable )
| ( négation )
| ( égalité )
| ( comparaison numérique )
| ( test d ' inclusion court )
* /
// }
// let root = {
// Variable: {
// 'concerne': types['expression'],
// 'ne concerne pas': types['expression']
// // 'applicable si': types['boolean logic'],
// // 'non applicable si': types['boolean logic']
// }
// }
/ *
Variable :
- applicable si : ( boolean logic )
- non applicable si : ( boolean logic )
- concerne : ( expression )
- ne concerne pas : ( expression )
( boolean logic ) :
toutes ces conditions : ( [ expression | boolean logic ] )
l ' une de ces conditions : ( [ expression | boolean logic ] )
conditions exclusives : ( [ expression | boolean logic ] )
"If you write a regular expression, walk away for a cup of coffee, come back, and can't easily understand what you just wrote, then you should look for a clearer way to express what you're doing."
Les expressions sont le seul mécanisme relativement embêtant pour le moteur . Dans un premier temps , il les gerera au moyen d 'expressions régulières, puis il faudra probablement mieux s' équiper avec un "javascript parser generator" :
https : //medium.com/@daffl/beyond-regex-writing-a-parser-in-javascript-8c9ed10576a6
( variable ) : ( string )
( négation ) :
! ( variable )
( égalité ) :
( variable ) = ( variable . type )
( comparaison numérique ) :
| ( variable ) < ( variable . type )
| ( variable ) <= ( variable . type )
| ( variable ) > ( variable . type )
| ( variable ) <= ( variable . type )
( test d ' inclusion court ) :
( variable ) ⊂ [ variable . type ]
in Variable . formule :
- composantes
- linéaire
- barème en taux marginaux
- test d 'inclusion: (test d' inclusion )
( test d ' inclusion ) :
variable : ( variable )
possibilités : [ variable . type ]
# pas nécessaire pour le CDD
in Variable
- variations : [ si ]
( si ) :
si : ( expression )
# corps
* /