diff --git a/site/source/design-system/field/NumberField.tsx b/site/source/design-system/field/NumberField.tsx index 0de8493e5..1a1255b60 100644 --- a/site/source/design-system/field/NumberField.tsx +++ b/site/source/design-system/field/NumberField.tsx @@ -142,7 +142,7 @@ export default function NumberField(props: NumberFieldProps) { )} - {props.label && ( + {props.label && !props.small && ( {props.label} )} diff --git a/site/source/locales/ui-en.yaml b/site/source/locales/ui-en.yaml index db8f8e82e..cf67e7da6 100644 --- a/site/source/locales/ui-en.yaml +++ b/site/source/locales/ui-en.yaml @@ -269,14 +269,8 @@ Revenu disponible: Disposable income Revenu du dirigeant par statut: Executive income by status Revenu net mensuel après impôts: Net monthly income after tax Règles de calculs: Calculation rules -Réduction annuelle: Annual discount Réduction générale: General reduction -"Réduction générale mois par mois :": "General discount month by month :" -Réduction mensuelle: Monthly discount -Réduction mois par mois: Monthly discount Régime d'imposition: Taxation system -Régularisation annuelle: Annual adjustment -Régularisation progressive: Progressive regularization Régularisaton: Regularization Réinitialiser: Reset Réinitialiser la situation enregistrée: Reset registered situation @@ -337,7 +331,6 @@ Tout plier: Fold everything Tout réinitialiser: Reset all Travailleurs Non Salariés (TNS): Self-employed workers (TNS) Type: Type -Type de régularisation: Type of adjustment URSSAF Mon entreprise, accéder à la page d'accueil: URSSAF Mon entreprise, go to home page Un <1>capital « orphelin » est versé aux <4>enfants des travailleurs indépendants décédés, sous certaines conditions.: An <1>"orphan" capital is paid to the <4>children of deceased @@ -1480,12 +1473,39 @@ pages: shortname: Liberal profession title: Income simulator for self-employed professionals réduction-générale: + legend: Employee's gross salary and applicable general reduction meta: description: Estimate of the amount of the general reduction in employer contributions (RGCP). This reduction applies to salaries below 1.6 times the SMIC. title: General reduction + month-by-month: + caption: "General discount month by month :" + option: + aria-label: Adds fields for adjusting remuneration (overtime) + label: + heures-complémentaires: Overtime + heures-supplémentaires: Overtime + popover: "<0>The number of hours of overtime or complementary work is used to + calculate the general reduction: the gross remuneration is compared + with the SMIC increased by the number of hours of overtime or + complementary work.<1>If you have answered the question on + overtime or complementary hours, the value will be overwritten by the + value you enter month by month." + title: More options (overtime) + régularisation: + annuelle: Annual adjustment + progressive: Progressive regularization + type: Type of adjustment + répartition: + chômage: of which unemployment + retraite: IRC + urssaf: URSSAF shortname: General reduction + tab: + month: Monthly discount + month-by-month: Monthly discount + year: Annual discount title: General contribution reduction simulator warnings: JEI: The general reduction cannot be combined with the Young Innovative Company diff --git a/site/source/locales/ui-fr.yaml b/site/source/locales/ui-fr.yaml index bf797a66c..ba0ead6be 100644 --- a/site/source/locales/ui-fr.yaml +++ b/site/source/locales/ui-fr.yaml @@ -284,14 +284,8 @@ Revenu disponible: Revenu disponible Revenu du dirigeant par statut: Revenu du dirigeant par statut Revenu net mensuel après impôts: Revenu net mensuel après impôts Règles de calculs: Règles de calculs -Réduction annuelle: Réduction annuelle Réduction générale: Réduction générale -"Réduction générale mois par mois :": "Réduction générale mois par mois :" -Réduction mensuelle: Réduction mensuelle -Réduction mois par mois: Réduction mois par mois Régime d'imposition: Régime d'imposition -Régularisation annuelle: Régularisation annuelle -Régularisation progressive: Régularisation progressive Régularisaton: Régularisaton Réinitialiser: Réinitialiser Réinitialiser la situation enregistrée: Réinitialiser la situation enregistrée @@ -352,7 +346,6 @@ Tout plier: Tout plier Tout réinitialiser: Tout réinitialiser Travailleurs Non Salariés (TNS): Travailleurs Non Salariés (TNS) Type: Type -Type de régularisation: Type de régularisation URSSAF Mon entreprise, accéder à la page d'accueil: URSSAF Mon entreprise, accéder à la page d'accueil Un <1>capital « orphelin » est versé aux <4>enfants des travailleurs indépendants décédés, sous certaines conditions.: Un <1>capital « orphelin » est versé aux <4>enfants des travailleurs @@ -1574,12 +1567,39 @@ pages: shortname: Profession libérale title: Simulateur de revenus pour profession libérale réduction-générale: + legend: Salaire brut du salarié et réduction générale applicable meta: description: Estimation du montant de la réduction générale des cotisations patronales (RGCP). Cette réduction est applicable pour les salaires inférieurs à 1,6 fois le SMIC. title: Réduction générale + month-by-month: + caption: "Réduction générale mois par mois :" + option: + aria-label: Ajoute des champs pour ajuster la rémunération (heures supplémentaires) + label: + heures-complémentaires: Heures complémentaires + heures-supplémentaires: Heures supplémentaires + popover: "<0>Le nombre d'heures supplémentaires et complémentaires est utilisé + dans le calcul de la réduction générale : la rémunération brute est + comparée au montant du SMIC majoré de ce nombre d'heures + supplémentaires ou complémentaires.<1>Si vous avez répondu à la + question sur les heures supplémentaires ou complémentaires, la valeur + sera écrasée par celle que vous saisissez mois par mois." + title: Plus d'options (heures supplémentaires) + régularisation: + annuelle: Régularisation annuelle + progressive: Régularisation progressive + type: Type de régularisation + répartition: + chômage: dont chômage + retraite: IRC + urssaf: URSSAF shortname: Réduction générale + tab: + month: Réduction mensuelle + month-by-month: Réduction mois par mois + year: Réduction annuelle title: Simulateur de réduction générale des cotisations warnings: JEI: La réduction générale n'est pas cumulable avec l'exonération Jeune diff --git a/site/source/pages/simulateurs/reduction-generale/RéductionGénérale.tsx b/site/source/pages/simulateurs/reduction-generale/RéductionGénérale.tsx index 4bb9ae6fb..6fb68782a 100644 --- a/site/source/pages/simulateurs/reduction-generale/RéductionGénérale.tsx +++ b/site/source/pages/simulateurs/reduction-generale/RéductionGénérale.tsx @@ -31,6 +31,7 @@ import { getInitialRéductionGénéraleMoisParMois, getRéductionGénéraleFromRémunération, MonthState, + Options, réductionGénéraleDottedName, reevaluateRéductionGénéraleMoisParMois, RégularisationMethod, @@ -42,15 +43,24 @@ export default function RéductionGénéraleSimulation() { const [monthByMonth, setMonthByMonth] = useState(false) const periods = [ { - label: t('Réduction mensuelle'), + label: t( + 'pages.simulateurs.réduction-générale.tab.month', + 'Réduction mensuelle' + ), unit: '€/mois', }, { - label: t('Réduction annuelle'), + label: t( + 'pages.simulateurs.réduction-générale.tab.year', + 'Réduction annuelle' + ), unit: '€/an', }, { - label: t('Réduction mois par mois'), + label: t( + 'pages.simulateurs.réduction-générale.tab.month-by-month', + 'Réduction mois par mois' + ), unit: '€', }, ] @@ -67,7 +77,10 @@ export default function RéductionGénéraleSimulation() { { const updatedData = [...previousData] updatedData[monthIndex] = { + ...updatedData[monthIndex], rémunérationBrute, réductionGénérale: getRéductionGénéraleFromRémunération( engine, - rémunérationBrute + rémunérationBrute, + updatedData[monthIndex].options ), régularisation: 0, } @@ -162,19 +177,40 @@ function RéductionGénéraleSimulationGoals({ }) } + const onOptionChange = (monthIndex: number, options: Options) => { + setData((previousData) => { + const updatedData = [...previousData] + const réductionGénérale = getRéductionGénéraleFromRémunération( + engine, + updatedData[monthIndex].rémunérationBrute, + options + ) + + updatedData[monthIndex] = { + ...updatedData[monthIndex], + options, + réductionGénérale, + régularisation: 0, + } + + return updatedData + }) + } + return ( {monthByMonth ? ( ) : ( <> diff --git a/site/source/pages/simulateurs/reduction-generale/RéductionGénéraleMoisParMois.tsx b/site/source/pages/simulateurs/reduction-generale/RéductionGénéraleMoisParMois.tsx index 5d53abcba..ae61da552 100644 --- a/site/source/pages/simulateurs/reduction-generale/RéductionGénéraleMoisParMois.tsx +++ b/site/source/pages/simulateurs/reduction-generale/RéductionGénéraleMoisParMois.tsx @@ -5,16 +5,18 @@ import { ExplicableRule } from '@/components/conversation/Explicable' import RéductionGénéraleMoisParMoisRow from './components/RéductionGénéraleMoisParMoisRow' import Warnings from './components/Warnings' -import { MonthState, réductionGénéraleDottedName } from './utils' +import { MonthState, Options, réductionGénéraleDottedName } from './utils' type Props = { data: MonthState[] - onChange: (monthIndex: number, rémunérationBrute: number) => void + onRémunérationChange: (monthIndex: number, rémunérationBrute: number) => void + onOptionChange: (monthIndex: number, options: Options) => void } export default function RéductionGénéraleMoisParMois({ data, - onChange, + onRémunérationChange, + onOptionChange, }: Props) { const { t } = useTranslation() @@ -36,14 +38,20 @@ export default function RéductionGénéraleMoisParMois({ return ( <> - {t('Réduction générale mois par mois :')} + + {t( + 'pages.simulateurs.réduction-générale.month-by-month.caption', + 'Réduction générale mois par mois :' + )} + {t('Mois')} - {t('Rémunération brute', 'Rémunération brute')} + {t('Rémunération brute')} + {t('Réduction générale')} @@ -59,8 +67,14 @@ export default function RéductionGénéraleMoisParMois({ monthName={monthName} data={data[monthIndex]} index={monthIndex} - onChange={(monthIndex: number, rémunérationBrute: number) => { - onChange(monthIndex, rémunérationBrute) + onRémunérationChange={( + monthIndex: number, + rémunérationBrute: number + ) => { + onRémunérationChange(monthIndex, rémunérationBrute) + }} + onOptionChange={(monthIndex: number, options: Options) => { + onOptionChange(monthIndex, options) }} /> ))} diff --git a/site/source/pages/simulateurs/reduction-generale/components/RéductionGénéraleMoisParMoisRow.tsx b/site/source/pages/simulateurs/reduction-generale/components/RéductionGénéraleMoisParMoisRow.tsx index 9ec86dbbf..b065b6be5 100644 --- a/site/source/pages/simulateurs/reduction-generale/components/RéductionGénéraleMoisParMoisRow.tsx +++ b/site/source/pages/simulateurs/reduction-generale/components/RéductionGénéraleMoisParMoisRow.tsx @@ -1,15 +1,21 @@ import { formatValue, PublicodesExpression } from 'publicodes' -import { useTranslation } from 'react-i18next' +import { useState } from 'react' +import { Trans, useTranslation } from 'react-i18next' import { styled } from 'styled-components' import NumberInput from '@/components/conversation/NumberInput' import { Condition } from '@/components/EngineValue/Condition' +import { Appear } from '@/components/ui/animate' import { useEngine } from '@/components/utils/EngineContext' -import { SearchIcon, WarningIcon } from '@/design-system/icons' +import { Message, NumberField } from '@/design-system' +import { HelpButtonWithPopover } from '@/design-system/buttons' +import { PlusCircleIcon, SearchIcon, WarningIcon } from '@/design-system/icons' import { Tooltip } from '@/design-system/tooltip' +import { Body, ExtraSmallBody } from '@/design-system/typography/paragraphs' import { MonthState, + Options, réductionGénéraleDottedName, rémunérationBruteDottedName, } from '../utils' @@ -20,7 +26,8 @@ type Props = { monthName: string data: MonthState index: number - onChange: (monthIndex: number, rémunérationBrute: number) => void + onRémunérationChange: (monthIndex: number, rémunérationBrute: number) => void + onOptionChange: (monthIndex: number, options: Options) => void } type RémunérationBruteInput = { @@ -32,20 +39,14 @@ export default function RéductionGénéraleMoisParMoisRow({ monthName, data, index, - onChange, + onRémunérationChange, + onOptionChange, }: Props) { const { t, i18n } = useTranslation() const language = i18n.language const displayedUnit = '€' const engine = useEngine() - const onRémunérationChange = ( - monthIndex: number, - rémunérationBrute: RémunérationBruteInput - ) => { - onChange(monthIndex, rémunérationBrute.valeur) - } - // TODO: enlever les 4 premières props après résolution de #3123 const ruleInputProps = { dottedName: rémunérationBruteDottedName, @@ -64,6 +65,16 @@ export default function RéductionGénéraleMoisParMoisRow({ }, } + const [isOptionVisible, setOptionVisible] = useState(false) + const heuresSupplémentairesLabel = t( + 'pages.simulateurs.réduction-générale.option.label.heures-supplémentaires', + 'Heures supplémentaires' + ) + const heuresComplémentairesLabel = t( + 'pages.simulateurs.réduction-générale.option.label.heures-complémentaires', + 'Heures complémentaires' + ) + const tooltip = ( - {monthName} - - + + {monthName} + + + onRémunérationChange( + index, + (rémunérationBrute as RémunérationBruteInput).valeur + ) + } + value={data.rémunérationBrute} + formatOptions={{ + maximumFractionDigits: 2, + }} + /> + + + setOptionVisible(!isOptionVisible)} + > + + + + - onRémunérationChange( - index, - rémunérationBrute as RémunérationBruteInput - ) - } - value={data.rémunérationBrute} - formatOptions={{ - maximumFractionDigits: 2, - }} - /> - - - {data.réductionGénérale ? ( - + > + {data.réductionGénérale ? ( + + + {formatValue( + { + nodeValue: data.réductionGénérale, + }, + { + displayedUnit, + language, + } + )} + + + + ) : ( - {formatValue( - { - nodeValue: data.réductionGénérale, - }, - { - displayedUnit, - language, - } - )} - - - - ) : ( - - {formatValue(0, { displayedUnit, language })} + {formatValue(0, { displayedUnit, language })} - 1.6 * SMIC`} - contexte={{ - [rémunérationBruteDottedName]: data.rémunérationBrute, - }} - > - }> - {t('Attention')} - - - - - )} - - - {formatValue( - { - nodeValue: data.régularisation, - }, - { - displayedUnit, - language, - } - )} - - + 1.6 * SMIC`} + contexte={{ + [rémunérationBruteDottedName]: data.rémunérationBrute, + }} + > + }> + {t('Attention')} + + + + + )} + + + {formatValue( + { + nodeValue: data.régularisation, + }, + { + displayedUnit, + language, + } + )} + + + {isOptionVisible && ( + + + + + + + + {heuresSupplémentairesLabel} + + + + + + + + onOptionChange(index, { + heuresSupplémentaires: value, + heuresComplémentaires: 0, + }) + } + aria-labelledby="heures-supplémentaires-label" + displayedUnit="heures" + /> + + + + + {heuresComplémentairesLabel} + + + + + + + + onOptionChange(index, { + heuresSupplémentaires: 0, + heuresComplémentaires: value, + }) + } + aria-labelledby="heures-complémentaires-label" + displayedUnit="heures" + /> + + + + + )} + ) } +function HeuresSupplémentairesPopoverContent() { + return ( + + + Le nombre d'heures supplémentaires et complémentaires est utilisé dans + le calcul de la réduction générale : la rémunération brute est comparée + au montant du SMIC majoré de ce nombre d'heures supplémentaires ou + complémentaires. + + + Si vous avez répondu à la question sur les heures supplémentaires ou + complémentaires, la valeur sera écrasée par celle que vous saisissez + mois par mois. + + + ) +} + +const StyledPlusIcon = styled.div` + cursor: pointer; + svg { + fill: ${({ theme }) => theme.colors.extended.grey[100]}; + } + &:hover { + svg { + fill: ${({ theme }) => theme.colors.extended.grey[300]}; + } + } +` + const StyledDiv = styled.div` display: flex; align-items: center; @@ -166,3 +286,14 @@ const StyledDiv = styled.div` const StyledWarningIcon = styled(WarningIcon)` margin-top: ${({ theme }) => theme.spacings.xxs}; ` + +const StyledLabel = styled.div` + margin-top: -${({ theme }) => theme.spacings.md}; + margin-bottom: ${({ theme }) => theme.spacings.xs}; + display: flex; + align-items: center; +` +const StyledExtraSmallBody = styled(ExtraSmallBody)` + margin-top: 0; + margin-bottom: 0; +` diff --git a/site/source/pages/simulateurs/reduction-generale/components/RégularisationSwitch.tsx b/site/source/pages/simulateurs/reduction-generale/components/RégularisationSwitch.tsx index 63c8c1d68..93c413860 100644 --- a/site/source/pages/simulateurs/reduction-generale/components/RégularisationSwitch.tsx +++ b/site/source/pages/simulateurs/reduction-generale/components/RégularisationSwitch.tsx @@ -21,10 +21,23 @@ export default function RégularisationSwitch({ onChange={(value) => { setRégularisationMethod(value as RégularisationMethod) }} - aria-label={t('Type de régularisation')} + aria-label={t( + 'pages.simulateurs.réduction-générale.régularisation.type', + 'Type de régularisation' + )} > - {t('Régularisation annuelle')} - {t('Régularisation progressive')} + + {t( + 'pages.simulateurs.réduction-générale.régularisation.annuelle', + 'Régularisation annuelle' + )} + + + {t( + 'pages.simulateurs.réduction-générale.régularisation.progressive', + 'Régularisation progressive' + )} + ) } diff --git a/site/source/pages/simulateurs/reduction-generale/components/Répartition.tsx b/site/source/pages/simulateurs/reduction-generale/components/Répartition.tsx index 9c7588f6a..f4296efbe 100644 --- a/site/source/pages/simulateurs/reduction-generale/components/Répartition.tsx +++ b/site/source/pages/simulateurs/reduction-generale/components/Répartition.tsx @@ -1,4 +1,4 @@ -import { Trans } from 'react-i18next' +import { Trans, useTranslation } from 'react-i18next' import { styled } from 'styled-components' import { SimulationValue } from '@/components/Simulation/SimulationValue' @@ -14,6 +14,8 @@ type Props = { } export default function Répartition({ contexte = {} }: Props) { + const { t } = useTranslation() + return ( <> @@ -25,7 +27,10 @@ export default function Répartition({ contexte = {} }: Props) { @@ -33,13 +38,19 @@ export default function Répartition({ contexte = {} }: Props) { diff --git a/site/source/pages/simulateurs/reduction-generale/utils.ts b/site/source/pages/simulateurs/reduction-generale/utils.ts index 95fb45948..9bb0f4bff 100644 --- a/site/source/pages/simulateurs/reduction-generale/utils.ts +++ b/site/source/pages/simulateurs/reduction-generale/utils.ts @@ -1,30 +1,43 @@ import { sumAll } from 'effect/Number' import { DottedName } from 'modele-social' -import Engine from 'publicodes' +import Engine, { PublicodesExpression } from 'publicodes' // TODO: remplacer "salarié . cotisations . assiette" par "salarié . rémunération . brut" // lorsqu'elle n'incluera plus les frais professionnels. export const rémunérationBruteDottedName = 'salarié . cotisations . assiette' export const réductionGénéraleDottedName = 'salarié . cotisations . exonérations . réduction générale' +export const heuresSupplémentairesDottedName = + 'salarié . temps de travail . heures supplémentaires' +export const heuresComplémentairesDottedName = + 'salarié . temps de travail . heures complémentaires' export type MonthState = { rémunérationBrute: number + options: Options réductionGénérale: number régularisation: number } +export type Options = { + heuresSupplémentaires?: number + heuresComplémentaires?: number +} + export type RégularisationMethod = 'annuelle' | 'progressive' export const getRéductionGénéraleFromRémunération = ( engine: Engine, - rémunérationBrute: number + rémunérationBrute: number, + options: Options ): number => { const réductionGénérale = engine.evaluate({ valeur: réductionGénéraleDottedName, unité: '€/mois', contexte: { [rémunérationBruteDottedName]: rémunérationBrute, + [heuresSupplémentairesDottedName]: options.heuresSupplémentaires ?? 0, + [heuresComplémentairesDottedName]: options.heuresComplémentaires ?? 0, }, }) @@ -40,12 +53,29 @@ export const getInitialRéductionGénéraleMoisParMois = ( arrondi: 'oui', unité: '€/mois', })?.nodeValue as number) || 0 + const heuresSupplémentaires = + (engine.evaluate({ + valeur: heuresSupplémentairesDottedName, + unité: 'heures/mois', + })?.nodeValue as number) || 0 + const heuresComplémentaires = + (engine.evaluate({ + valeur: heuresComplémentairesDottedName, + unité: 'heures/mois', + })?.nodeValue as number) || 0 const réductionGénérale = rémunérationBrute - ? getRéductionGénéraleFromRémunération(engine, rémunérationBrute) + ? getRéductionGénéraleFromRémunération(engine, rémunérationBrute, { + heuresSupplémentaires, + heuresComplémentaires, + }) : 0 return Array(12).fill({ rémunérationBrute, + options: { + heuresSupplémentaires, + heuresComplémentaires, + }, réductionGénérale, régularisation: 0, }) as MonthState[] @@ -56,16 +86,27 @@ export const reevaluateRéductionGénéraleMoisParMois = ( engine: Engine, régularisationMethod: RégularisationMethod ): MonthState[] => { - const SMICMensuel = engine.evaluate({ - valeur: 'salarié . temps de travail . SMIC', - unité: 'heures/mois', - }).nodeValue as number // Si on laisse l'engine calculer T dans le calcul de la réduction générale, // le résultat ne sera pas bon à cause de l'assiette de cotisations du contexte const coefT = engine.evaluate({ valeur: 'salarié . cotisations . exonérations . T', }).nodeValue as number + const heuresSupplémentaires = + (engine.evaluate({ + valeur: heuresSupplémentairesDottedName, + unité: 'heures/mois', + })?.nodeValue as number) || 0 + const heuresComplémentaires = + (engine.evaluate({ + valeur: heuresComplémentairesDottedName, + unité: 'heures/mois', + })?.nodeValue as number) || 0 + const options = { + heuresSupplémentaires, + heuresComplémentaires, + } + const reevaluatedData = data.reduce( (reevaluatedData: MonthState[], monthState: MonthState, index) => { const rémunérationBrute = monthState.rémunérationBrute @@ -76,6 +117,7 @@ export const reevaluateRéductionGénéraleMoisParMois = ( ...reevaluatedData, { rémunérationBrute, + options, réductionGénérale, régularisation, }, @@ -85,7 +127,6 @@ export const reevaluateRéductionGénéraleMoisParMois = ( régularisation = getRégularisationProgressive( index, partialData, - SMICMensuel, coefT, engine ) @@ -96,7 +137,8 @@ export const reevaluateRéductionGénéraleMoisParMois = ( } else if (régularisationMethod === 'annuelle') { réductionGénérale = getRéductionGénéraleFromRémunération( engine, - rémunérationBrute + rémunérationBrute, + options ) if (index === data.length - 1) { régularisation = getRégularisationAnnuelle( @@ -115,6 +157,7 @@ export const reevaluateRéductionGénéraleMoisParMois = ( ...reevaluatedData, { rémunérationBrute, + options, réductionGénérale, régularisation, }, @@ -134,15 +177,26 @@ const getRégularisationAnnuelle = ( réductionGénéraleDernierMois: number, engine: Engine ): number => { - const currentRéductionGénéraleAnnuelle = - réductionGénéraleDernierMois + - sumAll(data.map((monthData) => monthData.réductionGénérale)) + const totalHeuresSupplémentaires = sumAll( + data.map((monthData) => monthData.options.heuresSupplémentaires ?? 0) + ) + const totalHeuresComplémentaires = sumAll( + data.map((monthData) => monthData.options.heuresComplémentaires ?? 0) + ) const realRéductionGénéraleAnnuelle = engine.evaluate({ valeur: réductionGénéraleDottedName, arrondi: 'non', unité: '€/an', + contexte: { + [heuresSupplémentairesDottedName]: `${totalHeuresSupplémentaires} heures/an`, + [heuresComplémentairesDottedName]: `${totalHeuresComplémentaires} heures/an`, + }, }).nodeValue as number + const currentRéductionGénéraleAnnuelle = + réductionGénéraleDernierMois + + sumAll(data.map((monthData) => monthData.réductionGénérale)) + return realRéductionGénéraleAnnuelle - currentRéductionGénéraleAnnuelle } @@ -152,7 +206,6 @@ const getRégularisationAnnuelle = ( const getRégularisationProgressive = ( monthIndex: number, data: MonthState[], - SMICMensuel: number, coefT: number, engine: Engine ): number => { @@ -170,7 +223,30 @@ const getRégularisationProgressive = ( return 0 } - const SMICCumulé = nbOfMonths * SMICMensuel + // TODO: optimiser le calcul du SMIC + // (ne pas recalculer l'équivalent SMIC du mois de janvier à chaque mois de l'année) + const SMICCumulé = partialData.reduce( + (SMICCumulé: number, monthData: MonthState) => { + const contexte: PublicodesExpression = {} + if (monthData.options.heuresSupplémentaires) { + contexte[heuresSupplémentairesDottedName] = + monthData.options.heuresSupplémentaires + } + if (monthData.options.heuresComplémentaires) { + contexte[heuresComplémentairesDottedName] = + monthData.options.heuresComplémentaires + } + + const SMICCurrentMonth = engine.evaluate({ + valeur: 'salarié . temps de travail . SMIC', + unité: '€/mois', + contexte, + }).nodeValue as number + + return SMICCumulé + SMICCurrentMonth + }, + 0 + ) const réductionGénéraleTotale = engine.evaluate({ valeur: réductionGénéraleDottedName,