2020-04-23 07:30:03 +00:00
|
|
|
|
import { useEvaluation, EngineContext } from 'Components/utils/EngineContext'
|
|
|
|
|
import Value from 'Components/EngineValue'
|
|
|
|
|
import { formatValue } from 'Engine/format'
|
2019-12-13 16:22:18 +00:00
|
|
|
|
import React, { Fragment, useContext } from 'react'
|
|
|
|
|
import { Trans } from 'react-i18next'
|
2020-04-23 07:30:03 +00:00
|
|
|
|
import { DottedName } from 'Rules'
|
2019-12-13 16:22:18 +00:00
|
|
|
|
import './PaySlip.css'
|
|
|
|
|
import { Line, SalaireBrutSection, SalaireNetSection } from './PaySlipSections'
|
|
|
|
|
import RuleLink from './RuleLink'
|
2020-04-29 14:19:20 +00:00
|
|
|
|
import { ParsedRules, ParsedRule } from 'Rules'
|
2019-12-13 16:22:18 +00:00
|
|
|
|
|
2020-04-23 07:30:03 +00:00
|
|
|
|
export const SECTION_ORDER = [
|
|
|
|
|
'protection sociale . santé',
|
|
|
|
|
'protection sociale . accidents du travail et maladies professionnelles',
|
|
|
|
|
'protection sociale . retraite',
|
|
|
|
|
'protection sociale . famille',
|
|
|
|
|
'protection sociale . assurance chômage',
|
|
|
|
|
'protection sociale . formation',
|
|
|
|
|
'protection sociale . transport',
|
|
|
|
|
'protection sociale . autres'
|
|
|
|
|
] as const
|
2020-04-21 13:49:48 +00:00
|
|
|
|
|
2020-04-23 07:30:03 +00:00
|
|
|
|
type Section = typeof SECTION_ORDER[number]
|
|
|
|
|
|
2020-04-29 14:19:20 +00:00
|
|
|
|
function getSection(rule: ParsedRule): Section {
|
2020-04-23 07:30:03 +00:00
|
|
|
|
const section = ('protection sociale . ' +
|
2020-04-29 14:19:20 +00:00
|
|
|
|
rule.cotisation?.branche) as Section
|
2020-04-23 07:30:03 +00:00
|
|
|
|
if (SECTION_ORDER.includes(section)) {
|
|
|
|
|
return section
|
|
|
|
|
}
|
|
|
|
|
return 'protection sociale . autres'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function getCotisationsBySection(
|
2020-04-29 14:19:20 +00:00
|
|
|
|
parsedRules: ParsedRules
|
2020-04-23 07:30:03 +00:00
|
|
|
|
): Array<[Section, DottedName[]]> {
|
|
|
|
|
const cotisations = [
|
|
|
|
|
...parsedRules['contrat salarié . cotisations . patronales'].formule
|
|
|
|
|
.explanation.explanation,
|
|
|
|
|
...parsedRules['contrat salarié . cotisations . salariales'].formule
|
|
|
|
|
.explanation.explanation
|
|
|
|
|
]
|
|
|
|
|
.map(cotisation => cotisation.dottedName)
|
|
|
|
|
.filter(Boolean)
|
2020-04-29 14:19:20 +00:00
|
|
|
|
.reduce((acc, cotisation: DottedName) => {
|
2020-04-23 07:30:03 +00:00
|
|
|
|
const sectionName = getSection(parsedRules[cotisation])
|
|
|
|
|
return {
|
|
|
|
|
...acc,
|
|
|
|
|
[sectionName]: (acc[sectionName] ?? new Set()).add(cotisation)
|
|
|
|
|
}
|
|
|
|
|
}, {}) as Record<Section, Set<DottedName>>
|
|
|
|
|
|
|
|
|
|
return Object.entries(cotisations)
|
|
|
|
|
.map(([section, dottedNames]) => [section, [...dottedNames.values()]])
|
|
|
|
|
.sort(
|
|
|
|
|
([a], [b]) =>
|
|
|
|
|
SECTION_ORDER.indexOf(a as Section) -
|
|
|
|
|
SECTION_ORDER.indexOf(b as Section)
|
|
|
|
|
) as Array<[Section, DottedName[]]>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default function PaySlip() {
|
|
|
|
|
const parsedRules = useContext(EngineContext).getParsedRules()
|
|
|
|
|
const cotisationsBySection = getCotisationsBySection(parsedRules)
|
2020-02-12 10:50:58 +00:00
|
|
|
|
|
2020-02-07 14:59:22 +00:00
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
className="payslip__container"
|
|
|
|
|
css={`
|
2019-12-13 16:22:18 +00:00
|
|
|
|
.value {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: flex-end;
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
padding-right: 0.2em;
|
|
|
|
|
}
|
|
|
|
|
`}
|
2020-02-07 14:59:22 +00:00
|
|
|
|
>
|
|
|
|
|
<div className="payslip__salarySection">
|
|
|
|
|
<Line
|
2020-04-23 07:30:03 +00:00
|
|
|
|
rule="contrat salarié . temps de travail"
|
|
|
|
|
displayedUnit="heures/mois"
|
|
|
|
|
precision={1}
|
|
|
|
|
/>
|
|
|
|
|
<Line
|
|
|
|
|
rule="contrat salarié . temps de travail . heures supplémentaires"
|
|
|
|
|
displayedUnit="heures/mois"
|
|
|
|
|
precision={1}
|
2020-02-07 14:59:22 +00:00
|
|
|
|
/>
|
|
|
|
|
</div>
|
2019-12-13 16:22:18 +00:00
|
|
|
|
|
2020-04-23 07:30:03 +00:00
|
|
|
|
<SalaireBrutSection />
|
2020-02-07 14:59:22 +00:00
|
|
|
|
{/* Section cotisations */}
|
|
|
|
|
<div className="payslip__cotisationsSection">
|
|
|
|
|
<h4>
|
|
|
|
|
<Trans>Cotisations sociales</Trans>
|
|
|
|
|
</h4>
|
|
|
|
|
<h4>
|
|
|
|
|
<Trans>Part employeur</Trans>
|
|
|
|
|
</h4>
|
|
|
|
|
<h4>
|
|
|
|
|
<Trans>Part salarié</Trans>
|
|
|
|
|
</h4>
|
2020-04-23 07:30:03 +00:00
|
|
|
|
{cotisationsBySection.map(([sectionDottedName, cotisations]) => {
|
|
|
|
|
let section = parsedRules[sectionDottedName]
|
2020-02-07 14:59:22 +00:00
|
|
|
|
return (
|
2020-04-23 07:30:03 +00:00
|
|
|
|
<Fragment key={section.dottedName}>
|
2020-02-07 14:59:22 +00:00
|
|
|
|
<h5 className="payslip__cotisationTitle">
|
2020-04-23 07:30:03 +00:00
|
|
|
|
<RuleLink {...section} />
|
2020-02-07 14:59:22 +00:00
|
|
|
|
</h5>
|
2020-04-23 07:30:03 +00:00
|
|
|
|
{cotisations.map(cotisation => (
|
|
|
|
|
<Cotisation key={cotisation} dottedName={cotisation} />
|
2020-02-07 14:59:22 +00:00
|
|
|
|
))}
|
|
|
|
|
</Fragment>
|
|
|
|
|
)
|
|
|
|
|
})}
|
2020-04-24 16:11:54 +00:00
|
|
|
|
{/* Réductions */}
|
|
|
|
|
<div>
|
|
|
|
|
<Trans>Réductions</Trans>
|
|
|
|
|
</div>
|
|
|
|
|
<Value
|
|
|
|
|
expression="- contrat salarié . cotisations . patronales . réductions de cotisations"
|
|
|
|
|
displayedUnit="€"
|
|
|
|
|
/>
|
|
|
|
|
<Value
|
|
|
|
|
expression="- contrat salarié . cotisations . salariales . réduction heures supplémentaires"
|
|
|
|
|
displayedUnit="€"
|
|
|
|
|
/>
|
2020-02-07 14:59:22 +00:00
|
|
|
|
{/* Total cotisation */}
|
2020-04-24 16:11:54 +00:00
|
|
|
|
<p className="payslip__total">
|
2020-02-07 14:59:22 +00:00
|
|
|
|
<Trans>Total des retenues</Trans>
|
2020-04-24 16:11:54 +00:00
|
|
|
|
</p>
|
2020-02-07 14:59:22 +00:00
|
|
|
|
<Value
|
2020-04-23 07:30:03 +00:00
|
|
|
|
expression="contrat salarié . cotisations . patronales"
|
|
|
|
|
displayedUnit="€"
|
2020-02-07 14:59:22 +00:00
|
|
|
|
className="payslip__total"
|
|
|
|
|
/>
|
|
|
|
|
<Value
|
2020-04-23 07:30:03 +00:00
|
|
|
|
expression="contrat salarié . cotisations . salariales"
|
|
|
|
|
displayedUnit="€"
|
2020-02-07 14:59:22 +00:00
|
|
|
|
className="payslip__total"
|
|
|
|
|
/>
|
|
|
|
|
{/* Salaire chargé */}
|
2020-04-23 07:30:03 +00:00
|
|
|
|
<Line rule="contrat salarié . rémunération . total" />
|
2020-02-07 14:59:22 +00:00
|
|
|
|
<span />
|
|
|
|
|
</div>
|
|
|
|
|
{/* Section salaire net */}
|
2020-04-23 07:30:03 +00:00
|
|
|
|
<SalaireNetSection />
|
2020-02-07 14:59:22 +00:00
|
|
|
|
</div>
|
|
|
|
|
)
|
2019-12-13 16:22:18 +00:00
|
|
|
|
}
|
2020-04-23 07:30:03 +00:00
|
|
|
|
|
|
|
|
|
function Cotisation({ dottedName }: { dottedName: DottedName }) {
|
|
|
|
|
const parsedRules = useContext(EngineContext).getParsedRules()
|
|
|
|
|
|
|
|
|
|
const partSalariale = useEvaluation(
|
|
|
|
|
'contrat salarié . cotisations . salariales'
|
|
|
|
|
)?.formule.explanation.explanation.find(
|
2020-04-29 14:19:20 +00:00
|
|
|
|
(cotisation: ParsedRule) => cotisation.dottedName === dottedName
|
2020-04-23 07:30:03 +00:00
|
|
|
|
)
|
|
|
|
|
const partPatronale = useEvaluation(
|
|
|
|
|
'contrat salarié . cotisations . patronales'
|
|
|
|
|
)?.formule.explanation.explanation.find(
|
2020-04-29 14:19:20 +00:00
|
|
|
|
(cotisation: ParsedRule) => cotisation.dottedName === dottedName
|
2020-04-23 07:30:03 +00:00
|
|
|
|
)
|
|
|
|
|
if (!partPatronale?.nodeValue && !partSalariale?.nodeValue) {
|
|
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<RuleLink
|
|
|
|
|
{...parsedRules[dottedName]}
|
|
|
|
|
style={{ backgroundColor: 'var(--lightestColor)' }}
|
|
|
|
|
/>
|
|
|
|
|
<span style={{ backgroundColor: 'var(--lightestColor)' }}>
|
|
|
|
|
{partPatronale?.nodeValue
|
|
|
|
|
? formatValue({ ...partPatronale, unit: '€' })
|
|
|
|
|
: '–'}
|
|
|
|
|
</span>
|
|
|
|
|
<span style={{ backgroundColor: 'var(--lightestColor)' }}>
|
|
|
|
|
{partSalariale?.nodeValue
|
|
|
|
|
? formatValue({ ...partSalariale, unit: '€' })
|
|
|
|
|
: '–'}
|
|
|
|
|
</span>
|
|
|
|
|
</>
|
|
|
|
|
)
|
|
|
|
|
}
|