Merge pull request #825 from betagouv/mécanisme-recalcul

Mécanisme recalcul
branche-desactivée
Johan Girod 2020-02-26 10:53:41 +01:00 committed by GitHub
commit 38372927be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 204 additions and 30 deletions

View File

@ -1006,9 +1006,12 @@ dirigeant . indépendant . cotisations et contributions . exonérations . ZFU:
formule:
multiplication:
assiette: cotisations . maladie
# TODO : ceci n'est pas bon (le plafond est sur le revenu exonéré, et est proratisé en début / fin d'éxo)
taux: taux
plafond: 3042 heures/an * SMIC horaire
# TODO : Le plafond est proratisé en début / fin d'exonération
plafond:
recalcul:
avec:
indépendant . revenu net de cotisations: 3042 heures/an * SMIC horaire
dirigeant . indépendant . cotisations et contributions . exonérations . âge:
question: Bénéficiez-vous du dispositif d'exonération "âge"

View File

@ -90,8 +90,9 @@ impôt . revenu imposable . abattement contrat court:
- méthode de calcul . taux neutre
- contrat salarié
- contrat salarié . CDD
- contrat salarié . CDD . durée contrat <= 2
formule: 50% * contrat salarié . SMIC temps plein . net imposable * 1 mois
- contrat salarié . CDD . durée contrat <= 2 mois
formule:
arrondi: 50% * contrat salarié . SMIC temps plein . net imposable * 1 mois
note: Cet abattement s'applique aussi pour les conventions de stage ou les contrats de mission (intérim) de moins de 2 mois.
références:
Bofip - dispositions spécifiques aux contrats courts: https://bofip.impots.gouv.fr/bofip/11252-PGP.html?identifiant=BOI-IR-PAS-20-20-30-10-20180515

View File

@ -1217,9 +1217,13 @@ contrat salarié . SMIC temps plein:
décret: https://www.legifrance.gouv.fr/affichTexte.do?cidTexte=JORFTEXT000037833206
contrat salarié . SMIC temps plein . net imposable:
description: Montant du SMIC net imposable
formule: 1247.55 €/mois
note: Ce montant est codé en dur, il faudrait le calculer à partir du montant du SMIC brut
titre: SMIC net imposable
description: Montant du SMIC net imposable pour un temps plein.
formule:
recalcul:
règle: rémunération . net imposable . base
avec:
rémunération . brut de base: SMIC temps plein
références:
barème PAS: https://bofip.impots.gouv.fr/bofip/11255-PGP.html
@ -1753,10 +1757,11 @@ contrat salarié . statut JEI . exonération de cotisations:
unité: €/mois
formule:
# TODO - le plafonnement à 4,5 SMIC, précalculé pour 09/2017; cette approximation n'est bien sûr pas satisfaisante,
# il faut fournir un mécanisme "exonération" capable de recalculer une règle en introduisant un plafond
encadrement:
plafond: 1634.39 €/mois
plafond:
recalcul:
avec:
rémunération . brut de base: 4.5 * SMIC
valeur:
somme:
- allocations familiales

View File

@ -96,6 +96,14 @@ arrondi:
description: |
On arrondi à l'euro le plus proche
recalcul:
type: numeric
description: >-
Relance le calcul d'une règle dans une situation différente de la situation
courante. Permet par exemple de calculer le montant des cotisations au
niveau du SMIC, même si le salaire est plus élevé dans la situation
actuelle.
##########################################
# Ce qu'on appelle aujourd'hui des RuleProp
# Et qui deviendront des mécanismes classiques normalement par la suite #TODO

View File

@ -0,0 +1,41 @@
import RuleLink from 'Components/RuleLink'
import { makeJsx } from 'Engine/evaluation'
import React from 'react'
import { Trans } from 'react-i18next'
import { DottedName } from 'Types/rule'
import { Node } from './common'
export default function Recalcul(nodeValue, explanation) {
return (
<Node
classes="mecanism recalcul"
name="recalcul"
value={nodeValue}
unit={explanation.unit}
child={
<>
{explanation.règle && (
<Trans i18nKey="calcul-avec">
Calcul de <RuleLink dottedName={explanation.règle} /> avec :
</Trans>
)}
<ul>
{Object.keys(explanation.amendedSituation).map(dottedName => (
<li
key={dottedName}
css={`
.node.inlineExpression {
display: inline !important;
}
`}
>
<RuleLink dottedName={dottedName as DottedName} /> ={' '}
{makeJsx(explanation.amendedSituation[dottedName])}
</li>
))}
</ul>
</>
}
/>
)
}

View File

