mirror of
https://github.com/CatalaLang/catala.git
synced 2024-09-20 08:47:14 +03:00
Cross-test French housing benefits with official simulator (#338)
This commit is contained in:
commit
5e768ec747
@ -50,136 +50,102 @@ function run_computation_AF(log) {
|
|||||||
|
|
||||||
function run_computation_AL(log) {
|
function run_computation_AL(log) {
|
||||||
var result = Law.computeAidesAuLogement({
|
var result = Law.computeAidesAuLogement({
|
||||||
dateCouranteIn: "2022-01-01",
|
"menageIn": {
|
||||||
menageIn: {
|
"prestationsRecues": [],
|
||||||
prestationsRecues: [
|
"logement": {
|
||||||
{ kind: "AllocationSoutienEnfantHandicape", payload: null },
|
"residencePrincipale": true,
|
||||||
{ kind: "ComplementFamilial", payload: null },
|
"estEhpadOuMaisonAutonomieL31312Asf": false,
|
||||||
{ kind: "AllocationsFamiliales", payload: null },
|
"modeOccupation": {
|
||||||
|
"kind": "Locataire",
|
||||||
|
"payload": {
|
||||||
|
"bailleur": {
|
||||||
|
"kind": "BailleurPrive"
|
||||||
|
},
|
||||||
|
"beneficiaireAideAdulteOuEnfantHandicapes": false,
|
||||||
|
"logementEstChambre": false,
|
||||||
|
"colocation": false,
|
||||||
|
"ageesOuHandicapAdultesHebergeesOnereuxParticuliers": false,
|
||||||
|
"reductionLoyerSolidarite": 0,
|
||||||
|
"logementMeubleD8422": false,
|
||||||
|
"changementLogementD8424": {
|
||||||
|
"kind": "PasDeChangement",
|
||||||
|
"payload": null
|
||||||
|
},
|
||||||
|
"loyerPrincipal": 450
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"proprietaire": {
|
||||||
|
"kind": "Autre",
|
||||||
|
"payload": null
|
||||||
|
},
|
||||||
|
"loueOuSousLoueADesTiers": {
|
||||||
|
"kind": "Non"
|
||||||
|
},
|
||||||
|
"usufruit": {
|
||||||
|
"kind": "Autre",
|
||||||
|
"payload": null
|
||||||
|
},
|
||||||
|
"logementDecentL89462": true,
|
||||||
|
"zone": {
|
||||||
|
"kind": "Zone2"
|
||||||
|
},
|
||||||
|
"surfaceMCarres": 65
|
||||||
|
},
|
||||||
|
"personnesACharge": [
|
||||||
|
{
|
||||||
|
"kind": "EnfantACharge",
|
||||||
|
"payload": {
|
||||||
|
"beneficieTitrePersonnelAidePersonnelleLogement": false,
|
||||||
|
"aDejaOuvertDroitAuxAllocationsFamiliales": true,
|
||||||
|
"remunerationMensuelle": 0,
|
||||||
|
"obligationScolaire": {
|
||||||
|
"kind": "Pendant"
|
||||||
|
},
|
||||||
|
"situationGardeAlternee": {
|
||||||
|
"kind": "PasDeGardeAlternee"
|
||||||
|
},
|
||||||
|
"dateDeNaissance": "2015-01-01",
|
||||||
|
"identifiant": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "EnfantACharge",
|
||||||
|
"payload": {
|
||||||
|
"beneficieTitrePersonnelAidePersonnelleLogement": false,
|
||||||
|
"aDejaOuvertDroitAuxAllocationsFamiliales": true,
|
||||||
|
"remunerationMensuelle": 0,
|
||||||
|
"obligationScolaire": {
|
||||||
|
"kind": "Pendant"
|
||||||
|
},
|
||||||
|
"situationGardeAlternee": {
|
||||||
|
"kind": "PasDeGardeAlternee"
|
||||||
|
},
|
||||||
|
"dateDeNaissance": "2016-01-01",
|
||||||
|
"identifiant": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
],
|
],
|
||||||
situationFamiliale: {
|
"nombreAutresOccupantsLogement": 0,
|
||||||
kind: "Maries",
|
"situationFamiliale": {
|
||||||
payload: "2010-11-26",
|
"kind": "Concubins",
|
||||||
},
|
"payload": null
|
||||||
personnesACharge: [
|
|
||||||
{
|
|
||||||
kind: "EnfantACharge",
|
|
||||||
payload: {
|
|
||||||
beneficieTitrePersonnelAidePersonnelleLogement: false,
|
|
||||||
priseEnCharge: { kind: "EffectiveEtPermanente", payload: null },
|
|
||||||
age: 19,
|
|
||||||
identifiant: 0,
|
|
||||||
aDejaOuvertDroitAuxAllocationsFamiliales: true,
|
|
||||||
dateDeNaissance: "2003-01-01",
|
|
||||||
remunerationMensuelle: 0,
|
|
||||||
obligationScolaire: { kind: "Apres", payload: null },
|
|
||||||
situationGardeAlternee: {
|
|
||||||
kind: "GardeAlterneeCoefficientPriseEnCharge",
|
|
||||||
payload: 0.5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
kind: "EnfantACharge",
|
|
||||||
payload: {
|
|
||||||
beneficieTitrePersonnelAidePersonnelleLogement: false,
|
|
||||||
priseEnCharge: { kind: "EffectiveEtPermanente", payload: null },
|
|
||||||
age: 11,
|
|
||||||
identifiant: 1,
|
|
||||||
aDejaOuvertDroitAuxAllocationsFamiliales: true,
|
|
||||||
dateDeNaissance: "2011-01-01",
|
|
||||||
remunerationMensuelle: 0,
|
|
||||||
obligationScolaire: { kind: "Pendant", payload: null },
|
|
||||||
situationGardeAlternee: {
|
|
||||||
kind: "PasDeGardeAlternee",
|
|
||||||
payload: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
kind: "EnfantACharge",
|
|
||||||
payload: {
|
|
||||||
beneficieTitrePersonnelAidePersonnelleLogement: false,
|
|
||||||
priseEnCharge: { kind: "EffectiveEtPermanente", payload: null },
|
|
||||||
age: 8,
|
|
||||||
identifiant: 2,
|
|
||||||
aDejaOuvertDroitAuxAllocationsFamiliales: true,
|
|
||||||
dateDeNaissance: "2014-01-01",
|
|
||||||
remunerationMensuelle: 0,
|
|
||||||
obligationScolaire: { kind: "Pendant", payload: null },
|
|
||||||
situationGardeAlternee: {
|
|
||||||
kind: "PasDeGardeAlternee",
|
|
||||||
payload: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
logement: {
|
|
||||||
zone: { kind: "Zone1", payload: null },
|
|
||||||
residencePrincipale: true,
|
|
||||||
estEhpadOuMaisonAutonomieL31312Asf: false,
|
|
||||||
modeOccupation: {
|
|
||||||
kind: "Locataire",
|
|
||||||
payload: {
|
|
||||||
bailleur: {
|
|
||||||
typeBailleur: { kind: "BailleurPrive", payload: null },
|
|
||||||
respecteConventionTitreV: true,
|
|
||||||
respecteConventionTitreII: true,
|
|
||||||
construitAmelioreConditionsL83114: false,
|
|
||||||
acquisitionAidesEtatPretTitreIIOuLivreIII: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
proprietaire: { kind: "Autre", payload: null },
|
|
||||||
loueOuSousLoueADesTiers: { kind: "Non", payload: null },
|
|
||||||
usufruit: { kind: "Autre", payload: null },
|
|
||||||
logementDecentL89462: true,
|
|
||||||
loyersL8233: 700,
|
|
||||||
surfaceMCarres: 80,
|
|
||||||
estAncienL8312: false,
|
|
||||||
situeCommuneDesequilibreL8312: false,
|
|
||||||
},
|
|
||||||
nombreAutresOccupantsLogement: 1,
|
|
||||||
conditionRattacheFoyerFiscalParentIfi: false,
|
|
||||||
nombreEnfantsANaitreApresTroisiemeMoisGrossesse: 0,
|
|
||||||
enfantANaitreApresQuatriemeMoisGrossesse: false,
|
|
||||||
dateNaissanceTroisiemeEnfantOuDernierSiPlus: {
|
|
||||||
kind: "PlusDeTroisEnfants",
|
|
||||||
payload: {
|
|
||||||
kind: "DateDeNaissance",
|
|
||||||
payload: "2014-09-15",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
"conditionRattacheFoyerFiscalParentIfi": false,
|
||||||
|
"nombreEnfantsANaitreApresTroisiemeMoisGrossesse": 0,
|
||||||
},
|
},
|
||||||
demandeurIn: {
|
"demandeurIn": {
|
||||||
personneHebergeeCentreSoinLL162223SecuriteSociale: false,
|
"nationalite": {
|
||||||
satisfaitConditionsL5122CodeSecuriteSociale: true,
|
"kind": "Francaise"
|
||||||
ageDemandeur: 52,
|
|
||||||
dateNaissance: "1970-05-02",
|
|
||||||
contratDeTravail: { kind: "CDI", payload: null },
|
|
||||||
nationalite: { kind: "Francaise", payload: null },
|
|
||||||
patrimoine: {
|
|
||||||
produisantRevenuPeriodeR82233R8224: 0,
|
|
||||||
neProduisantPasRevenuPeriodeR82233R8224: 0,
|
|
||||||
},
|
},
|
||||||
},
|
"patrimoine": {
|
||||||
informationsCalculIn: {
|
"produisantRevenuPeriodeR82233R8224": 0,
|
||||||
kind: "InfosLocatif",
|
"neProduisantPasRevenuPeriodeR82233R8224": 0
|
||||||
payload: {
|
|
||||||
loyerPrincipal: 1700,
|
|
||||||
beneficiaireAideAdulteOuEnfantHandicapes: false,
|
|
||||||
logementEstChambre: false,
|
|
||||||
colocation: false,
|
|
||||||
ageesOuHandicapAdultesHebergeesOnereuxParticuliers: false,
|
|
||||||
reductionLoyerSolidarite: 0,
|
|
||||||
logementMeubleD8422: false,
|
|
||||||
changementLogementD8424: {
|
|
||||||
kind: "PasDeChangement",
|
|
||||||
payload: null,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
"personneHebergeeCentreSoinLL162223SecuriteSociale": false,
|
||||||
|
"dateNaissance": "1992-01-01"
|
||||||
},
|
},
|
||||||
ressourcesMenagePrisesEnCompteIn: 20000,
|
"dateCouranteIn": "2022-05-01",
|
||||||
|
"ressourcesMenagePrisesEnCompteIn": 11500
|
||||||
});
|
});
|
||||||
if (log) {
|
if (log) {
|
||||||
console.log(
|
console.log(
|
||||||
|
9072
french_law/js/french_law.js
generated
9072
french_law/js/french_law.js
generated
File diff suppressed because one or more lines are too long
2
french_law/ocaml/law_source/aides_logement.ml
generated
2
french_law/ocaml/law_source/aides_logement.ml
generated
@ -15253,7 +15253,7 @@ let ressources_aides_personnelle_logement (ressources_aides_personnelle_logement
|
|||||||
if
|
if
|
||||||
(demandeur_exerce_activite_remuneree_ &&
|
(demandeur_exerce_activite_remuneree_ &&
|
||||||
(conjoint_exerce_activite_remuneree_ &&
|
(conjoint_exerce_activite_remuneree_ &&
|
||||||
((ressources_conjoint_ +$ ressources_conjoint_) >=$
|
((ressources_demandeur_ +$ ressources_conjoint_) >=$
|
||||||
(base_mensuelle_allocations_familiales_dot_montant_ *$
|
(base_mensuelle_allocations_familiales_dot_montant_ *$
|
||||||
(decimal_of_string "12."))))) then
|
(decimal_of_string "12."))))) then
|
||||||
montant_forfaitaire_r_822_7_ else (money_of_cents_string "0")))
|
montant_forfaitaire_r_822_7_ else (money_of_cents_string "0")))
|
||||||
|
@ -13,7 +13,8 @@ format:
|
|||||||
autopep8 --in-place $(SOURCES)
|
autopep8 --in-place $(SOURCES)
|
||||||
|
|
||||||
bench:
|
bench:
|
||||||
python main.py bench
|
python main.py bench_family
|
||||||
|
python main.py bench_housing
|
||||||
|
|
||||||
show_log:
|
show_log:
|
||||||
python main.py show_log
|
python main.py show_log
|
||||||
|
145
french_law/python/cnaf_cross_tester/cnaf_to_catala.py
Normal file
145
french_law/python/cnaf_cross_tester/cnaf_to_catala.py
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
import datetime
|
||||||
|
from typing import List
|
||||||
|
from src.aides_logement import CategorieEquivalenceLoyerAllocationLogementFoyer_Code, LogementFoyer, ModeOccupation_Code, Nationalite_Code, SituationFamiliale_Code, SituationGardeAlternee_Code, SituationObligationScolaire_Code, TypeBailleur_Code, TypeLogementFoyer_Code, ZoneDHabitation_Code
|
||||||
|
from input import AppartementOuMaison, AppartementOuMaisonType, CnafSimulatorInput, Enfant, LogementCrous, LogementCrousType, LogementMaisonRetraite, LogementResidenceSocialeFJT, SeulOuCouple, Zone
|
||||||
|
from src.api import EnfantAPL, InfosLocation, InfosLogementFoyer, InfosSpecifiques, PersonneAChargeAPL, aides_logement
|
||||||
|
|
||||||
|
|
||||||
|
def run_catala_by_converting_cnaf_input(sample_input: CnafSimulatorInput) -> float:
|
||||||
|
enfants: List[PersonneAChargeAPL] = []
|
||||||
|
i = 0
|
||||||
|
for enfant in sample_input.enfants:
|
||||||
|
enfants.append(EnfantAPL(
|
||||||
|
identifiant=i,
|
||||||
|
beneficie_titre_personnel_aide_personnelle_logement=False,
|
||||||
|
a_deja_ouvert_droit_aux_allocations_familiales=False,
|
||||||
|
date_de_naissance=datetime.date.today() - datetime.timedelta(days=366 * enfant.age),
|
||||||
|
remuneration_mensuelle=int(
|
||||||
|
enfant.remuneration_derniere_annee / 12),
|
||||||
|
obligation_scolaire=SituationObligationScolaire_Code.Avant if enfant.age < 3 else (
|
||||||
|
SituationObligationScolaire_Code.Apres if enfant.age > 16 else SituationObligationScolaire_Code.Pendant),
|
||||||
|
situation_garde_alternee=SituationGardeAlternee_Code.PasDeGardeAlternee,
|
||||||
|
coefficient_garde_alternee=None
|
||||||
|
))
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
mode_occupation: ModeOccupation_Code
|
||||||
|
infos_specifiques: InfosSpecifiques
|
||||||
|
if isinstance(sample_input.logement, AppartementOuMaison):
|
||||||
|
mode_occupation = ModeOccupation_Code.Locataire
|
||||||
|
infos_specifiques = InfosLocation(
|
||||||
|
loyer_principal=sample_input.loyer,
|
||||||
|
beneficiaire_aide_adulte_ou_enfant_handicapes=False,
|
||||||
|
logement_est_chambre=False,
|
||||||
|
colocation=sample_input.logement.typ_v == AppartementOuMaisonType.Colocation,
|
||||||
|
agees_ou_handicap_adultes_hebergees_onereux_particuliers=False,
|
||||||
|
logement_meuble_d842_2=sample_input.logement.meuble_v,
|
||||||
|
ancien_loyer_et_apl_relogement=None,
|
||||||
|
type_bailleur=TypeBailleur_Code.BailleurPrive,
|
||||||
|
bailleur_conventionne=None,
|
||||||
|
reduction_loyer_solidarite=None
|
||||||
|
)
|
||||||
|
elif isinstance(sample_input.logement, LogementCrous):
|
||||||
|
# Les correspondances avec les catégories réglementaires sont faites selon DGALN/DHUP/FE4 (mail du 26/07/2022)
|
||||||
|
mode_occupation = ModeOccupation_Code.Locataire if sample_input.logement.typ_v == LogementCrousType.Studio else ModeOccupation_Code.ResidentLogementFoyer
|
||||||
|
infos_specifiques = InfosLocation(
|
||||||
|
loyer_principal=sample_input.loyer,
|
||||||
|
beneficiaire_aide_adulte_ou_enfant_handicapes=False,
|
||||||
|
logement_est_chambre=False,
|
||||||
|
colocation=False,
|
||||||
|
agees_ou_handicap_adultes_hebergees_onereux_particuliers=False,
|
||||||
|
logement_meuble_d842_2=False,
|
||||||
|
ancien_loyer_et_apl_relogement=None,
|
||||||
|
type_bailleur=TypeBailleur_Code.BailleurPrive,
|
||||||
|
bailleur_conventionne=None,
|
||||||
|
reduction_loyer_solidarite=None
|
||||||
|
) if sample_input.logement.typ_v == LogementCrousType.Studio else InfosLogementFoyer(
|
||||||
|
type=TypeLogementFoyer_Code.Autre,
|
||||||
|
remplit_conditions_r832_21=True,
|
||||||
|
conventionne_livre_III_titre_V_chap_III=True,
|
||||||
|
date_conventionnement=datetime.date(2000, 1, 1),
|
||||||
|
construit_application_loi_1957_12_III=False,
|
||||||
|
redevance=sample_input.loyer,
|
||||||
|
categorie_equivalence_loyer_d842_16=CategorieEquivalenceLoyerAllocationLogementFoyer_Code.EtudiantLogeEnChambreCROUS if
|
||||||
|
sample_input.logement.typ_v == LogementCrousType.Chambre else
|
||||||
|
CategorieEquivalenceLoyerAllocationLogementFoyer_Code.EtudiantLogeEnChambreCROUSRehabilitee
|
||||||
|
)
|
||||||
|
elif isinstance(sample_input.logement, LogementFoyer):
|
||||||
|
mode_occupation = ModeOccupation_Code.ResidentLogementFoyer
|
||||||
|
infos_specifiques = InfosLogementFoyer(
|
||||||
|
type=TypeLogementFoyer_Code.Autre,
|
||||||
|
remplit_conditions_r832_21=True,
|
||||||
|
conventionne_livre_III_titre_V_chap_III=True,
|
||||||
|
date_conventionnement=datetime.date(2000, 1, 1),
|
||||||
|
construit_application_loi_1957_12_III=False,
|
||||||
|
redevance=sample_input.loyer,
|
||||||
|
categorie_equivalence_loyer_d842_16=CategorieEquivalenceLoyerAllocationLogementFoyer_Code.AutresPersonnes
|
||||||
|
)
|
||||||
|
elif isinstance(sample_input.logement, LogementResidenceSocialeFJT):
|
||||||
|
# Correspond au 2° du D832-25 selon DGALN/DHUP/FE4 (mail du 26/07/2022)
|
||||||
|
mode_occupation = ModeOccupation_Code.ResidentLogementFoyer
|
||||||
|
infos_specifiques = InfosLogementFoyer(
|
||||||
|
type=TypeLogementFoyer_Code.ResidenceSociale,
|
||||||
|
remplit_conditions_r832_21=True,
|
||||||
|
conventionne_livre_III_titre_V_chap_III=True,
|
||||||
|
date_conventionnement=datetime.date(2000, 1, 1),
|
||||||
|
construit_application_loi_1957_12_III=False,
|
||||||
|
redevance=sample_input.loyer,
|
||||||
|
categorie_equivalence_loyer_d842_16=CategorieEquivalenceLoyerAllocationLogementFoyer_Code.AutresPersonnes
|
||||||
|
)
|
||||||
|
elif isinstance(sample_input.logement, LogementMaisonRetraite):
|
||||||
|
# Correspond au 3° du D842-16 et au 1° du R832-20 selon DGALN/DHUP/FE4 (mail du 26/07/2022)
|
||||||
|
mode_occupation = ModeOccupation_Code.ResidentLogementFoyer
|
||||||
|
infos_specifiques = InfosLogementFoyer(
|
||||||
|
type=TypeLogementFoyer_Code.LogementPersonnesAgeesOuHandicapees,
|
||||||
|
remplit_conditions_r832_21=True,
|
||||||
|
conventionne_livre_III_titre_V_chap_III=True,
|
||||||
|
date_conventionnement=datetime.date(2000, 1, 1),
|
||||||
|
construit_application_loi_1957_12_III=False,
|
||||||
|
redevance=sample_input.loyer,
|
||||||
|
categorie_equivalence_loyer_d842_16=CategorieEquivalenceLoyerAllocationLogementFoyer_Code.PersonnesAgeesSelon3DeD842_16
|
||||||
|
)
|
||||||
|
else: # isinstance(sample_input.logement, LogementChambre):
|
||||||
|
mode_occupation = ModeOccupation_Code.Locataire
|
||||||
|
infos_specifiques = InfosLocation(
|
||||||
|
loyer_principal=sample_input.loyer,
|
||||||
|
beneficiaire_aide_adulte_ou_enfant_handicapes=False,
|
||||||
|
logement_est_chambre=True,
|
||||||
|
colocation=False,
|
||||||
|
agees_ou_handicap_adultes_hebergees_onereux_particuliers=False,
|
||||||
|
logement_meuble_d842_2=False,
|
||||||
|
ancien_loyer_et_apl_relogement=None,
|
||||||
|
type_bailleur=TypeBailleur_Code.BailleurPrive,
|
||||||
|
bailleur_conventionne=None,
|
||||||
|
reduction_loyer_solidarite=None
|
||||||
|
)
|
||||||
|
|
||||||
|
housing_benefits_gross = aides_logement(
|
||||||
|
datetime.date.today(),
|
||||||
|
ressources_menage_prises_en_compte=sample_input.revenu_pris_en_compte,
|
||||||
|
date_naissance_demandeur=datetime.date(1992, 1, 1),
|
||||||
|
nationalite_demandeur=Nationalite_Code.Francaise,
|
||||||
|
patrimoine_produisant_revenu=0,
|
||||||
|
patrimoine_ne_produisant_pas_revenu=0,
|
||||||
|
personne_hebergee_centre_soins=False,
|
||||||
|
personne_rattache_foyer_fiscal_parent_ifi=False,
|
||||||
|
nombre_autres_occupants_logement_hors_menage=0,
|
||||||
|
enfant_a_naitre_apres_quatrieme_mois_grossesse=False,
|
||||||
|
situation_familiale=SituationFamiliale_Code.Celibataire if sample_input.seul_ou_couple == SeulOuCouple.Seul else SituationFamiliale_Code.Concubins,
|
||||||
|
date_mariage=None,
|
||||||
|
prestations_recues=[],
|
||||||
|
residence_principale=True,
|
||||||
|
logement_est_maison_de_retraite=True if isinstance(
|
||||||
|
sample_input.logement, LogementMaisonRetraite) else False,
|
||||||
|
logement_est_decent=True,
|
||||||
|
surface_logement_m_carres=10000,
|
||||||
|
zone=ZoneDHabitation_Code.Zone1 if sample_input.zone == Zone.Zone1 else (
|
||||||
|
ZoneDHabitation_Code.Zone2 if sample_input.zone == Zone.Zone2 else ZoneDHabitation_Code.Zone3),
|
||||||
|
parts_logement_propriete_famille=None,
|
||||||
|
parts_logement_usufruits_famille=None,
|
||||||
|
date_naissance_et_conformite_sous_locataire_tiers=None,
|
||||||
|
personnes_a_charge=enfants,
|
||||||
|
mode_occupation=mode_occupation,
|
||||||
|
infos_specifiques=infos_specifiques)
|
||||||
|
|
||||||
|
return round(housing_benefits_gross*0.995) # We take the CRDS
|
69
french_law/python/cnaf_cross_tester/differing_outputs.txt
Normal file
69
french_law/python/cnaf_cross_tester/differing_outputs.txt
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
🏡 Description du ménage
|
||||||
|
-> Code postal : Zone2
|
||||||
|
-> Logement : AppartementOuMaison(typ=Colocation,meuble=True)
|
||||||
|
-> Loyer : 1240 €
|
||||||
|
-> Seul of couple : Seul
|
||||||
|
-> Enfants :
|
||||||
|
Enfant(age=13,remuneration_derniere_annee=7385)
|
||||||
|
-> Revenus pris en compte : 5800 €
|
||||||
|
💰 Aides au logement (Catala): 394 €
|
||||||
|
💰 Aides au logement (CNAF) : 137 €
|
||||||
|
❌ Différence
|
||||||
|
|
||||||
|
🏡 Description du ménage
|
||||||
|
-> Code postal : Zone3
|
||||||
|
-> Logement : LogementResidenceSocialeFJT
|
||||||
|
-> Loyer : 1557 €
|
||||||
|
-> Seul of couple : Seul
|
||||||
|
-> Enfants :
|
||||||
|
Enfant(age=10,remuneration_derniere_annee=8827)
|
||||||
|
Enfant(age=7,remuneration_derniere_annee=8643)
|
||||||
|
-> Revenus pris en compte : 3800 €
|
||||||
|
💰 Aides au logement (Catala): 435 €
|
||||||
|
💰 Aides au logement (CNAF) : 81 €
|
||||||
|
❌ Différence
|
||||||
|
|
||||||
|
🏡 Description du ménage
|
||||||
|
-> Code postal : Zone1
|
||||||
|
-> Logement : LogementChambre(meuble=True)
|
||||||
|
-> Loyer : 1225 €
|
||||||
|
-> Seul of couple : EnCouple
|
||||||
|
-> Enfants :
|
||||||
|
Enfant(age=16,remuneration_derniere_annee=0)
|
||||||
|
Enfant(age=10,remuneration_derniere_annee=0)
|
||||||
|
Enfant(age=19,remuneration_derniere_annee=0)
|
||||||
|
Enfant(age=7,remuneration_derniere_annee=0)
|
||||||
|
-> Revenus pris en compte : 11800 €
|
||||||
|
💰 Aides au logement (Catala): 0 €
|
||||||
|
💰 Aides au logement (CNAF) : 291 €
|
||||||
|
❌ Différence
|
||||||
|
|
||||||
|
🏡 Description du ménage
|
||||||
|
-> Code postal : Zone3
|
||||||
|
-> Logement : LogementCrous(typ=Studio)
|
||||||
|
-> Loyer : 1271 €
|
||||||
|
-> Seul of couple : EnCouple
|
||||||
|
-> Enfants :
|
||||||
|
Enfant(age=12,remuneration_derniere_annee=3789)
|
||||||
|
Enfant(age=10,remuneration_derniere_annee=4198)
|
||||||
|
-> Revenus pris en compte : 9200 €
|
||||||
|
💰 Aides au logement (Catala): 0 €
|
||||||
|
💰 Aides au logement (CNAF) : 297 €
|
||||||
|
❌ Différence
|
||||||
|
|
||||||
|
🏡 Description du ménage
|
||||||
|
-> Code postal : Zone3
|
||||||
|
-> Logement : LogementCrous(typ=Studio)
|
||||||
|
-> Loyer : 513 €
|
||||||
|
-> Seul of couple : Seul
|
||||||
|
-> Enfants :
|
||||||
|
Enfant(age=18,remuneration_derniere_annee=0)
|
||||||
|
Enfant(age=7,remuneration_derniere_annee=0)
|
||||||
|
Enfant(age=17,remuneration_derniere_annee=0)
|
||||||
|
Enfant(age=21,remuneration_derniere_annee=0)
|
||||||
|
Enfant(age=6,remuneration_derniere_annee=0)
|
||||||
|
Enfant(age=5,remuneration_derniere_annee=0)
|
||||||
|
-> Revenus pris en compte : 11800 €
|
||||||
|
💰 Aides au logement (Catala): 524 €
|
||||||
|
💰 Aides au logement (CNAF) : 372 €
|
||||||
|
❌ Différence
|
182
french_law/python/cnaf_cross_tester/input.py
Normal file
182
french_law/python/cnaf_cross_tester/input.py
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
from abc import ABC
|
||||||
|
from enum import Enum
|
||||||
|
from typing import Any, List, Optional
|
||||||
|
|
||||||
|
|
||||||
|
class Logement(ABC):
|
||||||
|
def residence(self) -> str:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def typ(self) -> Optional[str]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def meublee(self) -> Optional[bool]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AppartementOuMaisonType(Enum):
|
||||||
|
Location = "LOCATION"
|
||||||
|
Colocation = "COLOCATION"
|
||||||
|
|
||||||
|
|
||||||
|
class AppartementOuMaison(Logement):
|
||||||
|
def __init__(self, typ: AppartementOuMaisonType, meuble: bool):
|
||||||
|
self.residence_v = "APPARTEMENT_OU_MAISON"
|
||||||
|
self.typ_v = typ
|
||||||
|
self.meuble_v = meuble
|
||||||
|
|
||||||
|
def residence(self) -> str:
|
||||||
|
return self.residence_v
|
||||||
|
|
||||||
|
def typ(self) -> Optional[str]:
|
||||||
|
return self.typ_v.value
|
||||||
|
|
||||||
|
def meublee(self) -> Optional[bool]:
|
||||||
|
return self.meuble_v
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return "AppartementOuMaison(typ={},meuble={})".format(self.typ_v.name, self.meuble_v)
|
||||||
|
|
||||||
|
|
||||||
|
class LogementCrousType(Enum):
|
||||||
|
Chambre = 'CHAMBRE'
|
||||||
|
Chambre_rehabilitee = 'CHAMBRE_REHABILITEE'
|
||||||
|
Studio = 'STUDIO'
|
||||||
|
|
||||||
|
|
||||||
|
class LogementCrous(Logement):
|
||||||
|
def __init__(self, typ: LogementCrousType):
|
||||||
|
self.residence_v = 'LOGEMENT_CROUS'
|
||||||
|
self.typ_v = typ
|
||||||
|
|
||||||
|
def residence(self) -> str:
|
||||||
|
return self.residence_v
|
||||||
|
|
||||||
|
def typ(self) -> Optional[str]:
|
||||||
|
return self.typ_v.value
|
||||||
|
|
||||||
|
def meublee(self) -> Optional[bool]:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return "LogementCrous(typ={})".format(self.typ_v.name)
|
||||||
|
|
||||||
|
|
||||||
|
class LogementFoyer(Logement):
|
||||||
|
def __init__(self):
|
||||||
|
self.residence_v = 'FOYER'
|
||||||
|
|
||||||
|
def residence(self) -> str:
|
||||||
|
return self.residence_v
|
||||||
|
|
||||||
|
def typ(self) -> Optional[str]:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def meublee(self) -> Optional[bool]:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return "LogementFoyer"
|
||||||
|
|
||||||
|
|
||||||
|
class LogementResidenceSocialeFJT(Logement):
|
||||||
|
def __init__(self):
|
||||||
|
self.residence_v = 'RESIDENCE_SOCIALE_FJT'
|
||||||
|
|
||||||
|
def residence(self) -> str:
|
||||||
|
return self.residence_v
|
||||||
|
|
||||||
|
def typ(self) -> Optional[str]:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def meublee(self) -> Optional[bool]:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return "LogementResidenceSocialeFJT"
|
||||||
|
|
||||||
|
|
||||||
|
class LogementMaisonRetraite(Logement):
|
||||||
|
def __init__(self):
|
||||||
|
self.residence_v = 'MAISON_RETRAITE_EHPAD'
|
||||||
|
|
||||||
|
def residence(self) -> str:
|
||||||
|
return self.residence_v
|
||||||
|
|
||||||
|
def typ(self) -> Optional[str]:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def meublee(self) -> Optional[bool]:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return "LogementMaisonRetraite"
|
||||||
|
|
||||||
|
|
||||||
|
class LogementChambre(Logement):
|
||||||
|
def __init__(self, meuble: bool):
|
||||||
|
self.residence_v = 'CHAMBRE'
|
||||||
|
self.meuble_v = meuble
|
||||||
|
|
||||||
|
def residence(self) -> str:
|
||||||
|
return self.residence_v
|
||||||
|
|
||||||
|
def typ(self) -> Optional[str]:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def meublee(self) -> Optional[bool]:
|
||||||
|
return self.meuble_v
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return "LogementChambre(meuble={})".format(self.meuble_v)
|
||||||
|
|
||||||
|
|
||||||
|
class SeulOuCouple(Enum):
|
||||||
|
Seul = 'CEL'
|
||||||
|
EnCouple = 'VIM'
|
||||||
|
|
||||||
|
|
||||||
|
class Enfant():
|
||||||
|
def __init__(self,
|
||||||
|
age: int,
|
||||||
|
remuneration_derniere_annee: int):
|
||||||
|
self.age = age
|
||||||
|
self.remuneration_derniere_annee = remuneration_derniere_annee
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return "Enfant(age={},remuneration_derniere_annee={})".format(self.age, self.remuneration_derniere_annee)
|
||||||
|
|
||||||
|
|
||||||
|
class Zone(Enum):
|
||||||
|
Zone1 = "75001"
|
||||||
|
Zone2 = "69001"
|
||||||
|
Zone3 = "46800"
|
||||||
|
|
||||||
|
|
||||||
|
class CnafSimulatorInput():
|
||||||
|
def __init__(self,
|
||||||
|
zone: Zone,
|
||||||
|
logement: Logement,
|
||||||
|
loyer: int,
|
||||||
|
seul_ou_couple: SeulOuCouple,
|
||||||
|
enfants: List[Enfant],
|
||||||
|
revenu_pris_en_compte: int):
|
||||||
|
self.zone = zone
|
||||||
|
self.logement = logement
|
||||||
|
self.loyer = loyer
|
||||||
|
self.seul_ou_couple = seul_ou_couple
|
||||||
|
self.enfants = enfants
|
||||||
|
self.revenu_pris_en_compte = revenu_pris_en_compte
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "-> Code postal : {}\n-> Logement : {}\n-> Loyer : {} €\n-> Seul of couple : {}\n-> Enfants :\n{}\n-> Revenus pris en compte : {} €".format(
|
||||||
|
self.zone.name,
|
||||||
|
self.logement,
|
||||||
|
self.loyer,
|
||||||
|
self.seul_ou_couple.name,
|
||||||
|
"\n".join(["{}".format(enfant) for enfant in self.enfants]),
|
||||||
|
self.revenu_pris_en_compte
|
||||||
|
)
|
33
french_law/python/cnaf_cross_tester/main.py
Normal file
33
french_law/python/cnaf_cross_tester/main.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
|
||||||
|
from cnaf_to_catala import run_catala_by_converting_cnaf_input
|
||||||
|
from pupeteer import run_simulator
|
||||||
|
from input import AppartementOuMaison, AppartementOuMaisonType, CnafSimulatorInput, Enfant, SeulOuCouple, Zone
|
||||||
|
from random_input_generator import generate_random_input
|
||||||
|
|
||||||
|
# input identical to the JS test of the housing benefits
|
||||||
|
sample_input = CnafSimulatorInput(
|
||||||
|
zone=Zone.Zone2,
|
||||||
|
logement=AppartementOuMaison(
|
||||||
|
AppartementOuMaisonType.Location, meuble=False),
|
||||||
|
loyer=450,
|
||||||
|
seul_ou_couple=SeulOuCouple.EnCouple,
|
||||||
|
enfants=[Enfant(age=7, remuneration_derniere_annee=0),
|
||||||
|
Enfant(age=8, remuneration_derniere_annee=0)],
|
||||||
|
revenu_pris_en_compte=11_500
|
||||||
|
)
|
||||||
|
# Or a random input
|
||||||
|
sample_input = generate_random_input()
|
||||||
|
print("🏡 Description du ménage")
|
||||||
|
print(sample_input)
|
||||||
|
housing_benefits_catala = run_catala_by_converting_cnaf_input(sample_input)
|
||||||
|
print("💰 Aides au logement (Catala): {} €".format(housing_benefits_catala))
|
||||||
|
housing_benefits_cnaf = run_simulator(sample_input)
|
||||||
|
print("💰 Aides au logement (CNAF) : {} €".format(housing_benefits_cnaf))
|
||||||
|
delta = abs(housing_benefits_catala - housing_benefits_cnaf)
|
||||||
|
if delta == 0:
|
||||||
|
print("✅ Pas de difference")
|
||||||
|
exit(0)
|
||||||
|
else:
|
||||||
|
print("❌ Différence")
|
||||||
|
exit(-1)
|
205
french_law/python/cnaf_cross_tester/pupeteer.py
Normal file
205
french_law/python/cnaf_cross_tester/pupeteer.py
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
# This code is ported from https://github.com/jboillot/apl-fetcher
|
||||||
|
|
||||||
|
from pdb import runeval
|
||||||
|
from playwright.sync_api import sync_playwright
|
||||||
|
from input import AppartementOuMaison, AppartementOuMaisonType, CnafSimulatorInput, Enfant, LogementCrous, SeulOuCouple
|
||||||
|
import re
|
||||||
|
|
||||||
|
HOME_PAGE = 'https://wwwd.caf.fr/wps/portal/caffr/aidesetservices/lesservicesenligne/estimervosdroits/lelogement'
|
||||||
|
|
||||||
|
|
||||||
|
def run_simulator(input: CnafSimulatorInput) -> int:
|
||||||
|
with sync_playwright() as p:
|
||||||
|
browser = p.firefox.launch(headless=False, slow_mo=100)
|
||||||
|
page = browser.new_page()
|
||||||
|
|
||||||
|
# Go to the CNAF simulator
|
||||||
|
page.goto(HOME_PAGE)
|
||||||
|
|
||||||
|
# Click on cookie banner
|
||||||
|
cookie_button = page.wait_for_selector(
|
||||||
|
"div[id=\"popup-accept-cookies\"] >> button")
|
||||||
|
if cookie_button is None:
|
||||||
|
raise RuntimeError
|
||||||
|
cookie_button.click(force=True)
|
||||||
|
|
||||||
|
# Click on 'Commencer'
|
||||||
|
commencer_button = page.wait_for_selector('button[id="btn-suivant"]')
|
||||||
|
if commencer_button is None:
|
||||||
|
raise RuntimeError
|
||||||
|
commencer_button.click(force=True)
|
||||||
|
|
||||||
|
# Code Postal
|
||||||
|
code_postal_input = page.wait_for_selector('input[id="cpCommune"]')
|
||||||
|
if code_postal_input is None:
|
||||||
|
raise RuntimeError
|
||||||
|
code_postal_input.fill(input.zone.value)
|
||||||
|
|
||||||
|
# Select first match
|
||||||
|
page.wait_for_selector('a[class="ng-tns-c31-0"]')
|
||||||
|
page.keyboard.press('Enter')
|
||||||
|
|
||||||
|
# Select residence type
|
||||||
|
type_residence_button = page.wait_for_selector(
|
||||||
|
"input[id=\"lieuResidence_{}\"]".format(input.logement.residence()))
|
||||||
|
if type_residence_button is None:
|
||||||
|
raise RuntimeError
|
||||||
|
type_residence_button.click(force=True)
|
||||||
|
|
||||||
|
# Select housing type for some things
|
||||||
|
if isinstance(input.logement, AppartementOuMaison):
|
||||||
|
type_appartement_ou_maison_button = page.wait_for_selector(
|
||||||
|
"input[id=\"typeOccupation_{}\"]".format(input.logement.typ()))
|
||||||
|
if type_appartement_ou_maison_button is None:
|
||||||
|
raise RuntimeError
|
||||||
|
type_appartement_ou_maison_button.click(force=True)
|
||||||
|
elif isinstance(input.logement, LogementCrous):
|
||||||
|
type_crous_button = page.wait_for_selector(
|
||||||
|
"input[id=\"typeCrous_{}\"]".format(input.logement.typ()))
|
||||||
|
if type_crous_button is None:
|
||||||
|
raise RuntimeError
|
||||||
|
type_crous_button.click(force=True)
|
||||||
|
|
||||||
|
# Is the location meublee
|
||||||
|
|
||||||
|
if not (input.logement.meublee() is None):
|
||||||
|
meuble_button = page.wait_for_selector(
|
||||||
|
"input[id=\"estMeuble_{}\"]".format("true" if input.logement.meublee() else "false"))
|
||||||
|
if meuble_button is None:
|
||||||
|
raise RuntimeError
|
||||||
|
meuble_button.click(force=True)
|
||||||
|
|
||||||
|
# Monthly rent
|
||||||
|
loyer_mensuel_input = page.wait_for_selector(
|
||||||
|
'input[id="mttDeclare"]')
|
||||||
|
if loyer_mensuel_input is None:
|
||||||
|
raise RuntimeError
|
||||||
|
loyer_mensuel_input.fill("{}".format(input.loyer))
|
||||||
|
|
||||||
|
# Couple or not
|
||||||
|
seul_button = page.wait_for_selector(
|
||||||
|
"input[id=\"situationFamiliale_{}\"]".format(input.seul_ou_couple.value))
|
||||||
|
if seul_button is None:
|
||||||
|
raise RuntimeError
|
||||||
|
seul_button.click(force=True)
|
||||||
|
|
||||||
|
# Number of children
|
||||||
|
if len(input.enfants) < 0 or len(input.enfants) > 20:
|
||||||
|
raise RuntimeError
|
||||||
|
plus_button = page.wait_for_selector('button:has-text("+")')
|
||||||
|
if plus_button is None:
|
||||||
|
raise RuntimeError
|
||||||
|
for i in range(len(input.enfants)):
|
||||||
|
plus_button.click(force=True)
|
||||||
|
|
||||||
|
# Main applicant salary
|
||||||
|
salaires_button = page.wait_for_selector(
|
||||||
|
"button[id=\"SALAIRE_0_checkbox\"]")
|
||||||
|
if salaires_button is None:
|
||||||
|
raise RuntimeError
|
||||||
|
salaires_button.click(force=True)
|
||||||
|
salaires_input = page.wait_for_selector(
|
||||||
|
"input[id=\"SALAIRE_0_montant\"]")
|
||||||
|
if salaires_input is None:
|
||||||
|
raise RuntimeError
|
||||||
|
salaires_input.fill("{}".format(
|
||||||
|
int(float(input.revenu_pris_en_compte) / 0.9)))
|
||||||
|
salaires_input.wait_for_element_state(state="stable")
|
||||||
|
# We divide by 0.9 because salaries have a 10% franchise
|
||||||
|
# Now if the salary is too low you have to click another button
|
||||||
|
status_selector = "input[id=\"sitro_0_SITPRO_ACT_INCONNUE\"]"
|
||||||
|
if not (page.query_selector is None):
|
||||||
|
status_button = page.wait_for_selector(status_selector)
|
||||||
|
if status_button is None:
|
||||||
|
raise RuntimeError
|
||||||
|
status_button.click(force=True)
|
||||||
|
|
||||||
|
# If there is a partner we assume no income for simplicity
|
||||||
|
if input.seul_ou_couple == SeulOuCouple.EnCouple:
|
||||||
|
sans_button = page.wait_for_selector(
|
||||||
|
"button[id=\"aucunRevenu_1\"]")
|
||||||
|
if sans_button is None:
|
||||||
|
raise RuntimeError
|
||||||
|
sans_button.click(force=True)
|
||||||
|
status_button = page.wait_for_selector(
|
||||||
|
"input[id=\"sitro_1_SITPRO_ACT_INCONNUE\"]")
|
||||||
|
if status_button is None:
|
||||||
|
raise RuntimeError
|
||||||
|
status_button.click(force=True)
|
||||||
|
|
||||||
|
# Continue
|
||||||
|
continuer_button = page.wait_for_selector('button[id="btn-suivant"]')
|
||||||
|
if continuer_button is None:
|
||||||
|
raise RuntimeError
|
||||||
|
continuer_button.click(force=True)
|
||||||
|
|
||||||
|
# Extra questions about children
|
||||||
|
if len(input.enfants) > 0:
|
||||||
|
for i in range(len(input.enfants)):
|
||||||
|
if input.enfants[i].age < 21:
|
||||||
|
yes_button = page.wait_for_selector(
|
||||||
|
"input[id=\"QUESTION_AGE_MAX_{}_true\"]".format(i))
|
||||||
|
if yes_button is None:
|
||||||
|
raise RuntimeError
|
||||||
|
yes_button.click(force=True)
|
||||||
|
else:
|
||||||
|
no_button = page.wait_for_selector(
|
||||||
|
"input[id=\"QUESTION_AGE_MAX_{}_false\"]".format(i))
|
||||||
|
if no_button is None:
|
||||||
|
raise RuntimeError
|
||||||
|
no_button.click(force=True)
|
||||||
|
if int(float(input.enfants[i].remuneration_derniere_annee) / 0.9) > 4500:
|
||||||
|
yes_button = page.wait_for_selector(
|
||||||
|
"input[id=\"QUESTION_REVENUS_DERNIERSMOIS_{}_true\"]".format(i))
|
||||||
|
if yes_button is None:
|
||||||
|
raise RuntimeError
|
||||||
|
yes_button.click(force=True)
|
||||||
|
# We have to provide the exact remuneration
|
||||||
|
salaires_button = page.wait_for_selector(
|
||||||
|
"button[id=\"salaire{}_checkbox\"]".format(i))
|
||||||
|
if salaires_button is None:
|
||||||
|
raise RuntimeError
|
||||||
|
salaires_button.click(force=True)
|
||||||
|
salaires_input = page.wait_for_selector(
|
||||||
|
"input[id=\"MONTANT_salaire{}\"]".format(i))
|
||||||
|
if salaires_input is None:
|
||||||
|
raise RuntimeError
|
||||||
|
salaires_input.fill("{}".format(
|
||||||
|
int(float(input.enfants[i].remuneration_derniere_annee) / 0.9)))
|
||||||
|
salaires_status = page.wait_for_selector(
|
||||||
|
"input[id=\"QUESTION_SITPRO_{}_SALARIE_CP\"]".format(i))
|
||||||
|
if salaires_status is None:
|
||||||
|
raise RuntimeError
|
||||||
|
salaires_status.click(force=True)
|
||||||
|
else:
|
||||||
|
no_button = page.wait_for_selector(
|
||||||
|
"input[id=\"QUESTION_REVENUS_DERNIERSMOIS_{}_false\"]".format(i))
|
||||||
|
if no_button is None:
|
||||||
|
raise RuntimeError
|
||||||
|
no_button.click(force=True)
|
||||||
|
|
||||||
|
# Continue
|
||||||
|
continuer_button = page.wait_for_selector(
|
||||||
|
'button[id="btn-suivant"]')
|
||||||
|
if continuer_button is None:
|
||||||
|
raise RuntimeError
|
||||||
|
continuer_button.click(force=True)
|
||||||
|
|
||||||
|
# Wait for result page
|
||||||
|
page.wait_for_selector("section[id=\"resultat\"]")
|
||||||
|
|
||||||
|
# Retrieve the amount
|
||||||
|
result = page.query_selector('text=/\\d+ € par mois/').text_content()
|
||||||
|
if result is None:
|
||||||
|
# Then no benefits!
|
||||||
|
housing_benefits = 0
|
||||||
|
else:
|
||||||
|
match = re.search("(\\d+) € par mois", result)
|
||||||
|
if match is None:
|
||||||
|
raise RuntimeError
|
||||||
|
housing_benefits = match.group(1)
|
||||||
|
if housing_benefits is None:
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
|
browser.close()
|
||||||
|
return int(housing_benefits)
|
@ -0,0 +1,67 @@
|
|||||||
|
import random
|
||||||
|
from input import AppartementOuMaison, AppartementOuMaisonType, CnafSimulatorInput, Enfant, Logement, LogementChambre, LogementCrous, LogementCrousType, LogementFoyer, LogementMaisonRetraite, LogementResidenceSocialeFJT, SeulOuCouple, Zone
|
||||||
|
|
||||||
|
|
||||||
|
def generate_random_child() -> Enfant:
|
||||||
|
age = random.randint(0, 25)
|
||||||
|
# For now we don't put income for children for simplicity
|
||||||
|
remuneration_derniere_annee = random.randint(0, 0)
|
||||||
|
return Enfant(age, remuneration_derniere_annee)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_random_input() -> CnafSimulatorInput:
|
||||||
|
zone_i = random.randint(1, 3)
|
||||||
|
if zone_i == 1:
|
||||||
|
zone = Zone.Zone1
|
||||||
|
elif zone_i == 2:
|
||||||
|
zone = Zone.Zone2
|
||||||
|
else: # zone_i == 3
|
||||||
|
zone = Zone.Zone3
|
||||||
|
loyer = random.randint(300, 1800)
|
||||||
|
revenus_pris_en_compte = random.randint(0, 200) * 100
|
||||||
|
seul_ou_couple_i = random.randint(1, 2)
|
||||||
|
if seul_ou_couple_i == 1:
|
||||||
|
seul_ou_couple = SeulOuCouple.Seul
|
||||||
|
else: # seul_ou_couple_i == 2
|
||||||
|
seul_ou_couple = SeulOuCouple.EnCouple
|
||||||
|
nb_enfants = random.randint(0, 8)
|
||||||
|
enfants = [generate_random_child() for i in range(nb_enfants)]
|
||||||
|
typ_logement = random.randint(1, 6)
|
||||||
|
meuble_i = random.randint(1, 2)
|
||||||
|
logement: Logement
|
||||||
|
if meuble_i == 1:
|
||||||
|
meuble = True
|
||||||
|
else: # meuble_i == 2
|
||||||
|
meuble = False
|
||||||
|
if typ_logement == 1:
|
||||||
|
typ_location_i = random.randint(1, 2)
|
||||||
|
if typ_location_i == 1:
|
||||||
|
typ_location = AppartementOuMaisonType.Location
|
||||||
|
else: # typ_location_i == 2
|
||||||
|
typ_location = AppartementOuMaisonType.Colocation
|
||||||
|
logement = AppartementOuMaison(typ_location, meuble)
|
||||||
|
elif typ_logement == 2:
|
||||||
|
typ_i = random.randint(1, 3)
|
||||||
|
if typ_i == 1:
|
||||||
|
typ = LogementCrousType.Chambre
|
||||||
|
elif typ_i == 2:
|
||||||
|
typ = LogementCrousType.Chambre_rehabilitee
|
||||||
|
else: # typ_i == 3
|
||||||
|
typ = LogementCrousType.Studio
|
||||||
|
logement = LogementCrous(typ)
|
||||||
|
elif typ_logement == 3:
|
||||||
|
logement = LogementFoyer()
|
||||||
|
elif typ_logement == 4:
|
||||||
|
logement = LogementResidenceSocialeFJT()
|
||||||
|
elif typ_logement == 5:
|
||||||
|
logement = LogementMaisonRetraite()
|
||||||
|
else: # typ_logement == 6:
|
||||||
|
logement = LogementChambre(meuble)
|
||||||
|
return CnafSimulatorInput(
|
||||||
|
zone=zone,
|
||||||
|
logement=logement,
|
||||||
|
loyer=loyer,
|
||||||
|
seul_ou_couple=seul_ou_couple,
|
||||||
|
enfants=enfants,
|
||||||
|
revenu_pris_en_compte=revenus_pris_en_compte
|
||||||
|
)
|
@ -1,8 +1,9 @@
|
|||||||
#!python3
|
#!python3
|
||||||
|
|
||||||
from datetime import date
|
from datetime import date
|
||||||
from src.allocations_familiales import PriseEnCharge_Code, Collectivite_Code
|
from src.aides_logement import ModeOccupation_Code, Nationalite_Code, PrestationRecue_Code, SituationFamiliale_Code, SituationGardeAlternee_Code, SituationObligationScolaire_Code, TypeBailleur_Code, ZoneDHabitation_Code
|
||||||
from src.api import allocations_familiales, Enfant
|
from src.allocations_familiales import PriseEnCharge_Code, Collectivite_Code, SituationObligationScolaire
|
||||||
|
from src.api import EnfantAPL, InfosLocation, aides_logement, allocations_familiales, Enfant
|
||||||
from catala.runtime import LogEvent, LogEventCode, reset_log, retrieve_log
|
from catala.runtime import LogEvent, LogEventCode, reset_log, retrieve_log
|
||||||
import timeit
|
import timeit
|
||||||
import argparse
|
import argparse
|
||||||
@ -33,11 +34,77 @@ def call_allocations_familiales() -> float:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def benchmark_iteration():
|
def call_aides_logement() -> float:
|
||||||
|
return aides_logement(
|
||||||
|
date_courante=date(2022, 5, 1),
|
||||||
|
ressources_menage_prises_en_compte=11_500,
|
||||||
|
date_naissance_demandeur=date(1992, 1, 1),
|
||||||
|
nationalite_demandeur=Nationalite_Code.Francaise,
|
||||||
|
patrimoine_produisant_revenu=0,
|
||||||
|
patrimoine_ne_produisant_pas_revenu=0,
|
||||||
|
personne_hebergee_centre_soins=False,
|
||||||
|
personne_rattache_foyer_fiscal_parent_ifi=False,
|
||||||
|
nombre_autres_occupants_logement_hors_menage=0,
|
||||||
|
enfant_a_naitre_apres_quatrieme_mois_grossesse=False,
|
||||||
|
situation_familiale=SituationFamiliale_Code.Concubins,
|
||||||
|
date_mariage=None,
|
||||||
|
prestations_recues=[],
|
||||||
|
residence_principale=True,
|
||||||
|
logement_est_maison_de_retraite=False,
|
||||||
|
surface_logement_m_carres=65,
|
||||||
|
zone=ZoneDHabitation_Code.Zone2,
|
||||||
|
parts_logement_propriete_famille=None,
|
||||||
|
parts_logement_usufruits_famille=None,
|
||||||
|
date_naissance_et_conformite_sous_locataire_tiers=None,
|
||||||
|
mode_occupation=ModeOccupation_Code.Locataire,
|
||||||
|
personnes_a_charge=[
|
||||||
|
EnfantAPL(
|
||||||
|
identifiant=1,
|
||||||
|
beneficie_titre_personnel_aide_personnelle_logement=False,
|
||||||
|
a_deja_ouvert_droit_aux_allocations_familiales=True,
|
||||||
|
date_de_naissance=date(2015, 1, 1),
|
||||||
|
remuneration_mensuelle=0,
|
||||||
|
obligation_scolaire=SituationObligationScolaire_Code.Pendant,
|
||||||
|
situation_garde_alternee=SituationGardeAlternee_Code.PasDeGardeAlternee,
|
||||||
|
coefficient_garde_alternee=None
|
||||||
|
),
|
||||||
|
EnfantAPL(
|
||||||
|
identifiant=2,
|
||||||
|
beneficie_titre_personnel_aide_personnelle_logement=False,
|
||||||
|
a_deja_ouvert_droit_aux_allocations_familiales=True,
|
||||||
|
date_de_naissance=date(2016, 1, 1),
|
||||||
|
remuneration_mensuelle=0,
|
||||||
|
obligation_scolaire=SituationObligationScolaire_Code.Pendant,
|
||||||
|
situation_garde_alternee=SituationGardeAlternee_Code.PasDeGardeAlternee,
|
||||||
|
coefficient_garde_alternee=None)
|
||||||
|
],
|
||||||
|
logement_est_decent=True,
|
||||||
|
infos_specifiques=InfosLocation(
|
||||||
|
loyer_principal=450,
|
||||||
|
beneficiaire_aide_adulte_ou_enfant_handicapes=False,
|
||||||
|
colocation=False,
|
||||||
|
logement_est_chambre=False,
|
||||||
|
agees_ou_handicap_adultes_hebergees_onereux_particuliers=False,
|
||||||
|
logement_meuble_d842_2=False,
|
||||||
|
ancien_loyer_et_apl_relogement=None,
|
||||||
|
type_bailleur=TypeBailleur_Code.BailleurPrive,
|
||||||
|
bailleur_conventionne=None,
|
||||||
|
reduction_loyer_solidarite=None
|
||||||
|
)
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def benchmark_iteration_family():
|
||||||
money_given = call_allocations_familiales()
|
money_given = call_allocations_familiales()
|
||||||
assert (money_given == 99.46)
|
assert (money_given == 99.46)
|
||||||
|
|
||||||
|
|
||||||
|
def benchmark_iteration_housing():
|
||||||
|
money_given = call_aides_logement()
|
||||||
|
assert (money_given == 352.77)
|
||||||
|
|
||||||
|
|
||||||
def run_with_log() -> List[LogEvent]:
|
def run_with_log() -> List[LogEvent]:
|
||||||
money_given = call_allocations_familiales()
|
money_given = call_allocations_familiales()
|
||||||
assert (money_given == 99.46)
|
assert (money_given == 99.46)
|
||||||
@ -61,11 +128,16 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
action = args.action[0]
|
action = args.action[0]
|
||||||
if action == "bench":
|
if action == "bench_family":
|
||||||
iterations = 1000
|
iterations = 1000
|
||||||
print("Iterating {} iterations of the family benefits computation. Total time (s):".format(
|
print("Iterating {} iterations of the family benefits computation. Total time (s):".format(
|
||||||
iterations))
|
iterations))
|
||||||
print(timeit.timeit(benchmark_iteration, number=iterations))
|
print(timeit.timeit(benchmark_iteration_family, number=iterations))
|
||||||
|
elif action == "bench_housing":
|
||||||
|
iterations = 1000
|
||||||
|
print("Iterating {} iterations of the family benefits computation. Total time (s):".format(
|
||||||
|
iterations))
|
||||||
|
print(timeit.timeit(benchmark_iteration_housing, number=iterations))
|
||||||
elif action == "show_log":
|
elif action == "show_log":
|
||||||
log = run_with_log()
|
log = run_with_log()
|
||||||
indentation = 0
|
indentation = 0
|
||||||
|
2749
french_law/python/src/aides_logement.py
generated
2749
french_law/python/src/aides_logement.py
generated
File diff suppressed because it is too large
Load Diff
138
french_law/python/src/allocations_familiales.py
generated
138
french_law/python/src/allocations_familiales.py
generated
@ -780,21 +780,23 @@ def prestations_familiales(prestations_familiales_in:PrestationsFamilialesIn):
|
|||||||
temp_smic_dot_date_courante = date_courante_2
|
temp_smic_dot_date_courante = date_courante_2
|
||||||
except EmptyError:
|
except EmptyError:
|
||||||
temp_smic_dot_date_courante = dead_value
|
temp_smic_dot_date_courante = dead_value
|
||||||
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/../smic/smic.catala_fr",
|
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/prologue.catala_fr",
|
||||||
start_line=9, start_column=10,
|
start_line=69, start_column=14,
|
||||||
end_line=9, end_column=23,
|
end_line=69, end_column=32,
|
||||||
law_headings=["Prologue",
|
law_headings=["Prestations familiales",
|
||||||
"Montant du salaire minimum de croissance"]))
|
"Champs d'applications",
|
||||||
|
"Prologue"]))
|
||||||
smic_dot_date_courante = temp_smic_dot_date_courante
|
smic_dot_date_courante = temp_smic_dot_date_courante
|
||||||
try:
|
try:
|
||||||
temp_smic_dot_residence = residence_1
|
temp_smic_dot_residence = residence_1
|
||||||
except EmptyError:
|
except EmptyError:
|
||||||
temp_smic_dot_residence = dead_value
|
temp_smic_dot_residence = dead_value
|
||||||
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/../smic/smic.catala_fr",
|
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/prologue.catala_fr",
|
||||||
start_line=10, start_column=10,
|
start_line=68, start_column=14,
|
||||||
end_line=10, end_column=19,
|
end_line=68, end_column=28,
|
||||||
law_headings=["Prologue",
|
law_headings=["Prestations familiales",
|
||||||
"Montant du salaire minimum de croissance"]))
|
"Champs d'applications",
|
||||||
|
"Prologue"]))
|
||||||
smic_dot_residence = temp_smic_dot_residence
|
smic_dot_residence = temp_smic_dot_residence
|
||||||
result = smic(SmicIn(date_courante_in = smic_dot_date_courante,
|
result = smic(SmicIn(date_courante_in = smic_dot_date_courante,
|
||||||
residence_in = smic_dot_residence))
|
residence_in = smic_dot_residence))
|
||||||
@ -1316,10 +1318,12 @@ def allocations_familiales(allocations_familiales_in:AllocationsFamilialesIn):
|
|||||||
temp_bmaf_dot_date_courante = date_courante_3
|
temp_bmaf_dot_date_courante = date_courante_3
|
||||||
except EmptyError:
|
except EmptyError:
|
||||||
temp_bmaf_dot_date_courante = dead_value
|
temp_bmaf_dot_date_courante = dead_value
|
||||||
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/../base_mensuelle_allocations_familiales/bmaf.catala_fr",
|
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/prologue.catala_fr",
|
||||||
start_line=5, start_column=10,
|
start_line=159, start_column=14,
|
||||||
end_line=5, end_column=23,
|
end_line=159, end_column=32,
|
||||||
law_headings=["Montant de la base mensuelle des allocations familiales"]))
|
law_headings=["Allocations familiales",
|
||||||
|
"Champs d'applications",
|
||||||
|
"Prologue"]))
|
||||||
bmaf_dot_date_courante = temp_bmaf_dot_date_courante
|
bmaf_dot_date_courante = temp_bmaf_dot_date_courante
|
||||||
result_2 = base_mensuelle_allocations_familiales(BaseMensuelleAllocationsFamilialesIn(date_courante_in = bmaf_dot_date_courante))
|
result_2 = base_mensuelle_allocations_familiales(BaseMensuelleAllocationsFamilialesIn(date_courante_in = bmaf_dot_date_courante))
|
||||||
bmaf_dot_montant = result_2.montant_out
|
bmaf_dot_montant = result_2.montant_out
|
||||||
@ -1328,9 +1332,9 @@ def allocations_familiales(allocations_familiales_in:AllocationsFamilialesIn):
|
|||||||
except EmptyError:
|
except EmptyError:
|
||||||
temp_prestations_familiales_dot_date_courante = dead_value
|
temp_prestations_familiales_dot_date_courante = dead_value
|
||||||
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/prologue.catala_fr",
|
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/prologue.catala_fr",
|
||||||
start_line=62, start_column=10,
|
start_line=155, start_column=14,
|
||||||
end_line=62, end_column=23,
|
end_line=155, end_column=50,
|
||||||
law_headings=["Prestations familiales",
|
law_headings=["Allocations familiales",
|
||||||
"Champs d'applications",
|
"Champs d'applications",
|
||||||
"Prologue"]))
|
"Prologue"]))
|
||||||
prestations_familiales_dot_date_courante = temp_prestations_familiales_dot_date_courante
|
prestations_familiales_dot_date_courante = temp_prestations_familiales_dot_date_courante
|
||||||
@ -1340,9 +1344,9 @@ def allocations_familiales(allocations_familiales_in:AllocationsFamilialesIn):
|
|||||||
except EmptyError:
|
except EmptyError:
|
||||||
temp_prestations_familiales_dot_prestation_courante = dead_value
|
temp_prestations_familiales_dot_prestation_courante = dead_value
|
||||||
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/prologue.catala_fr",
|
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/prologue.catala_fr",
|
||||||
start_line=63, start_column=10,
|
start_line=153, start_column=14,
|
||||||
end_line=63, end_column=29,
|
end_line=153, end_column=56,
|
||||||
law_headings=["Prestations familiales",
|
law_headings=["Allocations familiales",
|
||||||
"Champs d'applications",
|
"Champs d'applications",
|
||||||
"Prologue"]))
|
"Prologue"]))
|
||||||
prestations_familiales_dot_prestation_courante = temp_prestations_familiales_dot_prestation_courante
|
prestations_familiales_dot_prestation_courante = temp_prestations_familiales_dot_prestation_courante
|
||||||
@ -1351,9 +1355,9 @@ def allocations_familiales(allocations_familiales_in:AllocationsFamilialesIn):
|
|||||||
except EmptyError:
|
except EmptyError:
|
||||||
temp_prestations_familiales_dot_residence = dead_value
|
temp_prestations_familiales_dot_residence = dead_value
|
||||||
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/prologue.catala_fr",
|
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/prologue.catala_fr",
|
||||||
start_line=64, start_column=10,
|
start_line=157, start_column=14,
|
||||||
end_line=64, end_column=19,
|
end_line=157, end_column=46,
|
||||||
law_headings=["Prestations familiales",
|
law_headings=["Allocations familiales",
|
||||||
"Champs d'applications",
|
"Champs d'applications",
|
||||||
"Prologue"]))
|
"Prologue"]))
|
||||||
prestations_familiales_dot_residence = temp_prestations_familiales_dot_residence
|
prestations_familiales_dot_residence = temp_prestations_familiales_dot_residence
|
||||||
@ -1368,12 +1372,11 @@ def allocations_familiales(allocations_familiales_in:AllocationsFamilialesIn):
|
|||||||
temp_enfant_le_plus_age_dot_enfants = enfants_a_charge
|
temp_enfant_le_plus_age_dot_enfants = enfants_a_charge
|
||||||
except EmptyError:
|
except EmptyError:
|
||||||
temp_enfant_le_plus_age_dot_enfants = dead_value
|
temp_enfant_le_plus_age_dot_enfants = dead_value
|
||||||
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/prologue.catala_fr",
|
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/epilogue.catala_fr",
|
||||||
start_line=79, start_column=10,
|
start_line=32, start_column=14,
|
||||||
end_line=79, end_column=17,
|
end_line=32, end_column=40,
|
||||||
law_headings=["Allocations familiales",
|
law_headings=["Règles diverses",
|
||||||
"Champs d'applications",
|
"Épilogue"]))
|
||||||
"Prologue"]))
|
|
||||||
enfant_le_plus_age_dot_enfants = temp_enfant_le_plus_age_dot_enfants
|
enfant_le_plus_age_dot_enfants = temp_enfant_le_plus_age_dot_enfants
|
||||||
result_4 = enfant_le_plus_age(EnfantLePlusAgeIn(enfants_in = enfant_le_plus_age_dot_enfants))
|
result_4 = enfant_le_plus_age(EnfantLePlusAgeIn(enfants_in = enfant_le_plus_age_dot_enfants))
|
||||||
enfant_le_plus_age_dot_le_plus_age = result_4.le_plus_age_out
|
enfant_le_plus_age_dot_le_plus_age = result_4.le_plus_age_out
|
||||||
@ -3009,12 +3012,11 @@ def interface_allocations_familiales(interface_allocations_familiales_in:Interfa
|
|||||||
temp_allocations_familiales_dot_personne_charge_effective_permanente_est_parent_1 = temp_allocations_familiales_dot_personne_charge_effective_permanente_est_parent
|
temp_allocations_familiales_dot_personne_charge_effective_permanente_est_parent_1 = temp_allocations_familiales_dot_personne_charge_effective_permanente_est_parent
|
||||||
except EmptyError:
|
except EmptyError:
|
||||||
temp_allocations_familiales_dot_personne_charge_effective_permanente_est_parent_1 = dead_value
|
temp_allocations_familiales_dot_personne_charge_effective_permanente_est_parent_1 = dead_value
|
||||||
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/prologue.catala_fr",
|
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/epilogue.catala_fr",
|
||||||
start_line=85, start_column=10,
|
start_line=91, start_column=5,
|
||||||
end_line=85, end_column=57,
|
end_line=91, end_column=75,
|
||||||
law_headings=["Allocations familiales",
|
law_headings=["Interface du programme",
|
||||||
"Champs d'applications",
|
"Épilogue"]))
|
||||||
"Prologue"]))
|
|
||||||
allocations_familiales_dot_personne_charge_effective_permanente_est_parent = temp_allocations_familiales_dot_personne_charge_effective_permanente_est_parent_1
|
allocations_familiales_dot_personne_charge_effective_permanente_est_parent = temp_allocations_familiales_dot_personne_charge_effective_permanente_est_parent_1
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
@ -3028,56 +3030,51 @@ def interface_allocations_familiales(interface_allocations_familiales_in:Interfa
|
|||||||
temp_allocations_familiales_dot_personne_charge_effective_permanente_remplit_titre__i_1 = temp_allocations_familiales_dot_personne_charge_effective_permanente_remplit_titre__i
|
temp_allocations_familiales_dot_personne_charge_effective_permanente_remplit_titre__i_1 = temp_allocations_familiales_dot_personne_charge_effective_permanente_remplit_titre__i
|
||||||
except EmptyError:
|
except EmptyError:
|
||||||
temp_allocations_familiales_dot_personne_charge_effective_permanente_remplit_titre__i_1 = dead_value
|
temp_allocations_familiales_dot_personne_charge_effective_permanente_remplit_titre__i_1 = dead_value
|
||||||
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/prologue.catala_fr",
|
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/epilogue.catala_fr",
|
||||||
start_line=86, start_column=10,
|
start_line=95, start_column=5,
|
||||||
end_line=86, end_column=62,
|
end_line=95, end_column=80,
|
||||||
law_headings=["Allocations familiales",
|
law_headings=["Interface du programme",
|
||||||
"Champs d'applications",
|
"Épilogue"]))
|
||||||
"Prologue"]))
|
|
||||||
allocations_familiales_dot_personne_charge_effective_permanente_remplit_titre__i = temp_allocations_familiales_dot_personne_charge_effective_permanente_remplit_titre__i_1
|
allocations_familiales_dot_personne_charge_effective_permanente_remplit_titre__i = temp_allocations_familiales_dot_personne_charge_effective_permanente_remplit_titre__i_1
|
||||||
try:
|
try:
|
||||||
temp_allocations_familiales_dot_ressources_menage = i_ressources_menage
|
temp_allocations_familiales_dot_ressources_menage = i_ressources_menage
|
||||||
except EmptyError:
|
except EmptyError:
|
||||||
temp_allocations_familiales_dot_ressources_menage = dead_value
|
temp_allocations_familiales_dot_ressources_menage = dead_value
|
||||||
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/prologue.catala_fr",
|
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/epilogue.catala_fr",
|
||||||
start_line=87, start_column=10,
|
start_line=87, start_column=14,
|
||||||
end_line=87, end_column=27,
|
end_line=87, end_column=54,
|
||||||
law_headings=["Allocations familiales",
|
law_headings=["Interface du programme",
|
||||||
"Champs d'applications",
|
"Épilogue"]))
|
||||||
"Prologue"]))
|
|
||||||
allocations_familiales_dot_ressources_menage = temp_allocations_familiales_dot_ressources_menage
|
allocations_familiales_dot_ressources_menage = temp_allocations_familiales_dot_ressources_menage
|
||||||
try:
|
try:
|
||||||
temp_allocations_familiales_dot_residence = i_residence
|
temp_allocations_familiales_dot_residence = i_residence
|
||||||
except EmptyError:
|
except EmptyError:
|
||||||
temp_allocations_familiales_dot_residence = dead_value
|
temp_allocations_familiales_dot_residence = dead_value
|
||||||
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/prologue.catala_fr",
|
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/epilogue.catala_fr",
|
||||||
start_line=88, start_column=10,
|
start_line=88, start_column=14,
|
||||||
end_line=88, end_column=19,
|
end_line=88, end_column=46,
|
||||||
law_headings=["Allocations familiales",
|
law_headings=["Interface du programme",
|
||||||
"Champs d'applications",
|
"Épilogue"]))
|
||||||
"Prologue"]))
|
|
||||||
allocations_familiales_dot_residence = temp_allocations_familiales_dot_residence
|
allocations_familiales_dot_residence = temp_allocations_familiales_dot_residence
|
||||||
try:
|
try:
|
||||||
temp_allocations_familiales_dot_date_courante = i_date_courante
|
temp_allocations_familiales_dot_date_courante = i_date_courante
|
||||||
except EmptyError:
|
except EmptyError:
|
||||||
temp_allocations_familiales_dot_date_courante = dead_value
|
temp_allocations_familiales_dot_date_courante = dead_value
|
||||||
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/prologue.catala_fr",
|
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/epilogue.catala_fr",
|
||||||
start_line=91, start_column=10,
|
start_line=85, start_column=14,
|
||||||
end_line=91, end_column=23,
|
end_line=85, end_column=50,
|
||||||
law_headings=["Allocations familiales",
|
law_headings=["Interface du programme",
|
||||||
"Champs d'applications",
|
"Épilogue"]))
|
||||||
"Prologue"]))
|
|
||||||
allocations_familiales_dot_date_courante = temp_allocations_familiales_dot_date_courante
|
allocations_familiales_dot_date_courante = temp_allocations_familiales_dot_date_courante
|
||||||
try:
|
try:
|
||||||
temp_allocations_familiales_dot_enfants_a_charge = enfants_a_charge_1
|
temp_allocations_familiales_dot_enfants_a_charge = enfants_a_charge_1
|
||||||
except EmptyError:
|
except EmptyError:
|
||||||
temp_allocations_familiales_dot_enfants_a_charge = dead_value
|
temp_allocations_familiales_dot_enfants_a_charge = dead_value
|
||||||
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/prologue.catala_fr",
|
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/epilogue.catala_fr",
|
||||||
start_line=94, start_column=10,
|
start_line=86, start_column=14,
|
||||||
end_line=94, end_column=26,
|
end_line=86, end_column=53,
|
||||||
law_headings=["Allocations familiales",
|
law_headings=["Interface du programme",
|
||||||
"Champs d'applications",
|
"Épilogue"]))
|
||||||
"Prologue"]))
|
|
||||||
allocations_familiales_dot_enfants_a_charge = temp_allocations_familiales_dot_enfants_a_charge
|
allocations_familiales_dot_enfants_a_charge = temp_allocations_familiales_dot_enfants_a_charge
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
@ -3091,12 +3088,11 @@ def interface_allocations_familiales(interface_allocations_familiales_in:Interfa
|
|||||||
temp_allocations_familiales_dot_avait_enfant_a_charge_avant_1er_janvier_2012_1 = temp_allocations_familiales_dot_avait_enfant_a_charge_avant_1er_janvier_2012
|
temp_allocations_familiales_dot_avait_enfant_a_charge_avant_1er_janvier_2012_1 = temp_allocations_familiales_dot_avait_enfant_a_charge_avant_1er_janvier_2012
|
||||||
except EmptyError:
|
except EmptyError:
|
||||||
temp_allocations_familiales_dot_avait_enfant_a_charge_avant_1er_janvier_2012_1 = dead_value
|
temp_allocations_familiales_dot_avait_enfant_a_charge_avant_1er_janvier_2012_1 = dead_value
|
||||||
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/prologue.catala_fr",
|
raise NoValueProvided(SourcePosition(filename="examples/allocations_familiales/epilogue.catala_fr",
|
||||||
start_line=115, start_column=10,
|
start_line=99, start_column=5,
|
||||||
end_line=115, end_column=54,
|
end_line=99, end_column=72,
|
||||||
law_headings=["Allocations familiales",
|
law_headings=["Interface du programme",
|
||||||
"Champs d'applications",
|
"Épilogue"]))
|
||||||
"Prologue"]))
|
|
||||||
allocations_familiales_dot_avait_enfant_a_charge_avant_1er_janvier_2012 = temp_allocations_familiales_dot_avait_enfant_a_charge_avant_1er_janvier_2012_1
|
allocations_familiales_dot_avait_enfant_a_charge_avant_1er_janvier_2012 = temp_allocations_familiales_dot_avait_enfant_a_charge_avant_1er_janvier_2012_1
|
||||||
result_5 = allocations_familiales(AllocationsFamilialesIn(personne_charge_effective_permanente_est_parent_in = allocations_familiales_dot_personne_charge_effective_permanente_est_parent,
|
result_5 = allocations_familiales(AllocationsFamilialesIn(personne_charge_effective_permanente_est_parent_in = allocations_familiales_dot_personne_charge_effective_permanente_est_parent,
|
||||||
personne_charge_effective_permanente_remplit_titre_I_in = allocations_familiales_dot_personne_charge_effective_permanente_remplit_titre__i,
|
personne_charge_effective_permanente_remplit_titre_I_in = allocations_familiales_dot_personne_charge_effective_permanente_remplit_titre__i,
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
|
from abc import ABC
|
||||||
from catala.runtime import *
|
from catala.runtime import *
|
||||||
from .allocations_familiales import Collectivite, Collectivite_Code, InterfaceAllocationsFamilialesIn, PriseEnCharge, interface_allocations_familiales, PriseEnCharge_Code, EnfantEntree, InterfaceAllocationsFamilialesIn
|
from .allocations_familiales import Collectivite, Collectivite_Code, InterfaceAllocationsFamilialesIn, PriseEnCharge, interface_allocations_familiales, PriseEnCharge_Code, EnfantEntree, InterfaceAllocationsFamilialesIn
|
||||||
|
from .aides_logement import AutrePersonneACharge, CategorieEquivalenceLoyerAllocationLogementFoyer, CategorieEquivalenceLoyerAllocationLogementFoyer_Code, ChangementLogementD8424, ChangementLogementD8424_Code, ConventionANHA, ConventionBailleurSocial, EnfantACharge, InfosChangementLogementD8424, Location, Logement, LogementFoyer, LoueOuSousLoueADesTiers, LoueOuSousLoueADesTiers_Code, Menage, ModeOccupation, ModeOccupation_Code, Nationalite, Nationalite_Code, NeufOuAncien, NeufOuAncien_Code, ParentOuAutre, ParentOuAutre_Code, Parente, Parente_Code, Patrimoine, PersonneACharge, PersonneSousLocation, PrestationRecue, PrestationRecue_Code, Pret, Proprietaire, SituationFamiliale, SituationFamiliale_Code, SituationGardeAlternee_Code, SituationObligationScolaire_Code, TitulairePret, TitulairePret_Code, TypeBailleur, TypeBailleur_Code, TypeLogementFoyer, TypeLogementFoyer_Code, TypePret, TypePret_Code, TypeTravauxLogementD83215, TypeTravauxLogementD83215_Code, TypeTravauxLogementR8425, TypeTravauxLogementR8425_Code, ZoneDHabitation, ZoneDHabitation_Code, calculette_aides_au_logement_garde_alternee, CalculetteAidesAuLogementGardeAlterneeIn, ressources_aides_personnelle_logement, Demandeur, PersonneACharge_Code, SituationObligationScolaire, SituationGardeAlternee
|
||||||
|
|
||||||
|
# Allocations familiales
|
||||||
|
|
||||||
|
|
||||||
class Enfant:
|
class Enfant:
|
||||||
@ -51,3 +55,310 @@ def allocations_familiales(
|
|||||||
i_avait_enfant_a_charge_avant_1er_janvier_2012_in=avait_enfant_a_charge_avant_1er_janvier_2012
|
i_avait_enfant_a_charge_avant_1er_janvier_2012_in=avait_enfant_a_charge_avant_1er_janvier_2012
|
||||||
))
|
))
|
||||||
return money_to_float(out.i_montant_verse_out)
|
return money_to_float(out.i_montant_verse_out)
|
||||||
|
|
||||||
|
# Aides au logement
|
||||||
|
|
||||||
|
|
||||||
|
class PersonneAChargeAPL(ABC):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class EnfantAPL(PersonneAChargeAPL):
|
||||||
|
def __init__(self, identifiant: int, beneficie_titre_personnel_aide_personnelle_logement: bool,
|
||||||
|
a_deja_ouvert_droit_aux_allocations_familiales: bool,
|
||||||
|
date_de_naissance: datetime.date,
|
||||||
|
remuneration_mensuelle: int,
|
||||||
|
obligation_scolaire: SituationObligationScolaire_Code,
|
||||||
|
situation_garde_alternee: SituationGardeAlternee_Code,
|
||||||
|
coefficient_garde_alternee: Optional[int]):
|
||||||
|
self.identifiant = identifiant
|
||||||
|
self.beneficie_titre_personnel_aide_personnelle_logement = beneficie_titre_personnel_aide_personnelle_logement
|
||||||
|
self.a_deja_ouvert_droit_aux_allocations_familiales = a_deja_ouvert_droit_aux_allocations_familiales
|
||||||
|
self.date_de_naissance = date_de_naissance,
|
||||||
|
self.remuneration_mensuelle = remuneration_mensuelle
|
||||||
|
self.obligation_scolaire = obligation_scolaire
|
||||||
|
self.situation_garde_alternee = situation_garde_alternee
|
||||||
|
self.coefficient_garde_alternee = coefficient_garde_alternee
|
||||||
|
|
||||||
|
|
||||||
|
class ParentAPL(PersonneAChargeAPL):
|
||||||
|
def __init__(self, date_naissance: datetime.date,
|
||||||
|
ressources: int,
|
||||||
|
ascendant_descendant_collateral_deuxieme_troisieme_degre: bool,
|
||||||
|
parente: Parente_Code,
|
||||||
|
incapacite_80_pourcent_ou_restriction_emploi: bool,
|
||||||
|
beneficiaire_l161_19_l351_8_l643_3_secu: bool,
|
||||||
|
titulaire_allocation_personne_agee: bool):
|
||||||
|
self.date_naissance = date_naissance
|
||||||
|
self.ressources = ressources
|
||||||
|
self.ascendant_descendant_collateral_deuxieme_troisieme_degre = ascendant_descendant_collateral_deuxieme_troisieme_degre
|
||||||
|
self.parente = parente
|
||||||
|
self.incapacite_80_pourcent_ou_restriction_emploi = incapacite_80_pourcent_ou_restriction_emploi
|
||||||
|
self.beneficiaire_l161_19_l351_8_l643_3_secu = beneficiaire_l161_19_l351_8_l643_3_secu
|
||||||
|
self.titulaire_allocation_personne_agee = titulaire_allocation_personne_agee
|
||||||
|
|
||||||
|
|
||||||
|
class InfosSpecifiques(ABC):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class InfosLocation(InfosSpecifiques):
|
||||||
|
def __init__(self,
|
||||||
|
loyer_principal: int,
|
||||||
|
beneficiaire_aide_adulte_ou_enfant_handicapes: bool,
|
||||||
|
logement_est_chambre: bool,
|
||||||
|
colocation: bool,
|
||||||
|
agees_ou_handicap_adultes_hebergees_onereux_particuliers: bool,
|
||||||
|
logement_meuble_d842_2: bool,
|
||||||
|
ancien_loyer_et_apl_relogement: Optional[Tuple[int, int]],
|
||||||
|
type_bailleur: TypeBailleur_Code,
|
||||||
|
bailleur_conventionne: Optional[bool],
|
||||||
|
reduction_loyer_solidarite: Optional[int]):
|
||||||
|
self.loyer_principal = loyer_principal
|
||||||
|
self.beneficiaire_aide_adulte_ou_enfant_handicapes = beneficiaire_aide_adulte_ou_enfant_handicapes
|
||||||
|
self.logement_est_chambre = logement_est_chambre
|
||||||
|
self.colocation = colocation
|
||||||
|
self.agees_ou_handicap_adultes_hebergees_onereux_particuliers = agees_ou_handicap_adultes_hebergees_onereux_particuliers
|
||||||
|
self.logement_meuble_d842_2 = logement_meuble_d842_2
|
||||||
|
self.ancien_loyer_et_apl_relogement = ancien_loyer_et_apl_relogement
|
||||||
|
self.type_bailleur = type_bailleur
|
||||||
|
self.bailleur_conventionne = bailleur_conventionne
|
||||||
|
self.reduction_loyer_solidarite = reduction_loyer_solidarite
|
||||||
|
|
||||||
|
|
||||||
|
class InfosLogementFoyer(InfosSpecifiques):
|
||||||
|
def __init__(self,
|
||||||
|
type: TypeLogementFoyer_Code,
|
||||||
|
remplit_conditions_r832_21: bool,
|
||||||
|
conventionne_livre_III_titre_V_chap_III: bool,
|
||||||
|
date_conventionnement: datetime.date,
|
||||||
|
construit_application_loi_1957_12_III: bool,
|
||||||
|
redevance: int,
|
||||||
|
categorie_equivalence_loyer_d842_16: CategorieEquivalenceLoyerAllocationLogementFoyer_Code):
|
||||||
|
self.type = type
|
||||||
|
self.remplit_conditions_r832_21 = remplit_conditions_r832_21
|
||||||
|
self.conventionne_livre_III_titre_V_chap_III = conventionne_livre_III_titre_V_chap_III
|
||||||
|
self.date_conventionnement = date_conventionnement
|
||||||
|
self.construit_application_loi_1957_12_III = construit_application_loi_1957_12_III
|
||||||
|
self.redevance = redevance
|
||||||
|
self.categorie_equivalence_loyer_d842_16 = categorie_equivalence_loyer_d842_16
|
||||||
|
|
||||||
|
|
||||||
|
class InfosAccessionPropriete(InfosSpecifiques):
|
||||||
|
def __init__(self,
|
||||||
|
logement_situe_commune_desequilibre_l831_2: bool,
|
||||||
|
mensualite_principale: int,
|
||||||
|
charges_mensuelles_pret: int,
|
||||||
|
date_entree_logement: datetime.date,
|
||||||
|
local_habite_premiere_fois_beneficiaire: bool,
|
||||||
|
copropriete: bool,
|
||||||
|
situation_r822_11_13_17: bool,
|
||||||
|
type_travaux_logement_d832_15: TypeTravauxLogementD83215_Code,
|
||||||
|
type_travaux_logement_r842_5: TypeTravauxLogementR8425_Code,
|
||||||
|
anciennete_logement: NeufOuAncien_Code,
|
||||||
|
ameliore_par_occupant: Optional[bool],
|
||||||
|
type_pret: TypePret_Code,
|
||||||
|
date_signature_pret: datetime.date,
|
||||||
|
titulaire_pret: TitulairePret_Code):
|
||||||
|
self.logement_situe_commune_desequilibre_l831_2 = logement_situe_commune_desequilibre_l831_2
|
||||||
|
self.mensualite_principale = mensualite_principale
|
||||||
|
self.charges_mensuelles_pret = charges_mensuelles_pret
|
||||||
|
self.date_entree_logement = date_entree_logement
|
||||||
|
self.local_habite_premiere_fois_beneficiaire = local_habite_premiere_fois_beneficiaire
|
||||||
|
self.copropriete = copropriete
|
||||||
|
self.situation_r822_11_13_17 = situation_r822_11_13_17
|
||||||
|
self.type_travaux_logement_d832_15 = type_travaux_logement_d832_15
|
||||||
|
self.type_travaux_logement_r842_5 = type_travaux_logement_r842_5
|
||||||
|
self.anciennete_logement = anciennete_logement
|
||||||
|
self.ameliore_par_occupant = ameliore_par_occupant
|
||||||
|
self.type_pret = type_pret
|
||||||
|
self.date_signature_pret = date_signature_pret
|
||||||
|
self.titulaire_pret = titulaire_pret
|
||||||
|
|
||||||
|
|
||||||
|
def aides_logement(
|
||||||
|
date_courante: datetime.date,
|
||||||
|
ressources_menage_prises_en_compte: int,
|
||||||
|
date_naissance_demandeur: datetime.date,
|
||||||
|
nationalite_demandeur: Nationalite_Code,
|
||||||
|
patrimoine_produisant_revenu: int,
|
||||||
|
patrimoine_ne_produisant_pas_revenu: int,
|
||||||
|
personne_hebergee_centre_soins: bool,
|
||||||
|
personne_rattache_foyer_fiscal_parent_ifi: bool,
|
||||||
|
nombre_autres_occupants_logement_hors_menage: int,
|
||||||
|
enfant_a_naitre_apres_quatrieme_mois_grossesse: bool,
|
||||||
|
situation_familiale: SituationFamiliale_Code,
|
||||||
|
date_mariage: Optional[datetime.date],
|
||||||
|
prestations_recues: List[PrestationRecue_Code],
|
||||||
|
residence_principale: bool,
|
||||||
|
logement_est_maison_de_retraite: bool,
|
||||||
|
logement_est_decent: bool,
|
||||||
|
surface_logement_m_carres: int,
|
||||||
|
zone: ZoneDHabitation_Code,
|
||||||
|
parts_logement_propriete_famille: Optional[int],
|
||||||
|
parts_logement_usufruits_famille: Optional[int],
|
||||||
|
date_naissance_et_conformite_sous_locataire_tiers: Optional[Tuple[datetime.date, bool]],
|
||||||
|
mode_occupation: ModeOccupation_Code,
|
||||||
|
infos_specifiques: InfosSpecifiques,
|
||||||
|
personnes_a_charge: List[PersonneAChargeAPL],
|
||||||
|
):
|
||||||
|
out = calculette_aides_au_logement_garde_alternee(CalculetteAidesAuLogementGardeAlterneeIn(
|
||||||
|
menage_in=Menage(
|
||||||
|
prestations_recues=[PrestationRecue(
|
||||||
|
code=presta, value=Unit()) for presta in prestations_recues],
|
||||||
|
logement=Logement(
|
||||||
|
residence_principale=residence_principale,
|
||||||
|
est_ehpad_ou_maison_autonomie_l313_12_asf=logement_est_maison_de_retraite,
|
||||||
|
mode_occupation=ModeOccupation(
|
||||||
|
code=mode_occupation,
|
||||||
|
value=(Location(
|
||||||
|
loyer_principal=money_of_units_int(
|
||||||
|
infos_specifiques.loyer_principal),
|
||||||
|
beneficiaire_aide_adulte_ou_enfant_handicapes=infos_specifiques.beneficiaire_aide_adulte_ou_enfant_handicapes,
|
||||||
|
logement_est_chambre=infos_specifiques.logement_est_chambre,
|
||||||
|
colocation=infos_specifiques.colocation,
|
||||||
|
agees_ou_handicap_adultes_hebergees_onereux_particuliers=infos_specifiques.agees_ou_handicap_adultes_hebergees_onereux_particuliers,
|
||||||
|
logement_meuble_d842_2=infos_specifiques.logement_meuble_d842_2,
|
||||||
|
changement_logement_d842_4=ChangementLogementD8424(
|
||||||
|
code=ChangementLogementD8424_Code.PasDeChangement if infos_specifiques.ancien_loyer_et_apl_relogement is None else
|
||||||
|
ChangementLogementD8424_Code.Changement,
|
||||||
|
value=Unit() if infos_specifiques.ancien_loyer_et_apl_relogement is None else
|
||||||
|
InfosChangementLogementD8424(ancien_loyer_principal=money_of_units_int(infos_specifiques.ancien_loyer_et_apl_relogement[0]),
|
||||||
|
ancienne_allocation_logement=money_of_units_int(infos_specifiques.ancien_loyer_et_apl_relogement[1]))
|
||||||
|
),
|
||||||
|
bailleur=TypeBailleur(
|
||||||
|
code=infos_specifiques.type_bailleur,
|
||||||
|
value=Unit() if infos_specifiques.type_bailleur == TypeBailleur_Code.BailleurPrive else (
|
||||||
|
ConventionBailleurSocial(
|
||||||
|
conventionne_livre_III_titre_V_chap_III=False if infos_specifiques.bailleur_conventionne is None else infos_specifiques.bailleur_conventionne,
|
||||||
|
reduction_loyer_solidarite_percue=money_of_units_int(0 if infos_specifiques.reduction_loyer_solidarite is None else infos_specifiques.reduction_loyer_solidarite))
|
||||||
|
) if infos_specifiques.type_bailleur == TypeBailleur_Code.BailleurSocial else (
|
||||||
|
ConventionANHA(
|
||||||
|
conventionne_livre_III_titre_II_chap_I_sec_3=False if infos_specifiques.bailleur_conventionne is None else infos_specifiques.bailleur_conventionne)
|
||||||
|
if infos_specifiques.type_bailleur == TypeBailleur_Code.BailleurPriveAvecConventionnementSocial else
|
||||||
|
None # type: ignore
|
||||||
|
))
|
||||||
|
) if isinstance(infos_specifiques, InfosLocation) else
|
||||||
|
(LogementFoyer(
|
||||||
|
type=TypeLogementFoyer(
|
||||||
|
code=infos_specifiques.type, value=Unit()),
|
||||||
|
remplit_conditions_r832_21=infos_specifiques.remplit_conditions_r832_21,
|
||||||
|
conventionne_livre_III_titre_V_chap_III=infos_specifiques.conventionne_livre_III_titre_V_chap_III,
|
||||||
|
date_conventionnement=date_of_datetime(
|
||||||
|
infos_specifiques.date_conventionnement),
|
||||||
|
construit_application_loi_1957_12_III=infos_specifiques.construit_application_loi_1957_12_III,
|
||||||
|
redevance=money_of_units_int(
|
||||||
|
infos_specifiques.redevance),
|
||||||
|
categorie_equivalence_loyer_d842_16=CategorieEquivalenceLoyerAllocationLogementFoyer(
|
||||||
|
code=infos_specifiques.categorie_equivalence_loyer_d842_16,
|
||||||
|
value=Unit()
|
||||||
|
)
|
||||||
|
) if isinstance(infos_specifiques, InfosLogementFoyer) else
|
||||||
|
(Proprietaire(
|
||||||
|
logement_situe_commune_desequilibre_l831_2=infos_specifiques.logement_situe_commune_desequilibre_l831_2,
|
||||||
|
mensualite_principale=money_of_units_int(
|
||||||
|
infos_specifiques.mensualite_principale),
|
||||||
|
charges_mensuelles_pret=money_of_units_int(
|
||||||
|
infos_specifiques.charges_mensuelles_pret),
|
||||||
|
date_entree_logement=date_of_datetime(
|
||||||
|
infos_specifiques.date_entree_logement),
|
||||||
|
local_habite_premiere_fois_beneficiaire=infos_specifiques.local_habite_premiere_fois_beneficiaire,
|
||||||
|
copropriete=infos_specifiques.copropriete,
|
||||||
|
situation_r822_11_13_17=infos_specifiques.situation_r822_11_13_17,
|
||||||
|
type_travaux_logement_d832_15=TypeTravauxLogementD83215(
|
||||||
|
code=infos_specifiques.type_travaux_logement_d832_15, value=Unit()),
|
||||||
|
type_travaux_logement_r842_5=TypeTravauxLogementR8425(
|
||||||
|
code=infos_specifiques.type_travaux_logement_r842_5,
|
||||||
|
value=Unit()
|
||||||
|
),
|
||||||
|
anciennete_logement=NeufOuAncien(code=infos_specifiques.anciennete_logement,
|
||||||
|
value=Unit() if infos_specifiques.ameliore_par_occupant is None else infos_specifiques.ameliore_par_occupant),
|
||||||
|
pret=Pret(
|
||||||
|
type_pret=TypePret(
|
||||||
|
code=infos_specifiques.type_pret, value=Unit()),
|
||||||
|
date_signature=date_of_datetime(
|
||||||
|
infos_specifiques.date_signature_pret),
|
||||||
|
titulaire_pret=TitulairePret(
|
||||||
|
code=infos_specifiques.titulaire_pret, value=Unit())
|
||||||
|
)
|
||||||
|
) if isinstance(infos_specifiques, InfosAccessionPropriete)
|
||||||
|
else None # type: ignore
|
||||||
|
)))
|
||||||
|
),
|
||||||
|
proprietaire=ParentOuAutre(
|
||||||
|
code=ParentOuAutre_Code.Autre if parts_logement_propriete_famille is None else ParentOuAutre_Code.DemandeurOuConjointOuParentOuViaPartsSocietes,
|
||||||
|
value=Unit() if parts_logement_propriete_famille is None else parts_logement_propriete_famille),
|
||||||
|
usufruit=ParentOuAutre(
|
||||||
|
code=ParentOuAutre_Code.Autre if parts_logement_usufruits_famille is None else ParentOuAutre_Code.DemandeurOuConjointOuParentOuViaPartsSocietes,
|
||||||
|
value=Unit() if parts_logement_usufruits_famille is None else parts_logement_usufruits_famille),
|
||||||
|
loue_ou_sous_loue_a_des_tiers=LoueOuSousLoueADesTiers(
|
||||||
|
code=LoueOuSousLoueADesTiers_Code.Non if date_naissance_et_conformite_sous_locataire_tiers is None else LoueOuSousLoueADesTiers_Code.Oui,
|
||||||
|
value=Unit() if date_naissance_et_conformite_sous_locataire_tiers is None else PersonneSousLocation(
|
||||||
|
date_naissance_personne_sous_location=date_of_datetime(date_naissance_et_conformite_sous_locataire_tiers[
|
||||||
|
0]),
|
||||||
|
conforme_article_l442_1=date_naissance_et_conformite_sous_locataire_tiers[
|
||||||
|
1]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
logement_decent_l89_462=logement_est_decent,
|
||||||
|
surface_m_carres=integer_of_int(surface_logement_m_carres),
|
||||||
|
zone=ZoneDHabitation(code=zone, value=Unit())
|
||||||
|
),
|
||||||
|
personnes_a_charge=[
|
||||||
|
(PersonneACharge(code=PersonneACharge_Code.EnfantACharge,
|
||||||
|
value=EnfantACharge(
|
||||||
|
identifiant=integer_of_int(
|
||||||
|
personne_a_charge.identifiant),
|
||||||
|
beneficie_titre_personnel_aide_personnelle_logement=personne_a_charge.beneficie_titre_personnel_aide_personnelle_logement,
|
||||||
|
a_deja_ouvert_droit_aux_allocations_familiales=personne_a_charge.a_deja_ouvert_droit_aux_allocations_familiales,
|
||||||
|
date_de_naissance=date_of_datetime(
|
||||||
|
personne_a_charge.date_de_naissance[0]),
|
||||||
|
remuneration_mensuelle=money_of_units_int(
|
||||||
|
personne_a_charge.remuneration_mensuelle),
|
||||||
|
obligation_scolaire=SituationObligationScolaire(
|
||||||
|
code=personne_a_charge.obligation_scolaire, value=Unit()),
|
||||||
|
situation_garde_alternee=SituationGardeAlternee(code=personne_a_charge.situation_garde_alternee,
|
||||||
|
value=Unit() if personne_a_charge.coefficient_garde_alternee is None else personne_a_charge.coefficient_garde_alternee)
|
||||||
|
))
|
||||||
|
if isinstance(personne_a_charge, EnfantAPL)
|
||||||
|
else (PersonneACharge(
|
||||||
|
code=PersonneACharge_Code.AutrePersonneACharge,
|
||||||
|
value=AutrePersonneACharge(
|
||||||
|
date_naissance=date_of_datetime(
|
||||||
|
personne_a_charge.date_naissance),
|
||||||
|
ressources=money_of_units_int(
|
||||||
|
personne_a_charge.ressources),
|
||||||
|
ascendant_descendant_collateral_deuxieme_troisieme_degre=personne_a_charge.ascendant_descendant_collateral_deuxieme_troisieme_degre,
|
||||||
|
incapacite_80_pourcent_ou_restriction_emploi=personne_a_charge.incapacite_80_pourcent_ou_restriction_emploi,
|
||||||
|
beneficiaire_l161_19_l351_8_l643_3_secu=personne_a_charge.beneficiaire_l161_19_l351_8_l643_3_secu,
|
||||||
|
titulaire_allocation_personne_agee=personne_a_charge.titulaire_allocation_personne_agee,
|
||||||
|
parente=Parente(
|
||||||
|
code=personne_a_charge.parente, value=Unit())
|
||||||
|
)) if isinstance(personne_a_charge, ParentAPL)
|
||||||
|
else None # type: ignore
|
||||||
|
)) for personne_a_charge in personnes_a_charge],
|
||||||
|
nombre_autres_occupants_logement=integer_of_int(
|
||||||
|
nombre_autres_occupants_logement_hors_menage),
|
||||||
|
situation_familiale=SituationFamiliale(
|
||||||
|
code=situation_familiale,
|
||||||
|
value=Unit() if date_mariage is None else date_of_datetime(date_mariage)
|
||||||
|
),
|
||||||
|
condition_rattache_foyer_fiscal_parent_ifi=personne_rattache_foyer_fiscal_parent_ifi,
|
||||||
|
enfant_a_naitre_apres_quatrieme_mois_grossesse=enfant_a_naitre_apres_quatrieme_mois_grossesse
|
||||||
|
),
|
||||||
|
demandeur_in=Demandeur(
|
||||||
|
date_naissance=date_of_datetime(date_naissance_demandeur),
|
||||||
|
nationalite=Nationalite(code=nationalite_demandeur, value=Unit()),
|
||||||
|
patrimoine=Patrimoine(
|
||||||
|
produisant_revenu_periode_r822_3_3_r822_4=money_of_units_int(
|
||||||
|
patrimoine_produisant_revenu),
|
||||||
|
ne_produisant_pas_revenu_periode_r822_3_3_r822_4=money_of_units_int(
|
||||||
|
patrimoine_ne_produisant_pas_revenu)
|
||||||
|
),
|
||||||
|
personne_hebergee_centre_soin_l_L162_22_3_securite_sociale=personne_hebergee_centre_soins,
|
||||||
|
),
|
||||||
|
date_courante_in=date_of_datetime(date_courante),
|
||||||
|
ressources_menage_prises_en_compte_in=money_of_units_int(
|
||||||
|
ressources_menage_prises_en_compte),
|
||||||
|
))
|
||||||
|
return money_to_float(out.aide_finale_out)
|
||||||
|
@ -1,681 +0,0 @@
|
|||||||
"""
|
|
||||||
.. module:: catala_runtime
|
|
||||||
:platform: Unix, Windows
|
|
||||||
:synopsis: The Python bindings for the functions used in the generated Catala code
|
|
||||||
:noindex:
|
|
||||||
|
|
||||||
.. moduleauthor:: Denis Merigoux <denis.merigoux@inria.fr>
|
|
||||||
"""
|
|
||||||
|
|
||||||
# This file should be in sync with compiler/runtime.{ml, mli} !
|
|
||||||
|
|
||||||
from this import d
|
|
||||||
from gmpy2 import log2, mpz, mpq, mpfr, t_divmod, f_div, sign # type: ignore
|
|
||||||
import datetime
|
|
||||||
import calendar
|
|
||||||
import dateutil.relativedelta
|
|
||||||
from typing import NewType, List, Callable, Tuple, Optional, TypeVar, Iterable, Union, Any
|
|
||||||
from functools import reduce
|
|
||||||
from enum import Enum
|
|
||||||
import copy
|
|
||||||
|
|
||||||
Alpha = TypeVar('Alpha')
|
|
||||||
Beta = TypeVar('Beta')
|
|
||||||
|
|
||||||
# ============
|
|
||||||
# Type classes
|
|
||||||
# ============
|
|
||||||
|
|
||||||
|
|
||||||
class Integer:
|
|
||||||
def __init__(self, value: Union[str, int]) -> None:
|
|
||||||
self.value = mpz(value)
|
|
||||||
|
|
||||||
def __add__(self, other: 'Integer') -> 'Integer':
|
|
||||||
return Integer(self.value + other.value)
|
|
||||||
|
|
||||||
def __sub__(self, other: 'Integer') -> 'Integer':
|
|
||||||
return Integer(self.value - other.value)
|
|
||||||
|
|
||||||
def __mul__(self, other: 'Integer') -> 'Integer':
|
|
||||||
return Integer(self.value * other.value)
|
|
||||||
|
|
||||||
def __truediv__(self, other: 'Integer') -> 'Integer':
|
|
||||||
return Integer(self.value // other.value)
|
|
||||||
|
|
||||||
def __neg__(self: 'Integer') -> 'Integer':
|
|
||||||
return Integer(- self.value)
|
|
||||||
|
|
||||||
def __lt__(self, other: 'Integer') -> bool:
|
|
||||||
return self.value < other.value
|
|
||||||
|
|
||||||
def __le__(self, other: 'Integer') -> bool:
|
|
||||||
return self.value <= other.value
|
|
||||||
|
|
||||||
def __gt__(self, other: 'Integer') -> bool:
|
|
||||||
return self.value > other.value
|
|
||||||
|
|
||||||
def __ge__(self, other: 'Integer') -> bool:
|
|
||||||
return self.value >= other.value
|
|
||||||
|
|
||||||
def __ne__(self, other: object) -> bool:
|
|
||||||
if isinstance(other, Integer):
|
|
||||||
return self.value != other.value
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def __eq__(self, other: object) -> bool:
|
|
||||||
if isinstance(other, Integer):
|
|
||||||
return self.value == other.value
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return self.value.__str__()
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"Integer({self.value.__repr__()})"
|
|
||||||
|
|
||||||
|
|
||||||
class Decimal:
|
|
||||||
def __init__(self, value: Union[str, int, float]) -> None:
|
|
||||||
self.value = mpq(value)
|
|
||||||
|
|
||||||
def __add__(self, other: 'Decimal') -> 'Decimal':
|
|
||||||
return Decimal(self.value + other.value)
|
|
||||||
|
|
||||||
def __sub__(self, other: 'Decimal') -> 'Decimal':
|
|
||||||
return Decimal(self.value - other.value)
|
|
||||||
|
|
||||||
def __mul__(self, other: 'Decimal') -> 'Decimal':
|
|
||||||
return Decimal(self.value * other.value)
|
|
||||||
|
|
||||||
def __truediv__(self, other: 'Decimal') -> 'Decimal':
|
|
||||||
return Decimal(self.value / other.value)
|
|
||||||
|
|
||||||
def __neg__(self: 'Decimal') -> 'Decimal':
|
|
||||||
return Decimal(- self.value)
|
|
||||||
|
|
||||||
def __lt__(self, other: 'Decimal') -> bool:
|
|
||||||
return self.value < other.value
|
|
||||||
|
|
||||||
def __le__(self, other: 'Decimal') -> bool:
|
|
||||||
return self.value <= other.value
|
|
||||||
|
|
||||||
def __gt__(self, other: 'Decimal') -> bool:
|
|
||||||
return self.value > other.value
|
|
||||||
|
|
||||||
def __ge__(self, other: 'Decimal') -> bool:
|
|
||||||
return self.value >= other.value
|
|
||||||
|
|
||||||
def __ne__(self, other: object) -> bool:
|
|
||||||
if isinstance(other, Decimal):
|
|
||||||
return self.value != other.value
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def __eq__(self, other: object) -> bool:
|
|
||||||
if isinstance(other, Decimal):
|
|
||||||
return self.value == other.value
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return "{}".format(mpfr(self.value))
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"Decimal({self.value.__repr__()})"
|
|
||||||
|
|
||||||
|
|
||||||
class Money:
|
|
||||||
def __init__(self, value: Integer) -> None:
|
|
||||||
self.value = value
|
|
||||||
|
|
||||||
def __add__(self, other: 'Money') -> 'Money':
|
|
||||||
return Money(self.value + other.value)
|
|
||||||
|
|
||||||
def __sub__(self, other: 'Money') -> 'Money':
|
|
||||||
return Money(self.value - other.value)
|
|
||||||
|
|
||||||
def __mul__(self, other: Decimal) -> 'Money':
|
|
||||||
cents = self.value.value
|
|
||||||
coeff = other.value
|
|
||||||
# TODO: change, does not work with negative values. Must divide the
|
|
||||||
# absolute values and then multiply by the resulting sign.
|
|
||||||
rat_result = self.value.value * other.value
|
|
||||||
out = Money(Integer(rat_result))
|
|
||||||
res, remainder = t_divmod(rat_result.numerator, rat_result.denominator)
|
|
||||||
if 2 * remainder >= rat_result.denominator:
|
|
||||||
return Money(Integer(res + 1))
|
|
||||||
else:
|
|
||||||
return Money(Integer(res))
|
|
||||||
|
|
||||||
def __truediv__(self, other: 'Money') -> Decimal:
|
|
||||||
return Decimal(mpq(self.value.value / other.value.value))
|
|
||||||
|
|
||||||
def __neg__(self: 'Money') -> 'Money':
|
|
||||||
return Money(- self.value)
|
|
||||||
|
|
||||||
def __lt__(self, other: 'Money') -> bool:
|
|
||||||
return self.value < other.value
|
|
||||||
|
|
||||||
def __le__(self, other: 'Money') -> bool:
|
|
||||||
return self.value <= other.value
|
|
||||||
|
|
||||||
def __gt__(self, other: 'Money') -> bool:
|
|
||||||
return self.value > other.value
|
|
||||||
|
|
||||||
def __ge__(self, other: 'Money') -> bool:
|
|
||||||
return self.value >= other.value
|
|
||||||
|
|
||||||
def __ne__(self, other: object) -> bool:
|
|
||||||
if isinstance(other, Money):
|
|
||||||
return self.value != other.value
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def __eq__(self, other: object) -> bool:
|
|
||||||
if isinstance(other, Money):
|
|
||||||
return self.value == other.value
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return "${:.2}".format(self.value.value / 100)
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"Money({self.value.__repr__()})"
|
|
||||||
|
|
||||||
|
|
||||||
class Date:
|
|
||||||
def __init__(self, value: datetime.date) -> None:
|
|
||||||
self.value = value
|
|
||||||
|
|
||||||
def __add__(self, other: 'Duration') -> 'Date':
|
|
||||||
return Date(self.value + other.value)
|
|
||||||
|
|
||||||
def __sub__(self, other: 'Date') -> 'Duration':
|
|
||||||
return Duration(dateutil.relativedelta.relativedelta(self.value, other.value))
|
|
||||||
|
|
||||||
def __lt__(self, other: 'Date') -> bool:
|
|
||||||
return self.value < other.value
|
|
||||||
|
|
||||||
def __le__(self, other: 'Date') -> bool:
|
|
||||||
return self.value <= other.value
|
|
||||||
|
|
||||||
def __gt__(self, other: 'Date') -> bool:
|
|
||||||
return self.value > other.value
|
|
||||||
|
|
||||||
def __ge__(self, other: 'Date') -> bool:
|
|
||||||
return self.value >= other.value
|
|
||||||
|
|
||||||
def __ne__(self, other: object) -> bool:
|
|
||||||
if isinstance(other, Date):
|
|
||||||
return self.value != other.value
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def __eq__(self, other: object) -> bool:
|
|
||||||
if isinstance(other, Date):
|
|
||||||
return self.value == other.value
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return self.value.__str__()
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"Date({self.value.__repr__()})"
|
|
||||||
|
|
||||||
|
|
||||||
class Duration:
|
|
||||||
def __init__(self, value: dateutil.relativedelta.relativedelta) -> None:
|
|
||||||
self.value = value
|
|
||||||
|
|
||||||
def __add__(self, other: 'Duration') -> 'Duration':
|
|
||||||
return Duration(self.value + other.value)
|
|
||||||
|
|
||||||
def __sub__(self, other: 'Duration') -> 'Duration':
|
|
||||||
return Duration(self.value - other.value)
|
|
||||||
|
|
||||||
def __neg__(self: 'Duration') -> 'Duration':
|
|
||||||
return Duration(- self.value)
|
|
||||||
|
|
||||||
def __truediv__(self, other: 'Duration') -> Decimal:
|
|
||||||
x = self.value.normalized()
|
|
||||||
y = other.value.normalized()
|
|
||||||
if (x.years != 0 or y.years != 0 or x.months != 0 or y.months != 0):
|
|
||||||
raise Exception("Can only divide durations expressed in days")
|
|
||||||
else:
|
|
||||||
return Decimal(x.days / y.days)
|
|
||||||
|
|
||||||
def __mul__(self: 'Duration', rhs: Integer) -> 'Duration':
|
|
||||||
return Duration(
|
|
||||||
dateutil.relativedelta.relativedelta(years=self.value.years * rhs.value,
|
|
||||||
months=self.value.months * rhs.value,
|
|
||||||
days=self.value.days * rhs.value))
|
|
||||||
|
|
||||||
def __lt__(self, other: 'Duration') -> bool:
|
|
||||||
x = self.value.normalized()
|
|
||||||
y = other.value.normalized()
|
|
||||||
if (x.years != 0 or y.years != 0 or x.months != 0 or y.months != 0):
|
|
||||||
raise Exception("Can only compare durations expressed in days")
|
|
||||||
else:
|
|
||||||
return x.days < y.days
|
|
||||||
|
|
||||||
def __le__(self, other: 'Duration') -> bool:
|
|
||||||
x = self.value.normalized()
|
|
||||||
y = other.value.normalized()
|
|
||||||
if (x.years != 0 or y.years != 0 or x.months != 0 or y.months != 0):
|
|
||||||
raise Exception("Can only compare durations expressed in days")
|
|
||||||
else:
|
|
||||||
return x.days <= y.days
|
|
||||||
|
|
||||||
def __gt__(self, other: 'Duration') -> bool:
|
|
||||||
x = self.value.normalized()
|
|
||||||
y = other.value.normalized()
|
|
||||||
if (x.years != 0 or y.years != 0 or x.months != 0 or y.months != 0):
|
|
||||||
raise Exception("Can only compare durations expressed in days")
|
|
||||||
else:
|
|
||||||
return x.days > y.days
|
|
||||||
|
|
||||||
def __ge__(self, other: 'Duration') -> bool:
|
|
||||||
x = self.value.normalized()
|
|
||||||
y = other.value.normalized()
|
|
||||||
if (x.years != 0 or y.years != 0 or x.months != 0 or y.months != 0):
|
|
||||||
raise Exception("Can only compare durations expressed in days")
|
|
||||||
else:
|
|
||||||
return x.days >= y.days
|
|
||||||
|
|
||||||
def __ne__(self, other: object) -> bool:
|
|
||||||
if isinstance(other, Duration):
|
|
||||||
return self.value != other.value
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def __eq__(self, other: object) -> bool:
|
|
||||||
if isinstance(other, Duration):
|
|
||||||
return self.value == other.value
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return self.value.__str__()
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"Duration({self.value.__repr__()})"
|
|
||||||
|
|
||||||
|
|
||||||
class Unit:
|
|
||||||
def __init__(self) -> None:
|
|
||||||
...
|
|
||||||
|
|
||||||
def __eq__(self, other: object) -> bool:
|
|
||||||
if isinstance(other, Unit):
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def __ne__(self, other: object) -> bool:
|
|
||||||
if isinstance(other, Unit):
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return "()"
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return "Unit()"
|
|
||||||
|
|
||||||
|
|
||||||
class SourcePosition:
|
|
||||||
def __init__(self,
|
|
||||||
filename: str,
|
|
||||||
start_line: int,
|
|
||||||
start_column: int,
|
|
||||||
end_line: int,
|
|
||||||
end_column: int,
|
|
||||||
law_headings: List[str]) -> None:
|
|
||||||
self.filename = filename
|
|
||||||
self.start_line = start_line
|
|
||||||
self.start_column = start_column
|
|
||||||
self.end_line = end_line
|
|
||||||
self.end_column = end_column
|
|
||||||
self.law_headings = law_headings
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return "in file {}, from {}:{} to {}:{}".format(
|
|
||||||
self.filename, self.start_line, self.start_column, self.end_line, self.end_column)
|
|
||||||
|
|
||||||
# ==========
|
|
||||||
# Exceptions
|
|
||||||
# ==========
|
|
||||||
|
|
||||||
|
|
||||||
class EmptyError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class AssertionFailed(Exception):
|
|
||||||
def __init__(self, source_position: SourcePosition) -> None:
|
|
||||||
self.source_position = SourcePosition
|
|
||||||
|
|
||||||
|
|
||||||
class ConflictError(Exception):
|
|
||||||
def __init__(self, source_position: SourcePosition) -> None:
|
|
||||||
self.source_position = SourcePosition
|
|
||||||
|
|
||||||
|
|
||||||
class NoValueProvided(Exception):
|
|
||||||
def __init__(self, source_position: SourcePosition) -> None:
|
|
||||||
self.source_position = SourcePosition
|
|
||||||
|
|
||||||
|
|
||||||
class AssertionFailure(Exception):
|
|
||||||
def __init__(self, source_position: SourcePosition) -> None:
|
|
||||||
self.source_position = SourcePosition
|
|
||||||
|
|
||||||
|
|
||||||
# ============================
|
|
||||||
# Constructors and conversions
|
|
||||||
# ============================
|
|
||||||
|
|
||||||
# -----
|
|
||||||
# Money
|
|
||||||
# -----
|
|
||||||
|
|
||||||
|
|
||||||
def money_of_cents_string(v: str) -> Money:
|
|
||||||
return Money(Integer(v))
|
|
||||||
|
|
||||||
|
|
||||||
def money_of_units_int(v: int) -> Money:
|
|
||||||
return Money(Integer(v) * Integer(100))
|
|
||||||
|
|
||||||
|
|
||||||
def money_of_cents_integer(v: Integer) -> Money:
|
|
||||||
return Money(v)
|
|
||||||
|
|
||||||
|
|
||||||
def money_to_float(m: Money) -> float:
|
|
||||||
return float(mpfr(mpq(m.value.value, 100)))
|
|
||||||
|
|
||||||
|
|
||||||
def money_to_string(m: Money) -> str:
|
|
||||||
return str(money_to_float(m))
|
|
||||||
|
|
||||||
|
|
||||||
def money_to_cents(m: Money) -> Integer:
|
|
||||||
return m.value
|
|
||||||
|
|
||||||
|
|
||||||
def money_round(m: Money) -> Money:
|
|
||||||
res, remainder = t_divmod(m, 100)
|
|
||||||
if remainder < 50:
|
|
||||||
return res * 100
|
|
||||||
else:
|
|
||||||
return (res + sign(res)) * 100
|
|
||||||
|
|
||||||
|
|
||||||
def money_of_decimal(m: Decimal) -> Money:
|
|
||||||
"""
|
|
||||||
Warning: rounds to nearest cent.
|
|
||||||
"""
|
|
||||||
return Money(mpz(m.value))
|
|
||||||
|
|
||||||
# --------
|
|
||||||
# Decimals
|
|
||||||
# --------
|
|
||||||
|
|
||||||
|
|
||||||
def decimal_of_string(d: str) -> Decimal:
|
|
||||||
return Decimal(d)
|
|
||||||
|
|
||||||
|
|
||||||
def decimal_to_float(d: Decimal) -> float:
|
|
||||||
return float(mpfr(d.value))
|
|
||||||
|
|
||||||
|
|
||||||
def decimal_of_float(d: float) -> Decimal:
|
|
||||||
return Decimal(d)
|
|
||||||
|
|
||||||
|
|
||||||
def decimal_of_integer(d: Integer) -> Decimal:
|
|
||||||
return Decimal(d.value)
|
|
||||||
|
|
||||||
|
|
||||||
def decimal_to_string(precision: int, i: Decimal) -> str:
|
|
||||||
return "{1:.{0}}".format(precision, mpfr(i.value, precision * 10 // 2))
|
|
||||||
|
|
||||||
|
|
||||||
def decimal_round(q: Decimal) -> Decimal:
|
|
||||||
# Implements the workaround by
|
|
||||||
# https://gmplib.org/list-archives/gmp-discuss/2009-May/003767.html *)
|
|
||||||
return f_div(2*q.numerator + q.denominator, 2*q.denominator) # type:ignore
|
|
||||||
|
|
||||||
|
|
||||||
def decimal_of_money(m: Money) -> Decimal:
|
|
||||||
return Decimal(f_div(mpq(m.value), mpq(100)))
|
|
||||||
|
|
||||||
# --------
|
|
||||||
# Integers
|
|
||||||
# --------
|
|
||||||
|
|
||||||
|
|
||||||
def integer_of_string(s: str) -> Integer:
|
|
||||||
return Integer(s)
|
|
||||||
|
|
||||||
|
|
||||||
def integer_to_string(d: Integer) -> str:
|
|
||||||
return str(d.value)
|
|
||||||
|
|
||||||
|
|
||||||
def integer_of_int(d: int) -> Integer:
|
|
||||||
return Integer(d)
|
|
||||||
|
|
||||||
|
|
||||||
def integer_to_int(d: Integer) -> int:
|
|
||||||
return int(d.value)
|
|
||||||
|
|
||||||
|
|
||||||
def integer_exponentiation(i: Integer, e: int) -> Integer:
|
|
||||||
return i ** e # type: ignore
|
|
||||||
|
|
||||||
|
|
||||||
def integer_log2(i: Integer) -> int:
|
|
||||||
return int(log2(i.value))
|
|
||||||
|
|
||||||
# -----
|
|
||||||
# Dates
|
|
||||||
# -----
|
|
||||||
|
|
||||||
|
|
||||||
def day_of_month_of_date(d: Date) -> Integer:
|
|
||||||
return integer_of_int(d.value.day)
|
|
||||||
|
|
||||||
|
|
||||||
def month_number_of_date(d: Date) -> Integer:
|
|
||||||
return integer_of_int(d.value.month)
|
|
||||||
|
|
||||||
|
|
||||||
def year_of_date(d: Date) -> Integer:
|
|
||||||
return integer_of_int(d.value.year)
|
|
||||||
|
|
||||||
|
|
||||||
def date_to_string(d: Date) -> str:
|
|
||||||
return "{}".format(d.value)
|
|
||||||
|
|
||||||
|
|
||||||
def date_of_numbers(year: int, month: int, day: int) -> Date:
|
|
||||||
# The datetime.date does not take year=0 as an entry, we trick it into
|
|
||||||
# 1 in that case because year=0 cases don't care about the actual year
|
|
||||||
return Date(datetime.date(year if year != 0 else 1, month, day))
|
|
||||||
|
|
||||||
|
|
||||||
def date_of_datetime(d: datetime.date) -> Date:
|
|
||||||
return Date(d)
|
|
||||||
|
|
||||||
|
|
||||||
def first_day_of_month(d: Date) -> Date:
|
|
||||||
return Date(datetime.date(d.value.year, d.value.month, 1))
|
|
||||||
|
|
||||||
|
|
||||||
def last_day_of_month(d: Date) -> Date:
|
|
||||||
return Date(datetime.date(d.value.year, d.value.month, calendar.monthrange(d.value.year, d.value.month)[1]))
|
|
||||||
|
|
||||||
# ---------
|
|
||||||
# Durations
|
|
||||||
# ---------
|
|
||||||
|
|
||||||
|
|
||||||
def duration_of_numbers(years: int, months: int, days: int) -> Duration:
|
|
||||||
return Duration(dateutil.relativedelta.relativedelta(years=years, months=months, days=days))
|
|
||||||
|
|
||||||
|
|
||||||
def duration_to_years_months_days(d: Duration) -> Tuple[int, int, int]:
|
|
||||||
return (d.value.years, d.value.months, d.value.days) # type: ignore
|
|
||||||
|
|
||||||
|
|
||||||
def duration_to_string(s: Duration) -> str:
|
|
||||||
return "{}".format(s.value)
|
|
||||||
|
|
||||||
# -----
|
|
||||||
# Lists
|
|
||||||
# -----
|
|
||||||
|
|
||||||
|
|
||||||
def list_fold_left(f: Callable[[Alpha, Beta], Alpha], init: Alpha, l: List[Beta]) -> Alpha:
|
|
||||||
return reduce(f, l, init)
|
|
||||||
|
|
||||||
|
|
||||||
def list_filter(f: Callable[[Alpha], bool], l: List[Alpha]) -> List[Alpha]:
|
|
||||||
return [i for i in l if f(i)]
|
|
||||||
|
|
||||||
|
|
||||||
def list_map(f: Callable[[Alpha], Beta], l: List[Alpha]) -> List[Beta]:
|
|
||||||
return [f(i) for i in l]
|
|
||||||
|
|
||||||
|
|
||||||
def list_length(l: List[Alpha]) -> Integer:
|
|
||||||
return Integer(len(l))
|
|
||||||
|
|
||||||
# ========
|
|
||||||
# Defaults
|
|
||||||
# ========
|
|
||||||
|
|
||||||
|
|
||||||
def handle_default(
|
|
||||||
pos: SourcePosition,
|
|
||||||
exceptions: List[Callable[[Unit], Alpha]],
|
|
||||||
just: Callable[[Unit], Alpha],
|
|
||||||
cons: Callable[[Unit], Alpha]
|
|
||||||
) -> Alpha:
|
|
||||||
acc: Optional[Alpha] = None
|
|
||||||
for exception in exceptions:
|
|
||||||
new_val: Optional[Alpha]
|
|
||||||
try:
|
|
||||||
new_val = exception(Unit())
|
|
||||||
except EmptyError:
|
|
||||||
new_val = None
|
|
||||||
if acc is None:
|
|
||||||
acc = new_val
|
|
||||||
elif not (acc is None) and new_val is None:
|
|
||||||
pass # acc stays the same
|
|
||||||
elif not (acc is None) and not (new_val is None):
|
|
||||||
raise ConflictError(pos)
|
|
||||||
if acc is None:
|
|
||||||
if just(Unit()):
|
|
||||||
return cons(Unit())
|
|
||||||
else:
|
|
||||||
raise EmptyError
|
|
||||||
else:
|
|
||||||
return acc
|
|
||||||
|
|
||||||
|
|
||||||
def handle_default_opt(
|
|
||||||
pos: SourcePosition,
|
|
||||||
exceptions: List[Optional[Any]],
|
|
||||||
just: Optional[bool],
|
|
||||||
cons: Optional[Alpha]
|
|
||||||
) -> Optional[Alpha]:
|
|
||||||
acc: Optional[Alpha] = None
|
|
||||||
for exception in exceptions:
|
|
||||||
if acc is None:
|
|
||||||
acc = exception
|
|
||||||
elif not (acc is None) and exception is None:
|
|
||||||
pass # acc stays the same
|
|
||||||
elif not (acc is None) and not (exception is None):
|
|
||||||
raise ConflictError(pos)
|
|
||||||
if acc is None:
|
|
||||||
if just is None:
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
if just:
|
|
||||||
return cons
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
return acc
|
|
||||||
|
|
||||||
|
|
||||||
def no_input() -> Callable[[Unit], Alpha]:
|
|
||||||
def closure(_: Unit):
|
|
||||||
raise EmptyError
|
|
||||||
return closure
|
|
||||||
|
|
||||||
|
|
||||||
# This value is used for the Python code generation to trump mypy and forcing
|
|
||||||
# it to accept dead code. Indeed, when raising an exception during a variable
|
|
||||||
# definition, mypy complains that the later dead code will not know what
|
|
||||||
# this variable was. So we give this variable a dead value.
|
|
||||||
dead_value: Any = 0
|
|
||||||
|
|
||||||
# =======
|
|
||||||
# Logging
|
|
||||||
# =======
|
|
||||||
|
|
||||||
|
|
||||||
class LogEventCode(Enum):
|
|
||||||
VariableDefinition = 0
|
|
||||||
BeginCall = 1
|
|
||||||
EndCall = 2
|
|
||||||
DecisionTaken = 3
|
|
||||||
|
|
||||||
|
|
||||||
class LogEvent:
|
|
||||||
def __init__(self, code: LogEventCode, payload: Union[List[str], SourcePosition, Tuple[List[str], Alpha]]) -> None:
|
|
||||||
self.code = code
|
|
||||||
self.payload = payload
|
|
||||||
|
|
||||||
|
|
||||||
log: List[LogEvent] = []
|
|
||||||
|
|
||||||
|
|
||||||
def reset_log():
|
|
||||||
log = []
|
|
||||||
|
|
||||||
|
|
||||||
def retrieve_log() -> List[LogEvent]:
|
|
||||||
return log
|
|
||||||
|
|
||||||
|
|
||||||
def log_variable_definition(headings: List[str], value: Alpha) -> Alpha:
|
|
||||||
log.append(LogEvent(LogEventCode.VariableDefinition,
|
|
||||||
(headings, copy.deepcopy(value))))
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
def log_begin_call(headings: List[str], f: Callable[[Alpha], Beta], value: Alpha) -> Beta:
|
|
||||||
log.append(LogEvent(LogEventCode.BeginCall, headings))
|
|
||||||
return f(value)
|
|
||||||
|
|
||||||
|
|
||||||
def log_end_call(headings: List[str], value: Alpha) -> Alpha:
|
|
||||||
log.append(LogEvent(LogEventCode.EndCall, headings))
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
def log_decision_taken(pos: SourcePosition, value: bool) -> bool:
|
|
||||||
log.append(LogEvent(LogEventCode.DecisionTaken, pos))
|
|
||||||
return value
|
|
@ -1,3 +1,5 @@
|
|||||||
from setuptools import setup
|
from setuptools import setup # type: ignore
|
||||||
|
|
||||||
setup()
|
setup(package_data={
|
||||||
|
'catala-runtime': ['py.typed'],
|
||||||
|
},)
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
|
|
||||||
# This file should be in sync with compiler/runtime.{ml, mli} !
|
# This file should be in sync with compiler/runtime.{ml, mli} !
|
||||||
|
|
||||||
from this import d
|
from gmpy2 import log2, mpz, mpq, mpfr, t_divmod, qdiv, f_div, sign # type: ignore
|
||||||
from gmpy2 import log2, mpz, mpq, mpfr, t_divmod, f_div, sign # type: ignore
|
|
||||||
import datetime
|
import datetime
|
||||||
import calendar
|
import calendar
|
||||||
import dateutil.relativedelta
|
import dateutil.relativedelta
|
||||||
@ -411,18 +410,19 @@ def money_to_cents(m: Money) -> Integer:
|
|||||||
|
|
||||||
|
|
||||||
def money_round(m: Money) -> Money:
|
def money_round(m: Money) -> Money:
|
||||||
res, remainder = t_divmod(m, 100)
|
res, remainder = t_divmod(m.value.value, 100)
|
||||||
if remainder < 50:
|
if remainder < 50:
|
||||||
return res * 100
|
return Money(Integer(res * 100))
|
||||||
else:
|
else:
|
||||||
return (res + sign(res)) * 100
|
return Money(Integer((res + sign(res)) * 100))
|
||||||
|
|
||||||
|
|
||||||
def money_of_decimal(m: Decimal) -> Money:
|
def money_of_decimal(d: Decimal) -> Money:
|
||||||
"""
|
"""
|
||||||
Warning: rounds to nearest cent.
|
Warning: rounds to the nearest cent
|
||||||
"""
|
"""
|
||||||
return Money(mpz(m.value))
|
return Money(Integer(mpz(d.value)))
|
||||||
|
|
||||||
|
|
||||||
# --------
|
# --------
|
||||||
# Decimals
|
# Decimals
|
||||||
@ -450,13 +450,18 @@ def decimal_to_string(precision: int, i: Decimal) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def decimal_round(q: Decimal) -> Decimal:
|
def decimal_round(q: Decimal) -> Decimal:
|
||||||
# Implements the workaround by
|
"""
|
||||||
# https://gmplib.org/list-archives/gmp-discuss/2009-May/003767.html *)
|
Implements the workaround by
|
||||||
return f_div(2*q.numerator + q.denominator, 2*q.denominator) # type:ignore
|
https://gmplib.org/list-archives/gmp-discuss/2009-May/003767.html
|
||||||
|
"""
|
||||||
|
return Decimal(
|
||||||
|
mpq(f_div(2*q.value.numerator + q.value.denominator,
|
||||||
|
2*q.value.denominator), 1) # type:ignore
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def decimal_of_money(m: Money) -> Decimal:
|
def decimal_of_money(m: Money) -> Decimal:
|
||||||
return Decimal(f_div(mpq(m.value), mpq(100)))
|
return Decimal(mpq(qdiv(m.value.value, 100)))
|
||||||
|
|
||||||
# --------
|
# --------
|
||||||
# Integers
|
# Integers
|
||||||
|
Loading…
Reference in New Issue
Block a user