2017-01-09 17:17:51 +00:00
import removeDiacritics from './utils/remove-diacritics'
import R from 'ramda'
2017-01-10 14:39:40 +00:00
import rules from './load-rules'
2017-01-10 18:22:44 +00:00
// import initialSituation from './initialSituation'
2017-01-10 14:39:40 +00:00
import { findRuleByName , extractRuleTypeAndName } from './model'
2017-01-09 17:17:51 +00:00
/ *
L 'objectif dans un premier temps est de faire une démonstration d' interface de saisie pour calculer les obligations du CDD . Le CDD est un contrat d ' exception , ce qui le rend assez complexe .
Les Variables du système social comportent des entrées particulières ( des cléfs de l 'objet) que l' on nommera "mécanismes" . Elles diffèrent des entrées simples ( telle la description d ' une variable ) car elles sont susceptibles de comporter des variables , et la description de calculs .
Voici une liste des mécanismes qui sont à traverser pour notamment :
- d 'extraire les variables utilisées et donc que l' utilisateur devra saisir
- d ' attribuer une note à ces variables pour déterminer la prochaine saisie ( ou "question" )
- de court - circuiter les branches rendues inutiles par la situation courante saisie par l ' utilisateur , ce qui influence la note .
Dans un premier temps , l ' idée est de créer un formulaire à questions unitaires optimisées pour que la saisie de données inutiles soit évitée .
2017-01-10 11:17:02 +00:00
- Il faut résoudre le calcul des variables .
2017-01-09 17:17:51 +00:00
- ça introduit l ' assiette 2300 €
- ça nous donne son intervalle en % vu que l ' assiette est constante , et donc un avancement du formulaire
- ça nous donne des résultats ! ! ! ! ! ! : ) )
- Il faut donner des explications à TOUTES les variables . Aucune n ' est triviale !
- Il faut ajouter la notion d ' entité .
- Ce qui permettra de regrouper les questions par thème . Exemple , demander "Quel type de CDD" et ordonner les réponses possibles par influence ( e . g . si c 'est un CDD d' usage )
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
* /
let expressionTests = {
'negatedVariable' : v => / ! ( ( ? : [ a - z0 - 9 ] | \ s | _ ) + ) / g . exec ( v ) ,
// Cette regexp est trop complexe (il faut parser le tableau après le symbole d'inclusion) !
// 'variableIsIncludedIn': v => /((?:[a-z0-9]|\s|_)+)⊂*/g.exec(v),
'variableComparedToNumber' : v => / ( ( ? : [ a - z0 - 9 ] | \ s | _ ) + ) ( [ < | > ] = ? ) \ s + ( [ 0 - 9 ] + ) / g . exec ( v ) ,
2017-01-17 09:04:34 +00:00
'numberComparedToVariable' : v => / ( [ 0 - 9 ] + ) \ s + ( [ < | > ] = ? ) ( ( ? : [ a - z0 - 9 ] | \ s | _ ) + ) / g . exec ( v ) ,
'variableEqualsNumber' : v => / ( ( ? : [ a - z0 - 9 ] | \ s | _ ) + ) = ( ( ? : [ a - z0 - 9 ] | \ s | _ ) + ) / g . exec ( v ) ,
'variable' : v => / ( ( ? : [ a - z0 - 9 ] | \ s | _ ) + ) / g . exec ( v )
2017-01-09 17:17:51 +00:00
}
let recognizeExpression = rawValue => {
let
value = removeDiacritics ( rawValue ) . toLowerCase ( ) ,
match
match = expressionTests [ 'negatedVariable' ] ( value )
if ( match ) {
let [ , variableName ] = match
2017-01-10 18:22:44 +00:00
// return [variableName, `!${variableName}`]
return [ variableName , situation => situation ( variableName ) == 'non' ]
2017-01-09 17:17:51 +00:00
}
match = expressionTests [ 'variableComparedToNumber' ] ( value )
if ( match ) {
let [ , variableName , symbol , number ] = match
2017-01-17 09:04:34 +00:00
return [ variableName , situation => eval ( ` situation(" ${ variableName } ") ${ symbol } ${ number } ` ) ] // eslint-disable-line no-unused-vars
2017-01-09 17:17:51 +00:00
}
match = expressionTests [ 'numberComparedToVariable' ] ( value )
if ( match ) {
let [ , number , symbol , variableName ] = match
2017-01-17 09:04:34 +00:00
return [ variableName , situation => eval ( ` ${ number } ${ symbol } situation(" ${ variableName } ") ` ) ] // eslint-disable-line no-unused-vars
2017-01-09 17:17:51 +00:00
}
match = expressionTests [ 'variableEqualsNumber' ] ( value )
if ( match ) {
let [ , variableName , number ] = match
2017-01-10 18:22:44 +00:00
return [ variableName , situation => situation ( variableName ) == number ]
2017-01-09 17:17:51 +00:00
}
match = expressionTests [ 'variable' ] ( value )
if ( match ) {
let [ variableName ] = match
2017-01-10 18:22:44 +00:00
return [ variableName , situation => situation ( variableName ) == 'oui' ]
2017-01-09 17:17:51 +00:00
}
}
2017-01-10 18:22:44 +00:00
let knownVariable = ( situation , variableName ) => ( typeof situation ( variableName ) !== 'undefined' )
let deriveRule = situation => R . pipe (
R . toPairs ,
// Reduce to [variables needed to compute that variable, computed variable value]
R . reduce ( ( [ variableNames , result ] , [ key , value ] ) => {
2017-01-17 09:04:34 +00:00
if ( key === 'concerne' ) {
2017-01-10 18:22:44 +00:00
let [ variableName , evaluation ] = recognizeExpression ( value )
// Si cette variable a été renseignée
2017-01-17 09:04:34 +00:00
if ( knownVariable ( situation , variableName ) ) {
2017-01-10 18:22:44 +00:00
// Si l'expression n'est pas vraie...
2017-01-17 09:04:34 +00:00
if ( ! evaluation ( situation ) ) {
2017-01-10 18:22:44 +00:00
// On court-circuite toute la variable, et on n'a besoin d'aucune information !
return R . reduced ( [ [ ] ] )
} else {
// Sinon, on continue
return [ variableNames ]
}
// sinon on demande la valeur de cette variable
} else return [ [ ... variableNames , variableName ] ]
}
if ( key === 'non applicable si' ) {
let conditions = value [ 'l\'une de ces conditions' ]
let [ subVariableNames , reduced ] = R . reduce ( ( [ variableNames ] , expression ) => {
let [ variableName , evaluation ] = recognizeExpression ( expression )
2017-01-17 09:04:34 +00:00
if ( knownVariable ( situation , variableName ) ) {
2017-01-10 18:22:44 +00:00
if ( evaluation ( situation ) ) {
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 )
if ( reduced ) return R . reduced ( [ [ ] ] )
else return [ variableNames . concat ( subVariableNames ) ]
}
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
let assietteVariableName = removeDiacritics ( assiette ) ,
assietteValue = situation ( assietteVariableName ) ,
unknownAssiette = assietteValue == undefined
2017-01-17 09:04:34 +00:00
if ( unknownAssiette ) {
2017-01-10 18:22:44 +00:00
return [ [ ... variableNames , assietteVariableName ] ]
} else {
if ( variableNames . length > 0 ) {
return [ variableNames ]
2017-01-09 17:17:51 +00:00
}
2017-01-10 18:22:44 +00:00
}
2017-01-09 17:17:51 +00:00
2017-01-10 18:22:44 +00:00
// Arrivés là, cette formule devrait être calculable !
2017-01-09 17:17:51 +00:00
2017-01-10 18:22:44 +00:00
// A propos du taux
2017-01-17 09:04:34 +00:00
if ( typeof taux !== 'string' && typeof taux !== 'number' ) {
2017-01-10 18:22:44 +00:00
throw 'Oups, pas de taux compliqués s\'il-vous-plaît'
}
let tauxValue = taux . indexOf ( '%' ) > - 1 ?
2017-01-17 09:04:34 +00:00
+ taux . replace ( '%' , '' ) / 100 :
2017-01-10 18:22:44 +00:00
+ taux
2017-01-09 17:17:51 +00:00
2017-01-10 18:22:44 +00:00
return R . reduced ( [ null , assietteValue * tauxValue ] )
}
}
2017-01-09 17:17:51 +00:00
2017-01-10 18:22:44 +00:00
return [ variableNames ]
2017-01-17 09:04:34 +00:00
} , [ [ ] , null ] )
2017-01-10 18:22:44 +00:00
)
2017-01-09 17:17:51 +00:00
2017-01-10 18:22:44 +00:00
let analyseVariable = situation =>
R . pipe (
extractRuleTypeAndName , // -> {type, name, rule}
data => R . assoc (
'derived' ,
deriveRule ( situation ) ( data . rule )
) ( data )
2017-01-09 17:17:51 +00:00
)
2017-01-10 18:22:44 +00:00
// L'objectif de la simulation : quelles règles voulons nous calculer ?
2017-01-17 09:04:34 +00:00
let selectedRules = rules . filter ( rule =>
R . contains (
extractRuleTypeAndName ( rule ) . name ,
[ 'CIF CDD' , 'Indemnité de fin de contrat' ]
)
)
2017-01-10 14:39:40 +00:00
2017-01-10 18:22:44 +00:00
export let analyseSituation = situation =>
2017-01-10 11:17:02 +00:00
R . pipe (
2017-01-10 18:22:44 +00:00
R . map ( analyseVariable ( situation ) )
2017-01-10 14:39:40 +00:00
) ( selectedRules )
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-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
* /