diff --git a/passerelle/contrib/solis_afi_mss/__init__.py b/passerelle/contrib/solis_afi_mss/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/passerelle/contrib/solis_afi_mss/migrations/0001_initial.py b/passerelle/contrib/solis_afi_mss/migrations/0001_initial.py new file mode 100644 index 00000000..b2ac2c35 --- /dev/null +++ b/passerelle/contrib/solis_afi_mss/migrations/0001_initial.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.18 on 2020-10-19 10:15 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('base', '0022_auto_20200715_1033'), + ] + + operations = [ + migrations.CreateModel( + name='SolisAfiMss', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=50, verbose_name='Title')), + ('slug', models.SlugField(unique=True, verbose_name='Identifier')), + ('description', models.TextField(verbose_name='Description')), + ('basic_auth_username', models.CharField(blank=True, max_length=128, verbose_name='Basic authentication username')), + ('basic_auth_password', models.CharField(blank=True, max_length=128, verbose_name='Basic authentication password')), + ('client_certificate', models.FileField(blank=True, null=True, upload_to='', verbose_name='TLS client certificate')), + ('trusted_certificate_authorities', models.FileField(blank=True, null=True, upload_to='', verbose_name='TLS trusted CAs')), + ('verify_cert', models.BooleanField(default=True, verbose_name='TLS verify certificates')), + ('http_proxy', models.CharField(blank=True, max_length=128, verbose_name='HTTP and HTTPS proxy')), + ('base_url', models.CharField(help_text='example: https://solis.mon-application.fr/api-mss-afi/', max_length=256, verbose_name='Service URL')), + ('users', models.ManyToManyField(blank=True, related_name='_solisafimss_users_+', related_query_name='+', to='base.ApiUser')), + ], + options={ + 'verbose_name': 'Solis (mss-afi)', + }, + ), + ] diff --git a/passerelle/contrib/solis_afi_mss/migrations/__init__.py b/passerelle/contrib/solis_afi_mss/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/passerelle/contrib/solis_afi_mss/models.py b/passerelle/contrib/solis_afi_mss/models.py new file mode 100644 index 00000000..7c41ca7c --- /dev/null +++ b/passerelle/contrib/solis_afi_mss/models.py @@ -0,0 +1,274 @@ +# passerelle - uniform access to multiple data sources and services +# Copyright (C) 2020 Entr'ouvert +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from urllib.parse import urljoin + +from django.db import models +from django.utils.translation import ugettext_lazy as _ + +from passerelle.base.models import BaseResource, HTTPResource +from passerelle.utils.api import endpoint +from passerelle.utils.jsonresponse import APIError + +TAX_SCHEMA = { + '$schema': 'http://json-schema.org/draft-04/schema#', + "type": "object", + 'properties': { + 'email': { + 'description': "Agent's email address", + 'type': 'string', + }, + 'indexImposition': { + 'description': 'Tax index', + 'type': 'string', + }, + 'anneeImposition': { + 'description': 'Year of taxation (YYYY)', + 'type': 'string', + }, + 'nombrePartImposition': { + 'description': 'Number of tax shares', + 'type': 'string', + }, + 'montantImposition': { + 'description': 'Tax amount', + 'type': 'string', + }, + } +} + +DEMAND_SCHEMA = { + '$schema': 'http://json-schema.org/draft-04/schema#', + "type": "object", + 'properties': { + 'email': { + 'description': "Agent's email address", + 'type': 'string', + }, + 'codeTypeAide': { + 'description': 'Allowance type code', + 'type': 'string', + }, + 'natureTypeAide': { + 'description': 'Nature of the allowance (A, P or S)', + 'type': 'string', + }, + 'individusConcernes': { + 'description': "List of related family member indexes separated by ':'", + 'type': 'string', + 'pattern': r'^[0-9 :]+$' + }, + 'dateDebut': { + 'description': 'Start date (YYYY-MM-DD)"', + 'type': 'string', + }, + 'dateFin': { + 'description': 'End date (YYYY-MM-DD)', + 'type': 'string', + }, + 'montantFacture': { + 'description': 'Invoice amount', + 'type': 'string', + }, + } +} + + +class SolisAfiMss(BaseResource, HTTPResource): + base_url = models.CharField( + max_length=256, blank=False, + verbose_name=_('Service URL'), + help_text=_('example: https://solis.mon-application.fr/api-mss-afi/') + ) + + category = _('Business Process Connectors') + + class Meta: + verbose_name = _('Solis (mss-afi)') + + def request(self, uri, params=None, json=None): + url = urljoin(self.base_url, uri) + headers = {'Accept': 'application/json'} + if json: + response = self.requests.post(url, json=json, headers=headers) + else: + response = self.requests.get(url, params=params, headers=headers) + + if response.status_code // 100 != 2: + try: + json_content = response.json() + except ValueError: + json_content = None + raise APIError('error status:%s %r, content:%r' % + (response.status_code, response.reason, response.content[:1024]), + data={'status_code': response.status_code, + 'json_content': json_content}) + + if response.status_code == 204 or not response.content: # 204 No Content + return None + + try: + return response.json() + except ValueError: + raise APIError('invalid JSON content:%r' % response.content[:1024]) + + def check_status(self): + ''' + Raise an exception if something goes wrong. + ''' + return self.request('main/isAlive/') + + def search_from_email(self, email): + response = self.request('afi/agent/rechercherParEmail/', params={'adresseMail': email}) + index = response.get('indexAgent') + + adults = [] + for key in ('agent', 'conjointAgent'): + if response.get(key): + adults.append(response.get(key)) + children = response.get('enfantsAgent') + for record in adults + children: + record['id'] = record.get('indexIndividu') + record['text'] = '%(prenom)s %(nom)s' % record + + return index, adults, children + + @endpoint( + display_category=_('Agent'), display_order=1, + perm='can_access', methods=['get'], + description=_('Retrieve family composition'), + parameters={ + 'email': {'description': _("Agent's email address")}, + }) + def family(self, request, email): + index, adults, children = self.search_from_email(email) + return {'data': adults + children} + + @endpoint( + display_category=_('Agent'), display_order=1, + perm='can_access', methods=['get'], + description=_('Retrieve adults from family composition'), + parameters={ + 'email': {'description': _("Agent's email address")}, + }) + def adults(self, request, email): + adults, children = self.search_from_email(email)[1:] + return {'data': adults} + + @endpoint( + display_category=_('Agent'), display_order=1, + perm='can_access', methods=['get'], + description=_('Retrieve children from family composition'), + parameters={ + 'email': {'description': _("Agent's email address")}, + }) + def children(self, request, email): + children = self.search_from_email(email)[2] + return {'data': children} + + @endpoint( + display_category=_('Budget'), display_order=1, + perm='can_access', methods=['get'], + description=_('Retrieve the list of charges for an agent'), + parameters={ + 'email': {'description': _("Agent's email address")}, + 'year': {'description': _('Year of taxation (YYYY)')}, + }) + def taxes(self, request, email, year=None): + index = self.search_from_email(email)[0] + params = {'indexAgent': str(index)} + + if year: + params['anneeImposition'] = year + uri = 'afi/budget/getImposition/' + else: + uri = 'afi/budget/getImpositionsParAgent/' + + response = self.request(uri, params=params) + if year: + response = [response] if response else [] + + for record in response: + record['id'] = record.get('anneeImposition') + record['text'] = '%(anneeImposition)s: %(montantImposition)s' % record + return {'data': response} + + @endpoint( + display_category=_('Budget'), display_order=2, + name='declare-tax', perm='can_access', methods=['post'], + description=_("Register an agent's tax for one year"), + post={'request_body': {'schema': {'application/json': TAX_SCHEMA}}}) + def declare_tax(self, request, post_data): + email = post_data.pop('email') + post_data['indexAgent'] = str(self.search_from_email(email)[0]) + response = self.request('afi/budget/declarerImpot/', json=post_data) + return {'data': response} + + @endpoint( + display_category=_('Budget'), display_order=3, + name='simulate-quotient', perm='can_access', methods=['get'], + description=_( + 'Simulate the calculation of a Quotient from the tax amount and the number of shares'), + parameters={ + 'email': {'description': _("Agent's email address")}, + 'year': {'description': _('Year of taxation (YYYY)')}, + }) + def simulate_quotient(self, request, code, nb_parts, amount): + params = { + 'codeCalcul': code, + 'nbrPartImposition': nb_parts, + 'mntImposition': amount, + } + response = self.request('afi/budget/calculer/', params=params) + return {'data': response} + + @endpoint( + display_category=_('Allowance'), display_order=1, + perm='can_access', methods=['get'], + description=_('Retrieve the list of allowance from an agent'), + parameters={ + 'email': {'description': _("Agent's email address")}, + 'text_template': {'description': _('Text template')}, + }) + def helps(self, request, email): + params = {'indexAgent': str(self.search_from_email(email)[0])} + response = self.request('afi/aide/getAidesParAgent/', params=params) + + for record in response['aidesFinancieres']: + record['id'] = record.get('indexAideFinanciere') + record['text'] = '%(dateDemandeAide)s (%(suiviAide)s)' % record + return {'err': 0, 'data': response['aidesFinancieres']} + + @endpoint( + display_category=_('Allowance'), display_order=2, + name='demand-help', perm='can_access', methods=['post'], + description=_('Submit allowance for an agent'), + post={'request_body': {'schema': {'application/json': DEMAND_SCHEMA}}}) + def demand_help(self, request, post_data): + email = post_data.pop('email') + index_agent, adults, children = self.search_from_email(email) + + related_persons = [] + for person in adults + children: + for index in [ + x.strip() for x in post_data['individusConcernes'].split(':') if x.strip()]: + if str(person['indexIndividu']) == index: + related_persons.append({"indexIndividu": index}) + + post_data['indexAgent'] = str(index_agent) + post_data['individusConcernes'] = related_persons + response = self.request('afi/aide/deposer/', json=post_data) + return {'data': response} diff --git a/tests/data/solis_afi_mss/calculer.json b/tests/data/solis_afi_mss/calculer.json new file mode 100644 index 00000000..5efa6d48 --- /dev/null +++ b/tests/data/solis_afi_mss/calculer.json @@ -0,0 +1,8 @@ +{ + "anneeImposition": 0, + "codeCalcul": 2, + "libelleQuotient": "Quotient familial mensuel", + "montantImposition": 1444.44, + "nombrePartImposition": 2.3, + "resultatCalcul": 52.33 +} diff --git a/tests/data/solis_afi_mss/declarerImpot_389227.json b/tests/data/solis_afi_mss/declarerImpot_389227.json new file mode 100644 index 00000000..e9f399fa --- /dev/null +++ b/tests/data/solis_afi_mss/declarerImpot_389227.json @@ -0,0 +1,7 @@ +{ + "anneeImposition" : 2011, + "indexAgent" : 389227, + "indexImposition" : 368, + "montantImposition" : 777.77, + "nombrePartImposition" : 3.2 +} diff --git a/tests/data/solis_afi_mss/deposer_388405.json b/tests/data/solis_afi_mss/deposer_388405.json new file mode 100644 index 00000000..0cd49e2e --- /dev/null +++ b/tests/data/solis_afi_mss/deposer_388405.json @@ -0,0 +1,39 @@ +{ + "codeAideFinanciere" : 4, + "codeAideGlobale" : null, + "codePrestataireAideFi" : 1, + "codeTypeAide" : 24, + "dateDemandeAide" : "2020-09-29", + "datePremierPaiement" : null, + "dateReponse" : null, + "indexAideFinanciere" : 37152, + "indexDossier" : 243952, + "indexIndividuDemandeur" : 388405, + "individuDemandeur" : { + "codeRoleFamille" : 3, + "dateNaissance" : "1965-08-24", + "indexIndividu" : 388405, + "nom" : "HUREL", + "prenom" : "Jean-Christophe" + }, + "individusConcernes" : [], + "montantAccorde" : 0, + "montantDemande" : 0, + "natureAide" : "A", + "nbPersonne" : 1, + "prestataireAideFinanciere" : { + "codePrestataire" : 1, + "indexOrganisme" : 1, + "nomCompletOrganisme" : "Ministères sociaux", + "nomReduitOrganisme" : "Ministère" + }, + "prisesEnCharge" : [], + "quotient" : 80, + "suiviAide" : "En attente", + "typeAideFinanciere" : { + "codeCalculQf" : 6, + "codeTypeAideFinanciere" : 24, + "libelleTypeAideFinanciere" : "Séjour camping - 21 jours max (PM)", + "natureTypeAideFinanciere" : "A" + } +} diff --git a/tests/data/solis_afi_mss/error.json b/tests/data/solis_afi_mss/error.json new file mode 100644 index 00000000..b56165d4 --- /dev/null +++ b/tests/data/solis_afi_mss/error.json @@ -0,0 +1,7 @@ +[ + { + "links" : [], + "logref" : "29fdba95-16bb-4f1b-8b35-b157a8a785e5", + "message" : "Solis API MSS AFI - Erreur: XXX" + } +] diff --git a/tests/data/solis_afi_mss/getAidesParAgent_388405.json b/tests/data/solis_afi_mss/getAidesParAgent_388405.json new file mode 100644 index 00000000..64595145 --- /dev/null +++ b/tests/data/solis_afi_mss/getAidesParAgent_388405.json @@ -0,0 +1,373 @@ +{ + "aidesFinancieres": [ + { + "codeAideFinanciere": 1, + "codeAideGlobale": null, + "codePrestataireAideFi": 1, + "codeTypeAide": 33, + "dateDemandeAide": "2020-05-26", + "datePremierPaiement": null, + "dateReponse": null, + "indexAideFinanciere": 37145, + "indexDossier": 243952, + "indexIndividuDemandeur": 388405, + "individuDemandeur": { + "codeRoleFamille": 3, + "dateNaissance": "1965-08-24", + "indexIndividu": 388405, + "nom": "HUREL", + "prenom": "Jean-Christophe" + }, + "individusConcernes": [ + { + "codeRoleFamille": 3, + "dateNaissance": "1965-08-24", + "indexIndividu": 388405, + "nom": "HUREL", + "prenom": "Jean-Christophe" + }, + { + "codeRoleFamille": 1, + "dateNaissance": "1991-08-24", + "indexIndividu": 388407, + "nom": "HUREL", + "prenom": "Camille" + }, + { + "codeRoleFamille": 1, + "dateNaissance": "1996-08-05", + "indexIndividu": 388408, + "nom": "HUREL", + "prenom": "Valentin" + } + ], + "montantAccorde": 50, + "montantDemande": 0, + "natureAide": "A", + "nbPersonne": 0, + "prestataireAideFinanciere": { + "codePrestataire": 1, + "indexOrganisme": 1, + "nomCompletOrganisme": "Ministères sociaux", + "nomReduitOrganisme": "Ministère" + }, + "prisesEnCharge": [ + { + "codeAideFinanciere": 1, + "codePrestataireAideFi": 1, + "codeTypePriseEnCharge": 26, + "debutPeriode": "2020-04-28", + "finPeriode": "2020-05-13", + "indexAideFinanciere": 37145, + "indexDossier": 243952, + "montantParticipationAutre": 50, + "montantParticipationFamiliale": 0, + "montantTotal": 50.0, + "natureAide": "A", + "quantite": 1, + "tarif": 60, + "typePriseEnCharge": { + "codeTypePriseEnCharge": 26, + "inactivite": false, + "libelle": "Activité sportive", + "libelleReduit": "spcultu" + } + } + ], + "quotient": 80, + "suiviAide": "En attente", + "typeAideFinanciere": { + "codeCalculQf": 6, + "codeTypeAideFinanciere": 33, + "libelleTypeAideFinanciere": "Activité sportive et culturelle (PM)", + "natureTypeAideFinanciere": "A" + } + }, + { + "codeAideFinanciere": 2, + "codeAideGlobale": null, + "codePrestataireAideFi": 1, + "codeTypeAide": 27, + "dateDemandeAide": "2020-05-26", + "datePremierPaiement": null, + "dateReponse": null, + "indexAideFinanciere": 37146, + "indexDossier": 243952, + "indexIndividuDemandeur": 388405, + "individuDemandeur": { + "codeRoleFamille": 3, + "dateNaissance": "1965-08-24", + "indexIndividu": 388405, + "nom": "HUREL", + "prenom": "Jean-Christophe" + }, + "individusConcernes": [], + "montantAccorde": 47.15, + "montantDemande": 0, + "natureAide": "A", + "nbPersonne": 0, + "prestataireAideFinanciere": { + "codePrestataire": 1, + "indexOrganisme": 1, + "nomCompletOrganisme": "Ministères sociaux", + "nomReduitOrganisme": "Ministère" + }, + "prisesEnCharge": [ + { + "codeAideFinanciere": 2, + "codePrestataireAideFi": 1, + "codeTypePriseEnCharge": 2, + "debutPeriode": "2020-09-01", + "finPeriode": "2021-06-30", + "indexAideFinanciere": 37146, + "indexDossier": 243952, + "montantParticipationAutre": 0, + "montantParticipationFamiliale": 0, + "montantTotal": 47.15, + "natureAide": "A", + "quantite": 1, + "tarif": 58.94, + "typePriseEnCharge": { + "codeTypePriseEnCharge": 2, + "inactivite": false, + "libelle": "Collège", + "libelleReduit": "Collège" + } + } + ], + "quotient": 80, + "suiviAide": "En attente", + "typeAideFinanciere": { + "codeCalculQf": 6, + "codeTypeAideFinanciere": 27, + "libelleTypeAideFinanciere": "Aide éducation collège (PM)", + "natureTypeAideFinanciere": "A" + } + }, + { + "codeAideFinanciere": 3, + "codeAideGlobale": null, + "codePrestataireAideFi": 1, + "codeTypeAide": 33, + "dateDemandeAide": "2020-06-11", + "datePremierPaiement": null, + "dateReponse": null, + "indexAideFinanciere": 37149, + "indexDossier": 243952, + "indexIndividuDemandeur": 388405, + "individuDemandeur": { + "codeRoleFamille": 3, + "dateNaissance": "1965-08-24", + "indexIndividu": 388405, + "nom": "HUREL", + "prenom": "Jean-Christophe" + }, + "individusConcernes": [ + { + "codeRoleFamille": 3, + "dateNaissance": "1965-08-24", + "indexIndividu": 388405, + "nom": "HUREL", + "prenom": "Jean-Christophe" + }, + { + "codeRoleFamille": 5, + "dateNaissance": "1990-03-02", + "indexIndividu": 388406, + "nom": "HUREL", + "prenom": "Carole" + }, + { + "codeRoleFamille": 1, + "dateNaissance": "1991-08-24", + "indexIndividu": 388407, + "nom": "HUREL", + "prenom": "Camille" + }, + { + "codeRoleFamille": 1, + "dateNaissance": "1996-08-05", + "indexIndividu": 388408, + "nom": "HUREL", + "prenom": "Valentin" + } + ], + "montantAccorde": 0, + "montantDemande": 0, + "natureAide": "A", + "nbPersonne": 0, + "prestataireAideFinanciere": { + "codePrestataire": 1, + "indexOrganisme": 1, + "nomCompletOrganisme": "Ministères sociaux", + "nomReduitOrganisme": "Ministère" + }, + "prisesEnCharge": [], + "quotient": 0, + "suiviAide": "En attente", + "typeAideFinanciere": { + "codeCalculQf": 6, + "codeTypeAideFinanciere": 33, + "libelleTypeAideFinanciere": "Activité sportive et culturelle (PM)", + "natureTypeAideFinanciere": "A" + } + }, + { + "codeAideFinanciere": 4, + "codeAideGlobale": null, + "codePrestataireAideFi": 1, + "codeTypeAide": 24, + "dateDemandeAide": "2020-09-29", + "datePremierPaiement": null, + "dateReponse": null, + "indexAideFinanciere": 37152, + "indexDossier": 243952, + "indexIndividuDemandeur": 388405, + "individuDemandeur": { + "codeRoleFamille": 3, + "dateNaissance": "1965-08-24", + "indexIndividu": 388405, + "nom": "HUREL", + "prenom": "Jean-Christophe" + }, + "individusConcernes": [], + "montantAccorde": 0, + "montantDemande": 0, + "natureAide": "A", + "nbPersonne": 1, + "prestataireAideFinanciere": { + "codePrestataire": 1, + "indexOrganisme": 1, + "nomCompletOrganisme": "Ministères sociaux", + "nomReduitOrganisme": "Ministère" + }, + "prisesEnCharge": [], + "quotient": 80, + "suiviAide": "En attente", + "typeAideFinanciere": { + "codeCalculQf": 6, + "codeTypeAideFinanciere": 24, + "libelleTypeAideFinanciere": "Séjour camping - 21 jours max (PM)", + "natureTypeAideFinanciere": "A" + } + }, + { + "codeAideFinanciere": 5, + "codeAideGlobale": null, + "codePrestataireAideFi": 1, + "codeTypeAide": 24, + "dateDemandeAide": "2020-09-29", + "datePremierPaiement": null, + "dateReponse": null, + "indexAideFinanciere": 37153, + "indexDossier": 243952, + "indexIndividuDemandeur": 388405, + "individuDemandeur": { + "codeRoleFamille": 3, + "dateNaissance": "1965-08-24", + "indexIndividu": 388405, + "nom": "HUREL", + "prenom": "Jean-Christophe" + }, + "individusConcernes": [], + "montantAccorde": 0, + "montantDemande": 0, + "natureAide": "A", + "nbPersonne": 1, + "prestataireAideFinanciere": { + "codePrestataire": 1, + "indexOrganisme": 1, + "nomCompletOrganisme": "Ministères sociaux", + "nomReduitOrganisme": "Ministère" + }, + "prisesEnCharge": [], + "quotient": 80, + "suiviAide": "En attente", + "typeAideFinanciere": { + "codeCalculQf": 6, + "codeTypeAideFinanciere": 24, + "libelleTypeAideFinanciere": "Séjour camping - 21 jours max (PM)", + "natureTypeAideFinanciere": "A" + } + }, + { + "codeAideFinanciere": 6, + "codeAideGlobale": null, + "codePrestataireAideFi": 1, + "codeTypeAide": 24, + "dateDemandeAide": "2020-09-29", + "datePremierPaiement": null, + "dateReponse": null, + "indexAideFinanciere": 37154, + "indexDossier": 243952, + "indexIndividuDemandeur": 388405, + "individuDemandeur": { + "codeRoleFamille": 3, + "dateNaissance": "1965-08-24", + "indexIndividu": 388405, + "nom": "HUREL", + "prenom": "Jean-Christophe" + }, + "individusConcernes": [], + "montantAccorde": 0, + "montantDemande": 0, + "natureAide": "A", + "nbPersonne": 1, + "prestataireAideFinanciere": { + "codePrestataire": 1, + "indexOrganisme": 1, + "nomCompletOrganisme": "Ministères sociaux", + "nomReduitOrganisme": "Ministère" + }, + "prisesEnCharge": [], + "quotient": 80, + "suiviAide": "En attente", + "typeAideFinanciere": { + "codeCalculQf": 6, + "codeTypeAideFinanciere": 24, + "libelleTypeAideFinanciere": "Séjour camping - 21 jours max (PM)", + "natureTypeAideFinanciere": "A" + } + }, + { + "codeAideFinanciere": 7, + "codeAideGlobale": null, + "codePrestataireAideFi": 1, + "codeTypeAide": 24, + "dateDemandeAide": "2020-09-29", + "datePremierPaiement": null, + "dateReponse": null, + "indexAideFinanciere": 37155, + "indexDossier": 243952, + "indexIndividuDemandeur": 388405, + "individuDemandeur": { + "codeRoleFamille": 3, + "dateNaissance": "1965-08-24", + "indexIndividu": 388405, + "nom": "HUREL", + "prenom": "Jean-Christophe" + }, + "individusConcernes": [], + "montantAccorde": 0, + "montantDemande": 0, + "natureAide": "A", + "nbPersonne": 1, + "prestataireAideFinanciere": { + "codePrestataire": 1, + "indexOrganisme": 1, + "nomCompletOrganisme": "Ministères sociaux", + "nomReduitOrganisme": "Ministère" + }, + "prisesEnCharge": [], + "quotient": 80, + "suiviAide": "En attente", + "typeAideFinanciere": { + "codeCalculQf": 6, + "codeTypeAideFinanciere": 24, + "libelleTypeAideFinanciere": "Séjour camping - 21 jours max (PM)", + "natureTypeAideFinanciere": "A" + } + } + ], + "indexAgent": 388405 +} diff --git a/tests/data/solis_afi_mss/getAidesParAgent_394404.json b/tests/data/solis_afi_mss/getAidesParAgent_394404.json new file mode 100644 index 00000000..89776893 --- /dev/null +++ b/tests/data/solis_afi_mss/getAidesParAgent_394404.json @@ -0,0 +1,4 @@ +{ + "aidesFinancieres": [], + "indexAgent": 394404 +} diff --git a/tests/data/solis_afi_mss/getImposition_388405_2019.json b/tests/data/solis_afi_mss/getImposition_388405_2019.json new file mode 100644 index 00000000..9e3ac953 --- /dev/null +++ b/tests/data/solis_afi_mss/getImposition_388405_2019.json @@ -0,0 +1,7 @@ +{ + "anneeImposition" : 2019, + "indexAgent" : 388405, + "indexImposition" : 363, + "montantImposition" : 1000, + "nombrePartImposition" : 1 +} diff --git a/tests/data/solis_afi_mss/getImpositionsParAgent_388405.json b/tests/data/solis_afi_mss/getImpositionsParAgent_388405.json new file mode 100644 index 00000000..062be56c --- /dev/null +++ b/tests/data/solis_afi_mss/getImpositionsParAgent_388405.json @@ -0,0 +1,16 @@ +[ + { + "anneeImposition": 2018, + "indexAgent": 388405, + "indexImposition": 360, + "montantImposition": 15000, + "nombrePartImposition": 1 + }, + { + "anneeImposition": 2019, + "indexAgent": 388405, + "indexImposition": 363, + "montantImposition": 1000, + "nombrePartImposition": 1 + } +] diff --git a/tests/data/solis_afi_mss/isAlive.json b/tests/data/solis_afi_mss/isAlive.json new file mode 100644 index 00000000..ed5fb16a --- /dev/null +++ b/tests/data/solis_afi_mss/isAlive.json @@ -0,0 +1,3 @@ +{ + "response": "Solis API est opérationnel." +} diff --git a/tests/data/solis_afi_mss/rechercherParEmail_evelyne_pied.json b/tests/data/solis_afi_mss/rechercherParEmail_evelyne_pied.json new file mode 100644 index 00000000..028bc03d --- /dev/null +++ b/tests/data/solis_afi_mss/rechercherParEmail_evelyne_pied.json @@ -0,0 +1,28 @@ +{ + "adresseMailAgent" : "evelyne.pied@sg.social.gouv.fr", + "agent" : { + "dateNaissance" : "1957-06-21", + "indexIndividu" : 388412, + "lieuNaissance" : "", + "nom" : "PIED", + "prenom" : "Louise", + "profession" : null, + "roleFamille" : 3 + }, + "codeConfidentielAgent" : "dWyD23Hr", + "conjointAgent" : null, + "employeurAgent" : "Direction des finances, des achats et des services", + "enfantsAgent" : [ + { + "dateNaissance" : "1997-04-26", + "indexIndividu" : 388413, + "lieuNaissance" : "", + "nom" : "PIED", + "prenom" : "KEVIN", + "profession" : null, + "roleFamille" : 1 + } + ], + "indexAgent" : 388412, + "indexDossier" : 243954 +} diff --git a/tests/data/solis_afi_mss/rechercherParEmail_jacques_rousseau.json b/tests/data/solis_afi_mss/rechercherParEmail_jacques_rousseau.json new file mode 100644 index 00000000..eeadf9f5 --- /dev/null +++ b/tests/data/solis_afi_mss/rechercherParEmail_jacques_rousseau.json @@ -0,0 +1,54 @@ +{ + "adresseMailAgent" : "jacques.rousseau.cts@tiralarc-grand-est.fr", + "agent" : { + "dateNaissance" : "1958-04-03", + "indexIndividu" : 389227, + "lieuNaissance" : "", + "nom" : "ROUSSEAU", + "prenom" : "Jacques", + "profession" : null, + "roleFamille" : 3 + }, + "codeConfidentielAgent" : "DcB1QKAP", + "conjointAgent" : { + "dateNaissance" : null, + "indexIndividu" : 434729, + "lieuNaissance" : "", + "nom" : "DI MARINO", + "prenom" : "Rina", + "profession" : null, + "roleFamille" : 5 + }, + "employeurAgent" : "DRDJSCS Grand Est", + "enfantsAgent" : [ + { + "dateNaissance" : "1995-07-25", + "indexIndividu" : 389229, + "lieuNaissance" : "", + "nom" : "ROUSSEAU", + "prenom" : "Lola", + "profession" : null, + "roleFamille" : 1 + }, + { + "dateNaissance" : "1990-05-04", + "indexIndividu" : 389230, + "lieuNaissance" : "", + "nom" : "ROUSSEAU", + "prenom" : "Nicolas", + "profession" : null, + "roleFamille" : 1 + }, + { + "dateNaissance" : "1992-06-10", + "indexIndividu" : 389231, + "lieuNaissance" : "", + "nom" : "ROUSSEAU", + "prenom" : "Mélina", + "profession" : null, + "roleFamille" : 1 + } + ], + "indexAgent" : 389227, + "indexDossier" : 244226 +} diff --git a/tests/data/solis_afi_mss/rechercherParEmail_jean_christophe_hurel.json b/tests/data/solis_afi_mss/rechercherParEmail_jean_christophe_hurel.json new file mode 100644 index 00000000..2267edb6 --- /dev/null +++ b/tests/data/solis_afi_mss/rechercherParEmail_jean_christophe_hurel.json @@ -0,0 +1,45 @@ +{ + "adresseMailAgent" : "jean-christophe.hurel@sante.gouv.fr", + "agent" : { + "dateNaissance" : "1965-08-24", + "indexIndividu" : 388405, + "lieuNaissance" : "", + "nom" : "HUREL", + "prenom" : "Jean-Christophe", + "profession" : null, + "roleFamille" : 3 + }, + "codeConfidentielAgent" : "wd5rGSMv", + "conjointAgent" : { + "dateNaissance" : null, + "indexIndividu" : 434727, + "lieuNaissance" : "", + "nom" : "HUREL", + "prenom" : "CAROLE", + "profession" : null, + "roleFamille" : 5 + }, + "employeurAgent" : "Cabinets - DDC", + "enfantsAgent" : [ + { + "dateNaissance" : "1991-08-24", + "indexIndividu" : 388407, + "lieuNaissance" : "", + "nom" : "HUREL", + "prenom" : "Camille", + "profession" : null, + "roleFamille" : 1 + }, + { + "dateNaissance" : "1996-08-05", + "indexIndividu" : 388408, + "lieuNaissance" : "", + "nom" : "HUREL", + "prenom" : "Valentin", + "profession" : null, + "roleFamille" : 1 + } + ], + "indexAgent" : 388405, + "indexDossier" : 243952 +} diff --git a/tests/data/solis_afi_mss/rechercherParEmail_marie_noelle_basdevant.json b/tests/data/solis_afi_mss/rechercherParEmail_marie_noelle_basdevant.json new file mode 100644 index 00000000..48d46692 --- /dev/null +++ b/tests/data/solis_afi_mss/rechercherParEmail_marie_noelle_basdevant.json @@ -0,0 +1,26 @@ +{ + "adresseMailAgent" : "marie-noelle.basdevant@jeunesse-sports.gouv.fr", + "agent" : { + "dateNaissance" : "1967-12-31", + "indexIndividu" : 388420, + "lieuNaissance" : "", + "nom" : "BASDEVANT", + "prenom" : "Marie-Noëlle", + "profession" : "", + "roleFamille" : 3 + }, + "codeConfidentielAgent" : "Xi7pE4Cj", + "conjointAgent" : { + "dateNaissance" : null, + "indexIndividu" : 434728, + "lieuNaissance" : "", + "nom" : "BARTOLOMEO", + "prenom" : "PIETRO", + "profession" : null, + "roleFamille" : 5 + }, + "employeurAgent" : "Direction de la Jeunesse, de l'Education Populaire", + "enfantsAgent" : [], + "indexAgent" : 388420, + "indexDossier" : 243957 +} diff --git a/tests/data/solis_afi_mss/rechercherParEmail_michelle.delaunay.json b/tests/data/solis_afi_mss/rechercherParEmail_michelle.delaunay.json new file mode 100644 index 00000000..5d0d1c77 --- /dev/null +++ b/tests/data/solis_afi_mss/rechercherParEmail_michelle.delaunay.json @@ -0,0 +1,18 @@ +{ + "adresseMailAgent" : "michelle.delaunay@direccte.gouv.fr", + "agent" : { + "dateNaissance" : "1964-06-10", + "indexIndividu" : 394404, + "lieuNaissance" : "", + "nom" : "DELAUNAY", + "prenom" : "Michelle", + "profession" : null, + "roleFamille" : 3 + }, + "codeConfidentielAgent" : "tU8hLPuD", + "conjointAgent" : null, + "employeurAgent" : "DIRECCTE Provence-Alpes-Côte d'Azur-UD13", + "enfantsAgent" : [], + "indexAgent" : 394404, + "indexDossier" : 245978 +} diff --git a/tests/settings.py b/tests/settings.py index fac70d0b..ae8f8c66 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -29,6 +29,7 @@ INSTALLED_APPS += ( 'passerelle.contrib.nancypoll', 'passerelle.contrib.planitech', 'passerelle.contrib.solis_apa', + 'passerelle.contrib.solis_afi_mss', 'passerelle.contrib.strasbourg_eu', 'passerelle.contrib.stub_invoices', 'passerelle.contrib.teamnet_axel', diff --git a/tests/test_solis_afi_mss.py b/tests/test_solis_afi_mss.py new file mode 100644 index 00000000..4a8b0140 --- /dev/null +++ b/tests/test_solis_afi_mss.py @@ -0,0 +1,478 @@ +# passerelle - uniform access to multiple data sources and services +# Copyright (C) 2020 Entr'ouvert +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import json +import os + +import mock +import pytest + +import utils + +from passerelle.contrib.solis_afi_mss.models import SolisAfiMss +from passerelle.utils.jsonresponse import APIError + +@pytest.fixture +def connector(db): + return utils.setup_access_rights(SolisAfiMss.objects.create( + slug='test', + base_url='https://dummy-server.org' + )) + + +TEST_BASE_DIR = os.path.join(os.path.dirname(__file__), 'data', 'solis_afi_mss') + +def json_get_data(filename): + with open(os.path.join(TEST_BASE_DIR, "%s.json" % filename)) as fd: + return json.dumps(json.load(fd)) + +def response(status_code, content): + return utils.FakedResponse(content=content, status_code=status_code) + + +IS_ALIVE = response(200, json_get_data('isAlive')) + +ERROR_MSG = 'Solis API MSS AFI - Erreur: XXX' +ERROR = response(400, json_get_data('error')) + +RECHERCHE_PAR_EMAIL_1 = response(200, json_get_data('rechercherParEmail_jacques_rousseau')) +RECHERCHE_PAR_EMAIL_2 = response(200, json_get_data('rechercherParEmail_michelle.delaunay')) +RECHERCHE_PAR_EMAIL_3 = response(200, json_get_data('rechercherParEmail_evelyne_pied')) +RECHERCHE_PAR_EMAIL_4 = response(200, json_get_data('rechercherParEmail_marie_noelle_basdevant')) +RECHERCHE_PAR_EMAIL_5 = response(200, json_get_data('rechercherParEmail_jean_christophe_hurel')) + +GET_IMPOSITION_PAR_AGENT_5 = response(200, json_get_data('getImpositionsParAgent_388405')) +GET_IMPOSITION_5 = response(200, json_get_data('getImposition_388405_2019')) +GET_IMPOSITION_2 = response(204, "") +GET_IMPOSITION_0 = response(200, "") + +DECLARER_IMPOT_1 = response(200, json_get_data('declarerImpot_389227')) +CALCULER_1 = response(200, json_get_data('calculer')) +DEPOSER_5 = response(200, json_get_data('deposer_388405')) + +GET_AIDES_PAR_AGENT_2 = response(200, json_get_data('getAidesParAgent_394404')) +GET_AIDES_PAR_AGENT_5 = response(200, json_get_data('getAidesParAgent_388405')) + + +def get_endpoint(name): + return utils.generic_endpoint_url('solis-afi-mss', name) + + +@mock.patch('passerelle.utils.Request.get') +@pytest.mark.parametrize('status_code, json_content, a_dict', [ + (200, 'not json', None), + (500, '{"message": "help"}', {'message': 'help'}), + (500, 'not json', None), +]) +def test_request_error(mocked_get, app, connector, status_code, json_content, a_dict): + mocked_get.side_effect = [response(status_code, json_content)] + with pytest.raises(APIError) as exc: + connector.request('some-url') + assert exc.value.err + if status_code == 200: + exc.value.http_status == 200 + exc.value.args[0] == "invalid JSON content:'%s'" % json_content + else: + assert exc.value.data['status_code'] == status_code + assert exc.value.data['json_content'] == a_dict + + +@mock.patch('passerelle.utils.Request.get') +def test_check_status(mocked_get, app, connector): + mocked_get.side_effect = [IS_ALIVE] + connector.check_status() + assert mocked_get.mock_calls == [mock.call( + 'https://dummy-server.org/main/isAlive/', + headers={'Accept': 'application/json'}, + params=None + )] + + +@mock.patch('passerelle.utils.Request.get') +def test_check_status_error(mocked_get, app, connector): + mocked_get.side_effect = [response(500, '')] + with pytest.raises(APIError): + connector.check_status() + + +@mock.patch('passerelle.utils.Request.get') +@pytest.mark.parametrize('response1, adults, children', [ + (RECHERCHE_PAR_EMAIL_1, [ + (389227, 'Jacques ROUSSEAU'), + (434729, 'Rina DI MARINO'), + ], [ + (389229, 'Lola ROUSSEAU'), + (389230, 'Nicolas ROUSSEAU'), + (389231, 'Mélina ROUSSEAU'), + ]), + (RECHERCHE_PAR_EMAIL_2, [ + (394404, 'Michelle DELAUNAY'), + ], []), + (RECHERCHE_PAR_EMAIL_3, [ + (388412, 'Louise PIED'), + ], [ + (388413, 'KEVIN PIED'), + ]), + (RECHERCHE_PAR_EMAIL_4, [ + (388420, 'Marie-Noëlle BASDEVANT'), + (434728, 'PIETRO BARTOLOMEO'), + ], []), + (RECHERCHE_PAR_EMAIL_5, [ + (388405, 'Jean-Christophe HUREL'), + (434727, 'CAROLE HUREL'), + ], [ + (388407, 'Camille HUREL'), + (388408, 'Valentin HUREL'), + ]), +]) +def test_search_from_email(mocked_get, app, connector, response1, adults, children): + mocked_get.side_effect = [response1] + result = connector.search_from_email('foo@dummy.org') + assert mocked_get.mock_calls == [mock.call( + 'https://dummy-server.org/afi/agent/rechercherParEmail/', + headers={'Accept': 'application/json'}, + params={'adresseMail': 'foo@dummy.org'})] + assert result[0] == adults[0][0] # agent index + assert [(x['id'], x['text']) for x in result[1]] == adults + assert [(x['id'], x['text']) for x in result[2]] == children + + +@mock.patch('passerelle.utils.Request.get') +def test_search_from_email_error(mocked_get, app, connector): + mocked_get.side_effect = [ERROR] + with pytest.raises(APIError) as exc: + connector.search_from_email('foo@dummy.org') + exc.value.data['status_code'] == 400 + exc.value.data['json_content'][0]['message'] == ERROR_MSG + assert mocked_get.mock_calls == [mock.call( + 'https://dummy-server.org/afi/agent/rechercherParEmail/', + headers={'Accept': 'application/json'}, + params={'adresseMail': 'foo@dummy.org'})] + + +@mock.patch('passerelle.utils.Request.get') +@pytest.mark.parametrize('response1, family', [ + (RECHERCHE_PAR_EMAIL_1, [ + (389227, 'Jacques ROUSSEAU'), + (434729, 'Rina DI MARINO'), + (389229, 'Lola ROUSSEAU'), + (389230, 'Nicolas ROUSSEAU'), + (389231, 'Mélina ROUSSEAU'), + ]), + (RECHERCHE_PAR_EMAIL_2, [ + (394404, 'Michelle DELAUNAY'), + ]), + (RECHERCHE_PAR_EMAIL_3, [ + (388412, 'Louise PIED'), + (388413, 'KEVIN PIED'), + ]), + (RECHERCHE_PAR_EMAIL_4, [ + (388420, 'Marie-Noëlle BASDEVANT'), + (434728, 'PIETRO BARTOLOMEO'), + ]), + (RECHERCHE_PAR_EMAIL_5, [ + (388405, 'Jean-Christophe HUREL'), + (434727, 'CAROLE HUREL'), + (388407, 'Camille HUREL'), + (388408, 'Valentin HUREL'), + ]), +]) +def test_family(mocked_get, app, connector, response1, family): + mocked_get.side_effect = [response1] + endpoint = get_endpoint('family') + '?email=foo@dummy.org' + resp = app.get(endpoint) + assert not resp.json['err'] + assert [(x['id'], x['text']) for x in resp.json['data']] == family + + +@mock.patch('passerelle.utils.Request.get') +def test_family_error(mocked_get, app, connector): + mocked_get.side_effect = [ERROR] + endpoint = get_endpoint('family') + '?email=foo@dummy.org' + resp = app.get(endpoint) + assert resp.json['err'] + assert ERROR_MSG in resp.json['err_desc'] + assert resp.json['data']['json_content'][0]['message'] == ERROR_MSG + + +@mock.patch('passerelle.utils.Request.get') +@pytest.mark.parametrize('response1, adults', [ + (RECHERCHE_PAR_EMAIL_1, [ + (389227, 'Jacques ROUSSEAU'), + (434729, 'Rina DI MARINO'), + ]), + (RECHERCHE_PAR_EMAIL_2, [ + (394404, 'Michelle DELAUNAY'), + ]), + (RECHERCHE_PAR_EMAIL_3, [ + (388412, 'Louise PIED'), + ]), + (RECHERCHE_PAR_EMAIL_4, [ + (388420, 'Marie-Noëlle BASDEVANT'), + (434728, 'PIETRO BARTOLOMEO'), + ]), + (RECHERCHE_PAR_EMAIL_5, [ + (388405, 'Jean-Christophe HUREL'), + (434727, 'CAROLE HUREL'), + ]), +]) +def test_adults(mocked_get, app, connector, response1, adults): + mocked_get.side_effect = [response1] + endpoint = get_endpoint('adults') + '?email=foo@dummy.org' + resp = app.get(endpoint) + assert not resp.json['err'] + assert [(x['id'], x['text']) for x in resp.json['data']] == adults + + +@mock.patch('passerelle.utils.Request.get') +@pytest.mark.parametrize('response1, children', [ + (RECHERCHE_PAR_EMAIL_1, [ + (389229, 'Lola ROUSSEAU'), + (389230, 'Nicolas ROUSSEAU'), + (389231, 'Mélina ROUSSEAU'), + ]), + (RECHERCHE_PAR_EMAIL_2, [ + ]), + (RECHERCHE_PAR_EMAIL_3, [ + (388413, 'KEVIN PIED'), + ]), + (RECHERCHE_PAR_EMAIL_4, [ + ]), + (RECHERCHE_PAR_EMAIL_5, [ + (388407, 'Camille HUREL'), + (388408, 'Valentin HUREL'), + ]), +]) +def test_children(mocked_get, app, connector, response1, children): + mocked_get.side_effect = [response1] + endpoint = get_endpoint('children') + '?email=foo@dummy.org' + resp = app.get(endpoint) + assert not resp.json['err'] + assert [(x['id'], x['text']) for x in resp.json['data']] == children + + +@mock.patch('passerelle.utils.Request.get') +@pytest.mark.parametrize('response1, response2, taxes', [ + (RECHERCHE_PAR_EMAIL_5, GET_IMPOSITION_PAR_AGENT_5, + [(2018, '2018: 15000'), (2019, '2019: 1000')]) +]) +def test_taxes(mocked_get, app, connector, response1, response2, taxes): + mocked_get.side_effect = [response1, response2] + endpoint = get_endpoint('taxes') + '?email=foo@dummy.org' + resp = app.get(endpoint) + assert mocked_get.mock_calls[1] == mock.call( + 'https://dummy-server.org/afi/budget/getImpositionsParAgent/', + headers={'Accept': 'application/json'}, + params={'indexAgent': str(json.loads(response1.content)['indexAgent'])}) + assert not resp.json['err'] + assert [(x['id'], x['text']) for x in resp.json['data']] == taxes + + +@mock.patch('passerelle.utils.Request.get') +@pytest.mark.parametrize('response1, response2, tax', [ + (RECHERCHE_PAR_EMAIL_5, GET_IMPOSITION_5, 1000), + (RECHERCHE_PAR_EMAIL_5, GET_IMPOSITION_2, None), + (RECHERCHE_PAR_EMAIL_5, GET_IMPOSITION_0, None), +]) +def test_taxes_for_year(mocked_get, app, connector, response1, response2, tax): + mocked_get.side_effect = [response1, response2] + endpoint = get_endpoint('taxes') + '?email=foo@dummy.org&year=2019' + resp = app.get(endpoint) + assert mocked_get.mock_calls[1] == mock.call( + 'https://dummy-server.org/afi/budget/getImposition/', + headers={'Accept': 'application/json'}, + params={ + 'indexAgent': str(json.loads(response1.content)['indexAgent']), + 'anneeImposition': '2019'}) + assert not resp.json['err'] + if tax: + assert len(resp.json['data']) == 1 + assert resp.json['data'][0]['montantImposition'] == tax + else: + assert resp.json['data'] == [] + + +@mock.patch('passerelle.utils.Request.get') +@pytest.mark.parametrize('response1, response2', [ + (ERROR, None) +]) +def test_taxes_error(mocked_get, app, connector, response1, response2): + mocked_get.side_effect = [response1, response2] + endpoint = get_endpoint('taxes') + '?email=foo@dummy.org' + resp = app.get(endpoint) + assert resp.json['err'] + assert resp.json['data']['json_content'][0]['message'] == ERROR_MSG + + +@mock.patch('passerelle.utils.Request.get') +@mock.patch('passerelle.utils.Request.post') +@pytest.mark.parametrize('response1, response2', [ + (RECHERCHE_PAR_EMAIL_1, DECLARER_IMPOT_1), +]) +def test_declare_tax(mocked_post, mocked_get, app, connector, response1, response2): + mocked_get.side_effect = [response1] + mocked_post.side_effect = [response2] + endpoint = get_endpoint('declare-tax') + payload = { + 'email': 'foo@dummy.org', + 'indexImposition': '222', + 'anneeImposition': '2020', + 'nombrePartImposition': '3.2', + 'montantImposition': '777.77', + } + resp = app.post_json(endpoint, params=payload) + assert mocked_post.mock_calls == [mock.call( + 'https://dummy-server.org/afi/budget/declarerImpot/', + headers={'Accept': 'application/json'}, + json={ + 'indexAgent': '389227', + 'indexImposition': '222', + 'anneeImposition': '2020', + 'nombrePartImposition': '3.2', + 'montantImposition': '777.77', + })] + assert resp.json == {'err': 0, 'data': json.loads(response2.content)} + + +@mock.patch('passerelle.utils.Request.get') +@mock.patch('passerelle.utils.Request.post') +@pytest.mark.parametrize('response1, response2', [ + (ERROR, None), + (RECHERCHE_PAR_EMAIL_5, ERROR), +]) +def test_declare_tax_error(mocked_post, mocked_get, app, connector, response1, response2): + mocked_get.side_effect = [response1] + mocked_post.side_effect = [response2] + endpoint = get_endpoint('declare-tax') + payload = { + 'email': 'foo@dummy.org', + 'indexImposition': '222', + 'anneeImposition': '2020', + 'nombrePartImposition': '3.2', + 'montantImposition': '777.77', + } + resp = app.post_json(endpoint, params=payload) + assert resp.json['err'] + assert resp.json['data']['json_content'][0]['message'] == ERROR_MSG + + +@mock.patch('passerelle.utils.Request.get') +@pytest.mark.parametrize('response1, ratio', [ + (CALCULER_1, 52.33), +]) +def test_simulate_quotient(mocked_get, app, connector, response1, ratio): + mocked_get.side_effect = [response1] + endpoint = get_endpoint('simulate-quotient') + '?code=2&nb_parts=2.2&amount=222.22' + resp = app.get(endpoint) + assert mocked_get.mock_calls == [mock.call( + 'https://dummy-server.org/afi/budget/calculer/', + headers={'Accept': 'application/json'}, + params={'codeCalcul': '2', 'nbrPartImposition': '2.2', 'mntImposition': '222.22'})] + assert resp.json == {'err': 0, 'data': json.loads(response1.content)} + assert resp.json['data']['resultatCalcul'] == ratio + + +@mock.patch('passerelle.utils.Request.get') +def test_simulate_quotient_error(mocked_get, app, connector): + mocked_get.side_effect = [ERROR] + endpoint = get_endpoint('simulate-quotient') + '?code=2&nb_parts=2.2&amount=222.22' + resp = app.get(endpoint) + assert resp.json['err'] + assert resp.json['data']['json_content'][0]['message'] == ERROR_MSG + + +@mock.patch('passerelle.utils.Request.get') +@pytest.mark.parametrize('response1, response2, helps', [ + (RECHERCHE_PAR_EMAIL_5, GET_AIDES_PAR_AGENT_2, []), + (RECHERCHE_PAR_EMAIL_5, GET_AIDES_PAR_AGENT_5, [ + (37145, '2020-05-26 (En attente)'), + (37146, '2020-05-26 (En attente)'), + (37149, '2020-06-11 (En attente)'), + (37152, '2020-09-29 (En attente)'), + (37153, '2020-09-29 (En attente)'), + (37154, '2020-09-29 (En attente)'), + (37155, '2020-09-29 (En attente)')]), +]) +def test_helps(mocked_get, app, connector, response1, response2, helps): + mocked_get.side_effect = [response1, response2] + endpoint = get_endpoint('helps') + '?email=foo@dummy.org' + resp = app.get(endpoint) + assert mocked_get.mock_calls[1] == mock.call( + 'https://dummy-server.org/afi/aide/getAidesParAgent/', + headers={'Accept': 'application/json'}, + params={'indexAgent': str(json.loads(response1.content)['indexAgent'])}) + assert not resp.json['err'] + assert [(x['id'], x['text']) for x in resp.json['data']] == helps + + +@mock.patch('passerelle.utils.Request.get') +@mock.patch('passerelle.utils.Request.post') +@pytest.mark.parametrize('response1, response2', [ + (RECHERCHE_PAR_EMAIL_5, DEPOSER_5), +]) +def test_demand_help(mocked_post, mocked_get, app, connector, response1, response2): + mocked_get.side_effect = [response1] + mocked_post.side_effect = [response2] + endpoint = get_endpoint('demand-help') + + payload = { + 'email': 'foo@dummy.org', + 'codeTypeAide': '24', + 'natureTypeAide': 'A', + 'individusConcernes': '388407:388408', + 'dateDebut': '2020-07-15', + 'dateFin': '2020-07-31', + 'montantFacture': '2222.22', + } + resp = app.post_json(endpoint, params=payload) + assert mocked_post.mock_calls == [mock.call( + 'https://dummy-server.org/afi/aide/deposer/', + headers={'Accept': 'application/json'}, + json={ + 'indexAgent': '388405', + 'codeTypeAide': '24', + 'natureTypeAide': 'A', + 'individusConcernes': [{'indexIndividu': '388407'}, {'indexIndividu': '388408'}], + 'dateDebut': '2020-07-15', + 'dateFin': '2020-07-31', + 'montantFacture': '2222.22' + })] + assert resp.json == {'err': 0, 'data': json.loads(response2.content)} + + +@mock.patch('passerelle.utils.Request.get') +@mock.patch('passerelle.utils.Request.post') +@pytest.mark.parametrize('response1, response2', [ + (ERROR, None), + (RECHERCHE_PAR_EMAIL_5, ERROR), +]) +def test_demand_help_error(mocked_post, mocked_get, app, connector, response1, response2): + mocked_get.side_effect = [response1] + mocked_post.side_effect = [response2] + endpoint = get_endpoint('demand-help') + + payload = { + 'email': 'foo@dummy.org', + 'codeTypeAide': '24', + 'natureTypeAide': 'A', + 'individusConcernes': '388407:388408', + 'dateDebut': '2020-07-15', + 'dateFin': '2020-07-31', + 'montantFacture': '2222.22', + } + resp = app.post_json(endpoint, params=payload) + assert resp.json['err'] + assert resp.json['data']['json_content'][0]['message'] == ERROR_MSG