feat: affiche la réduction générale mois par mois
parent
efa20c9c07
commit
1cf26edea4
|
@ -275,6 +275,8 @@ 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
|
||||
|
@ -391,6 +393,7 @@ aide-déclaration-indépendant:
|
|||
results:
|
||||
title: Amounts to report on your tax return
|
||||
aides différées, voir le détail du calcul pour aides différées: deferred aid, see detailed calculation for deferred aid
|
||||
août: August
|
||||
api:
|
||||
description: Tools for developers
|
||||
title: Use our REST API
|
||||
|
@ -402,6 +405,7 @@ assistants:
|
|||
cta: Visit the site
|
||||
title: View your public data
|
||||
au bout de 10 ans: after 10 years
|
||||
avril: April
|
||||
betawarning: "<0><0>This tool is in beta version</0>: we are working on
|
||||
<3>validating the information and calculations</3>, but <6>errors may</6>
|
||||
still occur.</0>"
|
||||
|
@ -593,6 +597,7 @@ design-system:
|
|||
prev-month: Previous month
|
||||
year: Year
|
||||
dont chômage: of which unemployment
|
||||
décembre: December
|
||||
employeur: employer
|
||||
en cas d'accident pro: in the event of a professional accident
|
||||
en incluant: including
|
||||
|
@ -637,6 +642,7 @@ footer:
|
|||
accessibilitéAriaLabel: "Accessibility: partially compliant, find out more"
|
||||
github:
|
||||
text: View source code on Github
|
||||
février: February
|
||||
gestion sémantique de version, en savoir plus, nouvelle fenêtre: semantic version management, learn more, new window
|
||||
gérer:
|
||||
choix:
|
||||
|
@ -679,7 +685,10 @@ info: info
|
|||
intégration:
|
||||
description: Tools for developers
|
||||
title: Integration
|
||||
janvier: January
|
||||
jours: days
|
||||
juillet: July
|
||||
juin: June
|
||||
l'annuaire des entreprises, nouvelle fenêtre: business directory, new window
|
||||
landing:
|
||||
aboutUs: "<0>Who are we?</0><1>We're a small, independent, multi-disciplinary
|
||||
|
@ -735,6 +744,8 @@ library:
|
|||
description: Tools for developers
|
||||
title: Calculation library
|
||||
loading: Loading in progress...
|
||||
mai: May
|
||||
mars: March
|
||||
moins: less
|
||||
mois: month
|
||||
navbar:
|
||||
|
@ -753,6 +764,8 @@ nextSteps:
|
|||
cta: See the documentation
|
||||
title: Integrate the web module
|
||||
nombres de votes: number of votes
|
||||
novembre: November
|
||||
octobre: October
|
||||
pages:
|
||||
"404":
|
||||
description: The page you are looking for does not exist or no longer exists
|
||||
|
@ -1674,6 +1687,7 @@ search-code-ape:
|
|||
select:
|
||||
value:
|
||||
default: Choose an option
|
||||
septembre: September
|
||||
shareSimulation:
|
||||
banner: Generate a share link
|
||||
button:
|
||||
|
|
|
@ -291,6 +291,8 @@ 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
|
||||
|
@ -414,6 +416,7 @@ aide-déclaration-indépendant:
|
|||
results:
|
||||
title: Montants à reporter dans votre déclaration de revenus
|
||||
aides différées, voir le détail du calcul pour aides différées: aides différées, voir le détail du calcul pour aides différées
|
||||
août: août
|
||||
api:
|
||||
description: Outils pour les développeurs
|
||||
title: Utiliser notre API REST
|
||||
|
@ -426,6 +429,7 @@ assistants:
|
|||
cta: Visiter le site
|
||||
title: Voir vos données publiques
|
||||
au bout de 10 ans: au bout de 10 ans
|
||||
avril: avril
|
||||
betawarning: "<0><0>Cet outil est en version bêta</0> : nous travaillons à
|
||||
<3>valider les informations et les calculs</3>, mais des <6>erreurs peuvent
|
||||
être présentes.</6></0>"
|
||||
|
@ -624,6 +628,7 @@ design-system:
|
|||
prev-month: Mois précédent
|
||||
year: Année
|
||||
dont chômage: dont chômage
|
||||
décembre: décembre
|
||||
employeur: employeur
|
||||
en cas d'accident pro: en cas d'accident pro
|
||||
en incluant: en incluant
|
||||
|
@ -669,6 +674,7 @@ footer:
|
|||
accessibilitéAriaLabel: "Accessibilité : partiellement conforme, en savoir plus"
|
||||
github:
|
||||
text: Voir le code source sur Github
|
||||
février: février
|
||||
gestion sémantique de version, en savoir plus, nouvelle fenêtre: gestion sémantique de version, en savoir plus, nouvelle fenêtre
|
||||
gérer:
|
||||
choix:
|
||||
|
@ -714,7 +720,10 @@ info: info
|
|||
intégration:
|
||||
description: Outils pour les développeurs
|
||||
title: Intégration
|
||||
janvier: janvier
|
||||
jours: jours
|
||||
juillet: juillet
|
||||
juin: juin
|
||||
l'annuaire des entreprises, nouvelle fenêtre: l'annuaire des entreprises, nouvelle fenêtre
|
||||
landing:
|
||||
aboutUs: "<0>Qui sommes-nous ?</0><1>Nous sommes une petite <2>équipe</2>
|
||||
|
@ -774,6 +783,8 @@ library:
|
|||
description: Outils pour les développeurs
|
||||
title: Librairie de calcul
|
||||
loading: Chargement en cours...
|
||||
mai: mai
|
||||
mars: mars
|
||||
moins: moins
|
||||
mois: mois
|
||||
navbar:
|
||||
|
@ -792,6 +803,8 @@ nextSteps:
|
|||
cta: Voir la documentation
|
||||
title: Intégrer le module web
|
||||
nombres de votes: nombres de votes
|
||||
novembre: novembre
|
||||
octobre: octobre
|
||||
pages:
|
||||
"404":
|
||||
description: La page que vous cherchez n'existe pas ou n'existe plus
|
||||
|
@ -1782,6 +1795,7 @@ search-code-ape:
|
|||
select:
|
||||
value:
|
||||
default: Choisissez une option
|
||||
septembre: septembre
|
||||
shareSimulation:
|
||||
banner: Générer un lien de partage
|
||||
button:
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { useCallback, useState } from 'react'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { styled } from 'styled-components'
|
||||
|
||||
import { Condition } from '@/components/EngineValue/Condition'
|
||||
|
@ -11,12 +12,19 @@ import Simulation, {
|
|||
SimulationGoals,
|
||||
} 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 { Li, Ul } from '@/design-system/typography/list'
|
||||
import { Body } from '@/design-system/typography/paragraphs'
|
||||
|
||||
import EffectifSwitch from './components/EffectifSwitch'
|
||||
import RéductionGénéraleMoisParMois from './RéductionGénéraleMoisParMois'
|
||||
import {
|
||||
getInitialRéductionGénéraleMoisParMois,
|
||||
MonthState,
|
||||
rémunérationBruteDottedName,
|
||||
} from './utils'
|
||||
|
||||
export default function RéductionGénéraleSimulation() {
|
||||
const { t } = useTranslation()
|
||||
|
@ -80,22 +88,34 @@ function RéductionGénéraleSimulationGoals({
|
|||
toggles?: React.ReactNode
|
||||
legend: string
|
||||
}) {
|
||||
const engine = useEngine()
|
||||
const { t } = useTranslation()
|
||||
const [réductionGénéraleMoisParMoisData, setData] = useState<MonthState[]>([])
|
||||
|
||||
const initializeRéductionGénéraleMoisParMoisData = useCallback(() => {
|
||||
setData(getInitialRéductionGénéraleMoisParMois(engine))
|
||||
}, [engine, setData])
|
||||
|
||||
useEffect(() => {
|
||||
if (réductionGénéraleMoisParMoisData.length === 0) {
|
||||
initializeRéductionGénéraleMoisParMoisData()
|
||||
}
|
||||
}, [
|
||||
initializeRéductionGénéraleMoisParMoisData,
|
||||
réductionGénéraleMoisParMoisData,
|
||||
])
|
||||
|
||||
return (
|
||||
<SimulationGoals toggles={toggles} legend={legend}>
|
||||
{monthByMonth ? (
|
||||
<div>
|
||||
Réduction générale mensuelle
|
||||
</div>
|
||||
<RéductionGénéraleMoisParMois data={réductionGénéraleMoisParMoisData} />
|
||||
) : (
|
||||
<>
|
||||
{/* TODO: remplacer "salarié . cotisations . assiette" par "salarié . rémunération . brut"
|
||||
lorsqu'elle n'incluera plus les frais professionnels. */}
|
||||
<SimulationGoal
|
||||
dottedName="salarié . cotisations . assiette"
|
||||
dottedName={rémunérationBruteDottedName}
|
||||
round={false}
|
||||
label={t('Rémunération brute', 'Rémunération brute')}
|
||||
onUpdateSituation={initializeRéductionGénéraleMoisParMoisData}
|
||||
/>
|
||||
|
||||
<Condition expression="salarié . cotisations . exonérations . JEI = oui">
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
import { formatValue } from 'publicodes'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { styled } from 'styled-components'
|
||||
|
||||
import { ExplicableRule } from '@/components/conversation/Explicable'
|
||||
import NumberInput from '@/components/conversation/NumberInput'
|
||||
import { useEngine } from '@/components/utils/EngineContext'
|
||||
|
||||
import { MonthState, rémunérationBruteDottedName } from './utils'
|
||||
|
||||
export default function RéductionGénéraleMoisParMois({
|
||||
data,
|
||||
}: {
|
||||
data: MonthState[]
|
||||
}) {
|
||||
const engine = useEngine()
|
||||
const { t, i18n } = useTranslation()
|
||||
const language = i18n.language
|
||||
const displayedUnit = '€'
|
||||
|
||||
const months = [
|
||||
t('janvier'),
|
||||
t('février'),
|
||||
t('mars'),
|
||||
t('avril'),
|
||||
t('mai'),
|
||||
t('juin'),
|
||||
t('juillet'),
|
||||
t('août'),
|
||||
t('septembre'),
|
||||
t('octobre'),
|
||||
t('novembre'),
|
||||
t('décembre'),
|
||||
]
|
||||
|
||||
const onRémunérationChange = () => {}
|
||||
|
||||
// TODO: enlever les 4 premières props après résolution de #3123
|
||||
const ruleInputProps = {
|
||||
dottedName: rémunérationBruteDottedName,
|
||||
suggestions: {},
|
||||
description: undefined,
|
||||
question: undefined,
|
||||
engine,
|
||||
'aria-labelledby': 'simu-update-explaining',
|
||||
formatOptions: {
|
||||
maximumFractionDigits: 0,
|
||||
},
|
||||
displayedUnit,
|
||||
unit: {
|
||||
numerators: ['€'],
|
||||
denominators: [],
|
||||
},
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledTable style={{ width: '100%' }}>
|
||||
<caption>{t('Réduction générale mois par mois :')}</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">{t('Mois')}</th>
|
||||
<th scope="col">
|
||||
{t('Rémunération brute', 'Rémunération brute')}
|
||||
<ExplicableRule dottedName="salarié . rémunération . brut" />
|
||||
</th>
|
||||
<th scope="col">
|
||||
{t('Réduction générale')}
|
||||
<ExplicableRule
|
||||
dottedName="salarié . cotisations . exonérations . réduction générale"
|
||||
light
|
||||
/>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.length > 0 &&
|
||||
months.map((monthName, monthIndex) => (
|
||||
<tr key={`month-${monthIndex}`}>
|
||||
<th scope="row">{monthName}</th>
|
||||
<td>
|
||||
<NumberInput
|
||||
{...ruleInputProps}
|
||||
id={`${rémunérationBruteDottedName.replace(
|
||||
/\s|\./g,
|
||||
'_'
|
||||
)}-${monthIndex}`}
|
||||
aria-label={`${engine.getRule(rémunérationBruteDottedName)
|
||||
?.title} (${monthName})`}
|
||||
onChange={onRémunérationChange}
|
||||
value={data[monthIndex].rémunérationBrute}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
{data[monthIndex].réductionGénérale
|
||||
? formatValue(
|
||||
{ nodeValue: data[monthIndex].réductionGénérale },
|
||||
{
|
||||
displayedUnit,
|
||||
language,
|
||||
}
|
||||
)
|
||||
: formatValue(0, { displayedUnit, language })}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</StyledTable>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const StyledTable = styled.table`
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
color: ${({ theme }) => theme.colors.bases.primary[100]};
|
||||
font-family: ${({ theme }) => theme.fonts.main};
|
||||
caption {
|
||||
text-align: left;
|
||||
margin: ${({ theme }) => `${theme.spacings.sm} 0 `};
|
||||
}
|
||||
th {
|
||||
padding: ${({ theme }) => `${theme.spacings.xs} 0 ${theme.spacings.lg} 0`};
|
||||
}
|
||||
tbody tr td:not(:first-of-type) {
|
||||
padding: ${({ theme }) =>
|
||||
`${theme.spacings.xs} ${theme.spacings.xxs} ${theme.spacings.lg} ${theme.spacings.xxs}`};
|
||||
}
|
||||
tbody tr th {
|
||||
text-transform: capitalize;
|
||||
font-weight: normal;
|
||||
}
|
||||
`
|
|
@ -0,0 +1,59 @@
|
|||
import { DottedName } from 'modele-social'
|
||||
import Engine 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 type MonthState = {
|
||||
rémunérationBrute: number
|
||||
réductionGénérale: number
|
||||
}
|
||||
|
||||
export const getRéductionGénéraleFromRémunération = (
|
||||
engine: Engine<DottedName>,
|
||||
rémunérationBrute: number
|
||||
): number => {
|
||||
const réductionGénérale = engine.evaluate({
|
||||
valeur: 'salarié . cotisations . exonérations . réduction générale',
|
||||
unité: '€/mois',
|
||||
contexte: {
|
||||
[rémunérationBruteDottedName]: rémunérationBrute,
|
||||
},
|
||||
})
|
||||
|
||||
return réductionGénérale.nodeValue as number
|
||||
}
|
||||
|
||||
export const getInitialRéductionGénéraleMoisParMois = (
|
||||
engine: Engine<DottedName>
|
||||
): MonthState[] => {
|
||||
const rémunérationBrute =
|
||||
(engine.evaluate({
|
||||
valeur: rémunérationBruteDottedName,
|
||||
arrondi: 'oui',
|
||||
unité: '€/mois',
|
||||
})?.nodeValue as number) || 0
|
||||
const réductionGénérale = getRéductionGénéraleFromRémunération(
|
||||
engine,
|
||||
rémunérationBrute
|
||||
)
|
||||
|
||||
return Array(12).fill({
|
||||
rémunérationBrute,
|
||||
réductionGénérale,
|
||||
}) as MonthState[]
|
||||
}
|
||||
|
||||
export const reevaluateRéductionGénéraleMoisParMois = (
|
||||
data: MonthState[],
|
||||
engine: Engine<DottedName>
|
||||
): MonthState[] => {
|
||||
return data.map((item) => ({
|
||||
...item,
|
||||
réductionGénérale: getRéductionGénéraleFromRémunération(
|
||||
engine,
|
||||
item.rémunérationBrute
|
||||
),
|
||||
}))
|
||||
}
|
Loading…
Reference in New Issue