diff --git a/api/source/test-e2e/__snapshots__/index.test.ts.snap b/api/source/test-e2e/__snapshots__/index.test.ts.snap index 839419124..2aac40020 100644 --- a/api/source/test-e2e/__snapshots__/index.test.ts.snap +++ b/api/source/test-e2e/__snapshots__/index.test.ts.snap @@ -437,6 +437,7 @@ exports[`e2e test mon-entreprise api > Test evaluate brut => net + super brut 2` "salarié . cotisations . exonérations . lodeom . zone deux", "salarié . cotisations . exonérations . lodeom . zone un", "salarié . cotisations . exonérations . réduction générale . caisse de congés payés", + "salarié . cotisations . exonérations . zones lodeom", "salarié . cotisations . maladie . employeur . taux réduit", "salarié . cotisations . prévoyances . santé . montant", "salarié . cotisations . prévoyances . santé . taux employeur", diff --git a/modele-social/règles/salarié/cotisations.publicodes b/modele-social/règles/salarié/cotisations.publicodes index 5d5afc4fc..d8b2038c9 100644 --- a/modele-social/règles/salarié/cotisations.publicodes +++ b/modele-social/règles/salarié/cotisations.publicodes @@ -143,6 +143,22 @@ salarié . cotisations . exonérations . heures supplémentaires: - 1 / assiette plafond: 11.31% +salarié . cotisations . exonérations . zones lodeom: + question: Quelle est votre localisation ? + formule: + une possibilité: + choix obligatoire: oui + possibilités: + - zone un + - zone deux + avec: + zone un: + valeur: zones lodeom = 'zone un' + titre: Guadeloupe, Guyane, Martinique, La Réunion + zone deux: + valeur: zones lodeom = 'zone deux' + titre: Saint-Barthélémy, Saint-Martin + salarié . cotisations . exonérations . lodeom: experimental: oui applicable si: @@ -190,6 +206,7 @@ salarié . cotisations . exonérations . lodeom . zone un: titre: Guadeloupe, Guyane, Martinique, La Réunion par défaut: non une de ces conditions: + - zones lodeom = 'zone un' - établissement . commune . département = 'Guadeloupe' - établissement . commune . département = 'La Réunion' - établissement . commune . département = 'Martinique' @@ -405,6 +422,7 @@ salarié . cotisations . exonérations . lodeom . zone deux: titre: Saint-Barthélémy, Saint-Martin par défaut: non une de ces conditions: + - zones lodeom = 'zone deux' - établissement . commune . département = 'Saint-Barthélemy' - établissement . commune . département = 'Saint-Martin' références: diff --git a/site/cypress/integration/mon-entreprise/lodeom.ts b/site/cypress/integration/mon-entreprise/lodeom.ts index a351c08ff..e7b2fba13 100755 --- a/site/cypress/integration/mon-entreprise/lodeom.ts +++ b/site/cypress/integration/mon-entreprise/lodeom.ts @@ -62,17 +62,13 @@ describe('Simulateur lodeom', { testIsolation: false }, function () { }) it('should allow to select a scale', function () { - cy.get('#salarié___cotisations___exonérations___lodeom___zone_un___barèmes') - .contains('Barème de compétitivité renforcée') - .click() + cy.contains('Barème de compétitivité renforcée').click() cy.get( 'p[id="salarié___cotisations___exonérations___lodeom___montant-value"]' ).should('include.text', '1 117,90 €') - cy.get('#salarié___cotisations___exonérations___lodeom___zone_un___barèmes') - .contains("Barème d'innovation et croissance") - .click() + cy.contains("Barème d'innovation et croissance").click() cy.get( 'p[id="salarié___cotisations___exonérations___lodeom___montant-value"]' @@ -81,31 +77,19 @@ describe('Simulateur lodeom', { testIsolation: false }, function () { it('should allow to select a zone', function () { cy.contains('Saint-Barthélémy, Saint-Martin').click() - cy.get( - '#salarié___cotisations___exonérations___lodeom___zone_deux___barèmes' - ) - .contains('Barème pour les employeurs de moins de 11 salariés') - .click() + cy.contains('Barème pour les employeurs de moins de 11 salariés').click() cy.get( 'p[id="salarié___cotisations___exonérations___lodeom___montant-value"]' ).should('include.text', '530,25 €') - cy.get( - '#salarié___cotisations___exonérations___lodeom___zone_deux___barèmes' - ) - .contains("Barème d'exonération sectorielle") - .click() + cy.contains("Barème d'exonération sectorielle").click() cy.get( 'p[id="salarié___cotisations___exonérations___lodeom___montant-value"]' ).should('include.text', '350,35 €') - cy.get( - '#salarié___cotisations___exonérations___lodeom___zone_deux___barèmes' - ) - .contains("Barème d'exonération renforcée") - .click() + cy.contains("Barème d'exonération renforcée").click() cy.get( 'p[id="salarié___cotisations___exonérations___lodeom___montant-value"]' diff --git a/site/source/components/EffectifSwitch.tsx b/site/source/components/EffectifSwitch.tsx index 50edeb7b8..9d014a78a 100644 --- a/site/source/components/EffectifSwitch.tsx +++ b/site/source/components/EffectifSwitch.tsx @@ -26,7 +26,7 @@ export default function EffectifSwitch() { return ( - {t("Effectif de l'entreprise")} : + {t('Effectif de l’entreprise')} : theme.spacings.sm}; width: 100%; + margin-bottom: ${({ theme }) => theme.spacings.sm}; ` const StyledBody = styled(Body)` - margin: ${({ theme }) => theme.spacings.xxs} 0; + margin: 0; + margin-bottom: ${({ theme }) => theme.spacings.sm}; ` const StyledToggleGroup = styled(ToggleGroup)` display: flex; diff --git a/site/source/components/RéductionDeCotisations/RégularisationSwitch.tsx b/site/source/components/RéductionDeCotisations/RégularisationSwitch.tsx index 9d9cd3baa..76f19a741 100644 --- a/site/source/components/RéductionDeCotisations/RégularisationSwitch.tsx +++ b/site/source/components/RéductionDeCotisations/RégularisationSwitch.tsx @@ -60,9 +60,11 @@ const Container = styled.div` flex-wrap: wrap; column-gap: ${({ theme }) => theme.spacings.sm}; width: 100%; + margin-bottom: ${({ theme }) => theme.spacings.sm}; ` const StyledBody = styled(Body)` - margin: ${({ theme }) => theme.spacings.xxs} 0; + margin: 0; + margin-bottom: ${({ theme }) => theme.spacings.sm}; ` const StyledToggleGroup = styled(ToggleGroup)` display: flex; diff --git a/site/source/hooks/useBarèmeLodeom.ts b/site/source/hooks/useBarèmeLodeom.ts new file mode 100644 index 000000000..aaec9bfa3 --- /dev/null +++ b/site/source/hooks/useBarèmeLodeom.ts @@ -0,0 +1,29 @@ +import { DottedName } from 'modele-social' + +import { useEngine } from '@/components/utils/EngineContext' + +import { useZoneLodeom, ZoneLodeom } from './useZoneLodeom' + +const barèmes = [ + 'barème compétitivité', + 'barème compétitivité renforcée', + 'barème innovation et croissance', + 'barème moins de 11 salariés', + 'barème sectoriel', + 'barème renforcé', +] + +export type BarèmeLodeom = (typeof barèmes)[number] + +export const barèmeLodeomDottedName = (zone: ZoneLodeom) => + `salarié . cotisations . exonérations . lodeom . ${zone} . barèmes` as DottedName + +export const useBarèmeLodeom = (): BarèmeLodeom | undefined => { + const zone = useZoneLodeom() + const engine = useEngine() + + return ( + zone && + (engine.evaluate(barèmeLodeomDottedName(zone)).nodeValue as BarèmeLodeom) + ) +} diff --git a/site/source/hooks/useZoneLodeom.ts b/site/source/hooks/useZoneLodeom.ts index 1487a5e82..dbb873aa2 100644 --- a/site/source/hooks/useZoneLodeom.ts +++ b/site/source/hooks/useZoneLodeom.ts @@ -1,38 +1,16 @@ -import { useDispatch } from 'react-redux' +import { DottedName } from 'modele-social' import { useEngine } from '@/components/utils/EngineContext' -import { toOuiNon } from '@/domaine/engine/toOuiNon' -import { batchUpdateSituation } from '@/store/actions/actions' const zones = ['zone un', 'zone deux'] export type ZoneLodeom = (typeof zones)[number] -type ReturnType = { - currentZone?: ZoneLodeom - updateZone: (zone: ZoneLodeom) => void -} +export const zonesLodeomDottedName = + 'salarié . cotisations . exonérations . zones lodeom' as DottedName -export const useZoneLodeom = (): ReturnType => { +export const useZoneLodeom = (): ZoneLodeom | undefined => { const engine = useEngine() - const dispatch = useDispatch() - const dottedName = 'salarié . cotisations . exonérations . lodeom' - const currentZone = zones.find((zone) => { - const zoneValue = engine.evaluate(`${dottedName} . ${zone}`).nodeValue - - return !!zoneValue - }) - - const updateZone = (newZone: ZoneLodeom): void => { - const newSituation = zones.reduce((situation, zone) => { - return { - ...situation, - [`${dottedName} . ${zone}`]: toOuiNon(zone === newZone), - } - }, {}) - dispatch(batchUpdateSituation(newSituation)) - } - - return { currentZone, updateZone } + return engine.evaluate(zonesLodeomDottedName).nodeValue as ZoneLodeom } diff --git a/site/source/locales/rules-en.yaml b/site/source/locales/rules-en.yaml index e2c2f2a14..33ef7af08 100644 --- a/site/source/locales/rules-en.yaml +++ b/site/source/locales/rules-en.yaml @@ -10380,6 +10380,18 @@ salarié . cotisations . exonérations . réduction générale . régularisation - ou au titre du dernier trimestre de l’année pour les employeurs « trimestriels ». titre.en: '[automatic] regularization' titre.fr: régularisation +salarié . cotisations . exonérations . zones lodeom: + avec: + zone deux: + titre.en: '[automatic] Saint-Barthélémy, Saint-Martin' + titre.fr: Saint-Barthélémy, Saint-Martin + zone un: + titre.en: '[automatic] Guadeloupe, French Guiana, Martinique, Reunion Island' + titre.fr: Guadeloupe, Guyane, Martinique, La Réunion + question.en: '[automatic] Where are you located?' + question.fr: Quelle est votre localisation ? + titre.en: '[automatic] lodeom zones' + titre.fr: zones lodeom salarié . cotisations . forfait social: description.en: > [automatic] The social security contribution is a contribution paid by the diff --git a/site/source/locales/ui-en.yaml b/site/source/locales/ui-en.yaml index 663e93594..39bf66586 100644 --- a/site/source/locales/ui-en.yaml +++ b/site/source/locales/ui-en.yaml @@ -92,7 +92,7 @@ Décès: Deaths Déplier: Unfold "Détail du montant :": "Amount in detail :" Effacer mes réponses: Delete my answers -Effectif de l'entreprise: Number of employees +Effectif de l’entreprise: Number of employees "En cas d’<1>accident de travail, de <4>maladie professionnelle ou d’un <7>accident sur le trajet domicile-travail, vous serez indemnisé(e) à hauteur de :": "In the event of an<1>accident at work, <4>occupational illness or an <7>accident on the way to or from work, you will receive compensation of:" @@ -137,7 +137,6 @@ Graphique statistiques détaillés de la satisfaction, présence d’une alterna Graphique statistiques détaillés du nombre visites par jour, présence d’une alternative accessible après l’image: Graph showing detailed statistics on the number of visits per day, with an alternative accessible after the image -Guadeloupe, Guyane, Martinique, La Réunion: Guadeloupe, French Guiana, Martinique, Reunion Island Habituellement: Usually Impôt: Tax Impôt au barème: Tax scale @@ -279,7 +278,6 @@ Répartition du chiffre d'affaires: Sales breakdown Répondez à quelques questions additionnelles afin de préciser votre résultat.: Answer a few additional questions to clarify your result. Résultat fiscal: Taxable income Réussite: Success -Saint-Barthélémy, Saint-Martin: Saint-Barthélémy, Saint-Martin Saisissez votre domaine d'activité: Enter your field of activity Salaire brut: Gross salary Salaire brut mensuel: Gross monthly salary @@ -1490,7 +1488,7 @@ pages: salaries below 3.5 SMIC. This means, for 2024, a total remuneration not exceeding <2>€6,306.30 gross per month. stage: The Lodeom exemption does not apply to internship bonuses. - zone-switch-label: Company location + zone-switch-label: "Company location :" médecin: meta: description: Calculation of net income after deduction of contributions, based diff --git a/site/source/locales/ui-fr.yaml b/site/source/locales/ui-fr.yaml index 7abcaffec..e29190b37 100644 --- a/site/source/locales/ui-fr.yaml +++ b/site/source/locales/ui-fr.yaml @@ -98,7 +98,7 @@ Décès: Décès Déplier: Déplier "Détail du montant :": "Détail du montant :" Effacer mes réponses: Effacer mes réponses -Effectif de l'entreprise: Effectif de l'entreprise +Effectif de l’entreprise: Effectif de l’entreprise "En cas d’<1>accident de travail, de <4>maladie professionnelle ou d’un <7>accident sur le trajet domicile-travail, vous serez indemnisé(e) à hauteur de :": "En cas d’<1>accident de travail, de <4>maladie professionnelle ou d’un <7>accident sur le trajet domicile-travail, vous serez indemnisé(e) à @@ -146,7 +146,6 @@ Graphique statistiques détaillés de la satisfaction, présence d’une alterna Graphique statistiques détaillés du nombre visites par jour, présence d’une alternative accessible après l’image: Graphique statistiques détaillés du nombre visites par jour, présence d’une alternative accessible après l’image -Guadeloupe, Guyane, Martinique, La Réunion: Guadeloupe, Guyane, Martinique, La Réunion Habituellement: Habituellement Impôt: Impôt Impôt au barème: Impôt au barème @@ -294,7 +293,6 @@ Répartition du chiffre d'affaires: Répartition du chiffre d'affaires Répondez à quelques questions additionnelles afin de préciser votre résultat.: Répondez à quelques questions additionnelles afin de préciser votre résultat. Résultat fiscal: Résultat fiscal Réussite: Réussite -Saint-Barthélémy, Saint-Martin: Saint-Barthélémy, Saint-Martin Saisissez votre domaine d'activité: Saisissez votre domaine d'activité Salaire brut: Salaire brut Salaire brut mensuel: Salaire brut mensuel @@ -1587,7 +1585,7 @@ pages: 2024, une rémunération totale qui ne dépasse pas <2>6 306,30 € bruts par mois. stage: L'exonération Lodeom ne s'applique pas sur les gratifications de stage. - zone-switch-label: Localisation de l'entreprise + zone-switch-label: "Localisation de l’entreprise :" médecin: meta: description: Calcul du revenu net après déduction des cotisations à partir du diff --git a/site/source/pages/simulateurs/lodeom/Lodeom.tsx b/site/source/pages/simulateurs/lodeom/Lodeom.tsx index 5fd575da0..54be2c827 100644 --- a/site/source/pages/simulateurs/lodeom/Lodeom.tsx +++ b/site/source/pages/simulateurs/lodeom/Lodeom.tsx @@ -15,8 +15,9 @@ import ZoneSwitch from './components/ZoneSwitch' import LodeomSimulationGoals from './Goals' export default function LodeomSimulation() { - const { t } = useTranslation() + const currentZone = useZoneLodeom() const [monthByMonth, setMonthByMonth] = useState(false) + const { t } = useTranslation() const periods = [ { label: t('pages.simulateurs.lodeom.tab.month', 'Exonération mensuelle'), @@ -41,8 +42,6 @@ export default function LodeomSimulation() { const [régularisationMethod, setRégularisationMethod] = useState('progressive') - const { currentZone } = useZoneLodeom() - return ( <> }> diff --git a/site/source/pages/simulateurs/lodeom/components/BarèmeSwitch.tsx b/site/source/pages/simulateurs/lodeom/components/BarèmeSwitch.tsx index f6850f8f5..537546dde 100644 --- a/site/source/pages/simulateurs/lodeom/components/BarèmeSwitch.tsx +++ b/site/source/pages/simulateurs/lodeom/components/BarèmeSwitch.tsx @@ -1,23 +1,21 @@ -import { DottedName } from 'modele-social' import { renderToString } from 'react-dom/server' import { useTranslation } from 'react-i18next' import { styled } from 'styled-components' import { Body } from '@/design-system/typography/paragraphs' +import { barèmeLodeomDottedName } from '@/hooks/useBarèmeLodeom' import { useZoneLodeom } from '@/hooks/useZoneLodeom' import { SimpleField } from '@/pages/assistants/components/Fields' export default function BarèmeSwitch() { - const { currentZone } = useZoneLodeom() + const currentZone = useZoneLodeom() const { t } = useTranslation() return ( currentZone && ( @@ -42,8 +40,9 @@ const Container = styled.div` flex-wrap: wrap; column-gap: ${({ theme }) => theme.spacings.sm}; width: 100%; - margin-bottom: -${({ theme }) => theme.spacings.xl}; + margin-bottom: -${({ theme }) => theme.spacings.lg}; ` const StyledBody = styled(Body)` - margin: ${({ theme }) => theme.spacings.xxs} 0; + margin: 0; + margin-bottom: ${({ theme }) => theme.spacings.md}; ` diff --git a/site/source/pages/simulateurs/lodeom/components/WarningSalaireTrans.tsx b/site/source/pages/simulateurs/lodeom/components/WarningSalaireTrans.tsx index 5930be283..7964b3b66 100644 --- a/site/source/pages/simulateurs/lodeom/components/WarningSalaireTrans.tsx +++ b/site/source/pages/simulateurs/lodeom/components/WarningSalaireTrans.tsx @@ -1,16 +1,9 @@ import { Trans } from 'react-i18next' -import { useEngine } from '@/components/utils/EngineContext' -import { useZoneLodeom } from '@/hooks/useZoneLodeom' +import { useBarèmeLodeom } from '@/hooks/useBarèmeLodeom' export default function WarningSalaireTrans() { - const { currentZone } = useZoneLodeom() - const engine = useEngine() - const currentBarème = - currentZone && - engine.evaluate( - `salarié . cotisations . exonérations . lodeom . ${currentZone} . barèmes` - ).nodeValue + const currentBarème = useBarèmeLodeom() return ( currentBarème && ( diff --git a/site/source/pages/simulateurs/lodeom/components/ZoneSwitch.tsx b/site/source/pages/simulateurs/lodeom/components/ZoneSwitch.tsx index cbb6130bd..ac6b0a917 100644 --- a/site/source/pages/simulateurs/lodeom/components/ZoneSwitch.tsx +++ b/site/source/pages/simulateurs/lodeom/components/ZoneSwitch.tsx @@ -1,38 +1,30 @@ +import { renderToString } from 'react-dom/server' import { useTranslation } from 'react-i18next' import { styled } from 'styled-components' -import { Radio, ToggleGroup } from '@/design-system' -import { Strong } from '@/design-system/typography' import { Body } from '@/design-system/typography/paragraphs' -import { useZoneLodeom } from '@/hooks/useZoneLodeom' +import { zonesLodeomDottedName } from '@/hooks/useZoneLodeom' +import { SimpleField } from '@/pages/assistants/components/Fields' export default function ZoneSwitch() { - const { currentZone, updateZone } = useZoneLodeom() const { t } = useTranslation() return ( - - - {t( - 'pages.simulateurs.lodeom.zone-switch-label', - "Localisation de l'entreprise" - )}{' '} - : - - - - - {t('Guadeloupe, Guyane, Martinique, La Réunion')} - - - {t('Saint-Barthélémy, Saint-Martin')} - - + + + {t( + 'pages.simulateurs.lodeom.zone-switch-label', + 'Localisation de l’entreprise :' + )} + +

+ )} + labelStyle={StyledBody} + />
) } @@ -44,20 +36,9 @@ const Container = styled.div` flex-wrap: wrap; column-gap: ${({ theme }) => theme.spacings.sm}; width: 100%; + margin-bottom: -${({ theme }) => theme.spacings.lg}; ` const StyledBody = styled(Body)` - margin: ${({ theme }) => theme.spacings.xxs} 0; -` -const StyledToggleGroup = styled(ToggleGroup)` - display: flex; - > * { - display: flex; - flex-direction: column; - } -` -const StyledRadio = styled(Radio)` - white-space: nowrap; - > span { - width: 100%; - } + margin: 0; + margin-bottom: ${({ theme }) => theme.spacings.md}; ` diff --git a/site/source/pages/simulateurs/reduction-generale/components/CongésPayésSwitch.tsx b/site/source/pages/simulateurs/reduction-generale/components/CongésPayésSwitch.tsx index 55cbef09a..374bee0c9 100644 --- a/site/source/pages/simulateurs/reduction-generale/components/CongésPayésSwitch.tsx +++ b/site/source/pages/simulateurs/reduction-generale/components/CongésPayésSwitch.tsx @@ -54,9 +54,11 @@ const Container = styled.div` flex-wrap: wrap; column-gap: ${({ theme }) => theme.spacings.sm}; width: 100%; + margin-bottom: ${({ theme }) => theme.spacings.sm}; ` const StyledBody = styled(Body)` - margin: ${({ theme }) => theme.spacings.xxs} 0; + margin: 0; + margin-bottom: ${({ theme }) => theme.spacings.sm}; ` const StyledToggleGroup = styled(ToggleGroup)` display: flex;