From 6fea2217f662f37304d81d8272cf81d6cc00df38 Mon Sep 17 00:00:00 2001 From: mama Date: Wed, 14 Feb 2018 11:10:05 +0100 Subject: [PATCH 01/35] :hammer: :calendar: taxe sur les salaires 2018 --- source/règles/base.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/règles/base.yaml b/source/règles/base.yaml index 2b46293b4..f7b00e48f 100644 --- a/source/règles/base.yaml +++ b/source/règles/base.yaml @@ -1714,7 +1714,7 @@ branche: santé dû par: employeur description: Cotisations de la branche maladie - références: + références: fiche: https://www.urssaf.fr/portail/home/employeur/calculer-les-cotisations/les-taux-de-cotisations/la-cotisation-maladie---maternit.html Décret n° 2017-1891 relatif au taux des cotisations d'assurance maladie: https://www.legifrance.gouv.fr/eli/decret/2017/12/30/CPAS1732212D/jo/texte formule: @@ -1890,7 +1890,7 @@ à: 152279 taux: 13.6% - au-dessus de: 152279 - taux: 20% + taux: 0% exemples: - nom: salaire médian situation: From ca58184c55aed81f63b4d77b61102fc0b82905e1 Mon Sep 17 00:00:00 2001 From: mama Date: Wed, 14 Feb 2018 11:20:28 +0100 Subject: [PATCH 02/35] :hammer: Introduction de l'espace "taxe sur les salaires" --- source/règles/base.yaml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/source/règles/base.yaml b/source/règles/base.yaml index f7b00e48f..a904adf06 100644 --- a/source/règles/base.yaml +++ b/source/règles/base.yaml @@ -1860,8 +1860,8 @@ # TODO chantier droits: introduire la répartition entre part régionale, quota d'app., hors quota # https://www.service-public.fr/professionnels-entreprises/vosdroits/F22574 -- espace: contrat salarié - nom: assujettie à la taxe sur les salaires +- espace: contrat salarié . taxe sur les salaires + nom: assujetissement titre: Entreprise assujettie à la taxe sur les salaires description: | Sont assujetties les associations à but non lucratif et les entreprises non soumises à la TVA ou payant la TVA sur moins de 10% de leur chiffre. Les particuliers employeurs, les employeurs agricoles, les établissements d'enseignement supérieur, les auto-entrepreneurs ne sont pas concernés. @@ -1870,8 +1870,8 @@ # à ajouter quand nous aurons des mécanismes logiques plus évolués (notamment 'applicable si') par défaut: non -- espace: contrat salarié - nom: taxe sur les salaires annuelle +- espace: contrat salarié . taxe sur les salaires + nom: montant annuel références: description: https://www.service-public.fr/professionnels-entreprises/vosdroits/F22576 @@ -1879,7 +1879,7 @@ barème: # TODO - les barèmes étant exprimés en base annuelle, et également à cause des limitations # de la grammaire, on a recours à cette formulation trop compliquée; à simplifier - assiette: assiette taxe sur les salaires * 12 + assiette: assiette * 12 tranches: - en-dessous de: 7721 taux: 4.25% @@ -1894,13 +1894,13 @@ exemples: - nom: salaire médian situation: - assiette taxe sur les salaires: 2300 + assiette: 2300 valeur attendue: 2639.16 # calcul annuel : 7721×4.25%+(15417−7721)×8.5%+(27600−15417)×13.6% -- espace: contrat salarié - nom: assiette taxe sur les salaires +- espace: contrat salarié . taxe sur les salaires + nom: assiette formule: somme: - assiette cotisations sociales @@ -1912,7 +1912,7 @@ description: La taxe sur les salaires en France est un impôt progressif créé en 1948 que certains employeurs doivent acquitter sur les salaires qu'ils distribuent. non applicable si: ≠ entreprise . association non lucrative - formule: taxe sur les salaires annuelle / 12 + formule: montant annuel / 12 exemples: - nom: non applicable par défaut situation: @@ -1922,8 +1922,9 @@ # Ce test ne sert qu'à tester la condition "association non lucrative", tant que nous faisons face à la limitation des calculs temporels situation: entreprise . association non lucrative: oui - taxe sur les salaires annuelle: 2639.16 + montant annuel: 2639.16 valeur attendue: 219.93 + - espace: contrat salarié nom: versement transport description: Contribution sur le travail consacrée au financement des transports publics. From a10f746ec4e480dae0a4ecfb5b8bfab0be15724a Mon Sep 17 00:00:00 2001 From: mama Date: Wed, 14 Feb 2018 11:36:28 +0100 Subject: [PATCH 03/35] =?UTF-8?q?Am=C3=A9lioration=20de=20la=20magie=20dan?= =?UTF-8?q?s=20les=20r=C3=A9f=C3=A9rences=20aux=20variables?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "contrat salarie . taxe sur les salaires" peut maintenant faire référence à "contrat salarié . taxe sur les salaires . montant annuel" en mentionnant seulement "montant annuel". --- source/engine/rules.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/engine/rules.js b/source/engine/rules.js index 5905fcbe9..bef1e18eb 100644 --- a/source/engine/rules.js +++ b/source/engine/rules.js @@ -81,13 +81,12 @@ export let decodeRuleName = name => /* Les variables peuvent être exprimées dans la formule d'une règle relativement à son propre espace de nom, pour une plus grande lisibilité. Cette fonction résoud cette ambiguité. */ - export let disambiguateRuleReference = ( allRules, { ns, name }, partialName ) => { - let fragments = ns ? ns.split(' . ') : [], // ex. [CDD . événements . rupture] + let fragments = ns ? [...ns.split(' . '), name] : [], // ex. [CDD . événements . rupture] pathPossibilities = range(0, fragments.length + 1) // -> [ [CDD . événements . rupture], [CDD . événements], [CDD] ] .map(nbEl => take(nbEl)(fragments)) .reverse(), From 75e94965e22a6aff744811e9e855a2eecd771227 Mon Sep 17 00:00:00 2001 From: mama Date: Wed, 14 Feb 2018 15:08:05 +0100 Subject: [PATCH 04/35] =?UTF-8?q?Ajout=20des=20all=C3=A8gements=20de=20la?= =?UTF-8?q?=20taxe=20sur=20les=20salaires?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Franchise, décôte --- source/règles/base.yaml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/source/règles/base.yaml b/source/règles/base.yaml index a904adf06..9a0beb1f7 100644 --- a/source/règles/base.yaml +++ b/source/règles/base.yaml @@ -1870,8 +1870,8 @@ # à ajouter quand nous aurons des mécanismes logiques plus évolués (notamment 'applicable si') par défaut: non -- espace: contrat salarié . taxe sur les salaires - nom: montant annuel +- espace: contrat salarié . taxe sur les salaires + nom: barème annuel références: description: https://www.service-public.fr/professionnels-entreprises/vosdroits/F22576 @@ -1897,7 +1897,19 @@ assiette: 2300 valeur attendue: 2639.16 # calcul annuel : 7721×4.25%+(15417−7721)×8.5%+(27600−15417)×13.6% - +- espace: contrat salarié . taxe sur les salaires + nom: montant annuel + formule: + allègements: + assiette: barème annuel + franchise: 1200 + décote: + plafond: 2040 + taux: 75% + #abattement: + #applicable si: entreprise . association non lucrative + #valeur: 20507 + - espace: contrat salarié . taxe sur les salaires nom: assiette From a1207883b113d721bdc79e3b9d71b2ff369021ba Mon Sep 17 00:00:00 2001 From: mama Date: Wed, 14 Feb 2018 15:46:01 +0100 Subject: [PATCH 05/35] =?UTF-8?q?:white=5Fcheck=5Fmark:=20:gear:=20Tests?= =?UTF-8?q?=20pour=20le=20m=C3=A9ca=20all=C3=A8gements?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/engine/known-mecanisms.yaml | 7 +++ test/mécanismes/allègement.yaml | 78 ++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 test/mécanismes/allègement.yaml diff --git a/source/engine/known-mecanisms.yaml b/source/engine/known-mecanisms.yaml index de95a1917..844d0a4b9 100644 --- a/source/engine/known-mecanisms.yaml +++ b/source/engine/known-mecanisms.yaml @@ -141,3 +141,10 @@ composantes: Il est même possible, pour les mécanismes `barème` et `multiplication` de garder en commun un paramètre comme l'assiette, puis de déclarer des composantes pour le taux. > L'example le plus courant de composantes, c'est la distinction part employeur, part salarié (ex. retraite AGIRC). + +allègement: + type: numeric + description: | + Permet de réduire le montant d'une variable. + Très utilisé dans le contexte des impôts. + diff --git a/test/mécanismes/allègement.yaml b/test/mécanismes/allègement.yaml new file mode 100644 index 000000000..5a0814d92 --- /dev/null +++ b/test/mécanismes/allègement.yaml @@ -0,0 +1,78 @@ +- nom: montant + format: € + +- test: montant franchisé + format: € + formule: + allègement: + assiette: montant + franchise: 1200 + + exemples: + - situation: + montant: 1000 + valeur attendue: 0 + + +- test: montant décoté + format: € + formule: + allègement: + assiette: montant + décote: + 0: 0% + 2040: 100% + exemples: + - situation: + montant: 1000 + valeur attendue: 490 + + +# La décote aurait aussi pu s'écrire ainsi, tel que décrit par la documentation sur la taxe sur les salaires, mais notre mécanisme nous semble mieux retranscrire sa finalité +#décote: +# de: 1200 +# à: 2040 +# taux: 75% + +- test: montant abattu + format: € + formule: + allègement: + assiette: montant + abattement: 20507 + exemples: + - situation: + montant: 10000 + valeur attendue: 0 + - situation: + montant: 80000 + valeur attendue: 59493 + + +- test: montant franchisé et décoté + format: € + formule: + allègement: + assiette: montant + franchise: 1200 + décote: + 1200: 25% + 2040: 100% + exemples: + - situation: + montant: 100 + valeur attendue: 0 + - situation: + montant: 1200 + valeur attendue: 300 + + - situation: + montant: 1300 + valeur attendue: 441 + + - situation: + montant: 2040 + valeur attendue: 2040 + + + From 92f37cd5cef9c45c4ce3a59990aecefaa527ba2a Mon Sep 17 00:00:00 2001 From: mama Date: Wed, 14 Feb 2018 16:01:37 +0100 Subject: [PATCH 06/35] =?UTF-8?q?Acc=C3=A9l=C3=A9ration=20de=20la=20compil?= =?UTF-8?q?ation=20Webpack=20en=20dev?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + source/webpack.config.js | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 28048110f..f7e9b9dbc 100644 --- a/package.json +++ b/package.json @@ -83,6 +83,7 @@ "fantasy-land": "^3.3.0", "fantasy-tuples": "^1.0.0", "file-loader": "^1.1.6", + "hard-source-webpack-plugin": "^0.5.18", "html-loader": "^0.5.1", "img-loader": "^2.0.0", "jsdom": "^11.0.0", diff --git a/source/webpack.config.js b/source/webpack.config.js index f41eaec89..ff375db7b 100644 --- a/source/webpack.config.js +++ b/source/webpack.config.js @@ -1,6 +1,7 @@ var webpack = require('webpack'), path = require('path'), - prodEnv = process.env.NODE_ENV == 'production' // eslint-disable-line no-undef + prodEnv = process.env.NODE_ENV == 'production', // eslint-disable-line no-undef + HardSourceWebpackPlugin = require('hard-source-webpack-plugin') module.exports = { devtool: 'cheap-module-source-map', @@ -92,6 +93,13 @@ module.exports = { new webpack.EnvironmentPlugin({ NODE_ENV: 'development' }), new webpack.NoEmitOnErrorsPlugin() ] - .concat(!prodEnv ? [new webpack.HotModuleReplacementPlugin()] : []) + .concat( + !prodEnv + ? [ + new webpack.HotModuleReplacementPlugin(), + new HardSourceWebpackPlugin() + ] + : [] + ) .concat(prodEnv ? [new webpack.optimize.UglifyJsPlugin()] : []) } From cf352d4c74cb54b7243620df038b47d5867ae83b Mon Sep 17 00:00:00 2001 From: mama Date: Wed, 14 Feb 2018 17:50:47 +0100 Subject: [PATCH 07/35] =?UTF-8?q?:gear:=20Impl=C3=A9mentation=20de=20l'all?= =?UTF-8?q?=C3=A8gement,=20sans=20l'abattement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/engine/mecanisms.js | 45 +++++++++++++++++++++++++++++++++ source/engine/traverse.js | 6 +++-- test/mécanismes/allègement.yaml | 30 ++++++---------------- 3 files changed, 57 insertions(+), 24 deletions(-) diff --git a/source/engine/mecanisms.js b/source/engine/mecanisms.js index cab959c0e..d9debfa3e 100644 --- a/source/engine/mecanisms.js +++ b/source/engine/mecanisms.js @@ -535,6 +535,51 @@ export let mecanismSum = (recurse, k, v) => { } } + + +export let mecanismReduction = (recurse, k, v) => { + let objectShape = { + assiette: false, + abattement: constantNode(0), + franchise: constantNode(0) + } + + let effect = ({assiette, abattement, franchise, décote}) => { + let v_assiette = val(assiette), + nulled = v_assiette == null + + return nulled + ? null + : val(franchise) && v_assiette < val(franchise) + ? 0 + : décote + ? do { + let plafond = val(décote.plafond), + taux = val(décote.taux) + + max(0,(1+taux)*v_assiette - (taux * plafond)) + } + : v_assiette + } + + let base = parseObject(recurse, objectShape, v), + explanation = v.décote ? + { + ...base, + décote: map(recurse, v.décote) + } : base, + evaluate = evaluateObject(objectShape, effect) + + return { + evaluate, + jsx: (nodeValue, explanation) =>
Allègement
, + explanation, + category: 'mecanism', + name: 'allègement', + type: 'numeric' + } +} + export let mecanismProduct = (recurse, k, v) => { if (v.composantes) { //mécanisme de composantes. Voir known-mecanisms.md/composantes diff --git a/source/engine/traverse.js b/source/engine/traverse.js index 810196fc8..b9359c10b 100644 --- a/source/engine/traverse.js +++ b/source/engine/traverse.js @@ -48,7 +48,8 @@ import { mecanismError, mecanismComplement, mecanismSelection, - mecanismInversion + mecanismInversion, + mecanismReduction } from './mecanisms' import { evaluateNode, @@ -425,7 +426,8 @@ let treat = (rules, rule) => rawNode => { 'une possibilité': 'oui', collectMissing: () => [rule.dottedName] }), - inversion: mecanismInversion(rule.dottedName) + inversion: mecanismInversion(rule.dottedName), + allègement: mecanismReduction }, action = propOr(mecanismError, k, dispatch) diff --git a/test/mécanismes/allègement.yaml b/test/mécanismes/allègement.yaml index 5a0814d92..711d10e69 100644 --- a/test/mécanismes/allègement.yaml +++ b/test/mécanismes/allègement.yaml @@ -13,26 +13,18 @@ montant: 1000 valeur attendue: 0 - - test: montant décoté format: € formule: allègement: assiette: montant décote: - 0: 0% - 2040: 100% + plafond: 2040 + taux: 100% exemples: - situation: montant: 1000 - valeur attendue: 490 - - -# La décote aurait aussi pu s'écrire ainsi, tel que décrit par la documentation sur la taxe sur les salaires, mais notre mécanisme nous semble mieux retranscrire sa finalité -#décote: -# de: 1200 -# à: 2040 -# taux: 75% + valeur attendue: 0 - test: montant abattu format: € @@ -48,7 +40,6 @@ montant: 80000 valeur attendue: 59493 - - test: montant franchisé et décoté format: € formule: @@ -56,23 +47,18 @@ assiette: montant franchise: 1200 décote: - 1200: 25% - 2040: 100% + plafond: 2040 + taux: 75% exemples: - situation: montant: 100 valeur attendue: 0 - situation: montant: 1200 - valeur attendue: 300 - + valeur attendue: 570 - situation: - montant: 1300 - valeur attendue: 441 - + montant: 1620 + valeur attendue: 1305 - situation: montant: 2040 valeur attendue: 2040 - - - From ec7ff01cd435db910285e1a0f335ed4a0daae8f3 Mon Sep 17 00:00:00 2001 From: mama Date: Thu, 15 Feb 2018 15:36:04 +0100 Subject: [PATCH 08/35] =?UTF-8?q?:gear:=20Ajout=20de=20l'abattement=20?= =?UTF-8?q?=C3=A0=20la=20taxe=20sur=20les=20salaires?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/règles/base.yaml | 9 ++++----- test/mécanismes/allègement.yaml | 31 +++++++++++++++++-------------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/source/règles/base.yaml b/source/règles/base.yaml index 9a0beb1f7..0a85f1b82 100644 --- a/source/règles/base.yaml +++ b/source/règles/base.yaml @@ -1906,10 +1906,9 @@ décote: plafond: 2040 taux: 75% - #abattement: - #applicable si: entreprise . association non lucrative - #valeur: 20507 - + # Attention : l'abattement n'est valable que pour les organismes à but non lucratif. + # Il n'est pas conditionné ici car on réserve pour l'instant la taxe sur les salaires aux associations 1901 + abattement: 20507 - espace: contrat salarié . taxe sur les salaires nom: assiette @@ -1922,7 +1921,7 @@ - espace: contrat salarié nom: taxe sur les salaires description: La taxe sur les salaires en France est un impôt progressif créé en 1948 que certains employeurs doivent acquitter sur les salaires qu'ils distribuent. - non applicable si: ≠ entreprise . association non lucrative + applicable si: entreprise . association non lucrative formule: montant annuel / 12 exemples: diff --git a/test/mécanismes/allègement.yaml b/test/mécanismes/allègement.yaml index 711d10e69..d0600703e 100644 --- a/test/mécanismes/allègement.yaml +++ b/test/mécanismes/allègement.yaml @@ -26,20 +26,6 @@ montant: 1000 valeur attendue: 0 -- test: montant abattu - format: € - formule: - allègement: - assiette: montant - abattement: 20507 - exemples: - - situation: - montant: 10000 - valeur attendue: 0 - - situation: - montant: 80000 - valeur attendue: 59493 - - test: montant franchisé et décoté format: € formule: @@ -62,3 +48,20 @@ - situation: montant: 2040 valeur attendue: 2040 + + +- test: montant abattu + format: € + formule: + allègement: + assiette: montant + abattement: 20507 + exemples: + - situation: + montant: 10000 + valeur attendue: 0 + - situation: + montant: 80000 + valeur attendue: 59493 + + From 438b82879019d3c47e3eb2fbc6d5b1b9f299b187 Mon Sep 17 00:00:00 2001 From: mama Date: Thu, 15 Feb 2018 15:40:10 +0100 Subject: [PATCH 09/35] =?UTF-8?q?:gear:=20Impl=C3=A9mentation=20de=20l'aba?= =?UTF-8?q?ttement=20dans=20'all=C3=A8gement'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/engine/mecanisms.js | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/source/engine/mecanisms.js b/source/engine/mecanisms.js index d9debfa3e..d8827c0da 100644 --- a/source/engine/mecanisms.js +++ b/source/engine/mecanisms.js @@ -535,8 +535,6 @@ export let mecanismSum = (recurse, k, v) => { } } - - export let mecanismReduction = (recurse, k, v) => { let objectShape = { assiette: false, @@ -544,7 +542,7 @@ export let mecanismReduction = (recurse, k, v) => { franchise: constantNode(0) } - let effect = ({assiette, abattement, franchise, décote}) => { + let effect = ({ assiette, abattement, franchise, décote }) => { let v_assiette = val(assiette), nulled = v_assiette == null @@ -557,17 +555,18 @@ export let mecanismReduction = (recurse, k, v) => { let plafond = val(décote.plafond), taux = val(décote.taux) - max(0,(1+taux)*v_assiette - (taux * plafond)) + max(0, (1 + taux) * v_assiette - taux * plafond) } - : v_assiette + : abattement ? max(0, v_assiette - val(abattement)) : v_assiette } let base = parseObject(recurse, objectShape, v), - explanation = v.décote ? - { - ...base, - décote: map(recurse, v.décote) - } : base, + explanation = v.décote + ? { + ...base, + décote: map(recurse, v.décote) + } + : base, evaluate = evaluateObject(objectShape, effect) return { From 3d33b583275031508ab83728816eea05f2c2bf7f Mon Sep 17 00:00:00 2001 From: Mael Date: Thu, 15 Feb 2018 16:21:04 +0100 Subject: [PATCH 10/35] :fire: Dependance devenue inutile --- package.json | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index f7e9b9dbc..5a0558771 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,7 @@ "engines": { "node": ">=6.2.0 <10.0.0" }, - "browserslist": [ - "> 1% in FR", - "not ie < 11" - ], + "browserslist": ["> 1% in FR", "not ie < 11"], "dependencies": { "@babel/polyfill": "^7.0.0-beta.34", "classnames": "^2.2.5", @@ -85,7 +82,6 @@ "file-loader": "^1.1.6", "hard-source-webpack-plugin": "^0.5.18", "html-loader": "^0.5.1", - "img-loader": "^2.0.0", "jsdom": "^11.0.0", "json-loader": "^0.5.4", "nearley-loader": "0.0.2", @@ -103,13 +99,21 @@ }, "scripts": { "start": "node source/server.js", - "compile": "NODE_ENV='production' webpack --config source/webpack.config.js", - "surge": "npm run compile && surge --domain scientific-wish.surge.sh -p ./ && rm -rf dist/", - "test": "mocha-webpack --webpack-config source/webpack.test.config.js --require source-map-support/register --require test/helpers/browser.js \"test/**/*.test.js\"", - "test-watch": "mocha-webpack --webpack-config source/webpack.test.config.js --require source-map-support/register --require test/helpers/browser.js \"test/**/*.test.js\" --watch", - "test-meca": "mocha-webpack --webpack-config source/webpack.test.config.js --require source-map-support/register --require test/helpers/browser.js test/mecanisms.test.js --watch", - "test-rules": "mocha-webpack --webpack-config source/webpack.test.config.js --require source-map-support/register --require test/helpers/browser.js test/real-rules.test.js --watch", - "heroku-postbuild": "npm install --dev && webpack --config source/webpack.config.js --progress", - "test-inversions": "mocha-webpack --webpack-config source/webpack.test.config.js --require source-map-support/register --require test/helpers/browser.js \"test/inversion.test.js\" --watch" + "compile": + "NODE_ENV='production' webpack --config source/webpack.config.js", + "surge": + "npm run compile && surge --domain scientific-wish.surge.sh -p ./ && rm -rf dist/", + "test": + "mocha-webpack --webpack-config source/webpack.test.config.js --require source-map-support/register --require test/helpers/browser.js \"test/**/*.test.js\"", + "test-watch": + "mocha-webpack --webpack-config source/webpack.test.config.js --require source-map-support/register --require test/helpers/browser.js \"test/**/*.test.js\" --watch", + "test-meca": + "mocha-webpack --webpack-config source/webpack.test.config.js --require source-map-support/register --require test/helpers/browser.js test/mecanisms.test.js --watch", + "test-rules": + "mocha-webpack --webpack-config source/webpack.test.config.js --require source-map-support/register --require test/helpers/browser.js test/real-rules.test.js --watch", + "heroku-postbuild": + "npm install --dev && webpack --config source/webpack.config.js --progress", + "test-inversions": + "mocha-webpack --webpack-config source/webpack.test.config.js --require source-map-support/register --require test/helpers/browser.js \"test/inversion.test.js\" --watch" } } From ab7d298cb50dca884b37d6436ee4127afb995b75 Mon Sep 17 00:00:00 2001 From: Mael Date: Thu, 15 Feb 2018 17:57:03 +0100 Subject: [PATCH 11/35] :hammer: La taxe sur les salaires doit impliquer l'entreprise Ses reductions se calculent sur la masse salariale totale. --- source/règles/base.yaml | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/source/règles/base.yaml b/source/règles/base.yaml index 0a85f1b82..0424f3bf8 100644 --- a/source/règles/base.yaml +++ b/source/règles/base.yaml @@ -1858,6 +1858,14 @@ - entreprise . effectif >= 2000 - entreprise . ratio alternants < 1% +- espace: contrat salarié . taxe sur les salaires + nom: assiette + formule: + somme: + - assiette cotisations sociales + - prévoyance obligatoire cadre + - complémentaire santé (employeur) + # TODO chantier droits: introduire la répartition entre part régionale, quota d'app., hors quota # https://www.service-public.fr/professionnels-entreprises/vosdroits/F22574 - espace: contrat salarié . taxe sur les salaires @@ -1871,7 +1879,7 @@ par défaut: non - espace: contrat salarié . taxe sur les salaires - nom: barème annuel + nom: barème annuel références: description: https://www.service-public.fr/professionnels-entreprises/vosdroits/F22576 @@ -1897,11 +1905,16 @@ assiette: 2300 valeur attendue: 2639.16 # calcul annuel : 7721×4.25%+(15417−7721)×8.5%+(27600−15417)×13.6% -- espace: contrat salarié . taxe sur les salaires +- espace: entreprise . taxe sur les salaires + nom: barème annuel + formule: + contrat salarié . taxe sur les salaires . barème annuel * effectif + +- espace: entreprise . taxe sur les salaires nom: montant annuel formule: - allègements: - assiette: barème annuel + allègement: + assiette: barème annuel franchise: 1200 décote: plafond: 2040 @@ -1911,12 +1924,8 @@ abattement: 20507 - espace: contrat salarié . taxe sur les salaires - nom: assiette - formule: - somme: - - assiette cotisations sociales - - prévoyance obligatoire cadre - - complémentaire santé (employeur) + nom: montant annuel + formule: entreprise . taxe sur les salaires . montant annuel / entreprise . effectif - espace: contrat salarié nom: taxe sur les salaires @@ -1936,6 +1945,7 @@ montant annuel: 2639.16 valeur attendue: 219.93 + - espace: contrat salarié nom: versement transport description: Contribution sur le travail consacrée au financement des transports publics. From f84e421494210cdd028aa4651e92cfff64841ab7 Mon Sep 17 00:00:00 2001 From: Mael Date: Thu, 15 Feb 2018 18:12:04 +0100 Subject: [PATCH 12/35] Throw Errors, not strings Mocha webpack n'est pas tres sympa avec ces derniers --- source/engine/mecanisms.js | 14 +++++++++----- source/engine/rules.js | 2 +- source/engine/traverse.js | 8 ++++---- test/real-rules.test.js | 1 - 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/source/engine/mecanisms.js b/source/engine/mecanisms.js index d8827c0da..0e77c4ca1 100644 --- a/source/engine/mecanisms.js +++ b/source/engine/mecanisms.js @@ -194,7 +194,7 @@ let devariate = (recurse, k, v) => { } export let mecanismOneOf = (recurse, k, v) => { - if (!is(Array, v)) throw 'should be array' + if (!is(Array, v)) throw new Error('should be array') let explanation = map(recurse, v) @@ -238,7 +238,7 @@ export let mecanismOneOf = (recurse, k, v) => { } export let mecanismAllOf = (recurse, k, v) => { - if (!is(Array, v)) throw 'should be array' + if (!is(Array, v)) throw new Error('should be array') let explanation = map(recurse, v) @@ -287,7 +287,9 @@ export let mecanismNumericalSwitch = (recurse, k, v) => { if (is(String, v)) return recurse(v) if (!is(Object, v) || keys(v).length == 0) { - throw 'Le mécanisme "aiguillage numérique" et ses sous-logiques doivent contenir au moins une proposition' + throw new Error( + 'Le mécanisme "aiguillage numérique" et ses sous-logiques doivent contenir au moins une proposition' + ) } // les termes sont les couples (condition, conséquence) de l'aiguillage numérique @@ -399,7 +401,9 @@ export let mecanismNumericalSwitch = (recurse, k, v) => { export let findInversion = (situationGate, rules, v, dottedName) => { let inversions = v.avec if (!inversions) - throw "Une formule d'inversion doit préciser _avec_ quoi on peut inverser la variable" + throw new Error( + "Une formule d'inversion doit préciser _avec_ quoi on peut inverser la variable" + ) /* Quelle variable d'inversion possible a sa valeur renseignée dans la situation courante ? Ex. s'il nous est demandé de calculer le salaire de base, est-ce qu'un candidat à l'inversion, comme @@ -965,5 +969,5 @@ export let mecanismSelection = (recurse, k, v) => { } export let mecanismError = (recurse, k, v) => { - throw "Le mécanisme '" + k + "' est inconnu !" + v + throw new Error("Le mécanisme '" + k + "' est inconnu !" + v) } diff --git a/source/engine/rules.js b/source/engine/rules.js index bef1e18eb..892464c92 100644 --- a/source/engine/rules.js +++ b/source/engine/rules.js @@ -102,7 +102,7 @@ export let disambiguateRuleReference = ( return ( (found && found.dottedName) || do { - throw `OUUUUPS la référence '${partialName}' dans la règle '${name}' est introuvable dans la base` + throw new `OUUUUPS la référence '${partialName}' dans la règle '${name}' est introuvable dans la base`() } ) } diff --git a/source/engine/traverse.js b/source/engine/traverse.js index b9359c10b..616168f20 100644 --- a/source/engine/traverse.js +++ b/source/engine/traverse.js @@ -391,9 +391,9 @@ let treat = (rules, rule) => rawNode => { }, treatOther = rawNode => { console.log() // eslint-disable-line no-console - throw 'Cette donnée : ' + - rawNode + - ' doit être un Number, String ou Object' + throw new Error( + 'Cette donnée : ' + rawNode + ' doit être un Number, String ou Object' + ) }, treatObject = rawNode => { let mecanisms = intersection(keys(rawNode), keys(knownMecanisms)) @@ -405,7 +405,7 @@ let treat = (rules, rule) => rawNode => { mecanisms, rawNode ) - throw 'OUPS !' + throw new Error('OUPS !') } let k = head(mecanisms), diff --git a/test/real-rules.test.js b/test/real-rules.test.js index 391fd2ebf..b10d9f164 100644 --- a/test/real-rules.test.js +++ b/test/real-rules.test.js @@ -13,7 +13,6 @@ import R from 'ramda' import { runExamples, isFloat } from '../source/components/rule/Examples' let parsedRules = parseAll(rules) - describe('Tests des règles de notre base de règles', () => parsedRules.map(rule => { if (!rule.exemples) return null From 41c83753505ee5508f291ecbfb94b06dfac7c78e Mon Sep 17 00:00:00 2001 From: mama Date: Mon, 19 Feb 2018 15:02:58 +0100 Subject: [PATCH 13/35] =?UTF-8?q?:hammer:=20Simplification=20de=20l'applic?= =?UTF-8?q?abilit=C3=A9=20du=20CITS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/règles/base.yaml | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/source/règles/base.yaml b/source/règles/base.yaml index 0424f3bf8..3e80e8738 100644 --- a/source/règles/base.yaml +++ b/source/règles/base.yaml @@ -1015,10 +1015,8 @@ références: fiche: https://www.service-public.fr/associations/actualites/A11012 - non applicable si: - une de ces conditions: - - assiette cotisations sociales > plafond CITS - - ≠ entreprise . association non lucrative + applicable si: entreprise . association non lucrative + non applicable si: assiette cotisations sociales > plafond CITS formule: multiplication: @@ -1878,8 +1876,8 @@ # à ajouter quand nous aurons des mécanismes logiques plus évolués (notamment 'applicable si') par défaut: non -- espace: contrat salarié . taxe sur les salaires - nom: barème annuel +- espace: contrat salarié . taxe sur les salaires + nom: barème annuel références: description: https://www.service-public.fr/professionnels-entreprises/vosdroits/F22576 @@ -1907,19 +1905,19 @@ - espace: entreprise . taxe sur les salaires nom: barème annuel - formule: + formule: contrat salarié . taxe sur les salaires . barème annuel * effectif - espace: entreprise . taxe sur les salaires nom: montant annuel - formule: - allègement: - assiette: barème annuel - franchise: 1200 - décote: + formule: + allègement: + assiette: barème annuel + franchise: 1200 + décote: plafond: 2040 taux: 75% - # Attention : l'abattement n'est valable que pour les organismes à but non lucratif. + # Attention : l'abattement n'est valable que pour les organismes à but non lucratif. # Il n'est pas conditionné ici car on réserve pour l'instant la taxe sur les salaires aux associations 1901 abattement: 20507 From 5c4a82d2c8cb196e560d5f27d7b32e3e1fa5bcc6 Mon Sep 17 00:00:00 2001 From: mama Date: Mon, 19 Feb 2018 16:07:26 +0100 Subject: [PATCH 14/35] =?UTF-8?q?:hammer:=20Meilleure=20impl=C3=A9mentatio?= =?UTF-8?q?n=20du=20CITS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/règles/base.yaml | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/source/règles/base.yaml b/source/règles/base.yaml index 3e80e8738..cacf08933 100644 --- a/source/règles/base.yaml +++ b/source/règles/base.yaml @@ -1001,6 +1001,25 @@ formule: 2.5 +- espace: contrat salarié . CITS + nom: non abattu + formule: + multiplication: + assiette: assiette cotisations sociales + taux: 4% + +- espace: contrat salarié . CITS + nom: abattement mensuel par salarié + formule: + multiplication: + assiette: entreprise . taxe sur les salaires . abattement associations + taux: 1 / entreprise . effectif + facteur: 1 / 12 + note: | + Cette variable révèle deux lacunes de notre modélisation : + - on ne peut pas spécifier plusieurs salariés à l'entreprise, et donc calculer correctement le CITS. On fait donc comme si l'unique salarié simulé était le salarié type, multiplié. + - on ne gère pas la conversion entre les périodes temporelles. + On les résoud en exploitant à tort les capacités du mécanisme multiplication. - espace: contrat salarié nom: CITS @@ -1018,10 +1037,12 @@ applicable si: entreprise . association non lucrative non applicable si: assiette cotisations sociales > plafond CITS + note: Le CITS est un crédit sur la taxe sur les salaires. Celle-ci est abattue de ~20k. Le CITS est lui-même abattu de ~20k ! Quel intérêt, pourquoi ne pas simplement supprimer l'abattement initial ? Parce que dans certains cas, une entreprise d'un salarié au SMIC, 4% des rémunérations annuelles < abattement de 20k. Donc le crédit est nul. Donc la taxe sur les salaires reste abattue comme initialement prévu. + formule: - multiplication: - assiette: assiette cotisations sociales - taux: 4% + allègement: + assiette: non abattu + abattement: abattement mensuel par salarié exemples: - nom: SMIC @@ -1908,8 +1929,14 @@ formule: contrat salarié . taxe sur les salaires . barème annuel * effectif +- espace: entreprise . taxe sur les salaires + nom: abattement associations + formule: 20507 + + - espace: entreprise . taxe sur les salaires nom: montant annuel + formule: allègement: assiette: barème annuel @@ -1917,10 +1944,11 @@ décote: plafond: 2040 taux: 75% - # Attention : l'abattement n'est valable que pour les organismes à but non lucratif. - # Il n'est pas conditionné ici car on réserve pour l'instant la taxe sur les salaires aux associations 1901 - abattement: 20507 + abattement: abattement associations + note: | + Attention : l'abattement n'est valable que pour les organismes à but non lucratif. + Il n'est pas conditionné ici car on réserve pour l'instant la taxe sur les salaires aux associations 1901 - espace: contrat salarié . taxe sur les salaires nom: montant annuel formule: entreprise . taxe sur les salaires . montant annuel / entreprise . effectif From 6f32863a1a54ea2fb5ab2838f8d3898173f3dd97 Mon Sep 17 00:00:00 2001 From: mama Date: Mon, 19 Feb 2018 16:11:33 +0100 Subject: [PATCH 15/35] =?UTF-8?q?:hammer:=20Ajout=20d'une=20note=20de=20li?= =?UTF-8?q?mitations=20=C3=A0=20la=20taxe=20salaires?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/règles/base.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/règles/base.yaml b/source/règles/base.yaml index cacf08933..a50986f4a 100644 --- a/source/règles/base.yaml +++ b/source/règles/base.yaml @@ -1900,7 +1900,7 @@ - espace: contrat salarié . taxe sur les salaires nom: barème annuel références: - description: https://www.service-public.fr/professionnels-entreprises/vosdroits/F22576 + barème: https://www.service-public.fr/professionnels-entreprises/vosdroits/F22576 formule: barème: @@ -1959,6 +1959,9 @@ applicable si: entreprise . association non lucrative formule: montant annuel / 12 + + note: Cette implémentation de la taxe sur les salaires est spécifique aux associations à but non lucratif, elle est donc largement simplifiée. Plein d'autres organisations sont concernées, en fonction de la TVA qu'elles paient. Les associations y sont assujetties automatiquement. + exemples: - nom: non applicable par défaut situation: @@ -1971,6 +1974,8 @@ montant annuel: 2639.16 valeur attendue: 219.93 + références: + fiche: https://www.service-public.fr/professionnels-entreprises/vosdroits/F22576 - espace: contrat salarié nom: versement transport From 75e5aa705908363187e392d3e233f4b6dd7806a0 Mon Sep 17 00:00:00 2001 From: mama Date: Mon, 19 Feb 2018 16:33:18 +0100 Subject: [PATCH 16/35] :sparkles: :hammer: Nettoyage, notes -> note --- source/components/rule/Rule.js | 3 +++ source/règles/base.yaml | 42 ++++++++++++---------------------- 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/source/components/rule/Rule.js b/source/components/rule/Rule.js index 3179d2d04..228dc45cb 100644 --- a/source/components/rule/Rule.js +++ b/source/components/rule/Rule.js @@ -56,6 +56,9 @@ export default class Rule extends Component { rule={situationOrExampleRule} showValues={situationExists} /> + {rule.note && ( +
{createMarkdownDiv(rule.note)}
+ )} = 20 employés avant 2015, mais le résultat était le même. - explication: | - Si l'entreprise a un effectif supérieur ou égal à 20 salariés, elle doit verser 0,50 % sur la totalité des salaires. Pour les entreprises de moins de 20 salariés et pour les employeurs occupés aux activités mentionnées aux 1° à 4° de l'article L. 722-1 du code rural et de la pêche maritime et les coopératives mentionnées à l'article L. 521-1 du même code, la cotisation est de 0,10 % des salaires limités au plafond de sécurité sociale (tranche A). Intégrée aux cotisations de sécurité sociale, elle est recouvrée par les Urssaf pour le financement des allocations logement versées par les caisses d'allocations familiales. Les employeurs qui ont atteint ou dépassé pour la première fois, au titre des années 2008 à 2012, le seuil de 20 salariés ont été dispensés de l’ancien Fnal supplémentaire pendant 3 ans. La contribution était ensuite progressivement appelée sur les 3 années suivantes. Un dispositif est mis en place pour 2016, 2017 et 2018. Les employeurs qui atteignent ou dépassent au titre de ces années l'effectif de 20 salariés continuent d'appliquer le taux de 0,10 % pendant trois ans (suite au franchissement de seuil). Cette modalité n'implique pas d'adaptation du calcul du coefficient de la réduction générale. Le seuil de 20 salariés s'apprécie au 31 décembre et la modification de la cotisation est effective au 1er avril suivant. formule: multiplication: assiette: assiette cotisations sociales @@ -1778,10 +1765,9 @@ impôt: oui références: fiche: https://www.service-public.fr/professionnels-entreprises/vosdroits/F22583 - notes: | + note: | L'employeur a le choix entre verser cet impôt à un "organisme du 1 % patronal" agréé, investir la somme dans le logement de ses salariés, ou accorder à eux et leur famille des prêts de construction à taux réduit. - applicable si: entreprise . effectif >= 20 formule: multiplication: @@ -1817,7 +1803,7 @@ description: https://www.service-public.fr/professionnels-entreprises/vosdroits/F22574 csa: http://www.opcalia.com/employeurs/financer-la-formation-et-lapprentissage/taxe-dapprentissage/contribution-supplementaire-a-lapprentissage-csa/ - notes: Taxe complexe, comportant notamment des exonérations non prises en compte ici. + note: Taxe complexe, comportant notamment des exonérations non prises en compte ici. non applicable si: entreprise . association non lucrative # L'association a but non lucratif ne paie pas d'IS de droit commun article 206 du Code général des impôts From 1d35d76807545bf0fc61ad72f03e055307e50dad Mon Sep 17 00:00:00 2001 From: mama Date: Mon, 19 Feb 2018 16:33:51 +0100 Subject: [PATCH 17/35] =?UTF-8?q?:art:=20Am=C3=A9lioration=20de=20la=20pag?= =?UTF-8?q?e=20r=C3=A8gle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit En-tête de description moins austère Ajout des notes d'implémentation --- source/components/rule/Rule.css | 14 ++++++-------- source/components/rule/Rule.js | 5 ++++- source/webpack.config.js | 4 +--- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/source/components/rule/Rule.css b/source/components/rule/Rule.css index 68062c90a..c1133d57e 100644 --- a/source/components/rule/Rule.css +++ b/source/components/rule/Rule.css @@ -65,8 +65,8 @@ } #meta-content { - border-top: 1px solid rgba(51, 51, 80, 0.2); - background: rgba(51, 51, 80, 0.03); + border: 1px solid rgba(41, 117, 209, 0.3); + background: rgba(41, 117, 209, 0.08); padding: 1em; display: flex; justify-content: flex-start; @@ -78,12 +78,6 @@ font-size: 95%; } -#rule h3 { - font-size: 100%; - font-weight: 400; - margin: 0.4em 0; -} - #destinataire { text-align: center; max-width: 25%; @@ -127,3 +121,7 @@ margin: 3em auto 0; display: block; } + +#notes { + color: #666; +} diff --git a/source/components/rule/Rule.js b/source/components/rule/Rule.js index 228dc45cb..8910f84d2 100644 --- a/source/components/rule/Rule.js +++ b/source/components/rule/Rule.js @@ -57,7 +57,10 @@ export default class Rule extends Component { showValues={situationExists} /> {rule.note && ( -
{createMarkdownDiv(rule.note)}
+
+

Note:

+ {createMarkdownDiv(rule.note)} +
)} Date: Wed, 21 Feb 2018 11:19:48 +0100 Subject: [PATCH 18/35] Liens complets sur les pages /regle Auparavant, un clic sur le 'breadcrumb' ou sur la list des regles attachees pouvait mener a une desambiguation --- source/components/rule/Rule.js | 53 ++++++++++++++++++++-------------- source/règles/base.yaml | 4 +++ 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/source/components/rule/Rule.js b/source/components/rule/Rule.js index 8910f84d2..30c4df99d 100644 --- a/source/components/rule/Rule.js +++ b/source/components/rule/Rule.js @@ -1,5 +1,5 @@ import React, { Component } from 'react' -import { isEmpty, path } from 'ramda' +import { isEmpty, path, last } from 'ramda' import { connect } from 'react-redux' import './Rule.css' import { capitalise0 } from '../../utils' @@ -74,7 +74,7 @@ export default class Rule extends Component { } /> {!isEmpty(namespaceRules) && ( - + )} {this.renderReferences(rule)} @@ -92,7 +92,7 @@ export default class Rule extends Component { ) : null } -let NamespaceRules = withColours(({ namespaceRules, rule, colours }) => ( +let NamespaceRulesList = withColours(({ namespaceRules, rule, colours }) => (

Règles attachées @@ -107,7 +107,7 @@ let NamespaceRules = withColours(({ namespaceRules, rule, colours }) => ( color: colours.textColourOnWhite, textDecoration: 'underline' }} - to={'/règle/' + encodeRuleName(r.name)} + to={'/règle/' + encodeRuleName(r.dottedName)} > {r.name} @@ -139,24 +139,33 @@ let RuleMeta = ({ ns, type, description, question, rule, name }) => ( export let Namespace = withColours(({ ns, colours }) => (
    - {ns.split(' . ').map(fragment => ( -
  • - - {capitalise0(fragment)} - -