feat: ajout de la régularisation annuelle dans le simulateur RGCP mois par mois

pull/3212/head
Alice Dahan 2024-10-28 14:45:18 +01:00 committed by liliced
parent 65d4e4dd89
commit 227936935a
8 changed files with 72 additions and 18 deletions

View File

@ -112,12 +112,12 @@ describe(
cy.contains('Réduction mois par mois').click()
cy.get(inputSelector).first().type('{selectall}1900')
cy.get(inputSelector).last().type('{selectall}2000')
cy.get(inputSelector).eq(1).type('{selectall}2000')
cy.get(
'td[id="salarié___cotisations___exonérations___réduction_générale-janvier"]'
).should('include.text', '523,26 €')
cy.get(
'td[id="salarié___cotisations___exonérations___réduction_générale-décembre"]'
'td[id="salarié___cotisations___exonérations___réduction_générale-février"]'
).should('include.text', '470 €')
})
@ -127,7 +127,7 @@ describe(
cy.get(inputSelector).first().type('{selectall}1900')
cy.contains('Réduction mois par mois').click()
cy.get(inputSelector).first().type('{selectall}2000')
cy.get(inputSelector).last().type('{selectall}2000')
cy.get(inputSelector).eq(1).type('{selectall}2000')
cy.contains('Réduction mensuelle').click()
cy.get(inputSelector).first().should('have.value', '1916,67 €')
@ -136,13 +136,25 @@ describe(
cy.contains('Réduction mois par mois').click()
cy.get(inputSelector).each(($input, index) => {
let expectedValue = '1900 €'
if (index === 0 || index === 11) {
if (index < 2) {
expectedValue = '2000 €'
}
cy.wrap($input).should('have.value', expectedValue)
})
})
it('should include annual regularisation', function () {
cy.contains('Moins de 50 salariés').click()
cy.contains('Réduction mensuelle').click()
cy.get(inputSelector).first().type('{selectall}1900')
cy.contains('Réduction mois par mois').click()
cy.get(inputSelector).eq(1).type('{selectall}3000')
cy.get(
'td[id="salarié___cotisations___exonérations___réduction_générale-décembre"]'
).should('include.text', '460,38 €')
})
it('should be RGAA compliant', function () {
cy.contains('Réduction mensuelle').click()
checkA11Y()

View File

@ -206,8 +206,8 @@ export default function SimulateurWarning({
<abbr title="Réduction Générale des Cotisations Patronales">
RGCP
</abbr>{' '}
à partir d'une rémunération mensuelle ou annuelle, sans intégrer
la régularisation. Pour une version complète, utilisez{' '}
à partir d'une rémunération mensuelle ou annuelle. Pour une
version complète, utilisez{' '}
<Link
aria-label="Simulateur de calcul de la réduction générale des cotisations sur urssaf.fr, nouvelle fenêtre"
href="https://www.declaration.urssaf.fr/calcul/"

View File

@ -46,6 +46,7 @@ Aller directement au pied de page: Go directly to footer
Annuler: Cancel
Arrêt maladie: Sick leave
Assistants à la déclaration de revenu 2023 des indépendants: Assistants for the 2023 self-employed tax return
Attention: Warning
Attention, information importante: Important information
Attention, vos données sauvegardées seront supprimées de manière définitive.: Please note that your saved data will be permanently deleted.
Aucun: No
@ -1786,9 +1787,8 @@ simulateurs:
specific rates and/or distribution of supplementary pension
contributions applied in certain companies.
beta: <0>This simulator is currently under development.</0> It only calculates
the <3>RGCP</3> on the basis of monthly or annual remuneration, without
including regularization. For a full version, use <7>the urssaf.fr
simulator.</7>
<3>RGCP</3> on the basis of monthly or annual remuneration. For a full
version, use <7>the urssaf.fr simulator.</7>
salarié: The simulator does not currently take into account collective
agreements, nor the myriad of company subsidies. Find your collective
bargaining agreement <2>here</2>, and explore the range of assistance

View File

@ -49,6 +49,7 @@ Aller directement au pied de page: Aller directement au pied de page
Annuler: Annuler
Arrêt maladie: Arrêt maladie
Assistants à la déclaration de revenu 2023 des indépendants: Assistants à la déclaration de revenu 2023 des indépendants
Attention: Attention
Attention, information importante: Attention, information importante
Attention, vos données sauvegardées seront supprimées de manière définitive.: Attention, vos données sauvegardées seront supprimées de manière définitive.
Aucun: Aucun
@ -1904,8 +1905,8 @@ simulateurs:
complémentaire appliqués dans certaines entreprises.
beta: <0>Ce simulateur est en cours de développement.</0> Il propose uniquement
le calcul de la <3>RGCP</3> à partir d'une rémunération mensuelle ou
annuelle, sans intégrer la régularisation. Pour une version complète,
utilisez <7>le simulateur d'urssaf.fr.</7>
annuelle. Pour une version complète, utilisez <7>le simulateur
d'urssaf.fr.</7>
salarié: Le simulateur ne prend pour l'instant pas en compte les accords et
conventions collectives, ni la myriade d'aides aux entreprises. Trouvez
votre convention collective <2>ici</2>, et explorez les aides sur

View File

@ -1,13 +1,17 @@
import { ReactNode } from 'react'
import { useTranslation } from 'react-i18next'
import { styled } from 'styled-components'
import { WarningIcon } from '@/design-system/icons'
import { Tooltip } from '@/design-system/tooltip'
const WarningTooltip = ({ tooltip }: { tooltip: ReactNode }) => {
const { t } = useTranslation()
return (
<Tooltip tooltip={tooltip}>
<StyledWarningIcon aria-label="Attention" />
<span className="sr-only">{t('Attention')}</span>
<StyledWarningIcon aria-label={t('Attention')} />
</Tooltip>
)
}

View File

@ -142,6 +142,7 @@ function RéductionGénéraleSimulationGoals({
engine,
rémunérationBrute
),
régularisation: 0,
}
updateRémunérationBruteAnnuelle(updatedData)

View File

@ -7,7 +7,6 @@ import NumberInput from '@/components/conversation/NumberInput'
import { Condition } from '@/components/EngineValue/Condition'
import { useEngine } from '@/components/utils/EngineContext'
import { SearchIcon, WarningIcon } from '@/design-system/icons'
import { Spacing } from '@/design-system/layout'
import { Tooltip } from '@/design-system/tooltip'
import Répartition from './components/Répartition'
@ -101,6 +100,9 @@ export default function RéductionGénéraleMoisParMois({
contexte={{
[rémunérationBruteDottedName]:
data[monthIndex].rémunérationBrute,
[réductionGénéraleDottedName]:
data[monthIndex].réductionGénérale +
data[monthIndex].régularisation,
}}
/>
)
@ -135,11 +137,16 @@ export default function RéductionGénéraleMoisParMois({
'_'
)}-${monthName}`}
>
{data[monthIndex].réductionGénérale ? (
{data[monthIndex].réductionGénérale ||
data[monthIndex].régularisation ? (
<Tooltip tooltip={tooltip} hasArrow={true}>
<StyledDiv>
{formatValue(
{ nodeValue: data[monthIndex].réductionGénérale },
{
nodeValue:
data[monthIndex].réductionGénérale +
data[monthIndex].régularisation,
},
{
displayedUnit,
language,
@ -163,8 +170,8 @@ export default function RéductionGénéraleMoisParMois({
tooltip={<WarningSalaireTrans />}
hasArrow={true}
>
<Spacing xxs />
<WarningIcon />
<span className="sr-only">{t('Attention')}</span>
<StyledWarningIcon aria-label={t('Attention')} />
</Tooltip>
</Condition>
</StyledDiv>
@ -208,3 +215,7 @@ const StyledDiv = styled.div`
align-items: center;
gap: ${({ theme }) => theme.spacings.sm};
`
const StyledWarningIcon = styled(WarningIcon)`
margin-top: ${({ theme }) => theme.spacings.xxs};
`

View File

@ -1,3 +1,4 @@
import { sumAll } from 'effect/Number'
import { DottedName } from 'modele-social'
import Engine from 'publicodes'
@ -10,6 +11,7 @@ export const réductionGénéraleDottedName =
export type MonthState = {
rémunérationBrute: number
réductionGénérale: number
régularisation: number
}
export const getRéductionGénéraleFromRémunération = (
@ -44,6 +46,7 @@ export const getInitialRéductionGénéraleMoisParMois = (
return Array(12).fill({
rémunérationBrute,
réductionGénérale,
régularisation: 0,
}) as MonthState[]
}
@ -51,11 +54,33 @@ export const reevaluateRéductionGénéraleMoisParMois = (
data: MonthState[],
engine: Engine<DottedName>
): MonthState[] => {
return data.map((item) => ({
const reevaluatedData = data.map((item) => ({
...item,
réductionGénérale: getRéductionGénéraleFromRémunération(
engine,
item.rémunérationBrute
),
régularisation: 0,
}))
reevaluatedData[reevaluatedData.length - 1].régularisation =
getRégularisationAnnuelle(data, engine)
return reevaluatedData
}
const getRégularisationAnnuelle = (
data: MonthState[],
engine: Engine<DottedName>
): number => {
const currentRéductionGénéraleAnnuelle = sumAll(
data.map((monthData) => monthData.réductionGénérale)
)
const realRéductionGénéraleAnnuelle = engine.evaluate({
valeur: réductionGénéraleDottedName,
arrondi: 'non',
unité: '€/an',
}).nodeValue as number
return realRéductionGénéraleAnnuelle - currentRéductionGénéraleAnnuelle
}