[CDD][moteur] ajout de la maj chomage -> nouveau mécanisme

pull/6/head
Mael Thomas 2017-02-07 20:10:04 +01:00
parent 8bcce2c294
commit 29e1c40ea0
10 changed files with 91 additions and 58 deletions

View File

@ -8,20 +8,20 @@
- Variable: durée
attache: Salariat . CDD
type: période
contrainte: période
description: Durée du contrat de travail
- Variable: motif de recours
alias: motif # alias utilisé dans l'article L. 1242-1
attache: Salariat . CDD
description: |
Le CDD est un contrat d'exception: son recours doit être autorisé par l'une des motifs suivants
Le CDD est un contrat d'exception: son recours doit être autorisé par l'un des motifs suivants
choix exclusifs:
- saisonnier
- jeune vacances
- sénior
- usage
- accroissement temporaire d'activité
- accroissement temporaire activité
# remplacement salarié ?
# mission ?
# ambiguité : l'alternance / l'apprentissage / la fpro sont-ils des justification de CDD ?
@ -49,7 +49,7 @@
attache: Salariat . CDD . motif
titre: Contrat saisonnier
- Variable: accroissement temporaire d'activité
- Variable: accroissement temporaire activité
attache: Salariat . CDD . motif
titre: Accroissement temporaire d'activité
@ -66,7 +66,9 @@
- Variable: usage # Similaire pour intérim, mais domaines différents
attache: Salariat . CDD . motif
titre: Contrat d'usage
référence: https://www.service-public.fr/particuliers/vosdroits/F32476
# alias: extra
références:
service-public.fr: https://www.service-public.fr/professionnels-entreprises/vosdroits/F33693
# concerne: emploi temporaire par nature
formule:
choix exclusifs:

View File

@ -1,4 +1,4 @@
- Indemnité: Fin de contrat
- Indemnité: fin de contrat
attache: CDD
attributs:
type: indemnité

View File

@ -5,18 +5,20 @@
type: majoration
description: Majoration des contributions patronales dassurance chômage pour les contrats à durée déterminée courts (CDD)
concerne: Salariat . CDD . durée <= 3
non applicable si:
l'une de ces conditions:
- Salariat . CDD . durée > 3
- Salariat . CDD . événements . CDD poursuivi en CDI
formule:
linéaire:
assiette: assiette cotisations sociales
assiette: Salariat . salaire de base
taux:
logique numérique:
- Salariat . CDD . événements . CDD poursuivi en CDI: 0%
- Salariat . CDD . motif . accroissement temporaire d'activité:
- Salariat . CDD . durée ≤ 1: 3% # TODO 1 mois, pas 1 rien, évidemment
- Salariat . CDD . durée ≤ 3: 1.5%
- Salariat . CDD . motif . usage:
- Salariat . CDD . durée ≤ 3: 0.5%
Salariat . CDD . motif . accroissement temporaire activité:
Salariat . CDD . durée <= 1: 3% # TODO 1 mois, pas 1 rien, évidemment
Salariat . CDD . durée <= 3: 1.5%
Salariat . CDD . motif . usage:
Salariat . CDD . durée <= 3: 0.5%

View File

@ -32,7 +32,6 @@
}
#sim #help {
visibility: hidden;
border: 1px solid #ccc;
border-radius: 2px;
font-style: italic;

View File

@ -14,6 +14,7 @@ class Aide extends Component {
if (!steps.length) return null
let [{dependencyOfVariables, helpText}] = steps
return <section id="help">
{/*
{helpText}
<div className="dependency-of">
Cette question est nécessaire pour calculer :
@ -23,6 +24,7 @@ class Aide extends Component {
)}
</ul>
</div>
*/}
</section>
}
}

View File

@ -3,18 +3,19 @@ import React, { Component } from 'react'
export default class Results extends Component {
render() {
let {analysedSituation} = this.props
console.log('analysedSituation', analysedSituation)
return (
<section id="results">
<h2>Vos obligations</h2>
<ul>
{analysedSituation.map(({name, type, derived: [dependencies, value]}) =>
{analysedSituation.map(({name, type, derived: {missingVariables, computedValue}}) =>
<li key={name}>
<h3>{type} {name}</h3>
<p className="value">
{dependencies && dependencies.length ?
{missingVariables && missingVariables.length ?
'Répondez aux questions !'
: value != null ?
value + '€'
: computedValue != null ?
computedValue + '€'
: 'Non applicable'
}
</p>

View File

@ -6,15 +6,17 @@ import {parentName, nameLeaf} from './rules'
// composants des regexps
let
vn = '[A-Za-z\\u00C0-\\u017F\\s]+', //variableName
sep = '\\s\\.\\s'
vp = '[A-Za-z\\u00C0-\\u017F\\s]+', // variable part
sep = '\\s\\.\\s',
vn = `(${vp}(?:${sep}${vp})*)`
let expressionTests = {
// 'negatedVariable': v => /!((?:[a-z0-9]|\s|_)+)/g.exec(v),
// 'variableIsIncludedIn': v => /((?:[a-z0-9]|\s|_)+)⊂*/g.exec(v),
'variableComparedToNumber': v => /([\w\s]+(?:\s\.\s[\w\s]+)*)\s([<>]=?)\s([0-9]+)/g.exec(v),
// 'variableComparedToNumber': v => /([\w\s]+(?:\s\.\s[\w\s]+)*)\s([<>]=?)\s([0-9]+)/g.exec(v),
'variableComparedToNumber': v => new RegExp(`^${vn}\\s([<>]=?)\\s([0-9]+)$`, 'g').exec(v),
'variableEqualsString': v => /([\w\s]+(?:\s\.\s[\w\s]+)*)\s=\s([\w\s]+)/g.exec(v),
'variable': v => new RegExp(`^(${vn}(?:${sep}${vn})*)$`, 'g').exec(v)
'variable': v => new RegExp(`^${vn}$`, 'g').exec(v)
}
export let recognizeExpression = value => {
@ -29,6 +31,7 @@ export let recognizeExpression = value => {
match = expressionTests['variableComparedToNumber'](value)
if (match) {
let [, variableName, symbol, number] = match
return [variableName, situation => eval(`situation("${variableName}") ${symbol} ${number}`)] // eslint-disable-line no-unused-vars
}
@ -48,9 +51,9 @@ export let recognizeExpression = value => {
// let yo = parentName(variableName),
// ya = nameLeaf(variableName),
// yi = situation(parentName(variableName))
// debugger;
return removeDiacritics(situation(variableName)) == 'oui' ||
removeDiacritics(situation(parentName(variableName))) == nameLeaf(variableName)
// debugger
return situation(variableName) == 'oui' ||
situation(parentName(variableName)) == nameLeaf(variableName)
}]
}
}

View File

@ -60,7 +60,7 @@ export let searchRules = searchInput =>
export let findRuleByDottedName = dottedName => do {
let found = entityRules.find(rule => rule.dottedName == dottedName)
found || console.log('dottedName = ', dottedName, ' a déserté')
found
}
export let findGroup = R.pipe(

View File

@ -8,8 +8,10 @@ import {recognizeExpression} from './expressions'
let selectedRules = rules.filter(rule =>
R.contains(
enrichRule(rule).name,
['CIF CDD', 'Fin de contrat']
// ['CIF CDD']
[
'CIF CDD', 'fin de contrat',
'majoration chômage CDD'
]
)
)
@ -18,11 +20,15 @@ let knownVariable = (situation, variableName) => typeof R.or(
situation(parentName(variableName))
) !== 'undefined'
let transformPercentage = s =>
s.indexOf('%') > -1 ?
+s.replace('%', '') / 100 :
+s
let deriveRule = situationGate => R.pipe(
R.toPairs,
// Reduce to [variables needed to compute that variable, computed variable value]
R.reduce(([variableNames, result], [key, value]) => {
R.reduce(({missingVariables, computedValue}, [key, value]) => {
if (key === 'concerne') {
let [variableName, evaluation] = recognizeExpression(value)
// Si cette variable a été renseignée
@ -30,21 +36,19 @@ let deriveRule = situationGate => R.pipe(
// Si l'expression n'est pas vraie...
if (!evaluation(situationGate)) {
// On court-circuite toute la variable, et on n'a besoin d'aucune information !
return R.reduced([[]])
return R.reduced({missingVariables: []})
} else {
// Sinon, on continue
return [variableNames]
return {missingVariables}
}
// sinon on demande la valeur de cette variable
} else return [[...variableNames, variableName]]
} else return { missingVariables: [...missingVariables, 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)
if (knownVariable(situationGate, variableName)) {
if (evaluation(situationGate)) {
return R.reduced([[], true])
@ -54,8 +58,9 @@ let deriveRule = situationGate => R.pipe(
}
return [[...variableNames, variableName]]
}, [[], null])(conditions)
if (reduced) return R.reduced([[]])
else return [variableNames.concat(subVariableNames)]
if (reduced) return R.reduced({missingVariables: []})
else return {missingVariables: [...missingVariables, ...subVariableNames]}
}
if (key === 'formule') {
@ -67,30 +72,49 @@ let deriveRule = situationGate => R.pipe(
assietteValue = situationGate(assietteVariableName),
unknownAssiette = assietteValue == undefined
if (unknownAssiette) {
return [[...variableNames, assietteVariableName]]
} else {
if (variableNames.length > 0) {
return [variableNames]
}
}
// Arrivés là, cette formule devrait être calculable !
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'
// A propos du taux
if (typeof taux !== 'string' && typeof taux !== 'number') {
throw 'Oups, pas de taux compliqués s\'il-vous-plaît'
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]) => {
let [variableName, evaluation] = recognizeExpression(expression)
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
}
let tauxValue = taux.indexOf('%') > -1 ?
+taux.replace('%', '') / 100 :
+taux
return R.reduced([null, assietteValue * tauxValue])
return computedValue != null ? R.reduced(formulaResult) : formulaResult
}
}
return [variableNames]
}, [[], null])
return {missingVariables}
}, {missingVariables: []})
)
let analyseRule = situationGate =>

View File

@ -52,7 +52,6 @@ export default reduceReducers(
(state, action) => {
if (action.type == STEP_ACTION || action.type == START_CONVERSATION) {
let {newState, name} = action
console.log('action', action)
// une étape vient d'être validée : on va changer son état
let newSteps = R.pipe(
R.map(step => step.name == name ? {...step, state: newState} : step),
@ -68,7 +67,7 @@ export default reduceReducers(
),
missingVariables = R.pipe(
R.map( ({name, derived: [missingVariables]}) =>
R.map( ({name, derived: {missingVariables}}) =>
(missingVariables || []).map(mv => [mv, name])
),
R.unnest,
@ -91,10 +90,11 @@ export default reduceReducers(
[R.isNil, () => variables.map(dottedName => {
let rule = findRuleByDottedName(dottedName)
return Object.assign(constructStepMeta(rule),
rule.contrainte == 'nombre positif' ?
rule.contrainte == 'nombre positif' ||
rule.contrainte == 'période' ?
{
component: Input,
defaultValue: 0,
defaultValue: 1,
valueType: euro,
attributes: {
inputMode: 'numeric',