From 74310bd06d1b40b7c38814b85d676daaec74e77a Mon Sep 17 00:00:00 2001 From: Mael Date: Thu, 11 Jul 2019 13:53:02 +0200 Subject: [PATCH 01/32] :art: Changement de style des valeurs dans la /doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit L'idée est de les extraire visuellement du reste, et de ne plus utiliser les parenthèses qui ne sont pas faites pour convoyer ce sens --- source/engine/mecanismViews/common.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/source/engine/mecanismViews/common.js b/source/engine/mecanismViews/common.js index b8b5a517c..fb0ebbded 100644 --- a/source/engine/mecanismViews/common.js +++ b/source/engine/mecanismViews/common.js @@ -23,7 +23,18 @@ export let NodeValuePointer = ({ data, unit }) => ( + })} + css={` + background: white; + border-bottom: 0 !important; + padding: 0 0.2rem; + text-decoration: none !important; + margin: 0 0.3rem; + font-size: 80%; + box-shadow: 2px 2px 4px 1px #d9d9d9, 0 0 0 1px #d9d9d9; + line-height: 1.6em; + border-radius: 0.2rem; + `}> ) @@ -114,11 +125,9 @@ export const Leaf = compose( }> {rule.title || capitalise0(name)} {filter} - {!isNil(value) && ( - - )} + {!isNil(value) && } )} From d2a0904c994709917a683ca71cf0588ddccd68a8 Mon Sep 17 00:00:00 2001 From: Mael Date: Thu, 11 Jul 2019 13:56:24 +0200 Subject: [PATCH 02/32] =?UTF-8?q?:art:=20D=C3=A9placement=20et=20simplific?= =?UTF-8?q?ation=20des=20r=C3=A9sultats=20des=20m=C3=A9canismes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/components/rule/Algorithm.css | 7 +------ source/engine/mecanismViews/common.js | 10 ++++++++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/source/components/rule/Algorithm.css b/source/components/rule/Algorithm.css index 2933d4a45..de8d70715 100644 --- a/source/components/rule/Algorithm.css +++ b/source/components/rule/Algorithm.css @@ -166,13 +166,8 @@ .mecanism-result { position: absolute; display: none; - bottom: 0; + top: -4px; right: 0; - border-top: 1px solid; - border-left: 1px solid; - border-top-left-radius: 0.3rem; - border-color: inherit; - padding: 0.1rem 0.6rem; } #rule-rules.showValues .mecanism-result { display: initial; diff --git a/source/engine/mecanismViews/common.js b/source/engine/mecanismViews/common.js index fb0ebbded..d951424b3 100644 --- a/source/engine/mecanismViews/common.js +++ b/source/engine/mecanismViews/common.js @@ -29,7 +29,6 @@ export let NodeValuePointer = ({ data, unit }) => ( border-bottom: 0 !important; padding: 0 0.2rem; text-decoration: none !important; - margin: 0 0.3rem; font-size: 80%; box-shadow: 2px 2px 4px 1px #d9d9d9, 0 0 0 1px #d9d9d9; line-height: 1.6em; @@ -127,7 +126,14 @@ export const Leaf = compose( {rule.title || capitalise0(name)} {filter} - {!isNil(value) && } + {!isNil(value) && ( + + + + )} )} From 956a8662feeb7d6619bbb5c7eacc4e8f7b3bcb48 Mon Sep 17 00:00:00 2001 From: Mael Date: Thu, 11 Jul 2019 14:07:29 +0200 Subject: [PATCH 03/32] :fire: Un seul numberFormatter --- source/components/Value.js | 5 ++++- source/engine/mecanismViews/Barème.js | 26 +++++++++++++++----------- source/engine/mecanismViews/common.js | 6 ------ 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/source/components/Value.js b/source/components/Value.js index 67d02aa38..8831c6258 100644 --- a/source/components/Value.js +++ b/source/components/Value.js @@ -8,7 +8,10 @@ const NumberFormat = memoizeWith( Intl.NumberFormat ) -let numberFormatter = (style, numFractionDigits = 2) => (value, language) => +export let numberFormatter = (style, numFractionDigits = 2) => ( + value, + language +) => NumberFormat(language, { style, currency: 'EUR', diff --git a/source/engine/mecanismViews/Barème.js b/source/engine/mecanismViews/Barème.js index dd781f2bc..dcb9a90cf 100644 --- a/source/engine/mecanismViews/Barème.js +++ b/source/engine/mecanismViews/Barème.js @@ -7,7 +7,8 @@ import React from 'react' import { Trans } from 'react-i18next' import { makeJsx } from '../evaluation' import './Barème.css' -import { formatNumber, Node, NodeValuePointer } from './common' +import { Node, NodeValuePointer } from './common' +import { numberFormatter } from 'Components/Value' export let BarèmeAttributes = ({ explanation, lazyEval = identity }) => ( <> @@ -96,12 +97,13 @@ let Component = withLanguage(function Barème({ Taux final :{' '} - {formatNumber( - (nodeValue / - lazyEval(explanation['assiette']).nodeValue) * - 100, - language - )}{' '} + % )} @@ -113,6 +115,8 @@ let Component = withLanguage(function Barème({ ) }) +let number = numberFormatter(undefined, 0) + let Tranche = ({ tranche: { 'en-dessous de': maxOnly, @@ -132,16 +136,16 @@ let Tranche = ({ {maxOnly ? ( <> - En-dessous de {formatNumber(maxOnly, language)} + En-dessous de {number(maxOnly, language)} ) : minOnly ? ( <> - Au-dessus de {formatNumber(minOnly, language)} + Au-dessus de {number(minOnly, language)} ) : ( <> - De {formatNumber(min, language)} à{' '} - {formatNumber(max, language)} + De {number(min, language)} à{' '} + {number(max, language)} )} diff --git a/source/engine/mecanismViews/common.js b/source/engine/mecanismViews/common.js index d951424b3..11853fbd7 100644 --- a/source/engine/mecanismViews/common.js +++ b/source/engine/mecanismViews/common.js @@ -13,12 +13,6 @@ import mecanismColours from './colours' import classnames from 'classnames' import Value from 'Components/Value' -//TODO remove this one, it should reside in 'Value.js' -export let formatNumber = (data, language) => - !isNaN(data) - ? Intl.NumberFormat(language, { maximumFractionDigits: 4 }).format(data) - : data - export let NodeValuePointer = ({ data, unit }) => ( Date: Thu, 11 Jul 2019 16:29:05 +0200 Subject: [PATCH 04/32] =?UTF-8?q?Impl=C3=A9mentation=20plus=20g=C3=A9n?= =?UTF-8?q?=C3=A9rique=20des=20unit=C3=A9s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/components/rule/Rule.js | 1 + source/engine/mecanisms.js | 11 ++++++++-- source/engine/parse.js | 6 +---- source/engine/units.js | 40 ++++++++++++++++++++++------------ source/règles/base.yaml | 1 - test/units.test.js | 6 ++--- 6 files changed, 40 insertions(+), 25 deletions(-) diff --git a/source/components/rule/Rule.js b/source/components/rule/Rule.js index 573c6af19..f8f5d5b28 100644 --- a/source/components/rule/Rule.js +++ b/source/components/rule/Rule.js @@ -63,6 +63,7 @@ export default compose( namespaceRules = findRuleByNamespace(flatRules, dottedName) let displayedRule = analysedExample || analysedRule + return ( <> {this.state.viewSource ? ( diff --git a/source/engine/mecanisms.js b/source/engine/mecanisms.js index b514a3537..05f99932c 100644 --- a/source/engine/mecanisms.js +++ b/source/engine/mecanisms.js @@ -58,6 +58,7 @@ import Variations from './mecanismViews/Variations' import { disambiguateRuleReference, findRuleByDottedName } from './rules' import { anyNull, val } from './traverse-common-functions' import uniroot from './uniroot' +import { inferUnit } from 'Engine/units' /* @devariate = true => This function will produce variations of a same mecanism (e.g. product) that share some common properties */ export let mecanismVariations = (recurse, k, v, devariate) => { @@ -502,7 +503,8 @@ export let mecanismSum = (recurse, k, v) => { explanation, category: 'mecanism', name: 'somme', - type: 'numeric' + type: 'numeric', + unit: inferUnit('+', explanation.map(r => r.unit)) } } @@ -608,7 +610,12 @@ export let mecanismProduct = (recurse, k, v) => { explanation, category: 'mecanism', name: 'multiplication', - type: 'numeric' + type: 'numeric', + unit: inferUnit('*', [ + explanation.assiette, + explanation.taux, + explanation.facteur + ]) } } diff --git a/source/engine/parse.js b/source/engine/parse.js index 92ed57c24..3ac304185 100644 --- a/source/engine/parse.js +++ b/source/engine/parse.js @@ -202,11 +202,7 @@ let mecanismOperation = (k, operatorFunction, symbol) => (recurse, k, v) => { let explanation = v.explanation.map(recurse) - let unit = inferUnit( - k, - explanation[0].unit || undefined, - explanation[1].unit || undefined - ) + let unit = inferUnit(k, [explanation[0].unit, explanation[1].unit]) let jsx = (nodeValue, explanation) => ( { let [a, b = ''] = string.split('/'), @@ -9,7 +9,7 @@ export let parseUnit = string => { return result } -export let serialiseUnit = ({ numerators, denominators }) => { +export let serialiseUnit = ({ numerators = [], denominators = [] }) => { let n = !isEmpty(numerators) let d = !isEmpty(denominators) return !n && !d @@ -22,19 +22,31 @@ export let serialiseUnit = ({ numerators, denominators }) => { } let noUnit = { numerators: [], denominators: [] } -export let inferUnit = (operator, unit1 = noUnit, unit2 = noUnit) => - operator === '*' - ? simplify({ - numerators: [...unit1.numerators, ...unit2.numerators], - denominators: [...unit1.denominators, ...unit2.denominators] - }) - : operator === '/' - ? inferUnit('*', unit1, { - numerators: unit2.denominators, - denominators: unit2.numerators - }) - : null +export let inferUnit = (operator, rawUnits) => { + let units = rawUnits.map(u => u || noUnit) + if (operator === '*') + return simplify({ + numerators: unnest(units.map(u => u.numerators)), + denominators: unnest(units.map(u => u.denominators)) + }) + if (operator === '/') { + if (units.length !== 2) + throw new Error('Infer units of a division with units.length !== 2)') + return inferUnit('*', [ + units[0], + { + numerators: units[1].denominators, + denominators: units[1].numerators + } + ]) + } + if (operator === '-' || operator === '+') { + return rawUnits.find(u => u) + } + + return null +} export let removeOnce = element => list => { let index = list.indexOf(element) if (index > -1) return remove(index, 1)(list) diff --git a/source/règles/base.yaml b/source/règles/base.yaml index 830fa1282..e285e1969 100644 --- a/source/règles/base.yaml +++ b/source/règles/base.yaml @@ -990,7 +990,6 @@ - espace: contrat salarié nom: indemnités salarié période: flexible - unité: € formule: somme: - CDD . indemnités salarié CDD diff --git a/test/units.test.js b/test/units.test.js index 506c13f7b..2f73b954e 100644 --- a/test/units.test.js +++ b/test/units.test.js @@ -19,7 +19,7 @@ describe('Units', () => { it('should work with simple use case *', () => { let unit1 = { numerators: ['m'], denominators: ['s'] } let unit2 = { numerators: ['s'], denominators: [] } - let unit = inferUnit('*', unit1, unit2) + let unit = inferUnit('*', [unit1, unit2]) expect(unit).to.deep.equal({ numerators: ['m'], @@ -29,7 +29,7 @@ describe('Units', () => { it('should work with simple use case / ', () => { let unit1 = { numerators: ['m'], denominators: ['s'] } let unit2 = { numerators: ['m'], denominators: [] } - let unit = inferUnit('/', unit1, unit2) + let unit = inferUnit('/', [unit1, unit2]) expect(unit).to.deep.equal({ numerators: [], @@ -39,7 +39,7 @@ describe('Units', () => { it('should work with advanced use case /', () => { let unit1 = { numerators: ['a', 'b', 'a', 'z'], denominators: ['c'] } let unit2 = { numerators: ['a', 'e', 'f'], denominators: ['z', 'c'] } - let unit = inferUnit('/', unit1, unit2) + let unit = inferUnit('/', [unit1, unit2]) expect(unit).to.deep.equal({ numerators: ['b', 'a', 'z', 'z'], From 342605e86bf7e9870f0a54f5624b8179b015187c Mon Sep 17 00:00:00 2001 From: Mael Date: Thu, 11 Jul 2019 17:07:34 +0200 Subject: [PATCH 05/32] =?UTF-8?q?Unit=C3=A9s=20:=20pourcentage=20et=20mult?= =?UTF-8?q?iplication?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/components/Value.js | 11 +++++------ source/components/rule/Rule.js | 2 ++ source/engine/grammarFunctions.js | 2 ++ source/engine/mecanisms.js | 11 ++++++----- source/engine/parse.js | 1 + source/engine/units.js | 22 ++++++++++++++-------- 6 files changed, 30 insertions(+), 19 deletions(-) diff --git a/source/components/Value.js b/source/components/Value.js index 8831c6258..431a48805 100644 --- a/source/components/Value.js +++ b/source/components/Value.js @@ -8,10 +8,7 @@ const NumberFormat = memoizeWith( Intl.NumberFormat ) -export let numberFormatter = (style, numFractionDigits = 2) => ( - value, - language -) => +export let numberFormatter = (style, numFractionDigits) => (value, language) => NumberFormat(language, { style, currency: 'EUR', @@ -37,7 +34,7 @@ export default withLanguage( nodeValue: value, unit, nilValueSymbol, - numFractionDigits, + numFractionDigits = 2, children, negative, language, @@ -66,8 +63,10 @@ export default withLanguage( nodeValue.nom ) : valueType === 'boolean' ? ( booleanTranslations[language][nodeValue] - ) : unit === '€' ? ( + ) : unitText === '€' ? ( numberFormatter('currency', numFractionDigits)(nodeValue, language) + ) : unitText === '%' ? ( + numberFormatter('percent')(nodeValue) ) : ( <> {numberFormatter('decimal', numFractionDigits)(nodeValue)} diff --git a/source/components/rule/Rule.js b/source/components/rule/Rule.js index f8f5d5b28..f6b7624e4 100644 --- a/source/components/rule/Rule.js +++ b/source/components/rule/Rule.js @@ -64,6 +64,8 @@ export default compose( let displayedRule = analysedExample || analysedRule + console.log(displayedRule) + return ( <> {this.state.viewSource ? ( diff --git a/source/engine/grammarFunctions.js b/source/engine/grammarFunctions.js index 6f4b0c4ff..5f1c44e58 100644 --- a/source/engine/grammarFunctions.js +++ b/source/engine/grammarFunctions.js @@ -1,5 +1,6 @@ /* Those are postprocessor functions for the Nearley grammar.ne. The advantage of putting them here is to get prettier's JS formatting, since Nealrey doesn't support it https://github.com/kach/nearley/issues/310 */ +import { parseUnit } from 'Engine/units' export let operation = operationType => ([A, , operator, , B]) => ({ [operator]: { @@ -41,6 +42,7 @@ export let percentage = d => ({ constant: { rawNode: d, type: 'percentage', + unit: parseUnit('%'), nodeValue: parseFloat(d[0].join('') + (d[1] ? d[1][0] + d[1][1].join('') : '')) / 100 } diff --git a/source/engine/mecanisms.js b/source/engine/mecanisms.js index 05f99932c..c7c006fe4 100644 --- a/source/engine/mecanisms.js +++ b/source/engine/mecanisms.js @@ -611,11 +611,12 @@ export let mecanismProduct = (recurse, k, v) => { category: 'mecanism', name: 'multiplication', type: 'numeric', - unit: inferUnit('*', [ - explanation.assiette, - explanation.taux, - explanation.facteur - ]) + unit: inferUnit( + '*', + [explanation.assiette, explanation.taux, explanation.facteur].map( + el => el.unit + ) + ) } } diff --git a/source/engine/parse.js b/source/engine/parse.js index 3ac304185..5dca8e9f2 100644 --- a/source/engine/parse.js +++ b/source/engine/parse.js @@ -171,6 +171,7 @@ export let parseObject = (rules, rule, parsedRules) => rawNode => { constant: () => ({ type: v.type, nodeValue: v.nodeValue, + unit: v.unit, // eslint-disable-next-line jsx: () => {v.rawNode} }) diff --git a/source/engine/units.js b/source/engine/units.js index d61c90162..5c7ce6e29 100644 --- a/source/engine/units.js +++ b/source/engine/units.js @@ -9,16 +9,22 @@ export let parseUnit = string => { return result } -export let serialiseUnit = ({ numerators = [], denominators = [] }) => { +export let serialiseUnit = rawUnit => { + let unit = simplify(rawUnit), + { numerators = [], denominators = [] } = unit let n = !isEmpty(numerators) let d = !isEmpty(denominators) - return !n && !d - ? '' - : n && !d - ? numerators.join('') - : !n && d - ? `/${denominators.join('')}` - : `${numerators.join('')} / ${denominators.join('')}` + let string = + !n && !d + ? '' + : n && !d + ? numerators.join('') + : !n && d + ? `/${denominators.join('')}` + : `${numerators.join('')} / ${denominators.join('')}` + + if (string.length > 1) return string.replace(/%/g, '') + return string } let noUnit = { numerators: [], denominators: [] } From 1adce3e514c952a92a296ef6fe85387309b1906f Mon Sep 17 00:00:00 2001 From: Mael Date: Thu, 11 Jul 2019 17:28:43 +0200 Subject: [PATCH 06/32] :gear: On abandonne NegatedVariable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit C'est illisible dans l'explication, je n'arrive pas à faire mieux que '≠ oui' --- source/engine/grammar.ne | 3 --- source/engine/parse.js | 5 ---- source/engine/parseReference.js | 37 ----------------------------- source/règles/base.yaml | 18 +++++++------- source/règles/externalized.yaml | 4 ++-- test/inversion.test.js | 2 +- test/mecanisms.test.js | 7 +++++- test/mécanismes/expressions.yaml | 2 +- test/mécanismes/multiplication.yaml | 1 + test/mécanismes/variations.yaml | 4 ++-- 10 files changed, 22 insertions(+), 61 deletions(-) diff --git a/source/engine/grammar.ne b/source/engine/grammar.ne index e17a9a5d7..04c85cbe9 100644 --- a/source/engine/grammar.ne +++ b/source/engine/grammar.ne @@ -32,11 +32,8 @@ Comparable -> ( AdditionSubstraction | NonNumericTerminal) {% ([[e]]) => e %} NonNumericTerminal -> Boolean {% id %} | String {% id %} - | NegatedVariable {% id %} -NegatedVariable -> "≠" _ Variable {% ([,,{variable}]) => ({'≠': {explanation: variable} }) %} - FilteredVariable -> Variable _ Filter {% filteredVariable %} Filter -> "[" VariableFragment "]" {% ([,filter]) => filter %} diff --git a/source/engine/parse.js b/source/engine/parse.js index 5dca8e9f2..daba3a3fa 100644 --- a/source/engine/parse.js +++ b/source/engine/parse.js @@ -47,7 +47,6 @@ import { } from './mecanisms' import { Node } from './mecanismViews/common' import { - parseNegatedReference, parseReference, parseReferenceTransforms } from './parseReference' @@ -152,10 +151,6 @@ export let parseObject = (rules, rule, parsedRules) => rawNode => { variations: mecanismVariations, synchronisation: mecanismSynchronisation, ...operationDispatch, - '≠': () => - parseNegatedReference( - parseReference(rules, rule, parsedRules)(v.explanation) - ), filter: () => parseReferenceTransforms(rules, rule, parsedRules)({ filter: v.filter, diff --git a/source/engine/parseReference.js b/source/engine/parseReference.js index 18c40b710..dc25ef334 100644 --- a/source/engine/parseReference.js +++ b/source/engine/parseReference.js @@ -217,40 +217,3 @@ export let parseReferenceTransforms = ( evaluate: evaluateTransforms(node.evaluate) } } - -export let parseNegatedReference = variable => { - let evaluate = (cache, situation, parsedRules, node) => { - let explanation = evaluateNode( - cache, - situation, - parsedRules, - node.explanation - ), - nodeValue = explanation.nodeValue == null ? null : !explanation.nodeValue, - missingVariables = explanation.missingVariables - - return rewriteNode(node, nodeValue, explanation, missingVariables) - } - - let jsx = (nodeValue, explanation) => ( - - Non{' '} - {makeJsx(explanation)} - - } - /> - ) - - return { - evaluate, - jsx, - category: 'mecanism', - name: 'négation', - type: 'boolean', - explanation: variable - } -} diff --git a/source/règles/base.yaml b/source/règles/base.yaml index e285e1969..fff14d37e 100644 --- a/source/règles/base.yaml +++ b/source/règles/base.yaml @@ -753,7 +753,7 @@ - si: toutes ces conditions: - brut de base [mensuel] < SMIC [mensuel] - - ≠ assimilé salarié + - assimilé salarié != oui niveau: avertissement message: | Le salaire saisi est inférieur au SMIC. @@ -2038,8 +2038,8 @@ - si: toutes ces conditions: - cotisations . assiette < plafond de réduction - - ≠ statut JEI - - ≠ assimilé salarié + - statut JEI != oui + - assimilé salarié != oui alors: 3.45% - sinon: 5.25% références: @@ -2403,8 +2403,8 @@ - si: toutes ces conditions: - cotisations . assiette < plafond de réduction employeur - - ≠ statut JEI - - ≠ assimilé salarié + - statut JEI != oui + - assimilé salarié != oui alors: 7% - sinon: 13% - attributs: @@ -3327,7 +3327,7 @@ formule: toutes ces conditions: - entreprise . catégorie d'activité . libérale règlementée - - ≠ rattachée à la CIPAV + - rattachée à la CIPAV != oui note: D'autres conditions d'exclusions existent, il faudra les compléter, mais la question de la catégorie d'activité doit avant être complétée. - nom: indépendant @@ -3372,7 +3372,7 @@ formule: une de ces conditions: - toutes ces conditions: - - ≠ contrat salarié + - contrat salarié != oui - entreprise . catégorie d'activité . libérale règlementée - toutes ces conditions: - entreprise . année d'activité @@ -3547,7 +3547,7 @@ titre: assiette retraite de base formule: variations: - - si: ≠ situation personnelle . RSA + - si: situation personnelle . RSA != oui alors: le maximum de: - 11.5% * plafond sécurité sociale temps plein @@ -3619,7 +3619,7 @@ titre: assiette invalidité et décès formule: variations: - - si: ≠ situation personnelle . RSA + - si: situation personnelle . RSA != oui alors: le maximum de: - 11.5% * plafond sécurité sociale temps plein diff --git a/source/règles/externalized.yaml b/source/règles/externalized.yaml index a13052597..e41e2e203 100644 --- a/source/règles/externalized.yaml +++ b/source/règles/externalized.yaml @@ -580,7 +580,7 @@ contrat salarié . salaire . brut de base: - si: toutes ces conditions: - 'brut de base [mensuel] < SMIC [mensuel]' - - ≠ assimilé salarié + - assimilé salarié != oui niveau: avertissement message: | The wage entered is lower than the minimum wage. @@ -599,7 +599,7 @@ contrat salarié . salaire . brut de base: - si: toutes ces conditions: - 'brut de base [mensuel] < SMIC [mensuel]' - - ≠ assimilé salarié + - assimilé salarié != oui niveau: avertissement message: | Le salaire saisi est inférieur au SMIC. diff --git a/test/inversion.test.js b/test/inversion.test.js index 68bdac6c4..603f1353c 100644 --- a/test/inversion.test.js +++ b/test/inversion.test.js @@ -145,7 +145,7 @@ describe('inversions', () => { - si: cadre alors: taux: 80% - - si: ≠ cadre + - si: cadre != oui alors: taux: 70% diff --git a/test/mecanisms.test.js b/test/mecanisms.test.js index c4a6a3089..d4f7b366c 100644 --- a/test/mecanisms.test.js +++ b/test/mecanisms.test.js @@ -11,11 +11,12 @@ import { collectMissingVariables } from '../source/engine/generateQuestions' import testSuites from './load-mecanism-tests' import * as R from 'ramda' import { isNumeric } from '../source/utils' +import { serialiseUnit } from 'Engine/units' describe('Mécanismes', () => testSuites.map(([suiteName, suite]) => suite.map( - ({ exemples, test }) => + ({ exemples, test, 'unité attendue': unit }) => exemples && describe(`Suite ${suiteName}, test : ${test || 'Nom de test (propriété "test") manquant dans la variable contenant ces "exemples"'}`, () => @@ -51,6 +52,10 @@ describe('Mécanismes', () => if (expectedMissing) { expect(missing).to.eql(expectedMissing) } + + if (unit) { + expect(serialiseUnit(target.unit)).to.eql(unit) + } }) )) ) diff --git a/test/mécanismes/expressions.yaml b/test/mécanismes/expressions.yaml index 36c6d4bc1..cabd3204e 100644 --- a/test/mécanismes/expressions.yaml +++ b/test/mécanismes/expressions.yaml @@ -133,7 +133,7 @@ - valeur attendue: true - test: négation - formule: ≠ CDD . poursuivi en CDI + formule: CDD . poursuivi en CDI != oui exemples: - situation: CDD . poursuivi en CDI: oui diff --git a/test/mécanismes/multiplication.yaml b/test/mécanismes/multiplication.yaml index a3fe67ed4..65a57dc62 100644 --- a/test/mécanismes/multiplication.yaml +++ b/test/mécanismes/multiplication.yaml @@ -6,6 +6,7 @@ multiplication: assiette: mon assiette taux: 3% + unité attendue: € exemples: - nom: entier diff --git a/test/mécanismes/variations.yaml b/test/mécanismes/variations.yaml index d8b362ce7..566d800e8 100644 --- a/test/mécanismes/variations.yaml +++ b/test/mécanismes/variations.yaml @@ -21,7 +21,7 @@ variations: - si: statut cadre alors: 2300 - - si: ≠ statut cadre + - si: statut cadre != oui alors: 2100 exemples: @@ -143,7 +143,7 @@ - si: statut cadre alors: taux: 8% - - si: ≠ statut cadre + - si: statut cadre != oui alors: taux: 5% From 0d0fcabe1bdf1a7e54922e9a74d2a3d1a7562d19 Mon Sep 17 00:00:00 2001 From: Mael Date: Thu, 11 Jul 2019 18:12:34 +0200 Subject: [PATCH 07/32] =?UTF-8?q?Tests=20des=20unit=C3=A9s=20dans=20les=20?= =?UTF-8?q?tests=20de=20m=C3=A9canismes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/mécanismes/barème.yaml | 1 + test/mécanismes/expressions.yaml | 28 ++++++++++++++++++++++++++++ test/mécanismes/multiplication.yaml | 5 +++-- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/test/mécanismes/barème.yaml b/test/mécanismes/barème.yaml index 25915ed39..e9f589cee 100644 --- a/test/mécanismes/barème.yaml +++ b/test/mécanismes/barème.yaml @@ -18,6 +18,7 @@ - au-dessus de: 3 taux: 1% + exemples: - nom: 'petite assiette' situation: diff --git a/test/mécanismes/expressions.yaml b/test/mécanismes/expressions.yaml index cabd3204e..626794b83 100644 --- a/test/mécanismes/expressions.yaml +++ b/test/mécanismes/expressions.yaml @@ -29,10 +29,13 @@ - valeur attendue: 29 - nom: salaire de base + unité: $ + - nom: contrat . salaire de base - test: multiplication formule: salaire de base * 3 + unité attendue: $ exemples: - situation: salaire de base: 1000 @@ -46,9 +49,11 @@ valeur attendue: 3000 - nom: taux + unité: '%' - test: soustraction formule: 1 - taux + unité attendue: '%' exemples: - situation: taux: 0.89 @@ -56,6 +61,7 @@ - test: addition formule: salaire de base + 2000 + unité attendue: $ exemples: - situation: salaire de base: 3000 @@ -78,6 +84,27 @@ salaire de base: 3000 valeur attendue: 1000 +- test: division deux + formule: 2000 / salaire de base + unité attendue: /$ + exemples: + - situation: + salaire de base: 3000 + valeur attendue: 0.66667 + +- nom: nombre de personnes + unité: personne + +- test: division trois + formule: salaire de base / nombre de personnes + unité attendue: $ / personne + exemples: + - situation: + salaire de base: 3000 + nombre de personnes: 10 + valeur attendue: 300 + + - test: comparaison stricte formule: salaire de base < 3001 exemples: @@ -150,6 +177,7 @@ - test: multiplication et pourcentage formule: 38.1% * salaire de base + unité attendue: $ exemples: - situation: salaire de base: 1000 diff --git a/test/mécanismes/multiplication.yaml b/test/mécanismes/multiplication.yaml index 65a57dc62..0e21faa6f 100644 --- a/test/mécanismes/multiplication.yaml +++ b/test/mécanismes/multiplication.yaml @@ -7,7 +7,6 @@ assiette: mon assiette taux: 3% unité attendue: € - exemples: - nom: entier situation: @@ -52,9 +51,10 @@ valeur attendue: 1.5 - nom: mon facteur - unité: _ + unité: patates - test: Multiplication à facteur + unité attendue: patates formule: multiplication: assiette: 100 @@ -76,6 +76,7 @@ plafond: mon plafond taux: 0.5% + unité attendue: €patates exemples: - nom: situation: From 6606bb4f34ba7db0b5827fc4825cf26afb31d2a5 Mon Sep 17 00:00:00 2001 From: Mael Date: Thu, 11 Jul 2019 18:25:08 +0200 Subject: [PATCH 08/32] =?UTF-8?q?Unit=C3=A9s=20des=20bar=C3=A8mes=20et=20c?= =?UTF-8?q?omposantes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/components/Value.js | 1 + source/engine/mecanisms.js | 56 ------------------ source/engine/mecanisms/barème-continu.js | 63 ++++++++++++++++++++ source/engine/mecanisms/barème-linéaire.js | 68 ++++++++++++++++++++++ source/engine/mecanisms/barème.js | 4 +- source/engine/mecanisms/utils.js | 4 +- source/engine/parse.js | 13 ++--- source/engine/units.js | 1 + test/mecanisms.test.js | 1 + test/mécanismes/barème-continu.yaml | 12 ++-- test/mécanismes/barème-linéaire.yaml | 2 + test/mécanismes/barème.yaml | 9 ++- test/mécanismes/composantes.yaml | 7 ++- 13 files changed, 166 insertions(+), 75 deletions(-) create mode 100644 source/engine/mecanisms/barème-continu.js create mode 100644 source/engine/mecanisms/barème-linéaire.js diff --git a/source/components/Value.js b/source/components/Value.js index 431a48805..6942ef0e5 100644 --- a/source/components/Value.js +++ b/source/components/Value.js @@ -77,6 +77,7 @@ export default withLanguage( return nodeValue == undefined ? null : ( + unit: {unitText} {negative ? '-' : ''} {formattedValue} diff --git a/source/engine/mecanisms.js b/source/engine/mecanisms.js index c7c006fe4..aa4441fa9 100644 --- a/source/engine/mecanisms.js +++ b/source/engine/mecanisms.js @@ -620,62 +620,6 @@ export let mecanismProduct = (recurse, k, v) => { } } -/* on réécrit en une syntaxe plus bas niveau mais plus régulière les tranches : - `en-dessous de: 1` - devient - ``` - de: 0 - à: 1 - ``` - */ - -export let mecanismLinearScale = (recurse, k, v) => { - if (v.composantes) { - //mécanisme de composantes. Voir known-mecanisms.md/composantes - return decompose(recurse, k, v) - } - if (v.variations) { - return mecanismVariations(recurse, k, v, true) - } - let tranches = desugarScale(recurse)(v['tranches']), - objectShape = { - assiette: false, - multiplicateur: defaultNode(1) - } - - let effect = ({ assiette, multiplicateur, tranches }) => { - if (val(assiette) === null) return null - - let roundedAssiette = Math.round(val(assiette)) - - let matchedTranche = tranches.find( - ({ de: min, à: max }) => - roundedAssiette >= val(multiplicateur) * min && - roundedAssiette <= max * val(multiplicateur) - ) - - if (!matchedTranche) return 0 - if (matchedTranche.taux) - return matchedTranche.taux.nodeValue * val(assiette) - return matchedTranche.montant - } - - let explanation = { - ...parseObject(recurse, objectShape, v), - tranches - }, - evaluate = evaluateObject(objectShape, effect) - - return { - evaluate, - jsx: Barème('linéaire'), - explanation, - category: 'mecanism', - name: 'barème linéaire', - barème: 'en taux', - type: 'numeric' - } -} export let mecanismContinuousScale = (recurse, k, v) => { let objectShape = { diff --git a/source/engine/mecanisms/barème-continu.js b/source/engine/mecanisms/barème-continu.js new file mode 100644 index 000000000..4f9546d2a --- /dev/null +++ b/source/engine/mecanisms/barème-continu.js @@ -0,0 +1,63 @@ +import { defaultNode, evaluateObject } from 'Engine/evaluation' +import BarèmeContinu from 'Engine/mecanismViews/BarèmeContinu' +import { val, anyNull } from 'Engine/traverse-common-functions' +import { parseUnit } from 'Engine/units' +import { parseObject } from 'Engine/evaluation' +import { reduce, toPairs, sort, aperture, pipe, reduced, last } from 'ramda' + +export default (recurse, k, v) => { + let objectShape = { + assiette: false, + multiplicateur: defaultNode(1) + } + + let returnRate = v['retourne seulement le taux'] === 'oui' + let effect = ({ assiette, multiplicateur, points }) => { + if (anyNull([assiette, multiplicateur])) return null + //We'll build a linear function given the two constraints that must be respected + let result = pipe( + toPairs, + // we don't rely on the sorting of objects + sort(([k1], [k2]) => k1 - k2), + points => [...points, [Infinity, last(points)[1]]], + aperture(2), + reduce((_, [[lowerLimit, lowerRate], [upperLimit, upperRate]]) => { + let x1 = val(multiplicateur) * lowerLimit, + x2 = val(multiplicateur) * upperLimit, + y1 = val(assiette) * val(recurse(lowerRate)), + y2 = val(assiette) * val(recurse(upperRate)) + if (val(assiette) > x1 && val(assiette) <= x2) { + // Outside of these 2 limits, it's a linear function a * x + b + let a = (y2 - y1) / (x2 - x1), + b = y1 - x1 * a, + nodeValue = a * val(assiette) + b, + taux = nodeValue / val(assiette) + return reduced({ + nodeValue: returnRate ? taux : nodeValue, + additionalExplanation: { + seuil: val(assiette) / val(multiplicateur), + taux + } + }) + } + }, 0) + )(points) + + return result + } + let explanation = { + ...parseObject(recurse, objectShape, v), + points: v.points, + returnRate + }, + evaluate = evaluateObject(objectShape, effect) + return { + evaluate, + jsx: BarèmeContinu, + explanation, + category: 'mecanism', + name: 'barème continu', + type: 'numeric', + unit: returnRate ? parseUnit('%') : explanation.assiette.unit + } +} diff --git a/source/engine/mecanisms/barème-linéaire.js b/source/engine/mecanisms/barème-linéaire.js new file mode 100644 index 000000000..41e7437aa --- /dev/null +++ b/source/engine/mecanisms/barème-linéaire.js @@ -0,0 +1,68 @@ +import { defaultNode, evaluateObject } from 'Engine/evaluation' +import Barème from 'Engine/mecanismViews/Barème' +import { mecanismVariations } from 'Engine/mecanisms' +import { decompose } from 'Engine/mecanisms/utils' +import { val } from 'Engine/traverse-common-functions' +import { inferUnit, parseUnit } from 'Engine/units' +import { parseObject } from 'Engine/evaluation' +import { desugarScale } from './barème' +/* on réécrit en une syntaxe plus bas niveau mais plus régulière les tranches : + `en-dessous de: 1` + devient + ``` + de: 0 + à: 1 + ``` + */ + +export default (recurse, k, v) => { + if (v.composantes) { + //mécanisme de composantes. Voir known-mecanisms.md/composantes + return decompose(recurse, k, v) + } + if (v.variations) { + return mecanismVariations(recurse, k, v, true) + } + let tranches = desugarScale(recurse)(v['tranches']), + objectShape = { + assiette: false, + multiplicateur: defaultNode(1) + } + + let effect = ({ assiette, multiplicateur, tranches }) => { + if (val(assiette) === null) return null + + let roundedAssiette = Math.round(val(assiette)) + + let matchedTranche = tranches.find( + ({ de: min, à: max }) => + roundedAssiette >= val(multiplicateur) * min && + roundedAssiette <= max * val(multiplicateur) + ) + + if (!matchedTranche) return 0 + if (matchedTranche.taux) + return matchedTranche.taux.nodeValue * val(assiette) + return matchedTranche.montant + } + + let explanation = { + ...parseObject(recurse, objectShape, v), + tranches + }, + evaluate = evaluateObject(objectShape, effect) + + console.log('explanation', explanation) + + return { + evaluate, + jsx: Barème('linéaire'), + explanation, + category: 'mecanism', + name: 'barème linéaire', + barème: 'en taux', + type: 'numeric', + + unit: explanation.assiette.unit + } +} diff --git a/source/engine/mecanisms/barème.js b/source/engine/mecanisms/barème.js index a7b7c6754..270389a70 100644 --- a/source/engine/mecanisms/barème.js +++ b/source/engine/mecanisms/barème.js @@ -4,6 +4,7 @@ import { decompose } from 'Engine/mecanisms/utils' import Barème from 'Engine/mecanismViews/Barème' import { val } from 'Engine/traverse-common-functions' import { evolve, has, pluck, sum } from 'ramda' +import { inferUnit, parseUnit } from 'Engine/units' export let desugarScale = recurse => tranches => tranches @@ -85,6 +86,7 @@ export default (recurse, k, v) => { jsx: Barème('marginal'), category: 'mecanism', name: 'barème', - barème: 'marginal' + barème: 'marginal', + unit: inferUnit('*', [explanation.assiette.unit, parseUnit('%')]) } } diff --git a/source/engine/mecanisms/utils.js b/source/engine/mecanisms/utils.js index 88362872a..cf986ee25 100644 --- a/source/engine/mecanisms/utils.js +++ b/source/engine/mecanisms/utils.js @@ -1,6 +1,7 @@ import Composantes from 'Engine/mecanismViews/Composantes' import { add, dissoc, objOf } from 'ramda' import { evaluateArrayWithFilter } from 'Engine/evaluation' +import { inferUnit } from 'Engine/units' export let decompose = (recurse, k, v) => { let subProps = dissoc('composantes')(v), @@ -28,7 +29,8 @@ export let decompose = (recurse, k, v) => { evaluate: evaluateArrayWithFilter(filter, add, 0), category: 'mecanism', name: 'composantes', - type: 'numeric' + type: 'numeric', + unit: inferUnit('+', explanation.map(e => e.unit)) } } diff --git a/source/engine/parse.js b/source/engine/parse.js index daba3a3fa..7eebe2488 100644 --- a/source/engine/parse.js +++ b/source/engine/parse.js @@ -3,6 +3,8 @@ // TODO import them automatically // TODO convert the legacy functions to new files import barème from 'Engine/mecanisms/barème.js' +import barèmeContinu from 'Engine/mecanisms/barème-continu.js' +import barèmeLinéaire from 'Engine/mecanisms/barème-linéaire.js' import { Parser } from 'nearley' import { add, @@ -30,10 +32,8 @@ import Grammar from './grammar.ne' import { mecanismAllOf, mecanismComplement, - mecanismContinuousScale, mecanismError, mecanismInversion, - mecanismLinearScale, mecanismMax, mecanismMin, mecanismNumericalSwitch, @@ -46,10 +46,7 @@ import { mecanismOnePossibility } from './mecanisms' import { Node } from './mecanismViews/common' -import { - parseReference, - parseReferenceTransforms -} from './parseReference' +import { parseReferenceTransforms } from './parseReference' import { inferUnit } from 'Engine/units' export let parse = (rules, rule, parsedRules) => rawNode => { @@ -140,8 +137,8 @@ export let parseObject = (rules, rule, parsedRules) => rawNode => { somme: mecanismSum, multiplication: mecanismProduct, barème, - 'barème linéaire': mecanismLinearScale, - 'barème continu': mecanismContinuousScale, + 'barème linéaire': barèmeLinéaire, + 'barème continu': barèmeContinu, 'le maximum de': mecanismMax, 'le minimum de': mecanismMin, complément: mecanismComplement, diff --git a/source/engine/units.js b/source/engine/units.js index 5c7ce6e29..295a742f8 100644 --- a/source/engine/units.js +++ b/source/engine/units.js @@ -23,6 +23,7 @@ export let serialiseUnit = rawUnit => { ? `/${denominators.join('')}` : `${numerators.join('')} / ${denominators.join('')}` + // the unit '%' is only displayed when it is the only unit if (string.length > 1) return string.replace(/%/g, '') return string } diff --git a/test/mecanisms.test.js b/test/mecanisms.test.js index d4f7b366c..ddbbd63c9 100644 --- a/test/mecanisms.test.js +++ b/test/mecanisms.test.js @@ -54,6 +54,7 @@ describe('Mécanismes', () => } if (unit) { + expect(target.unit).not.to.be.equal(undefined) expect(serialiseUnit(target.unit)).to.eql(unit) } }) diff --git a/test/mécanismes/barème-continu.yaml b/test/mécanismes/barème-continu.yaml index 2931b671c..b204d2047 100644 --- a/test/mécanismes/barème-continu.yaml +++ b/test/mécanismes/barème-continu.yaml @@ -1,9 +1,9 @@ - nom: base - unité: _ + unité: £ formule: 300 - nom: assiette - unité: _ + unité: £ - test: Simple formule: @@ -14,7 +14,7 @@ 0: 0% 0.4: 3.16% 1.1: 6.35% - + unité attendue: £ exemples: - nom: Premier point situation: @@ -39,11 +39,12 @@ - nom: base deux - unité: _ + unité: µ formule: 300 - nom: assiette deux - unité: _ + unité: µ + - test: Retour de taux, pas d'assiette formule: barème continu: @@ -54,6 +55,7 @@ 0.75: 100% 1: 0% retourne seulement le taux: oui + unité attendue: '%' exemples: - nom: Premier point situation: diff --git a/test/mécanismes/barème-linéaire.yaml b/test/mécanismes/barème-linéaire.yaml index 97a55fb17..f2f2e9424 100644 --- a/test/mécanismes/barème-linéaire.yaml +++ b/test/mécanismes/barème-linéaire.yaml @@ -14,6 +14,7 @@ taux: 10% - au-dessus de: 2000 taux: 15% + unité attendue: € exemples: - nom: "petite assiette" @@ -51,6 +52,7 @@ - au-dessus de: 2000 montant: 400 + unité attendue: € exemples: - nom: "petite assiette" situation: diff --git a/test/mécanismes/barème.yaml b/test/mécanismes/barème.yaml index e9f589cee..5bc50b860 100644 --- a/test/mécanismes/barème.yaml +++ b/test/mécanismes/barème.yaml @@ -17,8 +17,7 @@ taux: 3% - au-dessus de: 3 taux: 1% - - + unité attendue: € exemples: - nom: 'petite assiette' situation: @@ -52,6 +51,7 @@ taux: 9% - au-dessus de: 2 taux: 29% + unité attendue: € exemples: - nom: @@ -62,12 +62,14 @@ - nom: ma condition -- nom: taux variable +- test: taux variable formule: variations: - si: ma condition alors: 29% - sinon: 56% + unité attendue: '%' + exemples: [] - nom: deuxième barème test: Barème à taux variable @@ -80,6 +82,7 @@ taux: taux variable - au-dessus de: 1 taux: 90% + unité attendue: € exemples: - nom: taux faible diff --git a/test/mécanismes/composantes.yaml b/test/mécanismes/composantes.yaml index db0f82701..270fd2f7d 100644 --- a/test/mécanismes/composantes.yaml +++ b/test/mécanismes/composantes.yaml @@ -1,12 +1,17 @@ - test: Composantes formule: multiplication: - assiette: 100 + assiette: richesse composantes: - taux: 8% - taux: 2% + unité attendue: crédits exemples: - nom: situation: valeur attendue: 10 + +- nom: richesse + unité: crédits + formule: 100 From 413b6197ef360e35e5303e1bc436a48b4e54fcf0 Mon Sep 17 00:00:00 2001 From: Mael Date: Fri, 19 Jul 2019 19:51:36 +0200 Subject: [PATCH 09/32] =?UTF-8?q?:bug:=20On=20arr=C3=AAte=20le=20parsing?= =?UTF-8?q?=20r=C3=A9cursif=20quand=20formule=20d'inversion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/engine/parseReference.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/engine/parseReference.js b/source/engine/parseReference.js index dc25ef334..c222c9a4d 100644 --- a/source/engine/parseReference.js +++ b/source/engine/parseReference.js @@ -17,9 +17,13 @@ export let parseReference = (rules, rule, parsedRules, filter) => ({ let partialReference = fragments.join(' . '), dottedName = disambiguateRuleReference(rules, rule, partialReference) + let inInversionFormula = rule.formule?.['inversion numérique'] + let parsedRule = parsedRules[dottedName] || - parseRule(rules, findRuleByDottedName(rules, dottedName), parsedRules) + // the 'inversion numérique' formula should not exist. The instructions to the evaluation should be enough to infer that an inversion is necessary (assuming it is possible, the client decides this) + (!inInversionFormula && + parseRule(rules, findRuleByDottedName(rules, dottedName), parsedRules)) let evaluate = (cache, situation, parsedRules, node) => { let dottedName = node.dottedName, @@ -155,11 +159,7 @@ export let parseReferenceTransforms = ( if (!rule.période && !inlinePeriodTransform) { if (supportedPeriods.includes(ruleToTransform.période)) throw new Error( - `Attention, une variable sans période, ${ - rule.dottedName - }, qui appelle une variable à période, ${ - ruleToTransform.dottedName - }, c'est suspect ! + `Attention, une variable sans période, ${rule.dottedName}, qui appelle une variable à période, ${ruleToTransform.dottedName}, c'est suspect ! Si la période de la variable appelée est neutralisée dans la formule de calcul, par exemple un montant mensuel divisé par 30 (comprendre 30 jours), utilisez "période: aucune" pour taire cette erreur et rassurer tout le monde. ` From 5de2231267994d30d0d40efa1b038461ae3d7579 Mon Sep 17 00:00:00 2001 From: Mael Date: Sat, 20 Jul 2019 18:30:41 +0200 Subject: [PATCH 10/32] Changement de la signature et des digits de NumberFormatter --- source/components/Distribution.js | 8 +++---- source/components/SchemeComparaison.js | 2 +- source/components/Value.js | 32 +++++++++++++++++++------- source/engine/mecanismViews/Barème.js | 11 ++++----- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/source/components/Distribution.js b/source/components/Distribution.js index 1fab70429..aa9d7b3cf 100644 --- a/source/components/Distribution.js +++ b/source/components/Distribution.js @@ -113,17 +113,17 @@ class Distribution extends Component {
- + + Cotisations - + {total.partPatronale + total.partSalariale}
= - +
) @@ -154,7 +154,7 @@ let ChartItemBar = ({ styles, colour, montant, total }) => ( margin-left: 1em; color: var(--textColourOnWhite); `}> - + {montant}
diff --git a/source/components/SchemeComparaison.js b/source/components/SchemeComparaison.js index 5fe06573b..d13cdc5e3 100644 --- a/source/components/SchemeComparaison.js +++ b/source/components/SchemeComparaison.js @@ -626,7 +626,7 @@ const RuleValueLink = compose( sitePaths.documentation.index + '/' + encodeRuleName(rule.dottedName) }> (value, language) => +export let numberFormatter = ({ + style, + maximumFractionDigits, + minimumFractionDigits = 0, + language +}) => value => NumberFormat(language, { style, currency: 'EUR', - maximumFractionDigits: numFractionDigits, - minimumFractionDigits: numFractionDigits + maximumFractionDigits, + minimumFractionDigits }).format(value) // let booleanTranslations = { true: '✅', false: '❌' } @@ -34,7 +39,8 @@ export default withLanguage( nodeValue: value, unit, nilValueSymbol, - numFractionDigits = 2, + maximumFractionDigits, + minimumFractionDigits, children, negative, language, @@ -64,12 +70,23 @@ export default withLanguage( ) : valueType === 'boolean' ? ( booleanTranslations[language][nodeValue] ) : unitText === '€' ? ( - numberFormatter('currency', numFractionDigits)(nodeValue, language) + numberFormatter({ + style: 'currency', + maximumFractionDigits, + minimumFractionDigits, + language + })(nodeValue) ) : unitText === '%' ? ( - numberFormatter('percent')(nodeValue) + numberFormatter({ style: 'percent', maximumFractionDigits: 3 })( + nodeValue + ) ) : ( <> - {numberFormatter('decimal', numFractionDigits)(nodeValue)} + {numberFormatter({ + style: 'decimal', + minimumFractionDigits, + maximumFractionDigits + })(nodeValue)}   {unitText} @@ -77,7 +94,6 @@ export default withLanguage( return nodeValue == undefined ? null : ( - unit: {unitText} {negative ? '-' : ''} {formattedValue} diff --git a/source/engine/mecanismViews/Barème.js b/source/engine/mecanismViews/Barème.js index dcb9a90cf..9c19d8f1a 100644 --- a/source/engine/mecanismViews/Barème.js +++ b/source/engine/mecanismViews/Barème.js @@ -115,8 +115,6 @@ let Component = withLanguage(function Barème({ ) }) -let number = numberFormatter(undefined, 0) - let Tranche = ({ tranche: { 'en-dessous de': maxOnly, @@ -136,16 +134,17 @@ let Tranche = ({ {maxOnly ? ( <> - En-dessous de {number(maxOnly, language)} + En-dessous de{' '} + {numberFormatter({ language })(maxOnly)} ) : minOnly ? ( <> - Au-dessus de {number(minOnly, language)} + Au-dessus de {numberFormatter({ language })(minOnly)} ) : ( <> - De {number(min, language)} à{' '} - {number(max, language)} + De {numberFormatter({ language })(min)}{' '} + à {numberFormatter({ language })(max)} )} From 60a8558daf2e5a469d14b0fecd4c7919cc3eaa2d Mon Sep 17 00:00:00 2001 From: Mael Date: Sat, 20 Jul 2019 18:30:42 +0200 Subject: [PATCH 11/32] =?UTF-8?q?Affichage=20des=20unit=C3=A9s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/engine/evaluation.js | 2 +- source/engine/mecanismViews/Composantes.js | 8 +++++--- source/engine/mecanismViews/Product.js | 3 ++- source/engine/mecanismViews/Somme.js | 15 ++++++++------- source/engine/mecanismViews/Variations.js | 8 +++++--- source/engine/mecanismViews/common.js | 12 ++++++------ source/engine/mecanisms.js | 8 ++++---- source/engine/parse.js | 1 + source/engine/parseReference.js | 20 +++++++++++--------- 9 files changed, 43 insertions(+), 34 deletions(-) diff --git a/source/engine/evaluation.js b/source/engine/evaluation.js index e27bb97f6..ca59b46d3 100644 --- a/source/engine/evaluation.js +++ b/source/engine/evaluation.js @@ -16,7 +16,7 @@ import { export let makeJsx = node => typeof node.jsx == 'function' - ? node.jsx(node.nodeValue, node.explanation, node.lazyEval) + ? node.jsx(node.nodeValue, node.explanation, node.lazyEval, node.unit) : node.jsx export let collectNodeMissing = node => node.missingVariables || {} diff --git a/source/engine/mecanismViews/Composantes.js b/source/engine/mecanismViews/Composantes.js index 26787882e..ba44b47fc 100644 --- a/source/engine/mecanismViews/Composantes.js +++ b/source/engine/mecanismViews/Composantes.js @@ -10,7 +10,8 @@ import withLanguage from 'Components/utils/withLanguage' let Comp = withLanguage(function Composantes({ language, nodeValue, - explanation + explanation, + unit }) { return (

@@ -51,6 +53,6 @@ let Comp = withLanguage(function Composantes({ }) // eslint-disable-next-line -export default (nodeValue, explanation) => ( - +export default (nodeValue, explanation, _, unit) => ( + ) diff --git a/source/engine/mecanismViews/Product.js b/source/engine/mecanismViews/Product.js index b8f74395d..1cb81521a 100644 --- a/source/engine/mecanismViews/Product.js +++ b/source/engine/mecanismViews/Product.js @@ -4,13 +4,14 @@ import { Trans } from 'react-i18next' import { Node } from './common' import './InversionNumérique.css' -export default function ProductView(nodeValue, explanation) { +export default function ProductView(nodeValue, explanation, _, unit) { return ( // The rate and factor and threshold are given defaut neutral values. If there is nothing to explain, don't display them at all ( +const SommeNode = ({ explanation, nodeValue, unit }) => ( } + unit={unit} + child={} /> ) export default SommeNode -let Table = ({ explanation }) => ( +let Table = ({ explanation, unit }) => (
{explanation.map((v, i) => ( - + ))}
@@ -30,7 +31,7 @@ class Row extends Component { folded: true } render() { - let { v, i } = this.props, + let { v, i, unit } = this.props, rowFormula = path(['explanation', 'formule', 'explanation'], v), isSomme = rowFormula && rowFormula.name == 'somme' @@ -50,13 +51,13 @@ class Row extends Component { )}
- +
, ...(isSomme && !this.state.folded ? [
-
+
] : []) diff --git a/source/engine/mecanismViews/Variations.js b/source/engine/mecanismViews/Variations.js index df68bb469..af9f868f4 100644 --- a/source/engine/mecanismViews/Variations.js +++ b/source/engine/mecanismViews/Variations.js @@ -12,7 +12,8 @@ import './Variations.css' let Comp = withLanguage(function Variations({ language, nodeValue, - explanation + explanation, + unit }) { let [expandedVariation, toggleVariation] = useState(null) @@ -23,6 +24,7 @@ let Comp = withLanguage(function Variations({ classes="mecanism variations" name="variations" inline + unit={unit} value={nodeValue} child={ <> @@ -111,6 +113,6 @@ let Comp = withLanguage(function Variations({ ) }) // eslint-disable-next-line -export default (nodeValue, explanation) => ( - +export default (nodeValue, explanation, _, unit) => ( + ) diff --git a/source/engine/mecanismViews/common.js b/source/engine/mecanismViews/common.js index 11853fbd7..51b37dba7 100644 --- a/source/engine/mecanismViews/common.js +++ b/source/engine/mecanismViews/common.js @@ -35,7 +35,7 @@ export let NodeValuePointer = ({ data, unit }) => ( // Un élément du graphe de calcul qui a une valeur interprétée (à afficher) export class Node extends Component { render() { - let { classes, name, value, child, inline } = this.props, + let { classes, name, value, child, inline, unit } = this.props, termDefinition = contains('mecanism', classes) && name return ( @@ -58,7 +58,7 @@ export class Node extends Component { {name ? ( !isNil(value) && (
- +
) ) : ( @@ -66,7 +66,7 @@ export class Node extends Component { {value !== true && value !== false && !isNil(value) && ( = )} - + )} @@ -98,7 +98,7 @@ export const Leaf = compose( classes, dottedName, name, - value, + nodeValue, flatRules, filter, sitePaths, @@ -120,12 +120,12 @@ export const Leaf = compose( {rule.title || capitalise0(name)} {filter} - {!isNil(value) && ( + {!isNil(nodeValue) && ( - + )} diff --git a/source/engine/mecanisms.js b/source/engine/mecanisms.js index aa4441fa9..4c36925fe 100644 --- a/source/engine/mecanisms.js +++ b/source/engine/mecanisms.js @@ -138,7 +138,8 @@ export let mecanismVariations = (recurse, k, v, devariate) => { jsx: Variations, category: 'mecanism', name: 'variations', - type: 'numeric' + type: 'numeric', + unit: inferUnit('+', explanation.map(r => r.consequence.unit)) } } @@ -497,8 +498,8 @@ export let mecanismSum = (recurse, k, v) => { return { evaluate, // eslint-disable-next-line - jsx: (nodeValue, explanation) => ( - + jsx: (nodeValue, explanation, _, unit) => ( + ), explanation, category: 'mecanism', @@ -620,7 +621,6 @@ export let mecanismProduct = (recurse, k, v) => { } } - export let mecanismContinuousScale = (recurse, k, v) => { let objectShape = { assiette: false, diff --git a/source/engine/parse.js b/source/engine/parse.js index 7eebe2488..663196bb4 100644 --- a/source/engine/parse.js +++ b/source/engine/parse.js @@ -201,6 +201,7 @@ let mecanismOperation = (k, operatorFunction, symbol) => (recurse, k, v) => { diff --git a/source/engine/parseReference.js b/source/engine/parseReference.js index c222c9a4d..879aece22 100644 --- a/source/engine/parseReference.js +++ b/source/engine/parseReference.js @@ -21,7 +21,7 @@ export let parseReference = (rules, rule, parsedRules, filter) => ({ let parsedRule = parsedRules[dottedName] || - // the 'inversion numérique' formula should not exist. The instructions to the evaluation should be enough to infer that an inversion is necessary (assuming it is possible, the client decides this) + // the 'inversion numérique' formula should not exist. The instructions to the evaluation should be enough to infer that an inversion is necessary (assuming it is possible, the client decides this) (!inInversionFormula && parseRule(rules, findRuleByDottedName(rules, dottedName), parsedRules)) @@ -97,14 +97,16 @@ export let parseReference = (rules, rule, parsedRules, filter) => ({ evaluate, //eslint-disable-next-line react/display-name jsx: nodeValue => ( - + <> + + ), name: partialReference, From adf556c36f862bcdb5a1beb9245c48210b083988 Mon Sep 17 00:00:00 2001 From: Mael Date: Mon, 22 Jul 2019 11:57:27 +0200 Subject: [PATCH 12/32] :art: Alignement des valeurs des expressions dans /doc --- source/components/rule/Algorithm.css | 14 +++++--------- source/engine/mecanismViews/Variations.js | 2 +- source/engine/mecanisms.js | 2 +- source/locales/en.yaml | 1 - 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/source/components/rule/Algorithm.css b/source/components/rule/Algorithm.css index de8d70715..42d1b1053 100644 --- a/source/components/rule/Algorithm.css +++ b/source/components/rule/Algorithm.css @@ -23,24 +23,22 @@ display: inline-block; } -.node.inlineExpression:not(.comparison):not(.negation) { +.node.inlineExpression:not(.comparison) { padding-left: 0; display: flex; align-items: baseline; flex-direction: row; flex-wrap: wrap; + justify-content: space-between; } .nodeContent { margin-right: 0.3em; } -#rule-rules - .inlineExpression:not(.comparison):not(.negation) - > .situationValue { +#rule-rules .inlineExpression:not(.comparison) > .situationValue { margin-left: 0.3em; margin-bottom: 0.6em; margin-top: 0.3em; align-items: flex-end; - flex: 1; text-align: right; } @@ -210,8 +208,7 @@ .mecanism.cond *:not(.nodeContent) > .variable .name, .mecanism.variations *:not(.nodeContent) > .variable .name, -.inlineExpression.comparison, -.inlineExpression.negation { +.inlineExpression.comparison { display: flex; align-items: baseline; } @@ -223,8 +220,7 @@ > .variable .name .situationValue, -.inlineExpression.comparison > .situationValue, -.inlineExpression.negation > .situationValue { +.inlineExpression.comparison > .situationValue { order: -1; } diff --git a/source/engine/mecanismViews/Variations.js b/source/engine/mecanismViews/Variations.js index af9f868f4..2683cf337 100644 --- a/source/engine/mecanismViews/Variations.js +++ b/source/engine/mecanismViews/Variations.js @@ -46,7 +46,7 @@ let Comp = withLanguage(function Variations({ }}> {!satisfied && showValues && ( <> - non applicable{' '} + non applicable {expandedVariation !== i ? (