2020-02-04 14:21:36 +00:00
Publicode est un langage déclaratif pour encoder les algorithmes d'intérêt
public. Il permet de réaliser des calculs généraux tout en fournissant une
explication permettant de comprendre et de documenter ces calculs.
Publicode est adapté pour modéliser des domaines métiers complexes pouvant être
2020-08-27 07:04:40 +00:00
décomposés en règles élémentaires simples (comme la [législation socio-fiscale ](https://github.com/betagouv/mon-entreprise/tree/master/publicodes ),
2020-03-24 16:50:18 +00:00
[un bilan carbone ](https://github.com/laem/futureco-data/blob/master/co2.yaml ),
un estimateur de rendement locatif, etc.).
2020-05-27 08:34:36 +00:00
Il permet de générer facilement des simulateurs web interactifs où l'on peut affiner
progressivement le résultat affiché, et d'exposer une documentation du calcul explorable.
2020-02-04 14:21:36 +00:00
2020-03-24 16:50:18 +00:00
## Projets phares
2020-11-24 16:22:34 +00:00
- ** [mon-entreprise.fr ](https://mon-entreprise.fr/simulateurs )** utilise publicodes
pour spécifier l'ensemble des calculs relatifs à la législation socio-fiscale
en France. Le site permet entre autre de simuler une fiche de paie complète,
de calculer les cotisations sociales pour un indépendant ou encore connaître
le montant du chômage partiel.
- ** [futur.eco ](https://futur.eco/ )** utilise publicodes pour calculer les bilans
carbone d'un grand nombre d'activités, plats, transports ou biens.
- ** [Nos Gestes Climat ](https://ecolab.ademe.fr/apps/climat )** utilise publicodes pour proposer un calculateur d'empreinte climat personnel de référence complètement ouvert
2020-03-24 16:50:18 +00:00
2020-12-07 17:24:19 +00:00
# Principes de base
2020-02-04 14:21:36 +00:00
La syntaxe de Publicode est basée sur le langage
2020-11-17 10:43:38 +00:00
[Yaml ](https://en.wikipedia.org/wiki/YAML ).
Un fichier Publicode contient une liste de _règles_ identifiées par leur _nom_ et
2020-12-07 17:24:19 +00:00
possédant une _valeur_ :
2020-02-04 14:21:36 +00:00
```yaml
2020-12-07 16:17:23 +00:00
prix d'un repas: 10 €
2020-02-04 14:21:36 +00:00
```
2020-11-17 10:43:38 +00:00
Une formule de calcul peut faire _référence_ à d'autres règles.
Dans l'exemple suivant la règle `prix total` aura pour valeur 50 (= 5 \* 10)
2020-02-04 14:21:36 +00:00
```yaml
2020-12-07 16:17:23 +00:00
prix d'un repas: 10 €
prix total: 5 * prix d'un repas
2020-02-04 14:21:36 +00:00
```
2020-11-24 16:22:34 +00:00
Il s'agit d'un langage déclaratif : comme dans une formule d'un tableur le `prix total` sera recalculé automatiquement si le prix d'un repas change. L'ordre de
2020-02-05 14:42:19 +00:00
définition des règles n'a pas d'importance.
2020-02-04 14:21:36 +00:00
2020-12-07 16:17:23 +00:00
## Unités
2020-02-04 14:21:36 +00:00
Pour fiabiliser les calculs et faciliter leur compréhension, on peut préciser
l'unité des valeurs littérales :
```yaml
2020-12-07 16:17:23 +00:00
prix d'un repas: 10 €/repas
nombre de repas: 5 repas
2020-02-04 14:21:36 +00:00
2020-12-07 16:17:23 +00:00
prix total: nombre de repas * prix d'un repas
2020-02-04 14:21:36 +00:00
```
Le calcul est inchangé mais on a indiqué que le "prix d'un repas" s'exprime en
`€/repas` et que le "nombre de repas" est un nombre de `repas` . L'unité du prix
total est inférée automatiquement comme étant en `€` . (`€/repas` \* `repas` =
2020-03-24 16:50:18 +00:00
`€` )
Ce système d'unité permet de typer les formules de calcul et de rejeter
2020-02-04 14:21:36 +00:00
automatiquement des formules incohérentes :
```yaml
2020-12-07 16:17:23 +00:00
prix d'un repas: 10 €/repas
nombre de repas: 5 repas
frais de réservation: 1 €/repas
2020-02-04 14:21:36 +00:00
2020-12-07 16:17:23 +00:00
prix total: nombre de repas * prix d'un repas + frais de réservation
2020-02-04 14:21:36 +00:00
# Erreur:
# La formule de "prix total" est invalide.
```
Dans l'exemple ci-dessus Publicode détecte une erreur car les termes de
l'addition ont des unités incompatibles : d'un côté on a des `€` et de l'autre
2020-12-07 16:17:23 +00:00
des `€/repas` .
Cette incohérence d'unité témoigne d'une erreur de logique. Ici une manière de corriger l'erreur peut être de factoriser la variable "nombre de repas" dans la formule du "prix total".
2020-02-04 14:21:36 +00:00
```yaml
2020-12-07 16:17:23 +00:00
prix total: nombre de repas * (prix d'un repas + frais de réservation)
2020-02-04 14:21:36 +00:00
```
2020-03-24 16:50:18 +00:00
> **Attention :** Il ne faut pas insérer d'espace autour de la barre oblique dans
> les unités, l'unité `€ / mois` doit être notée `€/mois`
2020-03-23 18:07:44 +00:00
2020-03-24 18:29:57 +00:00
Publicode convertit automatiquement les unités si besoin.
2020-03-24 16:50:18 +00:00
```yaml
2020-12-07 16:17:23 +00:00
salaire: 1500 €/mois
prime faible salaire applicable: salaire < 20 k € / an
2020-03-24 16:50:18 +00:00
```
2020-12-10 15:55:56 +00:00
> NB : On peut forcer la conversion des unités via le [mécanisme `unité`](/mécanismes#unité)
2020-03-24 16:50:18 +00:00
2020-11-17 10:43:38 +00:00
**Types de base disponibles pour la conversion :**
2020-03-24 16:50:18 +00:00
2020-11-24 16:22:34 +00:00
- `jour` / `mois` / `an`
- `€` / `k€`
2020-02-05 15:39:39 +00:00
2020-12-07 16:17:23 +00:00
## Mécanismes
Il existe une autre manière d'écrire des formules de calcul : les mécanismes. Au lieu de définir la formule sur une ligne, celle-ci prends la forme d'un objet sur plusieurs lignes.
Par exemple, la formule suivante :
```yaml
prix total: 5 repas * prix d'un repas
```
Peut également s'écrire en utilisant le mécanisme [`produit` ](/mécanismes/produit ) :
```yaml
prix total:
produit:
assiette: prix d'un repas
facteur: 5 repas
```
Un des avantages de cette écriture est que la syntaxe hiérarchique de Yaml permet d'imbriquer les mécanismes :
```yaml
prix TTC:
somme:
- prix d'un repas
- produit:
assiette: prix d'un repas
taux: TVA
```
### Mécanismes chaînés
Certains mécanismes peuvent apparaître au même niveau d'indentation. Dans ce cas, le moteur appliquera les transformations dans un ordre préetabli.
```yaml
remboursement repas:
valeur: nombre de repas * remboursement forfaitaire
plafond: 500 €/an
unité: €/an
arrondi: oui
```
> **[Pour en savoir plus sur les mécanismes](./mécanismes)**
## Pages d'explications
2020-11-17 10:43:38 +00:00
L'explication des règles est un des objectifs fondamentaux de Publicodes.
2020-02-05 14:42:19 +00:00
2020-11-17 10:43:38 +00:00
Chaque règle se voit générer automatiquement une page explicatives
correspondante dans le front-end, contenant une information facilement digeste
mise en regard des calculs eux-mêmes.
2020-02-05 14:42:19 +00:00
2020-11-17 10:43:38 +00:00
Plusieurs propriétés sont reprises dans ces pages d'explications :
2020-11-24 16:22:34 +00:00
- le **titre** , qui s'affiche en haut de la page. Par défaut on utilise le nom
de la règle, mais la propriété `titre` permet de choisir un titre plus
approprié ;
- la **description** qui peut être rédigée en Markdown et est généralement
affichée comme paragraphe d'introduction sur la page. On utilise le caractère
2020-12-07 16:17:23 +00:00
`|` pour indiquer au parseur Yaml que la description est sur plusieurs lignes ;
2020-11-24 16:22:34 +00:00
- les **références** externes (documentation utile) affichées en
bas de page et qui sont constituées d'une liste de liens avec une description.
2020-02-05 14:42:19 +00:00
```yaml
ticket resto:
2020-11-24 16:22:34 +00:00
titre: Prise en charge des titres-restaurants
formule: 4 €/repas
2020-12-07 16:17:23 +00:00
description: |
2020-11-24 16:22:34 +00:00
L'employeur peut remettre des titres restaurants sous plusieurs formats:
- ticket *papier*
- carte à *puce*
- appli *mobile*
références:
Fiche service public: https://www.service-public.fr/professionnels-entreprises/vosdroits/F21059
Fiche Urssaf: https://www.urssaf.fr/portail/home/taux-et-baremes/frais-professionnels/les-titres-restaurant.html
2020-02-05 14:42:19 +00:00
```
2020-12-07 16:17:23 +00:00
## Conditions booléennes
Publicode supporte des opérateurs booléens basiques.
```yaml
âge: 17 ans
mineur émancipé: non
nationalité française: oui
droit de vote:
toutes ces conditions:
- nationalité française
- une de ces conditions:
- âge >= 18 ans
- mineur émancipé
```
Il est possible de faire des branchements conditionnels via le mécanisme [`variations` ](/mécansime/variations )
## Applicabilité
On peut définir des conditions d'applicabilité pour des valeurs :
```yaml
date de début: 12/02/2020
ancienneté en fin d'année:
durée:
depuis: date de début
jusqu'à: 31/12/2020
prime de vacances:
applicable si: ancienneté en fin d'année > 1 an
valeur: 200€
```
Ici si l'ancienneté est inférieure à un an la prime de vacances ne sera pas
_applicable_. Les variables _non applicables_ sont égale à `non` . Elles sont ignorées au niveau des mécanismes numériques (par exemple le mécanisme `somme` comptera une prime non applicable
comme valant zéro, voir la page spécifique aux mécanismes).
La syntaxe suivante est également valable:
```yaml
assimilé salarié:
valeur: oui
rend non applicable: convention collective
```
2020-11-17 10:43:38 +00:00
2020-12-07 16:17:23 +00:00
## Espaces de noms
2020-02-04 14:21:36 +00:00
Les espaces de noms sont utiles pour organiser un grand nombre de règles. On
2020-11-17 10:43:38 +00:00
utilise le `.` pour exprimer la hiérarchie des noms.
2020-02-04 14:21:36 +00:00
```yaml
prime de vacances:
2020-11-24 16:22:34 +00:00
formule: taux * 1000 €
2020-02-04 14:21:36 +00:00
prime de vacances . taux:
2020-11-24 16:22:34 +00:00
formule: 6%
2020-02-04 14:21:36 +00:00
```
2020-11-17 10:43:38 +00:00
Ici `prime de vacances` est à la fois une règle et un espace de noms. La variable
`taux` est définie dans cet espace de noms et c'est elle qui est référencée dans
la formule de calcul de la règle `prime de vacances` .
La règle `prime de vacances` est elle-même définie dans l'espace de nom racine.
On pourrait avoir une autre variable `taux` dans un espace de nom
différent, sans que cela entre en conflit:
```yaml
# Ceci n'entre pas dans le calcul de `prime de vacances` définie plus haut
autre prime . taux:
2020-11-24 16:22:34 +00:00
formule: 19%
2020-11-17 10:43:38 +00:00
```
2020-02-04 14:21:36 +00:00
2020-11-17 10:43:38 +00:00
On dit que la formule de la règle `prime de vacances` fait référence à la
règle `prime de vacances . taux` via le nom raccourci `taux` .
Pour faire référence à une règle hors de son espace de nom, on peut écrire le
nom complet de cette règle:
```yaml
prime de vacances v2:
2020-11-24 16:22:34 +00:00
formule: autre prime . taux * 1000 €
2020-11-17 10:43:38 +00:00
```
Dans le cas d'espaces de noms imbriqués (à plus qu'un étage), le nom inscrit
dans une règle donnée est recherché de plus en plus haut dans la hiérarchie des
espaces de nom jusqu'à la racine.
```yaml
contrat salarié . rémunération . primes . prime de vacances:
2020-11-24 16:22:34 +00:00
formule: taux générique * 1000 €
2020-11-17 10:43:38 +00:00
contrat salarié . rémunération . taux générique:
2020-11-24 16:22:34 +00:00
formule: 10%
2020-11-17 10:43:38 +00:00
```
Ici `contrat salarié . rémunération . primes . prime de vacances` va faire
référence à `contrat salarié . rémunération . taux générique` trouvé deux
espaces de noms plus haut, et va donc valoir `100 €` .
2020-12-07 16:17:23 +00:00
### Désactivation de branche
2020-03-23 18:07:44 +00:00
2020-12-10 15:55:56 +00:00
Il est possible de désactiver l'ensemble des règles définies dans un espace de nom.
Toutes les règles possèdent une dépendance implicite à leur parent. Si ce dernier est égal à `non` alors leur valeur est également `non` .
2020-02-04 14:21:36 +00:00
```yaml
2020-12-07 16:17:23 +00:00
CDD: non
CDD . indemnité de précarité: 10% * 1500€/mois * 6 mois
2020-03-24 16:50:18 +00:00
2020-12-07 16:17:23 +00:00
indemnités:
somme:
- 100 €
2020-12-07 17:24:19 +00:00
- CDD . indemnité de précarité # non
2020-02-04 14:21:36 +00:00
```
2020-12-07 16:17:23 +00:00
## Remplacement
2020-02-04 14:21:36 +00:00
Certaines règles ne s'appliquent parfois que dans quelques situations
particulières et modifier la définition des règles générales pour prendre en
2020-12-07 16:17:23 +00:00
compte ces particularités pose des problème de maintenabilité de la base de
2020-02-04 14:21:36 +00:00
règle.
Publicode dispose d'un mécanisme de remplacement qui permet d'amender n'importe
quelle règle existante sans avoir besoin de la modifier :
```yaml
2020-12-07 16:17:23 +00:00
frais de repas: 5 €/repas
2020-02-04 14:21:36 +00:00
2020-12-07 16:17:23 +00:00
convention hôtels cafés restaurants: oui
2020-03-25 10:00:38 +00:00
convention hôtels cafés restaurants . frais de repas:
2020-11-24 16:22:34 +00:00
remplace: frais de repas
2020-12-07 16:17:23 +00:00
valeur: 6 €/repas
2020-03-25 10:00:38 +00:00
2020-12-07 16:17:23 +00:00
montant repas mensuels: 20 repas * frais de repas
2020-03-25 10:00:38 +00:00
```
2020-12-07 16:17:23 +00:00
On peut également choisir de remplacer dans un contexte donné:
2020-03-25 10:00:38 +00:00
```yaml
2020-12-07 16:17:23 +00:00
temps de préparation: 20 min
temps de cuisson: 20 min
2020-03-25 10:00:38 +00:00
2020-12-07 16:17:23 +00:00
robot de cuisine:
2020-11-24 16:22:34 +00:00
remplace:
2020-12-07 16:17:23 +00:00
- règle: temps de préparation
sauf dans: temps original
par: 10 min
valeur: oui
2020-03-25 10:00:38 +00:00
2020-12-07 16:17:23 +00:00
temps original:
2020-11-24 16:22:34 +00:00
formule: a + b
2020-03-25 10:00:38 +00:00
2020-12-07 16:17:23 +00:00
temps modifié:
2020-11-24 16:22:34 +00:00
formule: a + b
2020-02-04 14:21:36 +00:00
```
2020-12-07 16:17:23 +00:00
> [En savoir plus sur les remplacements](/manuel#remplacement)
## Définition de règle imbriquée
2020-03-25 17:06:07 +00:00
Si le mécanisme de remplacement permet de faire des substitutions de règles
complètes, il est parfois utile de ne modifier qu'un seul paramètre d'une règle
existante, par exemple modifier le facteur d'une multiplication tout en
conservant le reste de sa définition inchangée.
Une première manière de faire consiste à extraire le paramètre en question dans
une règle indépendante, le rendant ainsi accessible et modifiable depuis
l'extérieur :
```yaml
prime:
2020-11-24 16:22:34 +00:00
formule:
multiplication:
assiette: 1000€
taux: taux
2020-03-25 17:06:07 +00:00
prime . taux:
2020-11-24 16:22:34 +00:00
formule: 5%
2020-03-25 17:06:07 +00:00
super-prime:
2020-11-24 16:22:34 +00:00
remplace: prime . taux
formule: 10%
2020-03-25 17:06:07 +00:00
```
Ce code fonctionne mais il nous oblige a créer une règle `prime . taux` qui
n'est pas pertinente en tant qu'entité autonome (avec sa propre page de
documentation, etc.), uniquement pour pouvoir la modifier avec un `remplace` . On
a aussi introduit une indirection dans la définition de la prime en remplaçant
une ligne explicite `taux: 5%` par une référence vers une règle tierce
`taux: taux` , qui est loin d'être aussi claire.
2020-12-07 16:17:23 +00:00
Pour ce cas d'usage il est possible de définir une _règle imbriquée_ .
On garde la définition de la prime inchangée et on annote la valeur à laquelle
on veut accéder depuis l'extérieur avec le mot clé `nom` :
2020-03-25 17:06:07 +00:00
```yaml
prime:
2020-11-24 16:22:34 +00:00
formule:
multiplication:
assiette: 1000€
2020-12-07 16:17:23 +00:00
taux:
nom: taux
valeur: 5%
2020-03-25 17:06:07 +00:00
super-prime:
2020-11-24 16:22:34 +00:00
remplace: prime . taux
formule: 10%
2020-03-25 17:06:07 +00:00
```
2020-12-07 16:17:23 +00:00
## Évaluation
2020-03-25 17:06:07 +00:00
2020-12-10 15:55:56 +00:00
Lors de l'évaluation, les variables dont les valeurs ne sont pas renseignées sont remontées afin que ces dernières puissent être complétées par l'utilisateur (dans le cas d'un simulateur par exemple).
2020-03-25 17:06:07 +00:00
2020-12-07 16:17:23 +00:00
Il est possible de donner une valeur par défaut. Les variables manquantes seront quand même remontée, et le moteur utilisera la valeur par défaut pour le calcul.
2020-11-17 10:43:38 +00:00
```yaml
2020-12-07 16:17:23 +00:00
durée:
par défaut: 2 mois
2020-11-17 10:43:38 +00:00
2020-12-07 16:17:23 +00:00
salaire brut:
par défaut: 1500 €/mois
2020-11-17 10:43:38 +00:00
2020-12-07 16:17:23 +00:00
indemnité de CDD: 10 % * salaire brut * durée
```