Commit ae2e4a69 authored by David Foucher's avatar David Foucher
Browse files

Add behave functionality for remuneration

parent 85691f3c
......@@ -31,6 +31,23 @@ async def simulate(data, financements):
if key.startswith("financement"):
del data[key]
async def simulate_remuneration(data, remunerations):
# Prepare context
flatten(data)
context = Context(data.copy())
routine.extrapolate_context(context)
routine.preprocess(context)
for remuneration in remunerations:
copy = context.copy()
routine.check_remuneration(context, remuneration)
data.update(copy.cleaned_data)
# FIXME (limits of the single-store-all context object)
# Clean keys not meant to be exposed
for key in list(data.keys()):
if key.startswith("remuneration"):
del data[key]
def get_financements(tags=None):
financements = [config.Financement(f) for f in config.FINANCEMENTS]
......
......@@ -5,7 +5,13 @@ from roll.extensions import cors
import ujson as json
from . import VERSION, get_financements, get_remunerations, simulate
from . import (
VERSION,
get_financements,
get_remunerations,
simulate,
simulate_remuneration,
)
from . import routine
from .config import FINANCEMENTS, GLOSSARY, IDCC, NAF, RAW_RULES, SCHEMA
from .context import Context
......@@ -65,8 +71,8 @@ async def simulate_(request, response):
body = {"financements": financements}
if request.query.bool("context", False):
body["context"] = {
k: v for k, v in context.items()
if k in SCHEMA and "label" in SCHEMA[k]}
k: v for k, v in context.items() if k in SCHEMA and "label" in SCHEMA[k]
}
if request.query.bool("scenario", False):
body["scenario"] = make_scenario(context, financements)
response.json = body
......@@ -77,24 +83,10 @@ async def simulate_(request, response):
# TODO : add pointer error for bad region number + test
@app.route("/remuneration", methods=["POST"])
async def remuneration_(request, response):
data = request.json
context = request.json
remunerations = get_remunerations(tags=request.query.list("tags", []))
try:
flatten(data)
context = Context(data.copy())
routine.extrapolate_context(context)
routine.preprocess(context)
for remuneration in remunerations:
copy = context.copy()
routine.check_remuneration(context, remuneration)
data.update(copy.cleaned_data)
# FIXME (limits of the single-store-all context object)
# Clean keys not meant to be exposed
for key in list(data.keys()):
if key.startswith("remuneration"):
del data[key]
await simulate_remuneration(context, remunerations)
except DataError as err:
error = {err.key: err.error}
log_simulate(context, errors=error)
......
from behave import given, when, then, use_step_matcher
from behave.api.async_step import async_run_until_complete
from trefle import simulate, get_financements
from trefle import simulate, simulate_remuneration, get_financements, get_remunerations
from trefle.config import FINANCEMENTS
from trefle.helpers import revert_dict
from trefle.helpers import revert_dict, remove_namespace
from trefle.rules import LABELS, SCHEMA, Pointer
INTITULES_FINANCEMENTS = set(f["intitule"] for f in FINANCEMENTS)
......@@ -49,6 +49,20 @@ async def when_simulate(context):
context.passed = [f for f in financements if f['eligible']]
@when('je demande un calcul de rémunération')
@async_run_until_complete
async def when_remunerate(context):
remunerations = get_remunerations()
await simulate_remuneration(context.data, remunerations)
context.passed = [r for r in remunerations if r['remuneration']]
for result in context.passed:
if result['remuneration']:
context.result = result
break
else:
raise AssertionError(f'No result found')
@then(r"il y a (?P<expected>\d+) financements? proposés?")
def then_check_count(context, expected):
assert found == int(expected), f'Found {found}'
......@@ -86,10 +100,7 @@ def then_check_organisme(context, name):
@then(r"(?:le |la |l')(?P<label>.*) vaut (?P<value>.+)")
def then_check_output(context, label, value):
value = Pointer(value).get({})
if(LABELS[label].startswith("financement")):
key = LABELS[label][12:] # Remove "financement." namespace.
if(LABELS[label].startswith("remuneration")):
key = LABELS[label][13:] # Remove "remuneration." namespace.
key = remove_namespace(LABELS[label])
assert context.result[key] == value, (f'key = {key} '
f'label = {LABELS[label]}'
f'{context.result[key]} '
......@@ -111,6 +122,21 @@ def then_check_true_boolean_value(context, label):
f'{key} is True'
@then(r"une? (?P<label>.+) est éligible")
def then_check_true_eligibility(context, label):
key = LABELS[label]
assert context.result.get(remove_namespace(key)) \
and context.result[remove_namespace(key)] is True,\
f'{label} is True'
@then(r"aucune? (?P<label>.+) n'est éligible")
def then_check_false_eligibility(context, label):
key = LABELS[label]
assert context.result.get(remove_namespace(key)) is None,\
f'{label} is False'
@then("aucun financement n'est proposé")
def then_no_results(context):
assert not context.passed, f"Results found: {context.passed}"
......@@ -4,36 +4,63 @@ Si les codes financeur de la formation contiennent «Conseil régional»
Alors la rémunération applicable est égale au montant de l'allocation du bénéficiaire
# Par défaut
Si l'âge du bénéficiaire est inférieur à 18
Et la rémunération applicable est inférieure à 455.01
Alors la rémunération applicable vaut 455.01
Si l'âge du bénéficiaire est supérieur ou égal à 18
Et la rémunération applicable est inférieure à 652.18
Alors la rémunération applicable vaut 652.18
Si ce n'est pas un bénéficiaire qui a déjà travaillé six mois sur une période de douze mois
Et ce n'est pas un bénéficiaire qui a déjà travaillé douze mois sur une période de vingt-quatre mois
Et ce n'est pas un bénéficiaire non salarié qui a travaillé pendant douze mois dont au moins six mois consécutifs dans les trois ans qui précèdent l'entrée en formation
Alors l'aide au transport est éligible
Et le montant de l'aide au transport vaut «98,79€ par mois (sous condition)»
Et le texte de l'aide au transport vaut «Si la distance vers le lieu de votre formation est supérieure ou égale à 16km. Alors vous pouvez bénéficier d'une aide au transport.»
Si l'âge du bénéficiaire est inférieur à 18
Alors l'aide à l'hébergement est éligible
Et le montant de l'aide au logement vaut «37,20€ par mois (sous condition)»
Et le texte de l'aide au transport vaut «Si la distance vers le lieu de votre formation est inférieure ou égale à 15km. Alors vous pouvez bénéficier d'une aide au logement.»
Si la rémunération applicable est inférieure à 455.01
Alors la rémunération applicable vaut 455.01
Si l'âge du bénéficiaire est supérieur ou égal à 18
Et la rémunération applicable est inférieure à 652.18
Alors la rémunération applicable vaut 652.18
Si c'est un travailleur handicapé
Et la rémunération applicable est inférieure à 1001.02
Alors la rémunération applicable vaut 1001.02
Si c'est un bénéficiaire qui a déjà travaillé six mois sur une période de douze mois
Ou c'est un bénéficiaire qui a déjà travaillé douze mois sur une période de vingt-quatre mois
Et la rémunération applicable est inférieure à 863.00
Alors la rémunération applicable vaut 863.00
Et c'est un travailleur handicapé
Alors l'aide au transport est éligible
Et le texte de l'aide au transport vaut «l'indemnité de transport est limitée à un aller-retour sur la durée du stage»
Si la rémunération applicable est inférieure à 910.02
Alors la rémunération applicable vaut 910.02
Et le texte de la rémunération vaut «C'est une rémunération minimum en fonction de votre expérience»
Si c'est un bénéficiaire qui a déjà travaillé six mois sur une période de douze mois
Ou c'est un bénéficiaire qui a déjà travaillé douze mois sur une période de vingt-quatre mois
Si la rémunération applicable est inférieure à 863.0
Alors la rémunération applicable vaut 863.00
Si c'est un bénéficiaire non salarié qui a travaillé pendant douze mois dont au moins six mois consécutifs dans les trois ans qui précèdent l'entrée en formation
Alors l'aide au transport est éligible
Et le montant de l'aide au transport vaut «98,79€ par mois (sous condition)»
Et le texte de l'aide au transport vaut «Si la distance vers le lieu de votre formation est supérieure ou égale à 16km. Alors vous pouvez bénéficier d'une aide au transport.»
Si la rémunération applicable est inférieure à 708.59
Alors la rémunération applicable vaut 708.59
# Règles spécifiques
Si c'est un parent isolé
Ou c'est une mère de famille ayant au moins trois enfants
Ou c'est une femme divorcée, veuve ou séparée judiciairement depuis moins de trois ans
Ou c'est une femme seule et enceinte
#Ou c'est un demandeur d'emploi # A confirmer
Alors l'aide au transport est éligible
Et le montant de l'aide au transport vaut «98,79€ par mois (sous condition)»
Et le texte de l'aide au transport vaut «Si la distance vers le lieu de votre formation est supérieure à 16km. Alors vous pouvez bénéficier d'une aide au transport.»
Et le texte de l'aide au transport vaut «Si la distance vers le lieu de votre formation est supérieure ou égale à 16km. Alors vous pouvez bénéficier d'une aide au transport.»
Et l'aide au logement est éligible
Et le montant de l'aide au logement vaut «101,84€ par mois (sous condition)»
Et le texte de l'aide au logement vaut «Si la distance vers le lieu de votre formation est supérieure à 250km. Alors vous pouvez bénéficier d'une aide à l'hébergement. Cette aide est non cumulable avec l'aide au transport.»
Si la rémunération applicable est inférieure à 863.00
Alors la rémunération applicable vaut 863.00
Si c'est un travailleur handicapé
Et la rémunération applicable est inférieure à 910.02
Alors la rémunération applicable vaut 910.02
Et le texte de la rémunération vaut «C'est une rémunération minimum en fonction de votre expérience»
# TODO ajouter cas détenu
# Si c'est un détenu
......
......@@ -140,6 +140,10 @@ def revert_dict(d):
return {v: k for k, v in d.items()}
def remove_namespace(s):
return s[(s.find('.') + 1):]
def json_path(pattern, data):
steps = pattern.split(".")
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment