Merge pull request #51 from sgmap/versement-transport-local
Intègre le versement transportpull/60/head
commit
91956f2d4b
|
@ -3,3 +3,6 @@
|
|||
node_modules/
|
||||
dist/
|
||||
.DS_Store
|
||||
yarn.lock
|
||||
package-lock.json
|
||||
yarn-error.log
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -28,6 +28,10 @@
|
|||
"react-router": "^4.1.1",
|
||||
"react-router-dom": "^4.1.1",
|
||||
"react-scroll": "^1.5.4",
|
||||
"react-select": "^1.0.0-rc.10",
|
||||
"react-select-fast-filter-options": "^0.2.3",
|
||||
"react-virtualized": "^9.10.1",
|
||||
"react-virtualized-select": "^3.1.0",
|
||||
"reduce-reducers": "^0.1.2",
|
||||
"redux": "^3.6.0",
|
||||
"redux-form": "6.8.0",
|
||||
|
@ -43,6 +47,7 @@
|
|||
"babel-core": "^6.24.1",
|
||||
"babel-eslint": "^7.2.3",
|
||||
"babel-loader": "^7.0.0",
|
||||
"babel-plugin-syntax-dynamic-import": "^6.18.0",
|
||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
||||
"babel-plugin-transform-do-expressions": "^6.22.0",
|
||||
|
@ -55,6 +60,7 @@
|
|||
"chokidar": "^1.7.0",
|
||||
"core-js": "^2.4.1",
|
||||
"css-loader": "^0.28.1",
|
||||
"csv-loader": "^2.1.1",
|
||||
"daggy": "^1.1.0",
|
||||
"eslint": "^4.4.1",
|
||||
"eslint-plugin-react": "^7.0.1",
|
||||
|
@ -79,7 +85,7 @@
|
|||
"source-map-support": "^0.4.15",
|
||||
"style-loader": "^0.18.2",
|
||||
"url-loader": "^0.5.8",
|
||||
"webpack": "^3.5.4",
|
||||
"webpack": "^3.6.0",
|
||||
"webpack-dev-server": "^2.4.5"
|
||||
},
|
||||
"scripts": {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,29 @@
|
|||
- espace: contrat salarié
|
||||
nom: versement transport
|
||||
|
||||
non applicable si: entreprise . effectif < 11
|
||||
# TODO variations sur la période
|
||||
# variations:
|
||||
# - si: période >= 2016
|
||||
# condition: Entreprise . effectif >= 11
|
||||
# - si: période < 2016
|
||||
# condition: Entreprise . effectif >= 10
|
||||
|
||||
formule:
|
||||
multiplication:
|
||||
assiette: assiette cotisations sociales
|
||||
taux: établissement . taux versement transport
|
||||
|
||||
- espace: établissement
|
||||
nom: taux versement transport
|
||||
données: taux_versement_transport
|
||||
formule:
|
||||
sélection:
|
||||
données: taux versement transport
|
||||
cherche: commune
|
||||
dans: nomLaposte
|
||||
composantes:
|
||||
- nom: aot
|
||||
renvoie: aot
|
||||
- nom: smt
|
||||
renvoie: smt
|
|
@ -1,25 +0,0 @@
|
|||
- contrat salarié: versement transport
|
||||
|
||||
applicable si:
|
||||
# TODO variations sur la période
|
||||
# variations:
|
||||
# - si: période >= 2016
|
||||
# condition: Entreprise . effectif >= 11
|
||||
# - si: période < 2016
|
||||
# condition: Entreprise . effectif >= 10
|
||||
Entreprise . effectif >= 11
|
||||
|
||||
formule:
|
||||
multiplication:
|
||||
assiette: assiette cotisations sociales
|
||||
taux: Établissement . taux versement transport
|
||||
|
||||
- contrat salarié . versement transport: taux
|
||||
saisie:
|
||||
sélection:
|
||||
# On est ici sur l'option d'une recherche par mots clefs dans toutes les colonnes du tableau (ville par nom, par code postal, par code INSEE). On peut imaginer restreindre la recherche à l'une de ces clefs.
|
||||
données: https://raw.githubusercontent.com/openfisca/openfisca-france/master/openfisca_france/assets/versement_transport/taux.csv
|
||||
valeur clef:
|
||||
composantes:
|
||||
- taux # taux AOT
|
||||
- taux additionnel # taux SMT
|
|
@ -150,6 +150,7 @@
|
|||
- FNAL
|
||||
- Contribution au Dialogue Social
|
||||
- formation professionnelle
|
||||
- versement transport
|
||||
- taxe d'apprentissage
|
||||
- cotisation pénibilité
|
||||
- taxe sur les salaires
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
- espace: établissement
|
||||
nom: code postal
|
||||
titre: Code postal de l'établissement
|
||||
question: Quel est le code postal de la commune où est implanté l'établissement ?
|
||||
description: |
|
||||
Lorsqu'une entreprise dispose de plusieurs établissements, certaines cotisations sont
|
||||
calculées à l'échelle de l'établissement et sont fonction de règlementations locales.
|
||||
format: nombre
|
||||
|
||||
- espace: établissement
|
||||
nom: commune
|
||||
titre: Commune de l'établissement
|
||||
question: Quel est la commune où est implanté l'établissement ?
|
||||
description: |
|
||||
Lorsqu'une entreprise dispose de plusieurs établissements, certaines cotisations sont
|
||||
calculées à l'échelle de l'établissement et sont fonction de règlementations locales.
|
||||
# format: objet
|
||||
format: texte
|
||||
suggestions: communes
|
|
@ -13,6 +13,7 @@
|
|||
"transform-do-expressions",
|
||||
"transform-object-rest-spread",
|
||||
"transform-class-properties",
|
||||
"syntax-dynamic-import",
|
||||
["webpack-alias", { "config": "./source/webpack.config.js" }]
|
||||
]
|
||||
}
|
||||
|
|
|
@ -12,18 +12,19 @@ export default class Input extends Component {
|
|||
let {
|
||||
name,
|
||||
input,
|
||||
stepProps: {attributes, submit, valueType, suggestions, setFormValue},
|
||||
stepProps: {attributes, submit, valueType, suggestions},
|
||||
meta: {
|
||||
touched, error, active,
|
||||
},
|
||||
themeColours,
|
||||
|
||||
} = this.props,
|
||||
answerSuffix = valueType.suffix,
|
||||
suffixed = answerSuffix != null,
|
||||
inputError = touched && error,
|
||||
sendButtonDisabled = this.state.suggestedInput || !input.value || inputError
|
||||
|
||||
if (typeof suggestions == 'string')
|
||||
return <Select />
|
||||
return (
|
||||
<span>
|
||||
<span className="answer">
|
||||
|
@ -51,21 +52,28 @@ export default class Input extends Component {
|
|||
<span className="icon">✓</span>
|
||||
</button>
|
||||
</span>
|
||||
{suggestions && <span className="inputSuggestions">suggestions:
|
||||
<ul>
|
||||
{R.toPairs(suggestions).map(([text, value]) =>
|
||||
<li key={value}
|
||||
onClick={e => setFormValue('' + value) && submit() && e.preventDefault()}
|
||||
onMouseOver={() => setFormValue('' + value) && this.setState({suggestedInput: true})}
|
||||
onMouseOut={() => setFormValue('') && this.setState({suggestedInput: false})}>
|
||||
<a href="#" title="cliquer pour valider">{text}</a>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</span>
|
||||
}
|
||||
|
||||
{this.renderSuggestions()}
|
||||
|
||||
{inputError && <span className="step-input-error">{error}</span>}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
renderSuggestions(){
|
||||
let {setFormValue, submit, suggestions} = this.props.stepProps
|
||||
if (!suggestions) return null
|
||||
return (
|
||||
<span className="inputSuggestions">suggestions:
|
||||
<ul>
|
||||
{R.toPairs(suggestions).map(([text, value]) =>
|
||||
<li key={value}
|
||||
onClick={e => setFormValue('' + value) && submit() && e.preventDefault()}
|
||||
onMouseOver={() => setFormValue('' + value) && this.setState({suggestedInput: true})}
|
||||
onMouseOut={() => setFormValue('') && this.setState({suggestedInput: false})}>
|
||||
<a href="#" title="cliquer pour valider">{text}</a>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</span>)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,15 +29,20 @@ let jours = {
|
|||
}
|
||||
|
||||
let nombre = {
|
||||
suffix: '',
|
||||
human: value => value,
|
||||
validator: int
|
||||
}
|
||||
|
||||
let texte = {
|
||||
human: value => value,
|
||||
validator: {test: () => true}
|
||||
}
|
||||
|
||||
export default {
|
||||
pourcentage,
|
||||
euros,
|
||||
mois,
|
||||
jours,
|
||||
nombre
|
||||
nombre,
|
||||
texte
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
import React, { Component } from 'react'
|
||||
import {FormDecorator} from '../FormDecorator'
|
||||
import VirtualizedSelect from 'react-virtualized-select'
|
||||
import createFilterOptions from 'react-select-fast-filter-options'
|
||||
|
||||
import 'react-select/dist/react-select.css'
|
||||
import './Select.css'
|
||||
|
||||
|
||||
@FormDecorator('select')
|
||||
export default class Select extends Component {
|
||||
state = {
|
||||
data: null
|
||||
}
|
||||
componentDidMount(){
|
||||
import(/* webpackChunkName: "communescsv" */ 'Règles/communes.csv')
|
||||
.then(module => this.setState({
|
||||
data: module,
|
||||
}))
|
||||
.catch(error => 'An error occurred while loading the component')
|
||||
}
|
||||
render() {
|
||||
let {
|
||||
input: {
|
||||
onChange,
|
||||
},
|
||||
stepProps: {submit, suggestions}
|
||||
} = this.props,
|
||||
submitOnChange =
|
||||
option => {
|
||||
onChange(option.Nom_commune)
|
||||
submit()
|
||||
}
|
||||
|
||||
if (!this.state.data)
|
||||
return <div>Nous reçevons les données... </div>
|
||||
|
||||
return (
|
||||
<div className="select-answer commune">
|
||||
<VirtualizedSelect
|
||||
options={this.state.data}
|
||||
onChange={submitOnChange}
|
||||
ignoreAccents={false}
|
||||
labelKey="Nom_commune"
|
||||
valueKey="Nom_commune"
|
||||
placeholder="Entrez le nom de commune"
|
||||
noResultsText="Nous n'avons trouvé aucune commune"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ import R from 'ramda'
|
|||
import Explicable from 'Components/conversation/Explicable'
|
||||
import Question from 'Components/conversation/Question'
|
||||
import Input from 'Components/conversation/Input'
|
||||
import Select from 'Components/conversation/select/Select'
|
||||
import formValueTypes from 'Components/conversation/formValueTypes'
|
||||
|
||||
import {analyseSituation} from './traverse'
|
||||
|
@ -141,7 +142,7 @@ export let generateQuestion = flatRules => ([dottedName, objectives]) => {
|
|||
|
||||
// console.log(isVariant(rule)?"variant":"generateQuestion",[dottedName, objectives.length])
|
||||
|
||||
let numericQuestion = rule => ({
|
||||
let inputQuestion = rule => ({
|
||||
component: Input,
|
||||
valueType: formValueTypes[rule.format],
|
||||
attributes: {
|
||||
|
@ -150,6 +151,11 @@ export let generateQuestion = flatRules => ([dottedName, objectives]) => {
|
|||
},
|
||||
suggestions: rule.suggestions,
|
||||
})
|
||||
let selectQuestion = rule => ({
|
||||
component: Select,
|
||||
valueType: formValueTypes[rule.format],
|
||||
suggestions: rule.suggestions,
|
||||
})
|
||||
let binaryQuestion = rule => ({
|
||||
component: Question,
|
||||
choices: [
|
||||
|
@ -168,9 +174,12 @@ export let generateQuestion = flatRules => ([dottedName, objectives]) => {
|
|||
common,
|
||||
isVariant(rule) ?
|
||||
multiChoiceQuestion(rule) :
|
||||
rule.format != null ?
|
||||
numericQuestion(rule) :
|
||||
binaryQuestion(rule),
|
||||
rule.format == null ?
|
||||
binaryQuestion(rule) :
|
||||
typeof rule.suggestions == 'string' ?
|
||||
selectQuestion(rule) :
|
||||
inputQuestion(rule)
|
||||
,
|
||||
guidance
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
# Liste et description des différents mécanismes compris par le moteur.
|
||||
# La description peut être rédigée en markdown :-)
|
||||
|
||||
sélection:
|
||||
type: numeric
|
||||
description: |
|
||||
C'est tout simplement une valeur numérique exprimée en pourcentage.
|
||||
|
||||
une possibilité:
|
||||
type: enum
|
||||
|
||||
|
|
|
@ -3,6 +3,11 @@ import React from 'react'
|
|||
import {anyNull, val} from './traverse-common-functions'
|
||||
import {Node, Leaf} from './traverse-common-jsx'
|
||||
import {makeJsx, evaluateNode, rewriteNode, evaluateArray, evaluateArrayWithFilter, evaluateObject, parseObject, collectNodeMissing} from './evaluation'
|
||||
import {findRuleByName} from './rules'
|
||||
|
||||
import 'react-virtualized/styles.css'
|
||||
import {Table, Column} from 'react-virtualized'
|
||||
import taux_versement_transport from 'Règles/rémunération-travail/cotisations/ok/taux.json'
|
||||
|
||||
let constantNode = constant => ({nodeValue: constant, jsx: nodeValue => <span className="value">{nodeValue}</span>})
|
||||
|
||||
|
@ -153,7 +158,7 @@ export let mecanismOneOf = (recurse, k, v) => {
|
|||
|
||||
let evaluate = (situationGate, parsedRules, node) => {
|
||||
let evaluateOne = child => evaluateNode(situationGate, parsedRules, child),
|
||||
explanation = R.map(evaluateOne, node.explanation),
|
||||
explanation = R.map(evaluateOne, node.explanation),
|
||||
values = R.pluck("nodeValue",explanation),
|
||||
nodeValue = R.any(R.equals(true),values) ? true :
|
||||
(R.any(R.equals(null),values) ? null : false)
|
||||
|
@ -609,6 +614,88 @@ export let mecanismComplement = (recurse,k,v) => {
|
|||
}
|
||||
}
|
||||
|
||||
export let mecanismSelection = (recurse,k,v) => {
|
||||
if (v.composantes) { //mécanisme de composantes. Voir known-mecanisms.md/composantes
|
||||
return decompose(recurse,k,v)
|
||||
}
|
||||
|
||||
let dataSourceName = v['données']
|
||||
let dataSearchField = v['dans']
|
||||
let dataTargetName = v['renvoie']
|
||||
let explanation = recurse(v['cherche'])
|
||||
|
||||
let evaluate = (situationGate, parsedRules, node) => {
|
||||
let collectMissing = node => collectNodeMissing(node.explanation),
|
||||
explanation = evaluateNode(situationGate, parsedRules, node.explanation),
|
||||
dataSource = findRuleByName(parsedRules, dataSourceName),
|
||||
data = dataSource ? dataSource['data'] : null,
|
||||
dataKey = explanation.nodeValue,
|
||||
dataItems = (data && dataKey && dataSearchField) ? R.filter(item => item[dataSearchField] == dataKey, data) : null,
|
||||
dataItemValues = (dataItems && !R.isEmpty(dataItems)) ? R.values(dataItems) : null,
|
||||
// TODO - over-specific! transform the JSON instead
|
||||
dataItemSubValues = dataItemValues && dataItemValues[0][dataTargetName] ? dataItemValues[0][dataTargetName]["taux"] : null,
|
||||
sortedSubValues = dataItemSubValues ? R.sortBy(pair => pair[0], R.toPairs(dataItemSubValues)) : null,
|
||||
// return 0 if we found a match for the lookup but not for the specific field,
|
||||
// so that component sums don't sum to null
|
||||
nodeValue = dataItems ? (sortedSubValues ? Number.parseFloat(R.last(sortedSubValues)[1])/100 : 0) : null
|
||||
return rewriteNode(node,nodeValue,explanation,collectMissing)
|
||||
}
|
||||
|
||||
let indexOf = explanation => explanation.nodeValue ? R.findIndex(x => x['nomLaposte'] == explanation.nodeValue, R.values(taux_versement_transport)) : 0
|
||||
let indexOffset = 8
|
||||
|
||||
let jsx = (nodeValue, explanation) =>
|
||||
<Node
|
||||
classes="mecanism"
|
||||
name="sélection"
|
||||
value={nodeValue}
|
||||
child={
|
||||
<Table
|
||||
width={300}
|
||||
height={300}
|
||||
headerHeight={20}
|
||||
rowHeight={30}
|
||||
rowCount={R.values(taux_versement_transport).length}
|
||||
scrollToIndex={indexOf(explanation)+indexOffset}
|
||||
rowStyle={
|
||||
({ index }) => index == indexOf(explanation) ? { fontWeight: "bold" } : {}
|
||||
}
|
||||
rowGetter={
|
||||
({ index }) => {
|
||||
// transformation de données un peu crade du fichier taux.json qui gagnerait à être un CSV
|
||||
let line = R.values(taux_versement_transport)[index],
|
||||
getLastTaux = dataTargetName => {
|
||||
let lastTaux = R.values(R.path([dataTargetName, 'taux'], line))
|
||||
return (lastTaux && lastTaux.length && lastTaux[0]) || 0
|
||||
}
|
||||
return {
|
||||
nom: line['nomLaposte'],
|
||||
taux: getLastTaux(dataTargetName)
|
||||
}
|
||||
}
|
||||
}
|
||||
>
|
||||
<Column
|
||||
label='Nom de commune'
|
||||
dataKey='nom'
|
||||
width={200}
|
||||
/>
|
||||
<Column
|
||||
width={100}
|
||||
label={'Taux ' + dataTargetName}
|
||||
dataKey="taux"
|
||||
/>
|
||||
</Table>
|
||||
}
|
||||
/>
|
||||
|
||||
return {
|
||||
evaluate,
|
||||
explanation,
|
||||
jsx
|
||||
}
|
||||
}
|
||||
|
||||
export let mecanismError = (recurse,k,v) => {
|
||||
throw "Le mécanisme '"+k+"' est inconnu !"+v
|
||||
}
|
||||
|
|
|
@ -5,16 +5,20 @@ import R from 'ramda'
|
|||
import possibleVariableTypes from './possibleVariableTypes.yaml'
|
||||
import marked from './marked'
|
||||
|
||||
// TODO - should be in UI, not engine
|
||||
import taux_versement_transport from '../../règles/rémunération-travail/cotisations/ok/taux.json'
|
||||
|
||||
// console.log('rawRules', rawRules.map(({espace, nom}) => espace + nom))
|
||||
/***********************************
|
||||
Méthodes agissant sur une règle */
|
||||
|
||||
// Enrichissement de la règle avec des informations évidentes pour un lecteur humain
|
||||
export let enrichRule = rule => {
|
||||
export let enrichRule = (rule, sharedData = {}) => {
|
||||
let
|
||||
type = possibleVariableTypes.find(t => R.has(t, rule)),
|
||||
name = rule['nom'],
|
||||
ns = rule['espace'],
|
||||
data = rule['données'] ? sharedData[rule['données']] : null,
|
||||
dottedName = ns ? [
|
||||
ns,
|
||||
name
|
||||
|
@ -22,7 +26,7 @@ export let enrichRule = rule => {
|
|||
subquestionMarkdown = rule['sous-question'],
|
||||
subquestion = subquestionMarkdown && marked(subquestionMarkdown)
|
||||
|
||||
return {...rule, type, name, ns, dottedName, subquestion}
|
||||
return {...rule, type, name, ns, data, dottedName, subquestion}
|
||||
}
|
||||
|
||||
export let hasKnownRuleType = rule => rule && enrichRule(rule).type
|
||||
|
@ -64,7 +68,7 @@ export let disambiguateRuleReference = (allRules, {ns, name}, partialName) => {
|
|||
}
|
||||
|
||||
// On enrichit la base de règles avec des propriétés dérivées de celles du YAML
|
||||
export let rules = rawRules.map(enrichRule)
|
||||
export let rules = rawRules.map(rule => enrichRule(rule, {taux_versement_transport}))
|
||||
|
||||
|
||||
/****************************************
|
||||
|
|
|
@ -8,7 +8,8 @@ import Grammar from './grammar.ne'
|
|||
import {Node, Leaf} from './traverse-common-jsx'
|
||||
import {
|
||||
mecanismOneOf,mecanismAllOf,mecanismNumericalSwitch,mecanismSum,mecanismProduct,
|
||||
mecanismScale,mecanismMax,mecanismMin, mecanismError, mecanismComplement
|
||||
mecanismScale,mecanismMax,mecanismMin, mecanismError, mecanismComplement,
|
||||
mecanismSelection
|
||||
} from "./mecanisms"
|
||||
import {evaluateNode, rewriteNode, collectNodeMissing, makeJsx} from './evaluation'
|
||||
|
||||
|
@ -291,7 +292,7 @@ let treat = (rules, rule) => rawNode => {
|
|||
let mecanisms = R.intersection(R.keys(rawNode), R.keys(knownMecanisms))
|
||||
|
||||
if (mecanisms.length != 1) {
|
||||
console.log('Erreur : On ne devrait reconnaître que un et un seul mécanisme dans cet objet', rawNode)
|
||||
console.log('Erreur : On ne devrait reconnaître que un et un seul mécanisme dans cet objet', mecanisms, rawNode)
|
||||
throw 'OUPS !'
|
||||
}
|
||||
|
||||
|
@ -308,6 +309,7 @@ let treat = (rules, rule) => rawNode => {
|
|||
'le maximum de': mecanismMax,
|
||||
'le minimum de': mecanismMin,
|
||||
'complément': mecanismComplement,
|
||||
'sélection': mecanismSelection,
|
||||
'une possibilité': R.always({'une possibilité':'oui', collectMissing: node => [rule.dottedName]})
|
||||
},
|
||||
action = R.propOr(mecanismError, k, dispatch)
|
||||
|
|
|
@ -62,6 +62,15 @@ module.exports = {
|
|||
exclude: /node_modules/,
|
||||
loader: 'babel-loader'
|
||||
},
|
||||
{
|
||||
test: /\.csv$/,
|
||||
loader: 'csv-loader',
|
||||
options: {
|
||||
dynamicTyping: true,
|
||||
header: true,
|
||||
skipEmptyLines: true
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(jpe?g|png|gif|svg)$/i,
|
||||
loader: 'url-loader?limit=10000&name=images/[name].[ext]!img-loader?progressive=true'
|
||||
|
|
|
@ -27,6 +27,15 @@ module.exports = {
|
|||
exclude: /node_modules/,
|
||||
loader: 'babel-loader'
|
||||
},
|
||||
{
|
||||
test: /\.csv$/,
|
||||
loader: 'csv-loader',
|
||||
options: {
|
||||
dynamicTyping: true,
|
||||
header: true,
|
||||
skipEmptyLines: true
|
||||
}
|
||||
},
|
||||
{ //slow : ~ 3 seconds
|
||||
test: /\.(jpe?g|png|gif|svg)$/i,
|
||||
loader: 'ignore-loader'
|
||||
|
|
|
@ -265,16 +265,16 @@ describe('buildNextSteps', function() {
|
|||
});
|
||||
|
||||
it('should generate questions from the real rules, experimental version', function() {
|
||||
let stateSelector = (name) => ({"contrat salarié . type de contrat":"CDI"})[name]
|
||||
let stateSelector = (name) => ({"contrat salarié . type de contrat":"CDI","entreprise . effectif":"50"})[name]
|
||||
|
||||
let rules = realRules.map(enrichRule),
|
||||
situation = analyseTopDown(rules,"Salaire")(stateSelector),
|
||||
objectives = getObjectives(stateSelector, situation.root, situation.parsedRules),
|
||||
missing = collectMissingVariables()(stateSelector,situation),
|
||||
result = buildNextSteps(stateSelector, rules, situation)
|
||||
|
||||
expect(R.path(["question","props","label"])(result[0])).to.equal("Quel est le salaire brut ?")
|
||||
expect(R.path(["question","props","label"])(result[1])).to.equal("Le salarié a-t-il le statut cadre ?")
|
||||
expect(R.path(["question","props","label"])(result[2])).to.equal("Quel est l'effectif de l'entreprise ?")
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -12,6 +12,12 @@ describe('enrichRule', function() {
|
|||
expect(enrichRule(rule)).to.have.property('type','cotisation')
|
||||
});
|
||||
|
||||
it('should load external data into the rule', function() {
|
||||
let data = {taux_versement_transport: {one: "two"}}
|
||||
let rule = {cotisation:{}, données: 'taux_versement_transport'}
|
||||
expect(enrichRule(rule, data)).to.have.deep.property('data',{one: "two"})
|
||||
});
|
||||
|
||||
it('should extract the dotted name of the rule', function() {
|
||||
let rule = {espace:"contrat salarié", nom: "CDD"}
|
||||
expect(enrichRule(rule)).to.have.property('name','CDD')
|
||||
|
@ -22,4 +28,5 @@ describe('enrichRule', function() {
|
|||
let rule = {"sous-question":"**wut**"}
|
||||
expect(enrichRule(rule)).to.have.property('subquestion','<p><strong>wut</strong></p>\n')
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -240,4 +240,40 @@ describe('analyseSituation with mecanisms', function() {
|
|||
expect(analyseSituation(rules,"startHere")(stateSelector)).to.have.property('nodeValue',100+1200+80)
|
||||
});
|
||||
|
||||
it('should handle selection', function() {
|
||||
let stateSelector = (name) => ({"top . code postal":"2"})[name]
|
||||
let data = {taux_versement_transport: {xyz: {codePostal:1, aot: {taux: {"2019":"1.0"}}}, abc: {codePostal:2, smt: {taux: {"2019":"2.0"}}}}}
|
||||
let rawRules = [
|
||||
{ espace: "top",
|
||||
nom: "startHere",
|
||||
formule: {"sélection": {
|
||||
données: "startHere",
|
||||
cherche: "code postal",
|
||||
dans: "codePostal",
|
||||
renvoie: "smt"
|
||||
}},
|
||||
données: 'taux_versement_transport'},
|
||||
{espace: "top", nom: "code postal", format: "nombre"}],
|
||||
rules = rawRules.map(rule => enrichRule(rule,data))
|
||||
expect(analyseSituation(rules,"startHere")(stateSelector)).to.have.property('nodeValue',0.02)
|
||||
});
|
||||
|
||||
it('should handle failed selections', function() {
|
||||
let stateSelector = (name) => ({"top . code postal":"3"})[name]
|
||||
let data = {taux_versement_transport: {xyz: {codePostal:1, aot: {taux: {"2019":"1.0"}}}, abc: {codePostal:2, smt: {taux: {"2019":"2.0"}}}}}
|
||||
let rawRules = [
|
||||
{ espace: "top",
|
||||
nom: "startHere",
|
||||
formule: {"sélection": {
|
||||
données: "startHere",
|
||||
cherche: "code postal",
|
||||
dans: "codePostal",
|
||||
renvoie: "smt"
|
||||
}},
|
||||
données: 'taux_versement_transport'},
|
||||
{espace: "top", nom: "code postal", format: "nombre"}],
|
||||
rules = rawRules.map(rule => enrichRule(rule,data))
|
||||
expect(analyseSituation(rules,"startHere")(stateSelector)).to.have.property('nodeValue', 0)
|
||||
});
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue