diff --git a/source/components/simulationConfigs/indépendant.yaml b/source/components/simulationConfigs/indépendant.yaml index 080879745..1478bf954 100644 --- a/source/components/simulationConfigs/indépendant.yaml +++ b/source/components/simulationConfigs/indépendant.yaml @@ -5,6 +5,7 @@ objectifs: questions: - entreprise . charges - entreprise . catégorie d'activité + - entreprise . année d'activité questions à l'affiche: Charges: entreprise . charges diff --git a/source/engine/mecanismViews/BarèmeContinu.js b/source/engine/mecanismViews/BarèmeContinu.js index 4c6a0e885..c556faea7 100644 --- a/source/engine/mecanismViews/BarèmeContinu.js +++ b/source/engine/mecanismViews/BarèmeContinu.js @@ -5,7 +5,7 @@ import './Barème.css' import { ShowValuesConsumer } from 'Components/rule/ShowValuesContext' import withLanguage from 'Components/utils/withLanguage' import { BarèmeAttributes } from './Barème' -import { toPairs } from 'ramda' +import { sortObjectByKeys } from 'Engine/mecanismViews/common' let Comp = withLanguage(function Barème({ nodeValue, explanation }) { return ( @@ -30,7 +30,7 @@ let Comp = withLanguage(function Barème({ nodeValue, explanation }) { - {toPairs(explanation.points).map(([seuil, taux]) => ( + {sortObjectByKeys(explanation.points).map(([seuil, taux]) => ( {seuil} {taux} @@ -46,6 +46,9 @@ let Comp = withLanguage(function Barème({ nodeValue, explanation }) { {(100 * explanation.taux).toFixed(1)} % )} +

+ Ce barème ne retourne que le taux. +

} /> diff --git a/source/engine/mecanismViews/common.js b/source/engine/mecanismViews/common.js index ddebbeee1..64021f30b 100644 --- a/source/engine/mecanismViews/common.js +++ b/source/engine/mecanismViews/common.js @@ -1,7 +1,7 @@ import classNames from 'classnames' import withLanguage from 'Components/utils/withLanguage' import withSitePaths from 'Components/utils/withSitePaths' -import { compose, contains } from 'ramda' +import { sort, compose, contains, toPairs, pipe } from 'ramda' import React, { Component } from 'react' import { Trans } from 'react-i18next' import { connect } from 'react-redux' @@ -128,3 +128,9 @@ export function SimpleRuleLink({ rule: { dottedName, title, name } }) { ) } + +export let sortObjectByKeys = pipe( + toPairs, + // we don't rely on the sorting of objects + sort(([k1], [k2]) => k1 - k2) +) diff --git a/source/engine/mecanisms.js b/source/engine/mecanisms.js index dac39387b..750bd602e 100644 --- a/source/engine/mecanisms.js +++ b/source/engine/mecanisms.js @@ -671,6 +671,7 @@ export let mecanismProduct = (recurse, k, v) => { evaluate = evaluateObject(objectShape, effect) let jsx = (nodeValue, explanation) => ( + // The rate and factor and threshold are given defaut neutral values. If there is nothing to explain, don't display them at all { {makeJsx(explanation.assiette)} - {(explanation.taux.nodeValue != 1 || - explanation.taux.category == 'calcExpression') && ( + {explanation.taux.explanation && (
  • taux:{' '} @@ -692,8 +692,7 @@ export let mecanismProduct = (recurse, k, v) => { {makeJsx(explanation.taux)}
  • )} - {(explanation.facteur.nodeValue != 1 || - explanation.facteur.category == 'calcExpression') && ( + {explanation.facteur.explanation && (
  • facteur:{' '} @@ -701,7 +700,7 @@ export let mecanismProduct = (recurse, k, v) => { {makeJsx(explanation.facteur)}
  • )} - {explanation.plafond.nodeValue != Infinity && ( + {explanation.plafond.explanation && (
  • plafond:{' '} @@ -852,12 +851,14 @@ export let mecanismContinuousScale = (recurse, k, v) => { // 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 + nodeValue = a * val(assiette) + b, + taux = nodeValue / val(assiette) return reduced({ - nodeValue, + nodeValue: + v['retourne seulement le taux'] === 'oui' ? taux : nodeValue, additionalExplanation: { seuil: val(assiette) / val(multiplicateur), - taux: nodeValue / val(assiette) + taux } }) } diff --git a/source/engine/treatVariable.js b/source/engine/treatVariable.js index 48f841eb8..a5bcd59ae 100644 --- a/source/engine/treatVariable.js +++ b/source/engine/treatVariable.js @@ -1,9 +1,13 @@ -import React from 'react'; -import { Trans } from 'react-i18next'; -import { evaluateNode, makeJsx, rewriteNode } from './evaluation'; -import { Leaf, Node } from './mecanismViews/common'; -import { disambiguateRuleReference, findParentDependency, findRuleByDottedName } from './rules'; -import { getSituationValue } from './variables'; +import React from 'react' +import { Trans } from 'react-i18next' +import { evaluateNode, makeJsx, rewriteNode } from './evaluation' +import { Leaf, Node } from './mecanismViews/common' +import { + disambiguateRuleReference, + findParentDependency, + findRuleByDottedName +} from './rules' +import { getSituationValue } from './variables' export let treatVariable = (rules, rule, filter) => parseResult => { let evaluate = (cache, situation, parsedRules, node) => { @@ -41,7 +45,7 @@ export let treatVariable = (rules, rule, filter) => parseResult => { ) return cache[cacheName] } - const variableScore = variable.defaultValue ? 1 : 2; + const variableScore = variable.defaultValue ? 1 : 2 // SITUATION 1 : La variable est directement renseignée if (situationValue != null) return cacheAndNode(situationValue, {}) @@ -135,10 +139,7 @@ export let treatVariableTransforms = (rules, rule) => parseResult => { // Exceptions if (!rule.période && !inlinePeriodTransform) { - if ( - ruleToTransform.période == 'flexible' && - !cache.checkingParentDependencies.includes(rule.dottedName) - ) + if (ruleToTransform.période == 'flexible') throw new Error( `Attention, une variable sans période, ${ rule.dottedName @@ -153,13 +154,12 @@ export let treatVariableTransforms = (rules, rule) => parseResult => { if (!ruleToTransform.période) return filteredNode let environmentPeriod = situation('période') || 'mois' let callingPeriod = - inlinePeriodTransform || - (rule.période === 'flexible' ? environmentPeriod : rule.période) + inlinePeriodTransform || + (rule.période === 'flexible' ? environmentPeriod : rule.période) let calledPeriod = - ruleToTransform.période === 'flexible' - ? environmentPeriod - : ruleToTransform.période - + ruleToTransform.période === 'flexible' + ? environmentPeriod + : ruleToTransform.période let transformedNodeValue = callingPeriod === 'mois' && calledPeriod === 'année' diff --git a/source/règles/base.yaml b/source/règles/base.yaml index 074a1b9f6..75a02a481 100644 --- a/source/règles/base.yaml +++ b/source/règles/base.yaml @@ -846,9 +846,8 @@ description: Le plafond de Sécurité sociale est le montant maximum des rémunérations à prendre en compte pour le calcul de certaines cotisations. période: mois formule: 3377 - note: Prévision basée sur le rapport `Les comptes de la sécurité sociale, résultats 2017, prévisions 2018 et 2019` références: - estimation pour 2019: https://lentreprise.lexpress.fr/rh-management/remuneration-salaire/plafond-de-la-securite-sociale-pass-40-526-euros-en-2019_2037358.html + 2019: https://www.urssaf.fr/portail/home/actualites/toute-lactualite-employeur/plafond-de-la-securite-social-1.html arrêté: https://www.legifrance.gouv.fr/affichTexte.do?cidTexte=JORFTEXT000036171732 - espace: contrat salarié @@ -2648,13 +2647,34 @@ période: flexible par défaut: 0 format: euros - - espace: entreprise nom: charges non déductibles applicable si: autoentrepreneur formule: charges période: flexible +- espace: indépendant + nom: réduction ACRE + applicable si: entreprise . année d'activité = 'première année' + période: flexible + formule: + multiplication: + assiette: cotisations - cotisations . retraite complémentaire + taux: taux ACRE + +- espace: indépendant + nom: taux ACRE + période: flexible + formule: + barème continu: + assiette: revenu net de cotisations + multiplicateur: plafond sécurité sociale temps plein + points: + 0: 100% + 0.75: 100% + 1: 0% + retourne seulement le taux: oui + - espace: indépendant nom: revenu net de cotisations titre: Revenu net en tant qu'indépendant @@ -2662,7 +2682,7 @@ C'est le revenu professionel du travailleur indépendant. - Attention, **notre calcul est fait au régime de croisière** : l'indépendant qui se lance paiera pendant ses 2 premières années un forfait relativement réduit de cotisations sociales. Il devra ensuite régulariser cette situation par rapport au revenu qu'il a vraiment touché. + Attention, **notre calcul est fait au régime de croisière** : l'indépendant qui se lance paiera pendant ses 2 premières années un forfait relativement réduit de cotisations sociales. Il devra ensuite régulariser cette situation par rapport au revenu qu'il a vraiment touché. Il faut donc voir ce calcul comme *le montant qui devra de toute façon être payé* à court terme après 2 ans d'exercice. formule: @@ -2713,6 +2733,11 @@ par défaut: non question: Activité à la sécurité sociale des indépendants ? +- espace: indépendant + nom: cotisations à payer + période: flexible + formule: cotisations - réduction ACRE + - espace: indépendant nom: cotisations période: flexible @@ -2732,7 +2757,7 @@ période: flexible formule: somme: - - cotisations + - cotisations à payer - formation professionnelle - CSG et CRDS diff --git a/test/mécanismes/barème-continu.yaml b/test/mécanismes/barème-continu.yaml index b72126f90..965368a4f 100644 --- a/test/mécanismes/barème-continu.yaml +++ b/test/mécanismes/barème-continu.yaml @@ -38,3 +38,29 @@ valeur attendue: 63.5 +- nom: base deux + format: nombre + formule: 300 + +- nom: assiette deux + format: nombre + +- test: Retour de taux, pas d'assiette + formule: + barème continu: + assiette: assiette deux + multiplicateur: base deux + points: + 0: 100% + 0.75: 100% + 1: 0% + retourne seulement le taux: oui + exemples: + - nom: Premier intervale + situation: + assiette deux: 10 + valeur attendue: 0.026 + - nom: Deuxième intervale + situation: + assiette deux: 120 + valeur attendue: 3.792