feat(rgcp): ajout d'un récapitulatif trimestriel
parent
6454050828
commit
1c6bcd358b
|
@ -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 »</1> est versé aux <4>enfants des travailleurs indépendants</4> 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.</0>
|
||||
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
|
||||
|
|
|
@ -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 »</1> est versé aux <4>enfants des travailleurs indépendants</4> 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.</0>
|
||||
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
|
||||
|
|
|
@ -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 ? (
|
||||
<StyledTable>
|
||||
<caption>
|
||||
{t(
|
||||
'pages.simulateurs.réduction-générale.month-by-month.caption',
|
||||
'Réduction générale mois par mois :'
|
||||
)}
|
||||
</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">{t('Mois')}</th>
|
||||
<th scope="col">
|
||||
{/* TODO: remplacer par rémunérationBruteDottedName lorsque ... */}
|
||||
<RuleLink dottedName="salarié . rémunération . brut" />
|
||||
</th>
|
||||
<th scope="col">
|
||||
<RuleLink dottedName={réductionGénéraleDottedName} />
|
||||
</th>
|
||||
<th scope="col">
|
||||
<RuleLink dottedName="salarié . cotisations . exonérations . réduction générale . régularisation" />
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.length > 0 &&
|
||||
months.map((monthName, monthIndex) => (
|
||||
<RéductionGénéraleMois
|
||||
key={`month-${monthIndex}`}
|
||||
monthName={monthName}
|
||||
data={data[monthIndex]}
|
||||
index={monthIndex}
|
||||
onRémunérationChange={(
|
||||
monthIndex: number,
|
||||
rémunérationBrute: number
|
||||
) => {
|
||||
onRémunérationChange(monthIndex, rémunérationBrute)
|
||||
}}
|
||||
onOptionsChange={(monthIndex: number, options: Options) => {
|
||||
onOptionsChange(monthIndex, options)
|
||||
}}
|
||||
<>
|
||||
<StyledTable>
|
||||
<caption>
|
||||
{t(
|
||||
'pages.simulateurs.réduction-générale.month-by-month.caption',
|
||||
'Réduction générale mois par mois :'
|
||||
)}
|
||||
</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">{t('Mois')}</th>
|
||||
<th scope="col">
|
||||
{/* TODO: remplacer par rémunérationBruteDottedName lorsque ... */}
|
||||
<RuleLink dottedName="salarié . rémunération . brut" />
|
||||
</th>
|
||||
<th scope="col">
|
||||
<RuleLink dottedName={réductionGénéraleDottedName} />
|
||||
</th>
|
||||
<th scope="col">
|
||||
<RuleLink dottedName="salarié . cotisations . exonérations . réduction générale . régularisation" />
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.length > 0 &&
|
||||
months.map((monthName, monthIndex) => (
|
||||
<RéductionGénéraleMois
|
||||
key={`month-${monthIndex}`}
|
||||
monthName={monthName}
|
||||
data={data[monthIndex]}
|
||||
index={monthIndex}
|
||||
onRémunérationChange={(
|
||||
monthIndex: number,
|
||||
rémunérationBrute: number
|
||||
) => {
|
||||
onRémunérationChange(monthIndex, rémunérationBrute)
|
||||
}}
|
||||
onOptionsChange={(monthIndex: number, options: Options) => {
|
||||
onOptionsChange(monthIndex, options)
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</tbody>
|
||||
</StyledTable>
|
||||
|
||||
<Spacing xxl />
|
||||
|
||||
<StyledRecapTable>
|
||||
<caption>
|
||||
{t(
|
||||
'pages.simulateurs.réduction-générale.recap.caption',
|
||||
'Récapitulatif trimestriel :'
|
||||
)}
|
||||
</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">{t('Trimestre')}</th>
|
||||
<th scope="col">
|
||||
{t(
|
||||
'pages.simulateurs.réduction-générale.recap.header',
|
||||
'Réduction calculée'
|
||||
)}
|
||||
<br />
|
||||
{t(
|
||||
'pages.simulateurs.réduction-générale.recap.code671',
|
||||
'code 671(€)'
|
||||
)}
|
||||
</th>
|
||||
<th scope="col">
|
||||
{t(
|
||||
'pages.simulateurs.réduction-générale.recap.header',
|
||||
'Réduction calculée'
|
||||
)}
|
||||
<br />
|
||||
{t(
|
||||
'pages.simulateurs.réduction-générale.recap.code801',
|
||||
'code 801(€)'
|
||||
)}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{Object.keys(quarters).map((label, index) => (
|
||||
<RécapitulatifTrimestre
|
||||
key={index}
|
||||
label={label}
|
||||
data={quarters[label]}
|
||||
/>
|
||||
))}
|
||||
</tbody>
|
||||
</StyledTable>
|
||||
</tbody>
|
||||
</StyledRecapTable>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Body>
|
||||
|
@ -114,6 +176,23 @@ export default function RéductionGénéraleMoisParMois({
|
|||
mobileVersion={true}
|
||||
/>
|
||||
))}
|
||||
|
||||
<Spacing xxl />
|
||||
|
||||
<Body>
|
||||
{t(
|
||||
'pages.simulateurs.réduction-générale.recap.caption',
|
||||
'Récapitulatif trimestriel :'
|
||||
)}
|
||||
</Body>
|
||||
{Object.keys(quarters).map((label, index) => (
|
||||
<RécapitulatifTrimestre
|
||||
key={index}
|
||||
label={label}
|
||||
data={quarters[label]}
|
||||
mobileVersion={true}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
`
|
||||
|
|
|
@ -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 ? (
|
||||
<StyledTooltip tooltip={tooltip}>
|
||||
<FlexDiv id={id}>
|
||||
<FlexDiv id={id} $alignment={alignment}>
|
||||
{formatValue(
|
||||
{
|
||||
nodeValue: réductionGénérale,
|
||||
|
@ -54,7 +56,7 @@ export default function MontantRéduction({
|
|||
</StyledTooltip>
|
||||
) : (
|
||||
displayNull && (
|
||||
<FlexDiv id={id}>
|
||||
<FlexDiv id={id} $alignment={alignment}>
|
||||
{formatValue(0, { displayedUnit, language })}
|
||||
|
||||
<Condition
|
||||
|
@ -76,9 +78,9 @@ export default function MontantRéduction({
|
|||
const StyledTooltip = styled(Tooltip)`
|
||||
width: 100%;
|
||||
`
|
||||
const FlexDiv = styled.div`
|
||||
const FlexDiv = styled.div<{ $alignment: 'end' | 'center' }>`
|
||||
${FlexCenter}
|
||||
justify-content: end;
|
||||
justify-content: ${({ $alignment }) => $alignment};
|
||||
`
|
||||
const StyledSearchIcon = styled(SearchIcon)`
|
||||
margin-left: ${({ theme }) => theme.spacings.sm};
|
||||
|
|
|
@ -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 (
|
||||
<MontantRéduction
|
||||
rémunérationBrute={rémunération}
|
||||
réductionGénérale={réduction}
|
||||
répartition={répartition}
|
||||
displayedUnit={displayedUnit}
|
||||
language={language}
|
||||
displayNull={false}
|
||||
alignment="center"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const Montant801 = () => {
|
||||
return (
|
||||
<MontantRéduction
|
||||
rémunérationBrute={rémunération}
|
||||
réductionGénérale={régularisation}
|
||||
répartition={répartition}
|
||||
displayedUnit={displayedUnit}
|
||||
language={language}
|
||||
displayNull={false}
|
||||
alignment="center"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return mobileVersion ? (
|
||||
<div>
|
||||
<StyledMonth>{label}</StyledMonth>
|
||||
<GridContainer container spacing={2}>
|
||||
<Grid item>
|
||||
<StyledBody>
|
||||
{t(
|
||||
'pages.simulateurs.réduction-générale.recap.header',
|
||||
'Réduction calculée'
|
||||
)}
|
||||
<br />
|
||||
{t(
|
||||
'pages.simulateurs.réduction-générale.recap.code671',
|
||||
'code 671(€)'
|
||||
)}
|
||||
</StyledBody>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<StyledBody>
|
||||
<Montant671 />
|
||||
</StyledBody>
|
||||
</Grid>
|
||||
</GridContainer>
|
||||
|
||||
<GridContainer container spacing={2}>
|
||||
<Grid item>
|
||||
<StyledBody>
|
||||
{t(
|
||||
'pages.simulateurs.réduction-générale.recap.header',
|
||||
'Réduction calculée'
|
||||
)}
|
||||
<br />
|
||||
{t(
|
||||
'pages.simulateurs.réduction-générale.recap.code801',
|
||||
'code 801(€)'
|
||||
)}
|
||||
</StyledBody>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<StyledBody>
|
||||
<Montant801 />
|
||||
</StyledBody>
|
||||
</Grid>
|
||||
</GridContainer>
|
||||
</div>
|
||||
) : (
|
||||
<tr>
|
||||
<th scope="row">{label}</th>
|
||||
<td>
|
||||
<Montant671 />
|
||||
</td>
|
||||
<td>
|
||||
<Montant801 />
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
|
||||
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;
|
||||
`
|
Loading…
Reference in New Issue