Merge branch 'master' of github.com:betagouv/mon-entreprise

pull/2037/head^2
Jérémy Rialland 2022-02-21 11:01:19 +01:00
commit a92e33635e
30 changed files with 804 additions and 194 deletions

View File

@ -1,3 +1,6 @@
node_modules
dist
publicodes/example/
# TODO fix weird error in ./exoneration-covid/index.d.ts : Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.
exoneration-covid/index.d.ts

View File

@ -9,10 +9,8 @@ jobs:
if: ${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-20.04
strategy:
# On a seulement 1 paquet donc pas besoin de matrix ici, mais c'est en
# prévision du paquet covid à venir.
matrix:
package: ['modele-social']
package: ['modele-social', 'exoneration-covid']
steps:
- uses: actions/checkout@v2
- run: yarn install --frozen-lockfile

View File

@ -2,6 +2,7 @@ Ce dépôt contient :
- Le code source du site [mon-entreprise](https://mon-entreprise.urssaf.fr)
- Les [règles publicodes](https://github.com/betagouv/mon-entreprise/tree/master/modele-social) pour le calcul des cotisations sociales, des impôts et des droits sociaux.
- Les [règles publicodes](https://github.com/betagouv/mon-entreprise/tree/master/exoneration-covid) pour le calcul du montant des exonérations de cotisations liées au covid
## [mon-entreprise](https://mon-entreprise.urssaf.fr)</a>

View File

@ -0,0 +1,2 @@
version-tag-prefix exoneration-covid -v
version-git-message "⬆ Mise à jour du paquet \"exoneration-covid \" vers %s"

View File

@ -0,0 +1,7 @@
## 0.2.0
Change complètement l'organisation des règles publicodes pour être au plus proche de l'implémentation
## 0.1.0
Première version du paquet

158
exoneration-covid/README.md Normal file
View File

@ -0,0 +1,158 @@
# Modèle social français en publicodes
Ce paquet contient les règles [publicodes](https://publi.codes) utilisées sur https://mon-entreprise.urssaf.fr pour le calcul de l'exonération covid 2021.
### Installation
```
npm install publicodes exoneration-covid
```
### Exemple
```js
import Engine, { formatValue } from 'publicodes'
import rules from 'exoneration-covid'
const engine = new Engine(rules)
engine.setSituation({
"lieu d'exercice": "'métropole'",
"début d'activité": "'mai 2021'",
secteur: "'S1'",
'mois . avril 2021': 'LFSS 600',
'mois . mai 2021': 'non',
'mois . juin 2021': 'LFSS 600',
'mois . décembre 2021': 'LFSS 300',
})
console.log(formatValue(engine.evaluate('montant total')))
```
👉 **[Voir l'exemple complet](https://codesandbox.io/s/covidform-rxweh?file=/src/index.js)**
### Utilisation
#### 1. Récuperer la liste des mois à afficher
La première étape est de savoir quels sont les mois à afficher en fonction des données d'entrée (secteur, lieu et date de début d'activité). Pour cela, il suffit de récuperer la liste de toutes les variables manquantes à l'évaluation du montant dans la situation. Voici comment procéder :
```js
import Engine from 'publicodes'
import rules from 'exoneration-covid'
const engine = new Engine(rules)
// 1. On met à jour les valeurs de la première étape du formulaire
const step1Situation = {
"lieu d'exercice": "'métropole'",
"début d'activité": "'mai 2021'",
secteur: "'S1'",
}
engine.setSituation(step1Situation)
// 2. On lance le calcul pour le montant exonéré
const evaluation = engine.evaluate('montant total')
// 3. On récupère la liste des mois manquants
const missingVariables = Object.keys(evaluation.missingVariables)
```
Ci-dessus, `missingVariable` contiendra la liste des règles publicodes dont la valeur est manquante pour l'évaluation.
```json
[
"mois . mai 2021",
"mois . juin 2021",
"mois . juillet 2021",
"mois . août 2021",
"mois . décembre 2021",
"mois . janvier 2022",
"mois . février 2022"
]
```
#### 2. Obtenir les exonérations possibles pour un mois en particulier
Par défaut, on souhaite qu'aucune exonération ne soit selectionnée pour aucun des mois. On va donc mettre à jour la situation initiale en conséquence :
```js
import Engine, { formatValue } from 'publicodes'
import rules from 'exoneration-covid'
const engine = new Engine(rules)
const step1Situation = {
"lieu d'exercice": "'métropole'",
"début d'activité": "'mai 2021'",
secteur: "'S1'",
}
const monthToFill = Object.keys(
engine.evaluate('montant total').missingVariables
)
const currentSituation = Object.fromEntries(
monthToFill.map((month) => [month, 'non'])
)
engine.setSituation({ ...step1Situation, ...currentSituation })
```
Pour connaître la liste des éléments possibles pour un mois, il faut lister les possibilités :
```js
const currentMonth = 'mois . juillet 2022'
const options = Object.keys(engine.getParsedRules()).filter((name) =>
name.startsWith(currentMonth + ' . ')
) // Retourne ['mois . juillet . LFSS 600', 'mois . juillet . LFR 1' ]
```
Puis enlever les options qui ne sont pas applicables dans la situation actuelle. Pour cela, on utilise la situation courante en réinitialisant le mois selectionné.
```js
const situationWithoutCurrentMonth = {
...step1Situation,
...currentSituation,
}
delete situationWithoutCurrentMonth[currentMonth]
engine.setSituation(situationWithoutCurrentMonth)
const applicableOptions = options.filter(
(name) => engine.evaluate(name).nodeValue !== false
)
```
#### 3. Calculer le montant de l'exonération en temps réel
Pour calculer l'exonération en fonction des entrées de l'utilisateur, il suffit de mettre à jour la situation avec les informations saisies par ce dernier.
```js
import Engine, { formatValue } from 'publicodes'
import rules from 'exoneration-covid'
const engine = new Engine(rules)
const step1Situation = {
"lieu d'exercice": "'métropole'",
"début d'activité": "'mai 2021'",
secteur: "'S1'",
}
const currentSituation = {
'mois éligibles . mai 2021': "'LFSS 600'",
'mois éligibles . juin 2021': "'LFR1'",
'mois éligibles . juillet 2021': "'LFSS 600'",
'mois éligibles . août 2021': "'LFR1'",
'mois éligibles . décembre 2021': "'LFSS 300'",
'mois éligibles . janvier 2022': "'non'",
'mois éligibles . février 2022': "'LFSS 300'",
}
const montantTotal = engine
.setSituation({
...step1situation,
...currentSituation,
})
.evaluate('montant total')
console.log(montantTotal.nodeValue) // 3300
console.log(formatValue(montantTotal)) // "3300 €"
```

9
exoneration-covid/index.d.ts vendored Normal file
View File

@ -0,0 +1,9 @@
// Currenty we systematically bundle all the rules even if we only need a
// sub-section of them. We might support "code-splitting" the rules in the
// future.
import { Rule } from 'publicodes'
import { Names } from './dist/names'
export type DottedName = Names
declare let rules: Record<Names, Rule>
export default rules

View File

@ -0,0 +1,32 @@
{
"name": "exoneration-covid",
"version": "0.2.0",
"description": "Les règles publicodes pour le calcul de l'exonération de cotisations covid (année 2021)",
"main": "./dist/index.js",
"types": "./index.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/betagouv/mon-entreprise.git",
"directory": "exoneration-covid"
},
"bugs": "https://github.com/betagouv/mon-entreprise/issues?q=is%3Aopen+is%3Aissue+label%3A%22%F0%9F%93%95+l%C3%A9gislation%22",
"license": "MIT",
"files": [
"dist/index.js"
],
"type": "module",
"devDependencies": {
"js-yaml": "^4.1.0",
"publicodes": "^1.0.0-beta.30"
},
"peerDependencies": {
"publicodes": "^1.0.0-beta.30"
},
"scripts": {
"build": "node ../scripts/build-rules.js",
"clean": "rimraf dist node_modules",
"prepare": "yarn run build",
"up": "yarn version --minor && echo \" N'oubliez pas de poussez le tag git\"",
"test": "node ../scripts/check-changelog.js"
}
}

View File

@ -0,0 +1,392 @@
secteur:
question: De quel secteur relève votre activité principale ?
une possibilité:
choix obligatoire: oui
possibilités: [S1, S1bis, S2]
secteur . S1:
valeur: secteur = 'S1'
titre: Secteur dit S1
Description: Activités du tourisme, de lhôtellerie, de la restauration, du sport, de la culture, du transport aérien et de lévénementiel
secteur . S1bis:
valeur: secteur = 'S1bis'
titre: Secteur dit S1bis
Description: Activités dépendantes du secteur 1
secteur . S2:
valeur: secteur = 'S2'
titre: Secteur dit S2
Description: Autres activités ayant fait l'objet d'une interdiction (par exemple, commerces)
secteur . S1 ou S1bis:
une de ces conditions:
- S1
- S1bis
lieu d'exercice:
question: Où exercez-vous votre activité ?
une possibilité:
choix obligatoire: oui
possibilités:
- métropole
- outre-mer
lieu d'exercice . métropole:
titre: En métropole
lieu d'exercice . outre-mer:
titre: En outre-mer
début d'activité:
titre: Période de début dactivité
question: À quelle période avez-vous débuté votre activité ?
formulaire:
type: select
une possibilité:
choix obligatoire: oui
possibilités:
- avant 2021
- janvier 2021
- février 2021
- mars 2021
- avril 2021
- mai 2021
- juin 2021
- juillet 2021
- août 2021
- septembre 2021
- octobre 2021
- novembre 2021
- décembre 2021
début d'activité . avant 2021:
début d'activité . janvier 2021:
début d'activité . février 2021:
début d'activité . mars 2021:
début d'activité . avril 2021:
début d'activité . mai 2021:
début d'activité . juin 2021:
début d'activité . juillet 2021:
début d'activité . août 2021:
début d'activité . septembre 2021:
début d'activité . octobre 2021:
début d'activité . novembre 2021:
début d'activité . décembre 2021:
début d'activité . date:
# Converti les possibilités en date (dans le futur on aimerait avoir des select basé sur des types sommes, et un type pour exprimer un 'mois' d'une date)
variations:
- si: début d'activité = 'avant 2021'
alors: 12/2020
- si: début d'activité = 'janvier 2021'
alors: 01/2021
- si: début d'activité = 'février 2021'
alors: 02/2021
- si: début d'activité = 'mars 2021'
alors: 03/2021
- si: début d'activité = 'avril 2021'
alors: 04/2021
- si: début d'activité = 'mai 2021'
alors: 05/2021
- si: début d'activité = 'juin 2021'
alors: 06/2021
- si: début d'activité = 'juillet 2021'
alors: 07/2021
- si: début d'activité = 'août 2021'
alors: 08/2021
- si: début d'activité = 'septembre 2021'
alors: 09/2021
- si: début d'activité = 'octobre 2021'
alors: 10/2021
- si: début d'activité = 'novembre 2021'
alors: 11/2021
- si: début d'activité = 'décembre 2021'
alors: 12/2021
mois:
applicable si: secteur . S1 ou S1bis
valeur: oui
mois . janvier 2021:
applicable si: début d'activité . date >= 01/2021
non applicable si: début d'activité . date >= 02/2021
une possibilité:
possibilités:
- LFSS 600
mois . janvier 2021 . LFSS 600:
valeur: janvier 2021 = 'LFSS 600'
mois . février 2021:
non applicable si: début d'activité . date >= 03/2021
applicable si: début d'activité . date >= 01/2021
une possibilité:
possibilités:
- LFSS 600
mois . février 2021 . LFSS 600:
valeur: février 2021 = 'LFSS 600'
mois . mars 2021:
non applicable si: début d'activité . date >= 04/2021
applicable si: début d'activité . date >= 01/2021
une possibilité:
possibilités:
- LFSS 600
mois . mars 2021 . LFSS 600:
valeur: mars 2021 = 'LFSS 600'
mois . avril 2021:
non applicable si: début d'activité . date >= 05/2021
une possibilité:
possibilités:
- LFSS 600
mois . avril 2021 . LFSS 600:
valeur: avril 2021 = 'LFSS 600'
mois . mai 2021:
non applicable si: début d'activité . date >= 06/2021
une possibilité:
possibilités:
- LFSS 600
mois . mai 2021 . LFSS 600:
valeur: mai 2021 = 'LFSS 600'
mois . juin 2021:
non applicable si: début d'activité . date >= 07/2021
une possibilité:
possibilités:
- LFSS 600
- LFR1
mois . juin 2021 . LFSS 600:
valeur: juin 2021 = 'LFSS 600'
mois . juin 2021 . LFR1:
applicable si: LFR1 applicable
valeur: juin 2021 = 'LFR1'
mois . juillet 2021:
non applicable si: début d'activité . date >= 08/2021
une possibilité:
possibilités:
- LFSS 600
- LFR1
mois . juillet 2021 . LFSS 600:
valeur: juillet 2021 = 'LFSS 600'
mois . juillet 2021 . LFR1:
applicable si: LFR1 applicable
valeur: juillet 2021 = 'LFR1'
mois . août 2021:
non applicable si: début d'activité . date >= 09/2021
applicable si:
une de ces conditions:
- LFR1 applicable
- lieu d'exercice = 'outre-mer'
une possibilité:
possibilités:
- LFSS 600
- LFR1
mois . août 2021 . LFSS 600:
valeur: août 2021 = 'LFSS 600'
applicable si: lieu d'exercice = 'outre-mer'
mois . août 2021 . LFR1:
applicable si: LFR1 applicable
valeur: août 2021 = 'LFR1'
mois . septembre 2021:
non applicable si: début d'activité . date >= 10/2021
applicable si: lieu d'exercice = 'outre-mer'
une possibilité:
possibilités:
- LFSS 600
mois . septembre 2021 . LFSS 600:
valeur: septembre 2021 = 'LFSS 600'
mois . octobre 2021:
non applicable si: début d'activité . date >= 11/2021
applicable si: lieu d'exercice = 'outre-mer'
une possibilité:
possibilités:
- LFSS 600
mois . octobre 2021 . LFSS 600:
valeur: octobre 2021 = 'LFSS 600'
mois . novembre 2021:
non applicable si: début d'activité . date >= 12/2021
applicable si: lieu d'exercice = 'outre-mer'
une possibilité:
possibilités:
- LFSS 600
mois . novembre 2021 . LFSS 600:
valeur: novembre 2021 = 'LFSS 600'
mois . décembre 2021:
une possibilité:
possibilités:
- LFSS 600
- LFSS 300
mois . décembre 2021 . LFSS 600:
valeur: décembre 2021 = 'LFSS 600'
mois . décembre 2021 . LFSS 300:
valeur: décembre 2021 = 'LFSS 300'
mois . janvier 2022:
une possibilité:
possibilités:
- LFSS 600
- LFSS 300
mois . janvier 2022 . LFSS 600:
valeur: janvier 2022 = 'LFSS 600'
mois . janvier 2022 . LFSS 300:
valeur: janvier 2022 = 'LFSS 300'
mois . février 2022:
une possibilité:
possibilités:
- LFSS 600
- LFSS 300
mois . février 2022 . LFSS 600:
valeur: février 2022 = 'LFSS 600'
mois . février 2022 . LFSS 300:
valeur: février 2022 = 'LFSS 300'
LFSS 600:
applicable si: secteur . S1 ou S1bis
produit:
assiette: 600 €/mois
facteur:
nom: mois éligibles
unité: mois
description: Nombre de mois éligible à l'exonération LFSS à 600 €
somme:
- valeur: mois . janvier 2021 . LFSS 600
par défaut: non
- valeur: mois . février 2021 . LFSS 600
par défaut: non
- valeur: mois . mars 2021 . LFSS 600
par défaut: non
- valeur: mois . avril 2021 . LFSS 600
par défaut: non
- valeur: mois . mai 2021 . LFSS 600
par défaut: non
- valeur: mois . juin 2021 . LFSS 600
par défaut: non
- valeur: mois . juillet 2021 . LFSS 600
par défaut: non
- valeur: mois . août 2021 . LFSS 600
par défaut: non
- valeur: mois . septembre 2021 . LFSS 600
par défaut: non
- valeur: mois . octobre 2021 . LFSS 600
par défaut: non
- valeur: mois . novembre 2021 . LFSS 600
par défaut: non
- valeur: mois . décembre 2021 . LFSS 600
par défaut: non
- valeur: mois . janvier 2022 . LFSS 600
par défaut: non
- valeur: mois . février 2022 . LFSS 600
par défaut: non
LFSS 300:
applicable si: secteur . S1 ou S1bis
produit:
assiette: 300 €/mois
facteur:
nom: mois éligibles
description: Nombre de mois éligible à l'exonération LFSS à 300€
unité: mois
somme:
- valeur: mois . décembre 2021 . LFSS 300
par défaut: non
- valeur: mois . janvier 2022 . LFSS 300
par défaut: non
- valeur: mois . février 2022 . LFSS 300
par défaut: non
LFR1 applicable:
valeur: oui
applicable si:
toutes ces conditions:
- secteur . S1 ou S1bis
- début d'activité . date < 06/2021
non applicable si:
toutes ces conditions:
- début d'activité . date >= 01/2021
- mois . mars 2021 . LFSS 600 = non
- mois . avril 2021 . LFSS 600 = non
- mois . mai 2021 . LFSS 600 = non
LFR1:
produit:
assiette: 600 €/mois
facteur:
unité: mois
description: Nombre de mois éligible à l'exonération LFR1
nom: mois éligibles
somme:
- valeur: mois . juin 2021 . LFR1
par défaut: non
- valeur: mois . juillet 2021 . LFR1
par défaut: non
- valeur: mois . août 2021 . LFR1
par défaut: non
exonération S2:
produit:
assiette: 600 €/mois
facteur: mois éligibles
applicable si:
toutes ces conditions:
- secteur . S2
- début d'activité . date <= mois éligibles . dernier mois
exonération S2 . mois éligibles:
unité: mois
arrondi: oui
question:
texte: Précisez le nombre de mois entre {{ premier mois }} et {{ dernier mois }} durant lesquels vous avez fait lobjet dune mesure dinterdiction affectant de manière prépondérante la poursuite de votre activité
plafond:
nom: plafond
somme:
- durée:
depuis: premier mois
jusqu'à: dernier mois
arrondi: oui
unité: mois
- 1 mois
exonération S2 . mois éligibles . premier mois:
variations:
- si: début d'activité . date < 01/2021
alors: 04/2021
- sinon:
valeur: début d'activité . date
plancher: 02/2021
plafond: dernier mois
exonération S2 . mois éligibles . dernier mois:
variations:
- si: lieu d'exercice = 'outre-mer'
alors: 09/2021
- sinon: 07/2021
montant total:
somme:
- LFSS 600
- LFR1
- LFSS 300
- exonération S2

View File

@ -0,0 +1,7 @@
{
"compilerOptions": {
"allowJs": true,
"noEmit": true,
"strict": true
}
}

View File

@ -24,10 +24,10 @@
"publicodes": "^1.0.0-beta.30"
},
"scripts": {
"build": "node build.js",
"build": "node ../scripts/build-rules.js",
"clean": "rimraf dist node_modules",
"prepare": "yarn run build",
"up": "yarn version --minor && echo \" N'oubliez pas de poussez le tag git\"",
"test": "node check-changelog.js"
"test": "node ../scripts/check-changelog.js"
}
}

View File

@ -3,6 +3,5 @@
"allowJs": true,
"noEmit": true,
"strict": true
},
"include": ["build.js"]
}
}

View File

@ -10,6 +10,7 @@
},
"workspaces": [
"modele-social",
"exoneration-covid",
"site"
],
"type": "module",
@ -26,7 +27,7 @@
"test:type": "yarn workspaces run tsc --skipLibCheck --noEmit",
"clean": "yarn workspaces run clean && rimraf node_modules",
"start": "yarn workspace site start",
"moso:up": "yarn workspace modele-social run up && yarn workspace site upgrade modele-social",
"moso:up": "yarn workspace modele-social run up && yarn workspace exoneration-covid run up && yarn workspace site upgrade modele-social",
"i18n:check": "yarn workspace site i18n:check",
"i18n:translate": "yarn workspace site i18n:translate"
},

View File

@ -3,9 +3,8 @@ import fs from 'fs'
import path from 'path'
import yaml from 'js-yaml'
// utf8 url
const publicodesDir = decodeURI(new URL('./règles', import.meta.url).pathname)
const outDir = new URL('./dist', import.meta.url).pathname
const publicodesDir = './règles'
const outDir = './dist'
if (!fs.existsSync(outDir)) {
fs.mkdirSync(outDir)
@ -44,7 +43,7 @@ function readRules() {
// Note: we can't put the output file in the fs.watched directory
function writeJSFile() {
export default function writeJSFile() {
const rules = readRules()
const names = Object.keys(rules)
const jsString = `export default ${JSON.stringify(rules, null, 2)}`
@ -56,6 +55,3 @@ function writeJSFile() {
}
writeJSFile()
export function watchDottedNames() {
return fs.watch(publicodesDir, writeJSFile)
}

View File

@ -1,13 +1,9 @@
// Ensure that current package version is referenced in the Changelog.md
import { readFileSync } from 'fs'
const packageVersion = JSON.parse(
readFileSync(new URL('./package.json', import.meta.url).pathname)
).version
const packageVersion = JSON.parse(readFileSync('./package.json')).version
const changelog = readFileSync(
new URL('./CHANGELOG.md', import.meta.url).pathname
)
const changelog = readFileSync('./CHANGELOG.md')
if (!changelog.includes(`## ${packageVersion}\n`)) {
throw Error(

View File

@ -273,7 +273,30 @@ async function fetchUserFeedbackIssues() {
}
async function main() {
createDataDir()
// In case we cannot fetch the release (the API is down or the Authorization
// token isn't valid) we fallback to some fake data -- it would be better to
// have a static ressource accessible without authentification.
writeInDataDir('stats.json', {
visitesJours: [],
visitesMois: [],
satisfaction: [],
retoursUtilisateurs: {
open: [],
closed: [],
},
nbAnswersLast30days: 0,
})
try {
if (
!process.env.ATINTERNET_API_ACCESS_KEY ||
!process.env.ATINTERNET_API_SECRET_KEY ||
!process.env.ZAMMAD_API_SECRET_KEY
) {
console.log(
"Variables d'environnement manquantes : nous ne récupérons pas les statistiques d'usage"
)
return
}
const visitesJours = await fetchDailyVisits()
const visitesMois = await fetchMonthlyVisits()
const satisfaction = uniformiseData(
@ -296,23 +319,7 @@ async function main() {
nbAnswersLast30days,
})
} catch (e) {
console.error(e)
// In case we cannot fetch the release (the API is down or the Authorization
// token isn't valid) we fallback to some fake data -- it would be better to
// have a static ressource accessible without authentification.
writeInDataDir('stats.json', {
visitesJours: [],
visitesMois: [],
satisfaction: [],
retoursUtilisateurs: {
open: [],
closed: [],
},
nbAnswersLast30days: 0,
})
console.log(e)
}
}
main().catch((e) => {
throw new Error(e)
})
main()

View File

@ -6,7 +6,6 @@
width: 100%;
border: none;
align-items: center;
position: relative;
}
.distribution-chart__bar-container {

View File

@ -108,7 +108,6 @@ function getSerializedUnit(
}
const formatUnit = getFormatUnit(unit)
console.log(unit, locale, formatUnit)
if (!formatUnit) {
return (

View File

@ -1,4 +1,5 @@
import { setSimulationConfig } from 'Actions/actions'
import { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { useHistory } from 'react-router'
import { Company } from 'Reducers/inFranceAppReducer'
@ -24,9 +25,11 @@ export default function useSimulationConfig(
: undefined
const lastConfig = useSelector(configSelector)
if (config && lastConfig !== config) {
dispatch(setSimulationConfig(config ?? {}, url, initialSituation))
}
useEffect(() => {
if (config && lastConfig !== config) {
dispatch(setSimulationConfig(config ?? {}, url, initialSituation))
}
}, [config, dispatch, lastConfig, initialSituation, url])
}
export function getCompanySituation(company: Company | null): Situation {

View File

@ -32,7 +32,7 @@ export const Button = forwardRef(function Button(
{...buttonOrLinkProps}
className={className}
size={size}
light={light}
$light={light}
color={color}
/>
)
@ -41,7 +41,7 @@ export const Button = forwardRef(function Button(
type StyledButtonProps = {
color: Color
size: Size
light: boolean
$light: boolean
isDisabled?: boolean
}
@ -93,8 +93,8 @@ export const StyledButton = styled.button<StyledButtonProps>`
`}
/* Primary, secondary & tertiary light colors */
${({ light, color, theme }) =>
light &&
${({ $light, color, theme }) =>
$light &&
!theme.darkMode &&
css`
color: ${theme.colors.bases[color][color === 'primary' ? 700 : 700]};
@ -111,9 +111,9 @@ export const StyledButton = styled.button<StyledButtonProps>`
`}
/* White color and light mode (dark background mode) */
${({ light, theme }) =>
${({ $light, theme }) =>
theme.darkMode &&
light &&
$light &&
css`
background-color: transparent;
border-color: ${theme.colors.extended.grey[100]};
@ -122,11 +122,11 @@ export const StyledButton = styled.button<StyledButtonProps>`
}
/* HOVER STYLE */
:hover {
${({ theme, color, isDisabled, light }) =>
${({ theme, color, isDisabled, $light }) =>
isDisabled || theme.darkMode
? ''
: /* Primary, secondary & tertiary light colors */
light
$light
? css`
background-color: ${theme.colors.bases[color][
color === 'primary' ? 200 : color === 'secondary' ? 100 : 100
@ -143,11 +143,11 @@ export const StyledButton = styled.button<StyledButtonProps>`
/* Dark mode */
@media not print {
:hover {
${({ light, theme, isDisabled }) =>
${({ $light, theme, isDisabled }) =>
isDisabled || !theme.darkMode
? ''
: /* White color and light mode (dark background mode) */
light
$light
? css`
color: rgba(255, 255, 255, 25%);
opacity: 1;

View File

@ -20,7 +20,7 @@ export default function ButtonHelp({
return (
<PopoverWithTrigger
trigger={(buttonProps) => (
<StyledButton light={light ?? false} {...buttonProps}>
<StyledButton $light={light} {...buttonProps}>
<CircleIcon
aria-hidden="true"
width="24"
@ -61,7 +61,7 @@ const CircleIcon = styled.svg`
margin-right: ${({ theme }) => theme.spacings.xxs};
`
const StyledButton = styled(Button)<{ light: boolean }>`
const StyledButton = styled(Button)<{ $light?: boolean }>`
--padding: 2px;
&& {
height: calc(${({ theme }) => theme.spacings.md} + 2 * var(--padding));
@ -80,8 +80,8 @@ const StyledButton = styled(Button)<{ light: boolean }>`
align-items: center;
color: ${({ theme }) => theme.colors.bases.primary[600]} !important;
border: 1px solid ${({ theme }) => theme.colors.bases.primary[600]};
background-color: ${({ theme, light }) =>
light
background-color: ${({ theme, $light }) =>
$light
? theme.colors.extended.grey[100]
: theme.colors.bases.primary[100]};
border-radius: calc(
@ -89,8 +89,7 @@ const StyledButton = styled(Button)<{ light: boolean }>`
);
:hover {
background-color: ${({ theme, light }) =>
theme.colors.bases.primary[200]};
background-color: ${({ theme }) => theme.colors.bases.primary[200]};
}
}
`

View File

@ -39,7 +39,7 @@ export function Card({
return (
<ThemeProvider theme={(theme) => ({ ...theme, darkMode: false })}>
<CardContainer compact={compact} {...buttonOrLinkProps} tabIndex={0}>
<CardContainer $compact={compact} {...buttonOrLinkProps} tabIndex={0}>
{icon && <IconContainer>{icon}</IconContainer>}
{title && <StyledHeader {...titleProps} />}
<div
@ -53,7 +53,7 @@ export function Card({
</div>
{ctaLabel && (
// The button is not selectable with keyboard navigation because the whole card already is
<CardButton tabIndex={-1} size="XS" light color="primary">
<CardButton tabIndex={-1} size="XS" $light color="primary">
{ctaLabel}
{linkProps.external && <NewWindowLinkIcon />}
</CardButton>
@ -100,7 +100,7 @@ const IconContainer = styled.div`
margin-top: ${({ theme }) => theme.spacings.md};
`
export const CardContainer = styled.div<{ compact?: boolean }>`
export const CardContainer = styled.div<{ $compact?: boolean }>`
display: flex;
width: 100%;
height: 100%;
@ -119,8 +119,8 @@ export const CardContainer = styled.div<{ compact?: boolean }>`
&:focus-visible {
${FocusStyle}
}
padding: ${({ theme: { spacings }, compact = false }) =>
compact
padding: ${({ theme: { spacings }, $compact = false }) =>
$compact
? css`
${spacings.sm} ${spacings.md}
`

View File

@ -75,7 +75,6 @@ export default function SearchField(
{props.isSearchStalled ? <Loader /> : <SearchIcon />}
</IconContainer>
<SearchInput
{...(props as InputHTMLAttributes<HTMLInputElement>)}
{...inputProps}
placeholder={inputProps.placeholder ?? ''}
ref={ref}

View File

@ -71,7 +71,7 @@ const Value = styled.span`
margin-top: 1rem;
`
const StyledIcon = styled(CarretDown)<{ isOpen: boolean }>`
const StyledIcon = styled(CarretDown)`
margin: 0 4px;
`
export const Wrapper = styled.div<{
@ -218,7 +218,7 @@ export function Select<T extends Record<string, unknown>>(
? state.selectedItem.rendered
: t('select.value.default', 'Choisissez une option')}
</Value>
<StyledIcon isOpen={state.isOpen} />
<StyledIcon />
</Button>
{state.isOpen && (
<Popover isOpen={state.isOpen} onClose={() => state.close()}>

View File

@ -1206,32 +1206,32 @@ pages:
ogTitle: "Auto-entrepreneur: quickly calculate your net income from sales and
vice versa"
titre: "Auto-entrepreneurs: income simulator"
seo explanation: "<0>How do you calculate the net income for an
auto-entrepreneur?</0><1>An auto-entrepreneur has to pay social
security contributions to the administration (also known as
\"social charge\"). These social contributions are used to finance
social security, and give rights for retirement or health insurance.
They are also used to finance vocational training.</1><2><0></0> <2>See
details of how the contributions are calculated</2></2><3>But this is
not the only expense: to calculate net income, one must also take into
account all expenses incurred in the course of the professional activity
(assets, raw materials, premises, transport). Although they are not
useful for the calculation of contributions and taxes, they must be
taken into account to estimate the viability of one''s
activity.</3><4>The complete calculation formula is therefore:<1><0>Net
income = Turnover - Social contributions - Professional
expenses</0></1></4><5>How to calculate income tax for an
auto-entrepreneur ?</5><6>If you opted for the flat-rate payment when
you set up your business, income tax is paid at the same time as social
security contributions.</6><7><0></0> <2>See how the amount of the
flat-rate tax is calculated</2></7><8>Otherwise, you will be taxed
according to the standard income tax schedule. The taxable income is
then calculated as a percentage of turnover. This is called the lump-sum
allowance. This percentage varies according to the type of activity
carried out. It is said to be lump-sum because it does not take into
account the actual expenses incurred in the activity.</8><9><0></0>
<2>See details of the calculation of the income allowance for an
auto-entrepreneur</2></9><10>Useful resources</10><11><0></0></11>'"
seo explanation: <0>How to calculate the net income of an
auto-entrepreneur?</0><1>An auto-entrepreneur must pay social
contributions to the administration. These contributions are used to
finance the social security system, and open up rights, notably for
retirement and health insurance. They are also used to finance
professional training. Their amount varies according to the type of
activity.</1><2><0></0> <2>See the details of the calculation of the
contributions</2></2><3>Do not forget to subtract all expenses incurred
in the course of the business (equipment, raw materials, premises,
transport). Although they are not used for the calculation of
contributions and taxes, they must be taken into account to check
whether the activity is economically viable.</3><4>The complete
calculation formula is therefore</4><5><0>Net income = Sales - Social
security contributions - Business expenses</0></5><6>How to calculate
the income tax for an auto-entrepreneur ?</6><7>If you have opted for
the payment in full discharge when creating your auto-entrepreneur, the
income tax is paid at the same time as the social
contributions.</7><8><0></0> <2>See how the amount of the payment in
full discharge is calculated</2></8><9>Otherwise, you will be taxed
according to the standard income tax scale. The taxable income is then
calculated as a percentage of the turnover. This is called the standard
deduction. This percentage varies according to the type of activity
carried out. It is said to be flat rate because it does not take into
account the real expenses incurred in the course of the
activity.</9><10><0></0> <2>See the details of the calculation of the
abatement income for an auto-entrepreneur</2></10>
shortname: Auto-entrepreneur
title: Self-entrepreneur Income Simulator
titre: Auto-entrepreneur income simulator
@ -1396,30 +1396,31 @@ pages:
ogTitle: "Sole proprietorship: quickly calculate your net income from your
turnover and vice versa"
titre: "Sole proprietorship (EI): income simulator"
seo explanation: <0>How to calculate the net income of a sole trader?</0><1>A
sole trader must pay social security contributions to the authorities.
These contributions are used to finance social security, and open up
rights, particularly for retirement and health insurance. They are also
used to finance professional training.</1><2><0></0> <2>See the details
of the calculation of contributions</2></2><3>Do not forget to deduct
all expenses incurred in the course of the business (equipment, raw
materials, premises, transport). These are deductible from the company's
income, which means that you will not pay tax or contributions on their
amount (unless you have opted for the micro-tax option).</3><4>The
complete calculation formula is therefore :<1><0>Net income = Turnover -
Professional expenses - Social contributions</0></1></4><5>How do you
calculate the social security contributions of a sole
proprietorship?</5><6>The manager of a sole proprietorship pays social
security contributions in proportion to the company's <2>taxable
income</2>. Their amount also varies according to the type of activity
(liberal profession, craftsman, tradesman, etc.), or any exemptions
granted (ACRE, ZFU, RSA, etc.).</6><7> As a company's result is only
known at the end of the accounting period, the manager pays provisional
contributions which will then be adjusted once the actual income has
been declared, the following year.</7><8>This simulator allows you to
calculate the exact amount of social security contributions based on a
desired turnover or net income. You can specify your situation by
answering the questions displayed below the simulation.</8>
seo explanation: <0>How to calculate the net income of a sole proprietorship
manager (EI)?</0><1>A sole trader must pay social contributions to the
administration. These contributions are used to finance the social
security system, and open up rights, particularly for retirement and
health insurance. They are also used to finance professional
training.</1><2><0></0> <2>See the details of the calculation of the
contributions</2></2><3>Do not forget to deduct all expenses incurred in
the course of the business (equipment, raw materials, premises,
transport). These are deductible from the company's income, which means
that you will not pay taxes or contributions on their amount (unless you
have opted for the micro-tax option).</3><4>The complete calculation
formula is therefore :</4><5><0>Net income = Turnover - Professional
expenses - Social contributions</0></5><6>How to calculate the social
contributions of a sole proprietorship ?</6><7>The manager of a sole
proprietorship pays social contributions, proportional to the company's
<2>taxable income</2>. Their amount also varies according to the type of
activity (liberal profession, craftsman, tradesman, etc.), or the
possible exemptions granted (ACRE, ZFU, RSA, etc.).</7><8> As the result
of a company is only known at the end of the accounting year, the
manager pays provisional contributions which will then be adjusted once
the real income is declared, the following year.</8><9>This simulator
allows you to calculate the exact amount of social security
contributions based on a desired turnover or net income. You can specify
your situation by answering the questions displayed below the
simulation.</9>
shortname: Individual company
title: Simulator for sole proprietorship (EI)
eirl:

View File

@ -937,20 +937,20 @@ pages:
soient pas utilisées pour le calcul des cotisations et de l'impôt, elles
doivent être prises en compte pour vérifier si l'activité est viable
économiquement.</3><4>La formule de calcul complète est donc
:<1><0>Revenu net = Chiffres d'affaires Cotisations sociales
Dépenses professionnelles</0></1></4><5>Comment calculer l'impôt sur le
revenu pour un auto-entrepreneur ?</5><6>Si vous avez opté pour le
:</4><5><0>Revenu net = Chiffres d'affaires Cotisations sociales
Dépenses professionnelles</0></5><6>Comment calculer l'impôt sur le
revenu pour un auto-entrepreneur ?</6><7>Si vous avez opté pour le
versement libératoire lors de la création de votre auto-entreprise,
l'impôt sur le revenu est payé en même temps que les cotisations
sociales.</6><7><0></0> <2>Voir comment est calculé le montant du
versement libératoire</2></7><8>Sinon, vous serez imposé selon le barème
sociales.</7><8><0></0> <2>Voir comment est calculé le montant du
versement libératoire</2></8><9>Sinon, vous serez imposé selon le barème
standard de l'impôt sur le revenu. Le revenu imposable est alors calculé
comme un pourcentage du chiffre d'affaires. C'est qu'on appel
l'abattement forfaitaire. Ce pourcentage varie en fonction du type
d'activité excercé. On dit qu'il est forfaitaire car il ne prends pas en
compte les dépenses réelles effectuées dans le cadre de
l'activité.</8><9><0></0> <2>Voir le détail du calcul du revenu abattu
pour un auto-entrepreneur</2></9>
l'activité.</9><10><0></0> <2>Voir le détail du calcul du revenu abattu
pour un auto-entrepreneur</2></10>
shortname: Auto-entrepreneur
title: Simulateur de revenus auto-entrepreneur
auxiliaire:
@ -1074,21 +1074,21 @@ pages:
déductibles du résultat de l'entreprise, cela veut dire que vous ne
payerez pas d'impôt ou de cotisations sur leur montant (sauf si vous
avez opté pour l'option micro-fiscal).</3><4>La formule de calcul
complète est donc :<1><0>Revenu net = Chiffres d'affaires Dépenses
professionnelles - Cotisations sociales</0></1></4><5>Comment calculer
les cotisations sociales d'une entreprise individuelle ?</5><6>Le
dirigeant d'une entreprise individuelle paye des cotisations sociales,
complète est donc :</4><5><0>Revenu net = Chiffres d'affaires Dépenses
professionnelles - Cotisations sociales</0></5><6>Comment calculer les
cotisations sociales d'une entreprise individuelle ?</6><7>Le dirigeant
d'une entreprise individuelle paye des cotisations sociales,
proportionnelle au <2>résultat fiscal</2> de l'entreprise. Leur montant
varie également en fonction du type d'activité (profession libérale,
artisan, commerçants, etc), où des éventuelles exonérations accordées
(ACRE, ZFU, RSA, etc.).</6><7> Comme le résultat d'une entreprise n'est
(ACRE, ZFU, RSA, etc.).</7><8> Comme le résultat d'une entreprise n'est
connu qu'à la fin de l'exercice comptable, le dirigeant paye des
cotisations provisionnelles qui seront ensuite régularisée une fois le
revenu réel déclaré, l'année suivante.</7><8>Ce simulateur permet de
revenu réel déclaré, l'année suivante.</8><9>Ce simulateur permet de
calculer le montant exact des cotisations sociale en partant d'un
chiffre d'affaires ou d'un revenu net souhaité. Vous pourrez préciser
votre situation en répondant aux questions s'affichant en dessous de la
simulation.</8>
simulation.</9>
shortname: Entreprise Individuelle
title: Simulateur pour entreprise individuelle (EI)
eirl:

View File

@ -56,6 +56,7 @@ export default function MonEntrepriseRulePage() {
<ScrollToTop key={pathname} />
<Grid item md={10}>
<BackToSimulation />
<Spacing xl />
<Route
path={documentationPath + '/:name+'}
render={({ match }) =>
@ -241,6 +242,7 @@ function componentCSS(rules: any, props: any) {
const StyledDocumentation = styled.div`
h1 {
${(props) => componentCSS((H1.componentStyle as any).rules, props)}
margin-top: 1rem;
}
h2 {
${(props) => componentCSS((H2.componentStyle as any).rules, props)}

View File

@ -168,22 +168,25 @@ function ComparaisonTable({ rows: [head, ...body] }: ComparaisonTableProps) {
return (
<>
<ResultTable className="ui__ mobile-version">
<tr>
<th></th>
<th>
<select
onChange={(evt) =>
setCurrentColumnIndex(Number(evt.target.value))
}
>
{columns.map((name, i) => (
<option value={i} selected={i === currentColumnIndex} key={i}>
{name}
</option>
))}
</select>
</th>
</tr>
<thead>
<tr>
<th></th>
<th>
<select
onChange={(evt) =>
setCurrentColumnIndex(Number(evt.target.value))
}
value={currentColumnIndex}
>
{columns.map((name, i) => (
<option value={i} key={i}>
{name}
</option>
))}
</select>
</th>
</tr>
</thead>
<tbody>
{body.map(([label, ...line], i) => (
<tr key={i}>
@ -198,34 +201,36 @@ function ComparaisonTable({ rows: [head, ...body] }: ComparaisonTableProps) {
</tbody>
</ResultTable>
<ResultTable>
<tr>
{head.map((label, i) => (
<th key={i}>{label}</th>
))}
</tr>
{body.map(([label, ...line], i) => (
<tr key={i}>
<td>
<RowLabel {...label} />
</td>
{line.map((cell, j) => (
<td key={j}>
{' '}
<ValueWithLink {...cell} />
{cell.additionalText && (
<p
className="ui__ notice"
css={`
text-align: right;
`}
>
{cell.additionalText}
</p>
)}
</td>
<tbody>
<tr>
{head.map((label, i) => (
<th key={i}>{label}</th>
))}
</tr>
))}
{body.map(([label, ...line], i) => (
<tr key={i}>
<td>
<RowLabel {...label} />
</td>
{line.map((cell, j) => (
<td key={j}>
{' '}
<ValueWithLink {...cell} />
{cell.additionalText && (
<p
className="ui__ notice"
css={`
text-align: right;
`}
>
{cell.additionalText}
</p>
)}
</td>
))}
</tr>
))}
</tbody>
</ResultTable>
</>
)

View File

@ -244,15 +244,13 @@ export function getSimulatorsData({
d'impôt ou de cotisations sur leur montant (sauf si vous avez opté
pour l'option micro-fiscal).
</Body>
<Body>
La formule de calcul complète est donc :
<blockquote>
<strong>
Revenu net = Chiffres d'affaires Dépenses professionnelles -
Cotisations sociales
</strong>
</blockquote>
</Body>
<Body>La formule de calcul complète est donc :</Body>
<blockquote>
<strong>
Revenu net = Chiffres d'affaires Dépenses professionnelles -
Cotisations sociales
</strong>
</blockquote>
<H2>
Comment calculer les cotisations sociales d'une entreprise
individuelle ?
@ -391,15 +389,13 @@ export function getSimulatorsData({
prises en compte pour vérifier si l'activité est viable
économiquement.
</Body>
<Body>
La formule de calcul complète est donc :
<blockquote>
<strong>
Revenu net = Chiffres d'affaires Cotisations sociales
Dépenses professionnelles
</strong>
</blockquote>
</Body>
<Body>La formule de calcul complète est donc :</Body>
<blockquote>
<strong>
Revenu net = Chiffres d'affaires Cotisations sociales Dépenses
professionnelles
</strong>
</blockquote>
<H2>
Comment calculer l'impôt sur le revenu pour un auto-entrepreneur ?
</H2>

View File

@ -5,7 +5,6 @@ import fs from 'fs/promises'
import path from 'path'
import toml from 'rollup-plugin-toml'
import { defineConfig, Plugin } from 'vite'
import { watchDottedNames } from '../modele-social/build.js'
import shimReactPdf from 'vite-plugin-shim-react-pdf'
import serveStatic from 'serve-static'
@ -162,7 +161,7 @@ function monEntrepriseDevServer(): Plugin {
configureServer() {
// We could use native ViteJS watch API, but it would require changing
// more code and maybe the whole "modele-social" package build process.
watchDottedNames()
// watchDottedNames()
},
}
}