Ajoute l'activité mixte aux simulateurs indépendants
Factorise la logique de la saisie des CA dans un nouveau composantpull/1620/head
parent
acbfb58a3a
commit
ea24a47a3f
|
@ -833,18 +833,19 @@ entreprise . activité . mixte . proportions:
|
|||
- nom: service BIC
|
||||
variations:
|
||||
- si: activité = 'libérale'
|
||||
alors: 0
|
||||
alors: 0%
|
||||
- sinon: 50%
|
||||
- nom: service BNC
|
||||
variations:
|
||||
- si: activité = 'libérale'
|
||||
alors: 2 / 3
|
||||
- sinon: 0
|
||||
- sinon: 0%
|
||||
- nom: vente restauration hébergement
|
||||
variations:
|
||||
- si: activité = 'libérale'
|
||||
alors: 1 / 3
|
||||
- sinon: 50%
|
||||
note: Il appartient à l'utilisateur de bien vérifier que la somme des trois pourcentages renseignés vaut 100%.
|
||||
|
||||
|
||||
entreprise . activité . libérale réglementée:
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
import { batchUpdateSituation } from 'Actions/actions'
|
||||
import { DottedName } from 'modele-social'
|
||||
import { serializeEvaluation } from 'publicodes'
|
||||
import { useCallback } from 'react'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import { situationSelector } from 'Selectors/simulationSelectors'
|
||||
import { Explicable } from './conversation/Explicable'
|
||||
import { Condition } from './EngineValue'
|
||||
import { SimulationGoal } from './SimulationGoals'
|
||||
import { useEngine } from './utils/EngineContext'
|
||||
import { Markdown } from './utils/markdown'
|
||||
|
||||
const proportions = {
|
||||
'entreprise . activité . mixte . proportions . service BIC':
|
||||
"entreprise . chiffre d'affaires . service BIC",
|
||||
'entreprise . activité . mixte . proportions . service BNC':
|
||||
"entreprise . chiffre d'affaires . service BNC",
|
||||
'entreprise . activité . mixte . proportions . vente restauration hébergement':
|
||||
"entreprise . chiffre d'affaires . vente restauration hébergement",
|
||||
} as const
|
||||
|
||||
export default function ChiffreAffairesActivitéMixte({
|
||||
dottedName,
|
||||
}: {
|
||||
dottedName: DottedName
|
||||
}) {
|
||||
const adjustProportions = useAdjustProportions(dottedName)
|
||||
const dispatch = useDispatch()
|
||||
const clearChiffreAffaireMixte = useCallback(() => {
|
||||
dispatch(
|
||||
batchUpdateSituation(
|
||||
Object.values(proportions).reduce(
|
||||
(acc, chiffreAffaires) => ({ ...acc, [chiffreAffaires]: undefined }),
|
||||
{}
|
||||
)
|
||||
)
|
||||
)
|
||||
}, [dispatch])
|
||||
return (
|
||||
<>
|
||||
<SimulationGoal
|
||||
appear={false}
|
||||
onUpdateSituation={clearChiffreAffaireMixte}
|
||||
dottedName={dottedName}
|
||||
/>
|
||||
<ActivitéMixte />
|
||||
|
||||
<Condition expression="entreprise . activité . mixte">
|
||||
<li className="small-target">
|
||||
<ul>
|
||||
{Object.values(proportions).map((chiffreAffaires) => (
|
||||
<SimulationGoal
|
||||
key={chiffreAffaires}
|
||||
onUpdateSituation={adjustProportions}
|
||||
dottedName={chiffreAffaires}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
</li>
|
||||
</Condition>
|
||||
</>
|
||||
)
|
||||
}
|
||||
export function useAdjustProportions(CADottedName: DottedName): () => void {
|
||||
const engine = useEngine()
|
||||
const dispatch = useDispatch()
|
||||
|
||||
return useCallback(() => {
|
||||
const nouveauCA = serializeEvaluation(
|
||||
engine.evaluate({
|
||||
somme: Object.values(proportions)
|
||||
.map((chiffreAffaire) =>
|
||||
serializeEvaluation(engine.evaluate(chiffreAffaire))
|
||||
)
|
||||
.filter(Boolean),
|
||||
})
|
||||
)
|
||||
if (nouveauCA === '0€/an') {
|
||||
return // Avoid division by 0
|
||||
}
|
||||
const situation = Object.entries(proportions).reduce(
|
||||
(acc, [proportionName, valueName]) => {
|
||||
const value = serializeEvaluation(
|
||||
engine.evaluate({ valeur: valueName, 'par défaut': '0€/an' })
|
||||
)
|
||||
const newProportion = serializeEvaluation(
|
||||
engine.evaluate({
|
||||
valeur: `${value} / ${nouveauCA}`,
|
||||
unité: '%',
|
||||
})
|
||||
)
|
||||
|
||||
return { ...acc, [proportionName]: newProportion }
|
||||
},
|
||||
{ [CADottedName]: nouveauCA }
|
||||
)
|
||||
dispatch(batchUpdateSituation(situation))
|
||||
}, [engine, dispatch])
|
||||
}
|
||||
|
||||
function ActivitéMixte() {
|
||||
const dispatch = useDispatch()
|
||||
const situation = useSelector(situationSelector)
|
||||
const rule = useEngine().getRule('entreprise . activité . mixte')
|
||||
const defaultChecked =
|
||||
useEngine().evaluate('entreprise . activité . mixte').nodeValue === true
|
||||
|
||||
const onMixteChecked = useCallback(
|
||||
(checked: boolean) => {
|
||||
dispatch(
|
||||
batchUpdateSituation(
|
||||
Object.values(proportions).reduce(
|
||||
(acc, dottedName) => ({ ...acc, [dottedName]: undefined }),
|
||||
{ 'entreprise . activité . mixte': checked ? 'oui' : 'non' }
|
||||
)
|
||||
)
|
||||
)
|
||||
},
|
||||
[dispatch, situation]
|
||||
)
|
||||
return (
|
||||
<li
|
||||
className="small-target"
|
||||
css={`
|
||||
margin-top: -1rem;
|
||||
`}
|
||||
>
|
||||
<label
|
||||
css={`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
`}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
key={'' + defaultChecked}
|
||||
defaultChecked={defaultChecked}
|
||||
onChange={(evt) => onMixteChecked(evt.target.checked)}
|
||||
/>
|
||||
Activité mixte
|
||||
<Explicable>
|
||||
<Markdown source={`## ${rule.title}\n ${rule.rawNode.description}`} />
|
||||
</Explicable>
|
||||
</label>
|
||||
</li>
|
||||
)
|
||||
}
|
|
@ -1,104 +1,22 @@
|
|||
import { batchUpdateSituation } from 'Actions/actions'
|
||||
import { Explicable } from 'Components/conversation/Explicable'
|
||||
import { Condition, WhenAlreadyDefined } from 'Components/EngineValue'
|
||||
import ChiffreAffairesActivitéMixte from 'Components/ChiffreAffairesActivitéMixte'
|
||||
import { WhenAlreadyDefined } from 'Components/EngineValue'
|
||||
import PeriodSwitch from 'Components/PeriodSwitch'
|
||||
import SimulateurWarning from 'Components/SimulateurWarning'
|
||||
import Simulation from 'Components/Simulation'
|
||||
import { SimulationGoal, SimulationGoals } from 'Components/SimulationGoals'
|
||||
import StackedBarChart from 'Components/StackedBarChart'
|
||||
import { ThemeColorsContext } from 'Components/utils/colors'
|
||||
import { useEngine } from 'Components/utils/EngineContext'
|
||||
import { Markdown } from 'Components/utils/markdown'
|
||||
import { serializeEvaluation } from 'publicodes'
|
||||
import { default as React, useCallback, useContext } from 'react'
|
||||
import { default as React, useContext } from 'react'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import { situationSelector } from 'Selectors/simulationSelectors'
|
||||
|
||||
const proportions = {
|
||||
'entreprise . activité . mixte . proportions . service BIC':
|
||||
"entreprise . chiffre d'affaires . service BIC",
|
||||
'entreprise . activité . mixte . proportions . service BNC':
|
||||
"entreprise . chiffre d'affaires . service BNC",
|
||||
'entreprise . activité . mixte . proportions . vente restauration hébergement':
|
||||
"entreprise . chiffre d'affaires . vente restauration hébergement",
|
||||
} as const
|
||||
function useAdjustProportions(): () => void {
|
||||
const engine = useEngine()
|
||||
const dispatch = useDispatch()
|
||||
|
||||
return useCallback(() => {
|
||||
const nouveauCA = serializeEvaluation(
|
||||
engine.evaluate({
|
||||
somme: Object.values(proportions)
|
||||
.map((chiffreAffaire) =>
|
||||
serializeEvaluation(engine.evaluate(chiffreAffaire))
|
||||
)
|
||||
.filter(Boolean),
|
||||
})
|
||||
)
|
||||
if (nouveauCA === '0€/an') {
|
||||
return // Avoid division by 0
|
||||
}
|
||||
const situation = Object.entries(proportions).reduce(
|
||||
(acc, [proportionName, valueName]) => {
|
||||
const value = serializeEvaluation(
|
||||
engine.evaluate({ valeur: valueName, 'par défaut': '0€/an' })
|
||||
)
|
||||
const newProportion = serializeEvaluation(
|
||||
engine.evaluate({
|
||||
valeur: `${value} / ${nouveauCA}`,
|
||||
unité: '%',
|
||||
})
|
||||
)
|
||||
|
||||
return { ...acc, [proportionName]: newProportion }
|
||||
},
|
||||
{ "dirigeant . auto-entrepreneur . chiffre d'affaires": nouveauCA }
|
||||
)
|
||||
dispatch(batchUpdateSituation(situation))
|
||||
}, [engine, dispatch])
|
||||
}
|
||||
|
||||
export default function AutoEntrepreneur() {
|
||||
const adjustProportions = useAdjustProportions()
|
||||
const activitéMixte =
|
||||
useEngine().evaluate('entreprise . activité . mixte').nodeValue === true
|
||||
|
||||
return (
|
||||
<>
|
||||
<SimulateurWarning simulateur="auto-entrepreneur" />
|
||||
<Simulation explanations={<Explanation />}>
|
||||
<PeriodSwitch />
|
||||
<SimulationGoals className="plain">
|
||||
<SimulationGoal
|
||||
appear={false}
|
||||
editable={!activitéMixte}
|
||||
dottedName="dirigeant . auto-entrepreneur . chiffre d'affaires"
|
||||
/>
|
||||
|
||||
<Condition expression="entreprise . activité . mixte">
|
||||
<li className="small-target">
|
||||
<ul>
|
||||
<SimulationGoal
|
||||
onUpdateSituation={adjustProportions}
|
||||
dottedName="entreprise . chiffre d'affaires . vente restauration hébergement"
|
||||
/>
|
||||
<SimulationGoal
|
||||
onUpdateSituation={adjustProportions}
|
||||
dottedName="entreprise . chiffre d'affaires . service BIC"
|
||||
/>
|
||||
<SimulationGoal
|
||||
onUpdateSituation={adjustProportions}
|
||||
dottedName="entreprise . chiffre d'affaires . service BNC"
|
||||
/>
|
||||
</ul>
|
||||
</li>
|
||||
</Condition>
|
||||
<ActivitéMixte
|
||||
key={'' + activitéMixte}
|
||||
defaultChecked={activitéMixte}
|
||||
/>
|
||||
<ChiffreAffairesActivitéMixte dottedName="dirigeant . auto-entrepreneur . chiffre d'affaires" />
|
||||
<SimulationGoal
|
||||
small
|
||||
editable={false}
|
||||
|
@ -119,52 +37,6 @@ export default function AutoEntrepreneur() {
|
|||
)
|
||||
}
|
||||
|
||||
function ActivitéMixte({ defaultChecked }: { defaultChecked: boolean }) {
|
||||
const dispatch = useDispatch()
|
||||
const situation = useSelector(situationSelector)
|
||||
const rule = useEngine().getRule('entreprise . activité . mixte')
|
||||
|
||||
const onMixteChecked = useCallback(
|
||||
(checked: boolean) => {
|
||||
dispatch(
|
||||
batchUpdateSituation(
|
||||
Object.values(proportions).reduce(
|
||||
(acc, dottedName) => ({ ...acc, [dottedName]: undefined }),
|
||||
{ 'entreprise . activité . mixte': checked ? 'oui' : 'non' }
|
||||
)
|
||||
)
|
||||
)
|
||||
},
|
||||
[dispatch, situation]
|
||||
)
|
||||
return (
|
||||
<li
|
||||
className="small-target"
|
||||
css={`
|
||||
margin-top: -1rem;
|
||||
`}
|
||||
>
|
||||
<label
|
||||
css={`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
`}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
defaultChecked={defaultChecked}
|
||||
onChange={(evt) => onMixteChecked(evt.target.checked)}
|
||||
/>
|
||||
Activité mixte
|
||||
<Explicable>
|
||||
<Markdown source={`## ${rule.title}\n ${rule.rawNode.description}`} />
|
||||
</Explicable>
|
||||
</label>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
function Explanation() {
|
||||
const { t } = useTranslation()
|
||||
const { palettes } = useContext(ThemeColorsContext)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { updateSituation } from 'Actions/actions'
|
||||
import Banner from 'Components/Banner'
|
||||
import ChiffreAffairesActivitéMixte from 'Components/ChiffreAffairesActivitéMixte'
|
||||
import { Condition, WhenAlreadyDefined } from 'Components/EngineValue'
|
||||
import PeriodSwitch from 'Components/PeriodSwitch'
|
||||
import SimulateurWarning from 'Components/SimulateurWarning'
|
||||
|
@ -78,11 +79,16 @@ function IndépendantSimulationGoals() {
|
|||
return (
|
||||
<SimulationGoals className="plain">
|
||||
<Condition expression="entreprise . imposition = 'IR'">
|
||||
<SimulationGoal
|
||||
appear={false}
|
||||
alwaysShow
|
||||
dottedName="entreprise . chiffre d'affaires"
|
||||
/>
|
||||
<Condition expression="entreprise . imposition . IR . micro-fiscal = non">
|
||||
<SimulationGoal
|
||||
appear={false}
|
||||
alwaysShow
|
||||
dottedName="entreprise . chiffre d'affaires"
|
||||
/>
|
||||
</Condition>
|
||||
<Condition expression="entreprise . imposition . IR . micro-fiscal">
|
||||
<ChiffreAffairesActivitéMixte dottedName="entreprise . chiffre d'affaires" />
|
||||
</Condition>
|
||||
<Condition expression="entreprise . imposition . IR . micro-fiscal != oui">
|
||||
<SimulationGoal
|
||||
small
|
||||
|
|
|
@ -22,9 +22,7 @@ questions:
|
|||
liste noire:
|
||||
- entreprise . charges
|
||||
- entreprise . chiffre d'affaires
|
||||
- entreprise . chiffre d'affaires . vente restauration hébergement
|
||||
- entreprise . chiffre d'affaires . service BIC
|
||||
- entreprise . chiffre d'affaires . service BNC
|
||||
|
||||
unité par défaut: €/an
|
||||
situation:
|
||||
entreprise . activité . mixte: non
|
||||
|
|
Loading…
Reference in New Issue