diff --git a/.eslintignore b/.eslintignore
index 7e0cec355..2154f9afa 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -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
\ No newline at end of file
diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml
index bfb6a5f1b..a83026473 100644
--- a/.github/workflows/publish.yaml
+++ b/.github/workflows/publish.yaml
@@ -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
diff --git a/README.md b/README.md
index 779c86b46..42239bdd3 100644
--- a/README.md
+++ b/README.md
@@ -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)
diff --git a/exoneration-covid/.yarnrc b/exoneration-covid/.yarnrc
new file mode 100644
index 000000000..816ae2805
--- /dev/null
+++ b/exoneration-covid/.yarnrc
@@ -0,0 +1,2 @@
+version-tag-prefix exoneration-covid -v
+version-git-message "⬆ Mise à jour du paquet \"exoneration-covid \" vers %s"
diff --git a/exoneration-covid/CHANGELOG.md b/exoneration-covid/CHANGELOG.md
new file mode 100644
index 000000000..981ce8f09
--- /dev/null
+++ b/exoneration-covid/CHANGELOG.md
@@ -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
diff --git a/exoneration-covid/README.md b/exoneration-covid/README.md
new file mode 100644
index 000000000..5469c868b
--- /dev/null
+++ b/exoneration-covid/README.md
@@ -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)) // "3 300 €"
+```
diff --git a/exoneration-covid/index.d.ts b/exoneration-covid/index.d.ts
new file mode 100644
index 000000000..8cb6cf61e
--- /dev/null
+++ b/exoneration-covid/index.d.ts
@@ -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
+export default rules
diff --git a/exoneration-covid/package.json b/exoneration-covid/package.json
new file mode 100644
index 000000000..06b532612
--- /dev/null
+++ b/exoneration-covid/package.json
@@ -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"
+ }
+}
diff --git a/exoneration-covid/règles/exonération-covid.yaml b/exoneration-covid/règles/exonération-covid.yaml
new file mode 100644
index 000000000..c9dc27c8d
--- /dev/null
+++ b/exoneration-covid/règles/exonération-covid.yaml
@@ -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 l’hô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 d’activité
+ 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 l’objet d’une mesure d’interdiction 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
diff --git a/exoneration-covid/tsconfig.json b/exoneration-covid/tsconfig.json
new file mode 100644
index 000000000..f8fb691b2
--- /dev/null
+++ b/exoneration-covid/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "compilerOptions": {
+ "allowJs": true,
+ "noEmit": true,
+ "strict": true
+ }
+}
diff --git a/modele-social/package.json b/modele-social/package.json
index ee0a8b0b2..4c0f31a40 100644
--- a/modele-social/package.json
+++ b/modele-social/package.json
@@ -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"
}
}
diff --git a/modele-social/tsconfig.json b/modele-social/tsconfig.json
index 49fc71a60..f8fb691b2 100644
--- a/modele-social/tsconfig.json
+++ b/modele-social/tsconfig.json
@@ -3,6 +3,5 @@
"allowJs": true,
"noEmit": true,
"strict": true
- },
- "include": ["build.js"]
+ }
}
diff --git a/package.json b/package.json
index c6884e993..7ea7dbbe8 100644
--- a/package.json
+++ b/package.json
@@ -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"
},
diff --git a/modele-social/build.js b/scripts/build-rules.js
similarity index 84%
rename from modele-social/build.js
rename to scripts/build-rules.js
index 72636f7f5..83d59a36d 100644
--- a/modele-social/build.js
+++ b/scripts/build-rules.js
@@ -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)
-}
diff --git a/modele-social/check-changelog.js b/scripts/check-changelog.js
similarity index 58%
rename from modele-social/check-changelog.js
rename to scripts/check-changelog.js
index e875c9c28..995cc3543 100644
--- a/modele-social/check-changelog.js
+++ b/scripts/check-changelog.js
@@ -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(
diff --git a/site/scripts/fetch-stats.js b/site/scripts/fetch-stats.js
index de2775f89..fbf7cfab0 100644
--- a/site/scripts/fetch-stats.js
+++ b/site/scripts/fetch-stats.js
@@ -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()
diff --git a/site/source/components/Distribution.css b/site/source/components/Distribution.css
index 94df4c327..12791fd2e 100644
--- a/site/source/components/Distribution.css
+++ b/site/source/components/Distribution.css
@@ -6,7 +6,6 @@
width: 100%;
border: none;
align-items: center;
-
position: relative;
}
.distribution-chart__bar-container {
diff --git a/site/source/components/conversation/NumberInput.tsx b/site/source/components/conversation/NumberInput.tsx
index e19effa90..cc54a1078 100644
--- a/site/source/components/conversation/NumberInput.tsx
+++ b/site/source/components/conversation/NumberInput.tsx
@@ -108,7 +108,6 @@ function getSerializedUnit(
}
const formatUnit = getFormatUnit(unit)
- console.log(unit, locale, formatUnit)
if (!formatUnit) {
return (
diff --git a/site/source/components/utils/useSimulationConfig.ts b/site/source/components/utils/useSimulationConfig.ts
index 3fafee9c9..51874f97b 100644
--- a/site/source/components/utils/useSimulationConfig.ts
+++ b/site/source/components/utils/useSimulationConfig.ts
@@ -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 {
diff --git a/site/source/design-system/buttons/Button.tsx b/site/source/design-system/buttons/Button.tsx
index 5b02534f0..a7fb4ad60 100644
--- a/site/source/design-system/buttons/Button.tsx
+++ b/site/source/design-system/buttons/Button.tsx
@@ -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`
`}
/* 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`
`}
/* 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`
}
/* 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`
/* 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;
diff --git a/site/source/design-system/buttons/ButtonHelp.tsx b/site/source/design-system/buttons/ButtonHelp.tsx
index 87a733d39..8d1ae9622 100644
--- a/site/source/design-system/buttons/ButtonHelp.tsx
+++ b/site/source/design-system/buttons/ButtonHelp.tsx
@@ -20,7 +20,7 @@ export default function ButtonHelp({
return (
(
-
+ 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]};
}
}
`
diff --git a/site/source/design-system/card/Card.tsx b/site/source/design-system/card/Card.tsx
index e05aff4ce..a6aa512a9 100644
--- a/site/source/design-system/card/Card.tsx
+++ b/site/source/design-system/card/Card.tsx
@@ -39,7 +39,7 @@ export function Card({
return (
({ ...theme, darkMode: false })}>
-
+
{icon && {icon}}
{title && }
{ctaLabel && (
// The button is not selectable with keyboard navigation because the whole card already is
-
+
{ctaLabel}
{linkProps.external && }
@@ -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}
`
diff --git a/site/source/design-system/field/SearchField.tsx b/site/source/design-system/field/SearchField.tsx
index dcb75c12c..9df0f5b04 100644
--- a/site/source/design-system/field/SearchField.tsx
+++ b/site/source/design-system/field/SearchField.tsx
@@ -75,7 +75,6 @@ export default function SearchField(
{props.isSearchStalled ? : }
)}
{...inputProps}
placeholder={inputProps.placeholder ?? ''}
ref={ref}
diff --git a/site/source/design-system/field/Select/index.tsx b/site/source/design-system/field/Select/index.tsx
index 21868d081..506174a76 100644
--- a/site/source/design-system/field/Select/index.tsx
+++ b/site/source/design-system/field/Select/index.tsx
@@ -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>(
? state.selectedItem.rendered
: t('select.value.default', 'Choisissez une option')}
-
+
{state.isOpen && (
state.close()}>
diff --git a/site/source/locales/ui-en.yaml b/site/source/locales/ui-en.yaml
index 6c7e46f47..23276244a 100644
--- a/site/source/locales/ui-en.yaml
+++ b/site/source/locales/ui-en.yaml
@@ -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 calculated2>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
- expenses0>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 calculated2>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-entrepreneur2>9><10>Useful resources10><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
+ contributions2>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 therefore4><5><0>Net income = Sales - Social
+ security contributions - Business expenses0>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 calculated2>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-entrepreneur2>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 contributions2>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 contributions0>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
- income2>. 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
+ contributions2>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 contributions0>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 income2>. 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:
diff --git a/site/source/locales/ui-fr.yaml b/site/source/locales/ui-fr.yaml
index d919769d7..5a9cc0dbd 100644
--- a/site/source/locales/ui-fr.yaml
+++ b/site/source/locales/ui-fr.yaml
@@ -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 professionnelles0>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 professionnelles0>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ératoire2>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ératoire2>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-entrepreneur2>9>
+ l'activité.9><10><0>0> <2>Voir le détail du calcul du revenu abattu
+ pour un auto-entrepreneur2>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 sociales0>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 sociales0>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 fiscal2> 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:
diff --git a/site/source/pages/Documentation.tsx b/site/source/pages/Documentation.tsx
index d2ac1d951..c6c45cfb9 100644
--- a/site/source/pages/Documentation.tsx
+++ b/site/source/pages/Documentation.tsx
@@ -56,6 +56,7 @@ export default function MonEntrepriseRulePage() {
+
@@ -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)}
diff --git a/site/source/pages/Simulateurs/ChômagePartiel.tsx b/site/source/pages/Simulateurs/ChômagePartiel.tsx
index 443d3861a..2a1004c92 100644
--- a/site/source/pages/Simulateurs/ChômagePartiel.tsx
+++ b/site/source/pages/Simulateurs/ChômagePartiel.tsx
@@ -168,22 +168,25 @@ function ComparaisonTable({ rows: [head, ...body] }: ComparaisonTableProps) {
return (
<>
-
+ ))}
+
>
)
diff --git a/site/source/pages/Simulateurs/metadata.tsx b/site/source/pages/Simulateurs/metadata.tsx
index b3f75d131..3b211a50b 100644
--- a/site/source/pages/Simulateurs/metadata.tsx
+++ b/site/source/pages/Simulateurs/metadata.tsx
@@ -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).