From 06a7c2f43084bf6a34bc48e3023366dceb20e11d Mon Sep 17 00:00:00 2001 From: Alice Dahan Date: Tue, 10 Dec 2024 16:13:58 +0100 Subject: [PATCH 1/5] =?UTF-8?q?refactor(rgcp):=20cr=C3=A9e=20un=20composan?= =?UTF-8?q?t=20R=C3=A9ductionG=C3=A9n=C3=A9raleBasique?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reduction-generale/Basique.tsx | 54 +++++++++++++++++++ .../simulateurs/reduction-generale/Goals.tsx | 44 ++------------- 2 files changed, 59 insertions(+), 39 deletions(-) create mode 100644 site/source/pages/simulateurs/reduction-generale/Basique.tsx diff --git a/site/source/pages/simulateurs/reduction-generale/Basique.tsx b/site/source/pages/simulateurs/reduction-generale/Basique.tsx new file mode 100644 index 0000000000..a2dcea4b5d --- /dev/null +++ b/site/source/pages/simulateurs/reduction-generale/Basique.tsx @@ -0,0 +1,54 @@ +import { useTranslation } from 'react-i18next' + +import { Condition } from '@/components/EngineValue/Condition' +import { SimulationGoal } from '@/components/Simulation' +import { SimulationValue } from '@/components/Simulation/SimulationValue' +import { Message } from '@/design-system' +import { Spacing } from '@/design-system/layout' +import { Body } from '@/design-system/typography/paragraphs' + +import Répartition from './components/Répartition' +import Warnings from './components/Warnings' +import WarningSalaireTrans from './components/WarningSalaireTrans' +import { + réductionGénéraleDottedName, + rémunérationBruteDottedName, +} from './utils' + +type Props = { + onUpdate: () => void +} + +export default function RéductionGénéraleBasique({ onUpdate }: Props) { + const { t } = useTranslation() + + return ( + <> + + + + 1.6 * SMIC`}> + + + + + + + + = 0`}> + + + + + + ) +} diff --git a/site/source/pages/simulateurs/reduction-generale/Goals.tsx b/site/source/pages/simulateurs/reduction-generale/Goals.tsx index 9da9528e91..9b6ebc2554 100644 --- a/site/source/pages/simulateurs/reduction-generale/Goals.tsx +++ b/site/source/pages/simulateurs/reduction-generale/Goals.tsx @@ -1,25 +1,17 @@ import { DottedName } from 'modele-social' import { PublicodesExpression } from 'publicodes' import { useCallback, useEffect, useRef, useState } from 'react' -import { useTranslation } from 'react-i18next' import { useDispatch, useSelector } from 'react-redux' -import { Condition } from '@/components/EngineValue/Condition' -import { SimulationGoal, SimulationGoals } from '@/components/Simulation' -import { SimulationValue } from '@/components/Simulation/SimulationValue' +import { SimulationGoals } from '@/components/Simulation' import { useEngine } from '@/components/utils/EngineContext' import useYear from '@/components/utils/useYear' -import { Message } from '@/design-system' -import { Spacing } from '@/design-system/layout' -import { Body } from '@/design-system/typography/paragraphs' import { SimpleRuleEvaluation } from '@/domaine/engine/SimpleRuleEvaluation' import { Situation } from '@/domaine/Situation' import { ajusteLaSituation } from '@/store/actions/actions' import { situationSelector } from '@/store/selectors/simulationSelectors' -import Répartition from './components/Répartition' -import Warnings from './components/Warnings' -import WarningSalaireTrans from './components/WarningSalaireTrans' +import RéductionGénéraleBasique from './Basique' import RéductionGénéraleMoisParMois from './MoisParMois' import { getInitialRéductionGénéraleMoisParMois, @@ -27,7 +19,6 @@ import { heuresSupplémentairesDottedName, MonthState, Options, - réductionGénéraleDottedName, reevaluateRéductionGénéraleMoisParMois, RégularisationMethod, rémunérationBruteDottedName, @@ -57,7 +48,6 @@ export default function RéductionGénéraleSimulationGoals({ }) { const engine = useEngine() const dispatch = useDispatch() - const { t } = useTranslation() const [réductionGénéraleMoisParMoisData, setData] = useState([]) const year = useYear() const situation = useSelector(situationSelector) as SituationType @@ -196,33 +186,9 @@ export default function RéductionGénéraleSimulationGoals({ onOptionsChange={onOptionsChange} /> ) : ( - <> - - - - 1.6 * SMIC`}> - - - - - - - - = 0`}> - - - - - + )} ) From 5abf1fc852672e0d73620170cfb5fbbb28303bc8 Mon Sep 17 00:00:00 2001 From: Alice Dahan Date: Tue, 10 Dec 2024 16:16:43 +0100 Subject: [PATCH 2/5] =?UTF-8?q?refactor(rgcp):=20stocke=20la=20r=C3=A9part?= =?UTF-8?q?ition=20dans=20le=20state?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reduction-generale/Basique.tsx | 25 ++- .../reduction-generale/components/Mois.tsx | 9 +- .../components/MontantR\303\251duction.tsx" | 27 ++-- .../components/R\303\251partition.tsx" | 42 +++-- .../components/R\303\251partitionValue.tsx" | 62 +++++++ .../simulateurs/reduction-generale/utils.ts | 151 +++++++++++++++--- 6 files changed, 256 insertions(+), 60 deletions(-) create mode 100644 "site/source/pages/simulateurs/reduction-generale/components/R\303\251partitionValue.tsx" diff --git a/site/source/pages/simulateurs/reduction-generale/Basique.tsx b/site/source/pages/simulateurs/reduction-generale/Basique.tsx index a2dcea4b5d..76d3f439f5 100644 --- a/site/source/pages/simulateurs/reduction-generale/Basique.tsx +++ b/site/source/pages/simulateurs/reduction-generale/Basique.tsx @@ -1,11 +1,14 @@ import { useTranslation } from 'react-i18next' +import { useSelector } from 'react-redux' import { Condition } from '@/components/EngineValue/Condition' import { SimulationGoal } from '@/components/Simulation' import { SimulationValue } from '@/components/Simulation/SimulationValue' +import { useEngine } from '@/components/utils/EngineContext' import { Message } from '@/design-system' import { Spacing } from '@/design-system/layout' import { Body } from '@/design-system/typography/paragraphs' +import { targetUnitSelector } from '@/store/selectors/simulationSelectors' import Répartition from './components/Répartition' import Warnings from './components/Warnings' @@ -20,8 +23,28 @@ type Props = { } export default function RéductionGénéraleBasique({ onUpdate }: Props) { + const engine = useEngine() + const currentUnit = useSelector(targetUnitSelector) const { t } = useTranslation() + const répartition = { + IRC: + (engine.evaluate({ + valeur: `${réductionGénéraleDottedName} . imputation retraite complémentaire`, + unité: currentUnit, + })?.nodeValue as number) ?? 0, + Urssaf: + (engine.evaluate({ + valeur: `${réductionGénéraleDottedName} . imputation sécurité sociale`, + unité: currentUnit, + })?.nodeValue as number) ?? 0, + chômage: + (engine.evaluate({ + valeur: `${réductionGénéraleDottedName} . imputation chômage`, + unité: currentUnit, + })?.nodeValue as number) ?? 0, + } + return ( <> - + ) diff --git a/site/source/pages/simulateurs/reduction-generale/components/Mois.tsx b/site/source/pages/simulateurs/reduction-generale/components/Mois.tsx index 36535808c2..562525e330 100644 --- a/site/source/pages/simulateurs/reduction-generale/components/Mois.tsx +++ b/site/source/pages/simulateurs/reduction-generale/components/Mois.tsx @@ -117,10 +117,10 @@ export default function RéductionGénéraleMois({ '_' )}-${monthName}`} rémunérationBrute={data.rémunérationBrute} - réductionGénérale={data.réductionGénérale} + réductionGénérale={data.réductionGénérale.value} + répartition={data.réductionGénérale.répartition} displayedUnit={displayedUnit} language={language} - warning={true} /> ) } @@ -133,10 +133,11 @@ export default function RéductionGénéraleMois({ '_' )}__régularisation-${monthName}`} rémunérationBrute={data.rémunérationBrute} - réductionGénérale={data.régularisation} + réductionGénérale={data.régularisation.value} + répartition={data.régularisation.répartition} displayedUnit={displayedUnit} language={language} - warning={false} + displayNull={false} /> ) } diff --git "a/site/source/pages/simulateurs/reduction-generale/components/MontantR\303\251duction.tsx" "b/site/source/pages/simulateurs/reduction-generale/components/MontantR\303\251duction.tsx" index b3da9ec10e..f5bb474fb7 100644 --- "a/site/source/pages/simulateurs/reduction-generale/components/MontantR\303\251duction.tsx" +++ "b/site/source/pages/simulateurs/reduction-generale/components/MontantR\303\251duction.tsx" @@ -8,8 +8,8 @@ import { SearchIcon, WarningIcon } from '@/design-system/icons' import { Tooltip } from '@/design-system/tooltip' import { - réductionGénéraleDottedName, rémunérationBruteDottedName, + Répartition as RépartitionType, } from '../utils' import Répartition from './Répartition' import WarningSalaireTrans from './WarningSalaireTrans' @@ -18,29 +18,24 @@ type Props = { id?: string rémunérationBrute: number réductionGénérale: number + répartition: RépartitionType displayedUnit: string language: string - warning?: boolean + displayNull?: boolean } export default function MontantRéduction({ id, rémunérationBrute, réductionGénérale, + répartition, displayedUnit, language, - warning = false, + displayNull = true, }: Props) { const { t } = useTranslation() - const tooltip = ( - - ) + const tooltip = return réductionGénérale ? ( @@ -58,10 +53,10 @@ export default function MontantRéduction({ ) : ( - - {formatValue(0, { displayedUnit, language })} + displayNull && ( + + {formatValue(0, { displayedUnit, language })} - {warning && ( 1.6 * SMIC`} contexte={{ @@ -73,8 +68,8 @@ export default function MontantRéduction({ - )} - + + ) ) } diff --git "a/site/source/pages/simulateurs/reduction-generale/components/R\303\251partition.tsx" "b/site/source/pages/simulateurs/reduction-generale/components/R\303\251partition.tsx" index f4296efbe6..d958115083 100644 --- "a/site/source/pages/simulateurs/reduction-generale/components/R\303\251partition.tsx" +++ "b/site/source/pages/simulateurs/reduction-generale/components/R\303\251partition.tsx" @@ -1,19 +1,21 @@ import { Trans, useTranslation } from 'react-i18next' import { styled } from 'styled-components' -import { SimulationValue } from '@/components/Simulation/SimulationValue' import { Strong } from '@/design-system/typography' import { Li, Ul } from '@/design-system/typography/list' import { Body } from '@/design-system/typography/paragraphs' -import { Contexte } from '@/domaine/Contexte' -import { réductionGénéraleDottedName } from '../utils' +import { + réductionGénéraleDottedName, + Répartition as RépartitionType, +} from '../utils' +import RépartitionValue from './RépartitionValue' type Props = { - contexte?: Contexte + répartition: RépartitionType } -export default function Répartition({ contexte = {} }: Props) { +export default function Répartition({ répartition }: Props) { const { t } = useTranslation() return ( @@ -25,34 +27,40 @@ export default function Répartition({ contexte = {} }: Props) { - - - diff --git "a/site/source/pages/simulateurs/reduction-generale/components/R\303\251partitionValue.tsx" "b/site/source/pages/simulateurs/reduction-generale/components/R\303\251partitionValue.tsx" new file mode 100644 index 0000000000..423fd25680 --- /dev/null +++ "b/site/source/pages/simulateurs/reduction-generale/components/R\303\251partitionValue.tsx" @@ -0,0 +1,62 @@ +import { formatValue } from 'publicodes' +import { useTranslation } from 'react-i18next' +import { styled } from 'styled-components' + +import LectureGuide from '@/components/Simulation/LectureGuide' +import { Grid } from '@/design-system/layout' +import { Body } from '@/design-system/typography/paragraphs' + +type Props = { + value: number + label: string + idPrefix: string +} + +export default function RépartitionValue({ value, label, idPrefix }: Props) { + const language = useTranslation().i18n.language + + return ( + + + + {label} + + + + + + + {formatValue(value, { + displayedUnit: '€', + precision: 2, + language, + })} + + + + + ) +} + +const StyledValue = styled.div` + position: relative; + z-index: 1; + padding: ${({ theme }) => theme.spacings.xxs} 0; + + @media print { + padding: 0; + } +` + +const StyledBody = styled(Body)` + color: ${({ theme }) => theme.colors.extended.grey[100]}; + margin: 0; + padding: ${({ theme }) => `${theme.spacings.xs} ${theme.spacings.sm} 0 0`}; +` diff --git a/site/source/pages/simulateurs/reduction-generale/utils.ts b/site/source/pages/simulateurs/reduction-generale/utils.ts index eec3200263..6db7da764c 100644 --- a/site/source/pages/simulateurs/reduction-generale/utils.ts +++ b/site/source/pages/simulateurs/reduction-generale/utils.ts @@ -14,11 +14,23 @@ export const heuresSupplémentairesDottedName = export const heuresComplémentairesDottedName = 'salarié . temps de travail . heures complémentaires' +export type Répartition = { + IRC: number + Urssaf: number + chômage: number +} + export type MonthState = { rémunérationBrute: number options: Options - réductionGénérale: number - régularisation: number + réductionGénérale: { + value: number + répartition: Répartition + } + régularisation: { + value: number + répartition: Répartition + } } export type Options = { @@ -76,6 +88,47 @@ const getTotalRéductionGénérale = ( return réductionGénérale.nodeValue as number } +const emptyRépartition = { + IRC: 0, + Urssaf: 0, + chômage: 0, +} + +const getRépartition = ( + rémunération: number, + réduction: number, + engine: Engine +): Répartition => { + const contexte = { + [rémunérationBruteDottedName]: rémunération, + [réductionGénéraleDottedName]: réduction, + } + const IRC = + (engine.evaluate({ + valeur: `${réductionGénéraleDottedName} . imputation retraite complémentaire`, + unité: '€/mois', + contexte, + })?.nodeValue as number) ?? 0 + const Urssaf = + (engine.evaluate({ + valeur: `${réductionGénéraleDottedName} . imputation sécurité sociale`, + unité: '€/mois', + contexte, + })?.nodeValue as number) ?? 0 + const chômage = + (engine.evaluate({ + valeur: `${réductionGénéraleDottedName} . imputation chômage`, + unité: '€/mois', + contexte, + })?.nodeValue as number) ?? 0 + + return { + IRC, + Urssaf, + chômage, + } +} + export const getInitialRéductionGénéraleMoisParMois = ( year: number, engine: Engine @@ -110,8 +163,14 @@ export const getInitialRéductionGénéraleMoisParMois = ( rémunérationPrimes, rémunérationHeuresSup, }, - réductionGénérale: 0, - régularisation: 0, + réductionGénérale: { + value: 0, + répartition: emptyRépartition, + }, + régularisation: { + value: 0, + répartition: emptyRépartition, + }, }) as MonthState[] } @@ -130,6 +189,11 @@ export const getInitialRéductionGénéraleMoisParMois = ( }, engine ) + const répartition = getRépartition( + rémunérationBrute, + réductionGénérale, + engine + ) return { rémunérationBrute, @@ -140,8 +204,14 @@ export const getInitialRéductionGénéraleMoisParMois = ( rémunérationPrimes, rémunérationHeuresSup, }, - réductionGénérale, - régularisation: 0, + réductionGénérale: { + value: réductionGénérale, + répartition, + }, + régularisation: { + value: 0, + répartition: emptyRépartition, + }, } }) } @@ -160,8 +230,14 @@ export const reevaluateRéductionGénéraleMoisParMois = ( return data.map((monthData) => { return { ...monthData, - réductionGénérale: 0, - régularisation: 0, + réductionGénérale: { + value: 0, + répartition: emptyRépartition, + }, + régularisation: { + value: 0, + répartition: emptyRépartition, + }, } }) } @@ -178,8 +254,14 @@ export const reevaluateRéductionGénéraleMoisParMois = ( (reevaluatedData: MonthState[], monthState, monthIndex) => { const rémunérationBrute = monthState.rémunérationBrute const options = monthState.options - let réductionGénérale = 0 - let régularisation = 0 + const réductionGénérale = { + value: 0, + répartition: emptyRépartition, + } + const régularisation = { + value: 0, + répartition: emptyRépartition, + } if (!rémunérationBrute) { return [ @@ -206,18 +288,30 @@ export const reevaluateRéductionGénéraleMoisParMois = ( const réductionGénéraleCumulée = sumAll( reevaluatedData.map( (monthData) => - monthData.réductionGénérale + monthData.régularisation + monthData.réductionGénérale.value + monthData.régularisation.value ) ) - régularisation = réductionGénéraleTotale - réductionGénéraleCumulée + régularisation.value = + réductionGénéraleTotale - réductionGénéraleCumulée - if (régularisation > 0) { - réductionGénérale = régularisation - régularisation = 0 + if (régularisation.value > 0) { + réductionGénérale.value = régularisation.value + réductionGénérale.répartition = getRépartition( + rémunérationBrute, + réductionGénérale.value, + engine + ) + régularisation.value = 0 + } else if (régularisation.value < 0) { + régularisation.répartition = getRépartition( + rémunérationBrute, + régularisation.value, + engine + ) } } else if (régularisationMethod === 'annuelle') { const date = getDateForContexte(monthIndex, year) - réductionGénérale = getMonthlyRéductionGénérale( + réductionGénérale.value = getMonthlyRéductionGénérale( date, rémunérationBrute, options, @@ -235,16 +329,29 @@ export const reevaluateRéductionGénéraleMoisParMois = ( engine ) const currentRéductionGénéraleCumulée = - réductionGénérale + + réductionGénérale.value + sumAll( - reevaluatedData.map((monthData) => monthData.réductionGénérale) + reevaluatedData.map( + (monthData) => monthData.réductionGénérale.value + ) ) - régularisation = + régularisation.value = réductionGénéraleTotale - currentRéductionGénéraleCumulée - if (réductionGénérale + régularisation > 0) { - réductionGénérale += régularisation - régularisation = 0 + if (réductionGénérale.value + régularisation.value > 0) { + réductionGénérale.value += régularisation.value + réductionGénérale.répartition = getRépartition( + rémunérationBrute, + réductionGénérale.value, + engine + ) + régularisation.value = 0 + } else if (régularisation.value < 0) { + régularisation.répartition = getRépartition( + rémunérationBrute, + régularisation.value, + engine + ) } } } From 6cad4ea9eacc5e68be92d93f6264467cfa4bcbc2 Mon Sep 17 00:00:00 2001 From: Alice Dahan Date: Thu, 12 Dec 2024 15:40:18 +0100 Subject: [PATCH 3/5] =?UTF-8?q?feat(rgcp):=20ajout=20d'un=20r=C3=A9capitul?= =?UTF-8?q?atif=20trimestriel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- site/source/locales/ui-en.yaml | 10 + site/source/locales/ui-fr.yaml | 10 + .../reduction-generale/MoisParMois.tsx | 176 +++++++++++++----- .../components/MontantR\303\251duction.tsx" | 10 +- .../R\303\251capitulatifTrimestre.tsx" | 168 +++++++++++++++++ ...\251ductionG\303\251n\303\251raleMois.tsx" | 0 6 files changed, 328 insertions(+), 46 deletions(-) create mode 100644 "site/source/pages/simulateurs/reduction-generale/components/R\303\251capitulatifTrimestre.tsx" rename site/source/pages/simulateurs/reduction-generale/components/Mois.tsx => "site/source/pages/simulateurs/reduction-generale/components/R\303\251ductionG\303\251n\303\251raleMois.tsx" (100%) diff --git a/site/source/locales/ui-en.yaml b/site/source/locales/ui-en.yaml index fa873b375a..12da894f21 100644 --- a/site/source/locales/ui-en.yaml +++ b/site/source/locales/ui-en.yaml @@ -330,6 +330,7 @@ Tout déplier: Unfold all Tout plier: Fold everything Tout réinitialiser: Reset all Travailleurs Non Salariés (TNS): Self-employed workers (TNS) +Trimestre: Quarter Type: Type 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.: @@ -1514,6 +1515,15 @@ pages: rémunération-primes: popover: <0>Indicate here any elements of remuneration not affected by the absence, such as bonuses. + recap: + T1: 1st quarter + T2: 2nd quarter + T3: 3rd quarter + T4: 4th quarter + caption: "Quarterly summary :" + code671: code 671(€) + code801: code 801(€) + header: Calculated reduction régularisation: annuelle: Annual adjustment progressive: Progressive regularization diff --git a/site/source/locales/ui-fr.yaml b/site/source/locales/ui-fr.yaml index 8b58c45f85..a51e1f9e91 100644 --- a/site/source/locales/ui-fr.yaml +++ b/site/source/locales/ui-fr.yaml @@ -345,6 +345,7 @@ Tout déplier: Tout déplier Tout plier: Tout plier Tout réinitialiser: Tout réinitialiser Travailleurs Non Salariés (TNS): Travailleurs Non Salariés (TNS) +Trimestre: Trimestre Type: Type 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.: @@ -1608,6 +1609,15 @@ pages: rémunération-primes: popover: <0>Indiquez ici les éléments de rémunération non affectés par l'absence, comme les primes. + recap: + T1: 1er trimestre + T2: 2ème trimestre + T3: 3ème trimestre + T4: 4ème trimestre + caption: "Récapitulatif trimestriel :" + code671: code 671(€) + code801: code 801(€) + header: Réduction calculée régularisation: annuelle: Régularisation annuelle progressive: Régularisation progressive diff --git a/site/source/pages/simulateurs/reduction-generale/MoisParMois.tsx b/site/source/pages/simulateurs/reduction-generale/MoisParMois.tsx index 8bca7b14d1..1ffaab3349 100644 --- a/site/source/pages/simulateurs/reduction-generale/MoisParMois.tsx +++ b/site/source/pages/simulateurs/reduction-generale/MoisParMois.tsx @@ -2,11 +2,13 @@ import { useTranslation } from 'react-i18next' import { styled } from 'styled-components' import RuleLink from '@/components/RuleLink' +import { Spacing } from '@/design-system/layout' import { baseTheme } from '@/design-system/theme' import { Body } from '@/design-system/typography/paragraphs' import { useMediaQuery } from '@/hooks/useMediaQuery' -import RéductionGénéraleMois from './components/Mois' +import RécapitulatifTrimestre from './components/RécapitulatifTrimestre' +import RéductionGénéraleMois from './components/RéductionGénéraleMois' import Warnings from './components/Warnings' import { MonthState, Options, réductionGénéraleDottedName } from './utils' @@ -41,52 +43,112 @@ export default function RéductionGénéraleMoisParMois({ t('décembre'), ] + const quarters = { + [t('pages.simulateurs.réduction-générale.recap.T1', '1er trimestre')]: + data.slice(0, 3), + [t('pages.simulateurs.réduction-générale.recap.T2', '2ème trimestre')]: + data.slice(3, 6), + [t('pages.simulateurs.réduction-générale.recap.T3', '3ème trimestre')]: + data.slice(6, 9), + [t('pages.simulateurs.réduction-générale.recap.T4', '4ème trimestre')]: + data.slice(9), + } + return ( <> {isDesktop ? ( - - - {t( - 'pages.simulateurs.réduction-générale.month-by-month.caption', - 'Réduction générale mois par mois :' - )} - - - - {t('Mois')} - - {/* TODO: remplacer par rémunérationBruteDottedName lorsque ... */} - - - - - - - - - - - - {data.length > 0 && - months.map((monthName, monthIndex) => ( - { - onRémunérationChange(monthIndex, rémunérationBrute) - }} - onOptionsChange={(monthIndex: number, options: Options) => { - onOptionsChange(monthIndex, options) - }} + <> + + + {t( + 'pages.simulateurs.réduction-générale.month-by-month.caption', + 'Réduction générale mois par mois :' + )} + + + + {t('Mois')} + + {/* TODO: remplacer par rémunérationBruteDottedName lorsque ... */} + + + + + + + + + + + + {data.length > 0 && + months.map((monthName, monthIndex) => ( + { + onRémunérationChange(monthIndex, rémunérationBrute) + }} + onOptionsChange={(monthIndex: number, options: Options) => { + onOptionsChange(monthIndex, options) + }} + /> + ))} + + + + + + + + {t( + 'pages.simulateurs.réduction-générale.recap.caption', + 'Récapitulatif trimestriel :' + )} + + + + {t('Trimestre')} + + {t( + 'pages.simulateurs.réduction-générale.recap.header', + 'Réduction calculée' + )} +
+ {t( + 'pages.simulateurs.réduction-générale.recap.code671', + 'code 671(€)' + )} + + + {t( + 'pages.simulateurs.réduction-générale.recap.header', + 'Réduction calculée' + )} +
+ {t( + 'pages.simulateurs.réduction-générale.recap.code801', + 'code 801(€)' + )} + + + + + {Object.keys(quarters).map((label, index) => ( + ))} - -
+ + + ) : ( <> @@ -114,6 +176,23 @@ export default function RéductionGénéraleMoisParMois({ mobileVersion={true} /> ))} + + + + + {t( + 'pages.simulateurs.réduction-générale.recap.caption', + 'Récapitulatif trimestriel :' + )} + + {Object.keys(quarters).map((label, index) => ( + + ))} )} @@ -148,3 +227,16 @@ const StyledTable = styled.table` font-weight: normal; } ` +const StyledRecapTable = styled(StyledTable)` + thead { + border-bottom: solid 1px; + } + thead th:not(:last-of-type), + tbody th, + td:not(:last-of-type) { + border-right: solid 1px; + } + thead th:not(:first-of-type) { + text-align: center; + } +` diff --git "a/site/source/pages/simulateurs/reduction-generale/components/MontantR\303\251duction.tsx" "b/site/source/pages/simulateurs/reduction-generale/components/MontantR\303\251duction.tsx" index f5bb474fb7..5f39630a59 100644 --- "a/site/source/pages/simulateurs/reduction-generale/components/MontantR\303\251duction.tsx" +++ "b/site/source/pages/simulateurs/reduction-generale/components/MontantR\303\251duction.tsx" @@ -22,6 +22,7 @@ type Props = { displayedUnit: string language: string displayNull?: boolean + alignment?: 'center' | 'end' } export default function MontantRéduction({ @@ -32,6 +33,7 @@ export default function MontantRéduction({ displayedUnit, language, displayNull = true, + alignment = 'end', }: Props) { const { t } = useTranslation() @@ -39,7 +41,7 @@ export default function MontantRéduction({ return réductionGénérale ? ( - + {formatValue( { nodeValue: réductionGénérale, @@ -54,7 +56,7 @@ export default function MontantRéduction({ ) : ( displayNull && ( - + {formatValue(0, { displayedUnit, language })} ` ${FlexCenter} - justify-content: end; + justify-content: ${({ $alignment }) => $alignment}; ` const StyledSearchIcon = styled(SearchIcon)` margin-left: ${({ theme }) => theme.spacings.sm}; diff --git "a/site/source/pages/simulateurs/reduction-generale/components/R\303\251capitulatifTrimestre.tsx" "b/site/source/pages/simulateurs/reduction-generale/components/R\303\251capitulatifTrimestre.tsx" new file mode 100644 index 0000000000..51e69ba35a --- /dev/null +++ "b/site/source/pages/simulateurs/reduction-generale/components/R\303\251capitulatifTrimestre.tsx" @@ -0,0 +1,168 @@ +import { sumAll } from 'effect/Number' +import { useTranslation } from 'react-i18next' +import { styled } from 'styled-components' + +import { Grid } from '@/design-system/layout' +import { Body } from '@/design-system/typography/paragraphs' + +import { MonthState } from '../utils' +import MontantRéduction from './MontantRéduction' + +type Props = { + label: string + data: MonthState[] + mobileVersion?: boolean +} + +export type RémunérationBruteInput = { + unité: string + valeur: number +} + +export default function RécapitulatifTrimestre({ + label, + data, + mobileVersion = false, +}: Props) { + const { t, i18n } = useTranslation() + const language = i18n.language + const displayedUnit = '€' + + const rémunération = sumAll( + data.map((monthData) => monthData.rémunérationBrute) + ) + const répartition = { + IRC: sumAll( + data.map( + (monthData) => + monthData.réductionGénérale.répartition.IRC + + monthData.régularisation.répartition.IRC + ) + ), + Urssaf: sumAll( + data.map( + (monthData) => + monthData.réductionGénérale.répartition.Urssaf + + monthData.régularisation.répartition.Urssaf + ) + ), + chômage: sumAll( + data.map( + (monthData) => + monthData.réductionGénérale.répartition.chômage + + monthData.régularisation.répartition.chômage + ) + ), + } + let réduction = sumAll( + data.map((monthData) => monthData.réductionGénérale.value) + ) + let régularisation = sumAll( + data.map((monthData) => monthData.régularisation.value) + ) + if (réduction + régularisation > 0) { + réduction += régularisation + régularisation = 0 + } else { + régularisation += réduction + réduction = 0 + } + + const Montant671 = () => { + return ( + + ) + } + + const Montant801 = () => { + return ( + + ) + } + + return mobileVersion ? ( +
+ {label} + + + + {t( + 'pages.simulateurs.réduction-générale.recap.header', + 'Réduction calculée' + )} +
+ {t( + 'pages.simulateurs.réduction-générale.recap.code671', + 'code 671(€)' + )} +
+
+ + + + + +
+ + + + + {t( + 'pages.simulateurs.réduction-générale.recap.header', + 'Réduction calculée' + )} +
+ {t( + 'pages.simulateurs.réduction-générale.recap.code801', + 'code 801(€)' + )} +
+
+ + + + + +
+
+ ) : ( + + {label} + + + + + + + + ) +} + +const StyledMonth = styled(Body)` + font-weight: bold; + text-transform: capitalize; + border-bottom: solid 1px ${({ theme }) => theme.colors.bases.primary[100]}; +` +const GridContainer = styled(Grid)` + align-items: center; + justify-content: space-between; +` +const StyledBody = styled(Body)` + margin-top: 0; +` diff --git a/site/source/pages/simulateurs/reduction-generale/components/Mois.tsx "b/site/source/pages/simulateurs/reduction-generale/components/R\303\251ductionG\303\251n\303\251raleMois.tsx" similarity index 100% rename from site/source/pages/simulateurs/reduction-generale/components/Mois.tsx rename to "site/source/pages/simulateurs/reduction-generale/components/R\303\251ductionG\303\251n\303\251raleMois.tsx" From 4612d367fa1305f09725b65be71cb8209b73c403 Mon Sep 17 00:00:00 2001 From: Alice Dahan Date: Thu, 12 Dec 2024 15:49:49 +0100 Subject: [PATCH 4/5] style(rgcp): ajout de titres --- .../reduction-generale/MoisParMois.tsx | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/site/source/pages/simulateurs/reduction-generale/MoisParMois.tsx b/site/source/pages/simulateurs/reduction-generale/MoisParMois.tsx index 1ffaab3349..30e67471f7 100644 --- a/site/source/pages/simulateurs/reduction-generale/MoisParMois.tsx +++ b/site/source/pages/simulateurs/reduction-generale/MoisParMois.tsx @@ -4,7 +4,7 @@ import { styled } from 'styled-components' import RuleLink from '@/components/RuleLink' import { Spacing } from '@/design-system/layout' import { baseTheme } from '@/design-system/theme' -import { Body } from '@/design-system/typography/paragraphs' +import { H3 } from '@/design-system/typography/heading' import { useMediaQuery } from '@/hooks/useMediaQuery' import RécapitulatifTrimestre from './components/RécapitulatifTrimestre' @@ -58,8 +58,14 @@ export default function RéductionGénéraleMoisParMois({ <> {isDesktop ? ( <> +

+ {t( + 'pages.simulateurs.réduction-générale.month-by-month.caption', + '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 :' @@ -102,10 +108,16 @@ export default function RéductionGénéraleMoisParMois({ - + +

+ {t( + 'pages.simulateurs.réduction-générale.recap.caption', + 'Récapitulatif trimestriel :' + )} +

- + {t( 'pages.simulateurs.réduction-générale.recap.caption', 'Récapitulatif trimestriel :' @@ -151,12 +163,12 @@ export default function RéductionGénéraleMoisParMois({ ) : ( <> - +

{t( 'pages.simulateurs.réduction-générale.month-by-month.caption', 'Réduction générale mois par mois :' )} - +

{data.length > 0 && months.map((monthName, monthIndex) => ( - +

{t( 'pages.simulateurs.réduction-générale.recap.caption', 'Récapitulatif trimestriel :' )} - +

{Object.keys(quarters).map((label, index) => ( Date: Thu, 12 Dec 2024 16:19:44 +0100 Subject: [PATCH 5/5] =?UTF-8?q?tests(rgcp):=20correction=20et=20ajout=20de?= =?UTF-8?q?=20tests=20pour=20le=20r=C3=A9cap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mon-entreprise/reduction-generale.ts | 90 ++++++++++++------- .../R\303\251capitulatifTrimestre.tsx" | 2 + 2 files changed, 58 insertions(+), 34 deletions(-) diff --git a/site/cypress/integration/mon-entreprise/reduction-generale.ts b/site/cypress/integration/mon-entreprise/reduction-generale.ts index 022aa893f3..365be4e5c4 100755 --- a/site/cypress/integration/mon-entreprise/reduction-generale.ts +++ b/site/cypress/integration/mon-entreprise/reduction-generale.ts @@ -20,16 +20,16 @@ describe( }) it('should allow to change time period', function () { - cy.contains('Réduction mensuelle').click() - cy.get(inputSelector).first().type('{selectall}1900') + cy.get(inputSelector).first().type('{selectall}22800') - cy.contains('Réduction annuelle').click() - cy.get(inputSelector).first().should('have.value', '22 800 €') + cy.contains('Réduction mensuelle').click() + // Wait for values to update + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.wait(750) + cy.get(inputSelector).first().should('have.value', '1 900 €') }) it('should display values for the réduction générale', function () { - cy.contains('Réduction mensuelle').click() - cy.get( 'p[id="salarié___cotisations___exonérations___réduction_générale-value"]' ).should('include.text', '523,26 €') @@ -83,7 +83,6 @@ describe( }) it('should display a warning for a remuneration too high', function () { - cy.contains('Réduction mensuelle').click() cy.get(inputSelector).first().type('{selectall}3000') cy.get('div[id="simulator-legend"]').should( @@ -91,15 +90,18 @@ describe( 'La RGCP concerne uniquement les salaires inférieurs à 1,6 SMIC.' ) + cy.get( + 'p[id="salarié___cotisations___exonérations___réduction_générale-value"]' + ).should('have.text', '0 €') cy.get( 'p[id="salarié___cotisations___exonérations___réduction_générale___imputation_retraite_complémentaire-value"]' - ).should('include.text', '0 €') + ).should('have.text', '0 €') cy.get( 'p[id="salarié___cotisations___exonérations___réduction_générale___imputation_sécurité_sociale-value"]' - ).should('include.text', '0 €') + ).should('have.text', '0 €') cy.get( 'p[id="salarié___cotisations___exonérations___réduction_générale___imputation_chômage-value"]' - ).should('include.text', '0 €') + ).should('have.text', '0 €') }) it('should display remuneration and RGCP month by month', function () { @@ -108,7 +110,7 @@ describe( cy.contains('Réduction mois par mois').click() cy.contains('Réduction générale mois par mois :') - // Wait for 1 ms in order for values to update + // Wait for values to update // eslint-disable-next-line cypress/no-unnecessary-waiting cy.wait(1) cy.get(inputSelector) @@ -128,11 +130,8 @@ describe( }) it('should calculate RGCP month by month independently', function () { - cy.contains('Moins de 50 salariés').click() - cy.contains('Réduction mois par mois').click() - - cy.get(inputSelector).first().type('{selectall}1900') cy.get(inputSelector).eq(1).type('{selectall}2000') + cy.get( '#salarié___cotisations___exonérations___réduction_générale-janvier' ).should('include.text', '493,43 €') @@ -142,21 +141,14 @@ describe( }) it('should save remuneration between tabs', 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).first().type('{selectall}2000') - cy.get(inputSelector).eq(1).type('{selectall}2000') - - cy.contains('Réduction mensuelle').click() - cy.get(inputSelector).first().should('have.value', '1 916,67 €') + cy.get(inputSelector).first().should('have.value', '1 908,33 €') cy.contains('Réduction annuelle').click() - cy.get(inputSelector).first().should('have.value', '23 000 €') + cy.get(inputSelector).first().should('have.value', '22 900 €') cy.contains('Réduction mois par mois').click() cy.get(inputSelector).each(($input, index) => { let expectedValue = '1 900 €' - if (index < 2) { + if (index === 1) { expectedValue = '2 000 €' } cy.wrap($input).should('have.value', expectedValue) @@ -164,9 +156,6 @@ describe( }) it('should include progressive regularisation', function () { - 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( @@ -191,7 +180,7 @@ describe( ).should('include.text', '0 €') cy.get( '#salarié___cotisations___exonérations___réduction_générale__régularisation-février' - ).should('include.text', '0 €') + ).should('not.exist') cy.get( '#salarié___cotisations___exonérations___réduction_générale-mars' ).should('include.text', '493,43 €') @@ -225,13 +214,46 @@ describe( ) .should('be.visible') .click() - cy.get('input[id="option-rémunération-etp-janvier"]').should('be.visible') - cy.get('input[id="option-rémunération-primes-janvier"]').should( - 'be.visible' + cy.get('input[id="option-rémunération-etp-janvier"]') + .should('be.visible') + .type('{selectall}1900') + cy.get('input[id="option-rémunération-primes-janvier"]') + .should('be.visible') + .type('{selectall}200') + cy.get('input[id="option-rémunération-heures-sup-janvier"]') + .should('be.visible') + .type('{selectall}100') + + cy.get( + '#salarié___cotisations___exonérations___réduction_générale-janvier' + ).should('include.text', '479,10 €') + + cy.get( + 'div[id="simulator-legend"] button[aria-describedby="options-description"]' ) - cy.get('input[id="option-rémunération-heures-sup-janvier"]').should( - 'be.visible' + .first() + .click() + }) + + it('should include a recap table', function () { + cy.contains('Régularisation progressive').click() + cy.get('div[id="simulator-legend"]').should( + 'include.text', + 'Récapitulatif trimestriel' ) + + cy.get(inputSelector).each(($input, index) => { + if (index > 2 && index < 6) { + cy.wrap($input).type('{selectall}3000') + } + }) + // Wait for values to update + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.wait(500) + cy.get('#recap-1er_trimestre-671').should('include.text', '602,88 €') + cy.get('#recap-2ème_trimestre-801').should('include.text', '-276,40 €') + cy.get('#recap-3ème_trimestre-671').should('include.text', '1 481,79 €') + cy.get('#recap-4ème_trimestre-671').should('include.text', '1 539,05 €') }) it('should be RGAA compliant', function () { diff --git "a/site/source/pages/simulateurs/reduction-generale/components/R\303\251capitulatifTrimestre.tsx" "b/site/source/pages/simulateurs/reduction-generale/components/R\303\251capitulatifTrimestre.tsx" index 51e69ba35a..ed944f8893 100644 --- "a/site/source/pages/simulateurs/reduction-generale/components/R\303\251capitulatifTrimestre.tsx" +++ "b/site/source/pages/simulateurs/reduction-generale/components/R\303\251capitulatifTrimestre.tsx" @@ -71,6 +71,7 @@ export default function RécapitulatifTrimestre({ const Montant671 = () => { return ( { return (