Commit 05985407 authored by David Foucher's avatar David Foucher

Merge branch 'remuneration' into 'master'

Remuneration

See merge request !3
parents 95b6296f 389af47c
Pipeline #1822 passed with stage
in 1 minute and 21 seconds
__pycache__/
.mypy_cache/
.pytest_cache/
docs/
tmp/
......
......@@ -12,6 +12,7 @@ from openapi_spec_validator import validate_spec
from trefle.config import FINANCEMENTS
from trefle.config import REMUNERATIONS
from trefle import VERSION
pytestmark = pytest.mark.asyncio
......@@ -55,6 +56,33 @@ async def test_simulate_endpoint(client):
result.raise_for_errors()
async def test_remuneration_endpoint(client):
resp = await client.get("/schema")
spec = create_spec(json.loads(resp.body))
resp = await client.post(
"/remuneration",
body={
"beneficiaire.age": 20,
"formation.region": 27,
"formation.codes_financeur": [2],
},
)
assert resp.status == HTTPStatus.OK
assert "remunerations" in json.loads(resp.body)
remunerations = json.loads(resp.body)["remunerations"]
assert remunerations
print(remunerations[0])
assert "remuneration" in remunerations[0]
assert "Version" in resp.headers
validator = ResponseValidator(spec)
request = MockRequest("http://trefle.pole-emploi.fr", "post", "/remuneration")
response = MockResponse(resp.body, resp.status.value)
result = validator.validate(request, response)
result.raise_for_errors()
async def test_simulate_endpoint_without_formation_prix_horaire(client):
resp = await client.get("/schema")
......
......@@ -4,10 +4,10 @@ from pathlib import Path
import pytest
from trefle.config import IDCC
from trefle.context import Context
from trefle import exceptions
from trefle import routine
from trefle.config import IDCC
from trefle.context import Context
@pytest.mark.asyncio
......
......@@ -37,3 +37,10 @@ def get_financements(tags=None):
for tag in tags or []:
financements = [f for f in financements if tag in f["tags"]]
return financements
def get_remunerations(tags=None):
remunerations = [config.Remuneration(f) for f in config.REMUNERATIONS]
for tag in tags or []:
remunerations = [f for f in remunerations if tag in f["tags"]]
return remunerations
......@@ -2,12 +2,16 @@ from http import HTTPStatus
from roll import HttpError, Roll
from roll.extensions import cors
import ujson as json
from . import VERSION, simulate, get_financements
from .config import FINANCEMENTS, GLOSSARY, NAF, IDCC, RAW_RULES, SCHEMA
from .debugging import data_from_lbf_url, make_scenario, SCENARIOS
from . import VERSION, get_financements, get_remunerations, simulate
from . import routine
from .config import FINANCEMENTS, GLOSSARY, IDCC, NAF, RAW_RULES, SCHEMA
from .context import Context
from .debugging import SCENARIOS, data_from_lbf_url, make_scenario
from .exceptions import DataError
from .helpers import flatten
from .legacy import simulate_legacy
from .loggers import log_simulate, logger
from .openapis import OPENAPI
......@@ -45,6 +49,77 @@ async def simulate_(request, response):
log_simulate(context, errors=error)
raise HttpError(HTTPStatus.UNPROCESSABLE_ENTITY, error)
eligible = request.query.bool("eligible", None)
if eligible is not None:
financements = [f for f in financements if f["eligible"] == eligible]
else:
financements = sorted(
financements, key=lambda value: value["eligible"], reverse=True
)
explain = request.query.bool("explain", False)
for financement in financements:
financement["explain"] = (
[s.json for s in financement["explain"]] if explain else None
)
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]}
if request.query.bool("scenario", False):
body["scenario"] = make_scenario(context, financements)
response.json = body
log_simulate(context, financements=financements)
@app.route("/remuneration", methods=["POST"])
async def remuneration_(request, response):
data = 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]
except DataError as err:
error = {err.key: err.error}
log_simulate(context, errors=error)
raise HttpError(HTTPStatus.UNPROCESSABLE_ENTITY, error)
# TODO: explain only for financement see routine.py check_remuneration
# explain = request.query.bool("explain", False)
# for remuneration in remunerations:
# remuneration["explain"] = (
# [s.json for s in remunerations["explain"]] if explain else None
# )
body = {"remunerations": remunerations}
# 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]}
response.json = body
"""
try:
await simulate(context, financements)
except DataError as err:
error = {err.key: err.error}
log_simulate(context, errors=error)
raise HttpError(HTTPStatus.UNPROCESSABLE_ENTITY, error)
eligible = request.query.bool("eligible", None)
if eligible is not None:
financements = [f for f in financements if f["eligible"] == eligible]
......@@ -67,6 +142,7 @@ async def simulate_(request, response):
response.json = body
log_simulate(context, financements=financements)
"""
app.route("/legacy", methods=["POST"])(simulate_legacy)
......
......@@ -14,6 +14,7 @@ from ..rules import Rule, SCHEMA, LABELS, RULES, IDCC
CONSTANTS = {}
FINANCEMENTS = []
REMUNERATIONS = []