@ -36,6 +36,7 @@ import Allègement from './mecanismViews/Allègement'
import { Node, SimpleRuleLink } from './mecanismViews/common'
import InversionNumérique from './mecanismViews/InversionNumérique'
import Product from './mecanismViews/Product'
import Recalcul from './mecanismViews/Recalcul'
import Somme from './mecanismViews/Somme'
import { disambiguateRuleReference, findRuleByDottedName } from './rules'
import { anyNull, val } from './traverse-common-functions'
@ -286,6 +287,70 @@ export let mecanismInversion = dottedName => (recurse, k, v) => {
}
}
export let mecanismRecalcul = dottedNameContext => (recurse, k, v) => {
let evaluate = (currentCache, situationGate, parsedRules, node) => {
let defaultRuleToEvaluate = dottedNameContext
let nodeToEvaluate = recurse(node?.règle ?? defaultRuleToEvaluate)
let cache = { _meta: currentCache._meta, _metaInRecalcul: true } // Create an empty cache
let amendedSituation = Object.fromEntries(
Object.keys(node.avec).map(dottedName => [
disambiguateRuleReference(
parsedRules,
{ dottedName: dottedNameContext },
dottedName
),
node.avec[dottedName]
])
)
if (currentCache._metaInRecalcul) {
return defaultNode(false)
}
let amendedSituationGate = dottedName =>
Object.keys(amendedSituation).includes(dottedName)
? evaluateNode(
cache,
amendedSituationGate,
parsedRules,
recurse(amendedSituation[dottedName])
).nodeValue
: situationGate(dottedName)
let evaluatedNode = evaluateNode(
cache,
amendedSituationGate,
parsedRules,
nodeToEvaluate
)
return {
...evaluatedNode,
explanation: {
...evaluateNode.explanation,
unit: evaluatedNode.unit,
amendedSituation: Object.fromEntries(
Object.keys(amendedSituation).map(dottedName => [
dottedName,
evaluateNode(
cache,
amendedSituationGate,
parsedRules,
recurse(amendedSituation[dottedName])
)
])
)
},
jsx: Recalcul
}
}
return {
...v,
evaluate
}
}
export let mecanismSum = (recurse, k, v) => {
let explanation = v.map(recurse)

View File

@ -21,7 +21,7 @@ export default (recurse, k, v) => {
const child = evaluateNode(cache, situation, parsedRules, node.explanation)
const nodeValue =
child.nodeValue === null ? null : Math.round(child.nodeValue)
return { ...node, nodeValue, explanation: child }
return { ...node, unit: child.unit, nodeValue, explanation: child }
}
return {

View File

@ -62,6 +62,9 @@ const evaluate = (cache, situation, parsedRules, node) => {
let evaluateAttribute = evaluateNode.bind(null, cache, situation, parsedRules)
const valeur = evaluateAttribute(node.explanation.valeur)
let plafond = evaluateAttribute(node.explanation.plafond)
if (val(plafond) === false) {
plafond = objectShape.plafond
}
let plancher = evaluateAttribute(node.explanation.plancher)
if (valeur.unit) {
try {

View File

@ -35,6 +35,7 @@ import {
mecanismOneOf,
mecanismOnePossibility,
mecanismProduct,
mecanismRecalcul,
mecanismReduction,
mecanismSum,
mecanismSynchronisation
@ -103,6 +104,7 @@ Cela vient probablement d'une erreur dans l'indentation
...statelessParseFunction,
'une possibilité': mecanismOnePossibility(rule.dottedName),
'inversion numérique': mecanismInversion(rule.dottedName),
recalcul: mecanismRecalcul(rule.dottedName),
filter: () =>
parseReferenceTransforms(
rules,

View File

@ -217,6 +217,7 @@ autoentrepreneur:
titre: Auto-entrepeneur
back: Resume simulation
barème: scale
calcul-avec: 'Calculation from <1></1>with :'
cancelExample: Back to your situation
car dépend de: because it depends on
cible: target

View File

@ -713,16 +713,10 @@ contrat salarié . SMIC temps plein:
titre.en: full-time mimimum wage (SMIC)
titre.fr: SMIC temps plein
contrat salarié . SMIC temps plein . net imposable:
description.en: Amount of the net taxable minimum wage (SMIC net imposable)
description.fr: Montant du SMIC net imposable
note.en: >-
[automatic] This amount is hard-coded, it should be calculated from the
amount of the gross minimum wage.
note.fr: >-
Ce montant est codé en dur, il faudrait le calculer à partir du montant du
SMIC brut
titre.en: net taxable
titre.fr: net imposable
description.en: '[automatic] Amount of the net taxable SMIC for a full-time employee.'
description.fr: Montant du SMIC net imposable pour un temps plein.
titre.en: '[automatic] minimum net taxable income'
titre.fr: SMIC net imposable
contrat salarié . aides employeur:
description.en: >
Some aids can be requested by the employer to help hires.

View File

@ -1,5 +1,11 @@
cotisation retraite:
demie part:
formule:
arrondi: 50% * 100.2€
exemples:
- valeur attendue: 50
Arrondi:
formule:
arrondi: cotisation retraite

View File

@ -1,21 +1,38 @@
Plafonnement:
plafonnement:
formule:
encadrement:
valeur: 1000
plafond: 250
exemples:
- nom:
situation:
valeur attendue: 250
- valeur attendue: 250
Plancher:
plafonnement inactif:
formule:
encadrement:
valeur: 1000
plafond: false
exemples:
- valeur attendue: 1000
plafonnement reference inactive:
formule:
encadrement:
valeur: 1000
plafond: plafond
exemples:
- valeur attendue: 1000
plafonnement reference inactive . plafond:
formule: non
plancher:
formule:
encadrement:
valeur: 1000
plancher: 2500
exemples:
- nom:
situation:
valeur attendue: 2500
- valeur attendue: 2500

View File

@ -0,0 +1,28 @@
salaire brut:
formule: 2000
salaire net:
formule: 0.5 * salaire brut
SMIC brut:
formule: 1000
SMIC net:
formule:
recalcul:
règle: salaire net
avec:
salaire brut: SMIC brut
exemples:
- valeur attendue: 500
Recalcule règle courante:
formule:
encadrement:
valeur: 10% * salaire brut
plafond:
recalcul:
avec:
salaire brut: 100
exemples:
- valeur attendue: 10

View File

@ -190,7 +190,7 @@ exports[`calculate simulations-rémunération-dirigeant: Indépendant - échell
exports[`calculate simulations-salarié: JEI 1`] = `"[3440,0,0,3000,2353,2187]"`;
exports[`calculate simulations-salarié: JEI 2`] = `"[26710,0,0,20000,15969,10681]"`;
exports[`calculate simulations-salarié: JEI 2`] = `"[26635,0,0,20000,15969,10681]"`;
exports[`calculate simulations-salarié: JEI 3`] = `"[4517,0,0,4000,3141,2741]"`;