⚙️ Mécanisme recalcul

Utilisé pour le plafond des exonérations JEI et ZFU.

MAJ d'un test de non-regression car le plafonnement JEI n'était plus à
jour.
pull/825/head
Maxime Quandalle 2020-01-02 15:39:31 +01:00
parent e5a51e9c10
commit bfcf165c02
No known key found for this signature in database
GPG Key ID: 428641C03D29CA10
10 changed files with 166 additions and 19 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

@ -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

@ -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

@ -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]"`;