From 1b8378584ceb5e4ca6154b12127c8e91305499e4 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Thu, 28 May 2020 17:04:48 +0200 Subject: [PATCH] add avis imposition --- passerelle/apps/avis_imposition/__init__.py | 0 .../migrations/0001_initial.py | 30 +++ passerelle/apps/avis_imposition/models.py | 193 ++++++++++++++++++ passerelle/settings.py | 1 + setup.py | 1 + tests/data/avis-imposition.html | 85 ++++++++ tests/data/avis-imposition.json | 52 +++++ tests/test_avis_imposition.py | 116 +++++++++++ 8 files changed, 478 insertions(+) create mode 100644 passerelle/apps/avis_imposition/__init__.py create mode 100644 passerelle/apps/avis_imposition/migrations/0001_initial.py create mode 100644 passerelle/apps/avis_imposition/models.py create mode 100644 tests/data/avis-imposition.html create mode 100644 tests/data/avis-imposition.json create mode 100644 tests/test_avis_imposition.py diff --git a/passerelle/apps/avis_imposition/__init__.py b/passerelle/apps/avis_imposition/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/passerelle/apps/avis_imposition/migrations/0001_initial.py b/passerelle/apps/avis_imposition/migrations/0001_initial.py new file mode 100644 index 00000000..b205680f --- /dev/null +++ b/passerelle/apps/avis_imposition/migrations/0001_initial.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2020-05-28 19:49 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('base', '0020_auto_20200515_1923'), + ] + + operations = [ + migrations.CreateModel( + name='AvisImposition', + 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')), + ('users', models.ManyToManyField(blank=True, related_name='_avisimposition_users_+', related_query_name='+', to='base.ApiUser')), + ], + options={ + 'verbose_name': 'API Particulier', + }, + ), + ] diff --git a/passerelle/apps/avis_imposition/models.py b/passerelle/apps/avis_imposition/models.py new file mode 100644 index 00000000..4fb300b7 --- /dev/null +++ b/passerelle/apps/avis_imposition/models.py @@ -0,0 +1,193 @@ +# coding: utf-8 +# passerelle - uniform access to multiple data sources and services +# Copyright (C) 2017 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 . + +'''Interface with "Service de vérification des avis" of impots.gouv.fr +''' + +from __future__ import unicode_literals + +import decimal +import logging +import re + +import lxml.html +import requests + +from django.utils.translation import ugettext_lazy as _ +from django.utils.six.moves.urllib_parse import urljoin + +from passerelle.base.models import BaseResource +from passerelle.utils.api import endpoint +from passerelle.utils.jsonresponse import APIError +from passerelle.utils.xml import text_content + +AVIS_IMPOSITION_GOUV_FR_URL = 'https://cfsmsp.impots.gouv.fr/secavis/' + + +def remove_spaces(value): + return re.sub(r'\s', '', value) + + +FIELD_INDEXES = { + 'nom_declarant_1': 4, + 'nom_declarant_2': 5, + 'nom_de_naissance_declarant_1': 7, + 'nom_de_naissance_declarant_2': 8, + 'prenom_declarant_1': 10, + 'prenom_declarant_2': 11, + 'date_de_naissance_declarant_1': 13, + 'date_de_naissance_declarant_2': 14, + 'adresse_ligne_1': 16, + 'adresse_ligne_2': 19, + 'adresse_ligne_3': 21, + 'nombre_de_parts': 28, + 'situation_familiale': 30, + 'revenu_brut_global': 34, + 'revenu_imposable': 36, + 'impot_avant_correction': 38, + 'revenu_fiscal_de_reference': 42, +} + + +def nombre_de_parts(value): + try: + return decimal.Decimal(value) + except (ValueError, TypeError): + return None + + +def euros(value): + if not value: + return None + value = remove_spaces(value) + value = value.rstrip('€') + return int(value) + + +def situation_familiale(value): + if value == 'Pacs\xe9(e)s': + return 'pacs' + if value == 'Mari\xe9(e)s': + return 'mariage' + if value == 'Divorc\xe9(e)': + return 'divorce' + if value == 'C\xe9libataire': + return 'celibataire' + raise NotImplementedError(value) + + +ADAPTERS = { + 'nombre_de_parts': nombre_de_parts, + 'revenu_brut_global': euros, + 'revenu_imposable': euros, + 'impot_avant_correction': euros, + 'revenu_fiscal_de_reference': euros, + 'situation_familiale': situation_familiale, +} + + +def get_form(logger=None): + logger = logger or logging + try: + response = requests.get(AVIS_IMPOSITION_GOUV_FR_URL) + response.raise_for_status() + except requests.RequestException as e: + raise APIError('service-is-down', data=str(e)) + + if 'Saisissez les identifiants' not in response.text: + raise RuntimeError('service has changed') + + html = lxml.html.fromstring(response.content) + data = {} + for form_elt in html.xpath('//form'): + if 'action' not in form_elt.attrib: + continue + action_url = form_elt.attrib['action'] + break + else: + raise RuntimeError('service has changed') + logger.debug('using found action_url %s', action_url) + + for input_elt in html.xpath('//input'): + if 'value' in input_elt.attrib: + data[input_elt.attrib['name']] = input_elt.attrib['value'] + + return action_url, data + + +def get_avis_imposition(numero_fiscal, reference_avis, logger=None): + logger = logger or logging + + action_url, data = get_form() + data['j_id_7:spi'] = numero_fiscal + data['j_id_7:num_facture'] = reference_avis + + logger.debug('sending data %s', data) + + try: + response = requests.post(urljoin(AVIS_IMPOSITION_GOUV_FR_URL, action_url), params=data) + response.raise_for_status() + except requests.RequestException as e: + raise APIError('service-is-down', data=str(e)) + + if 'Saisissez les identifiants' in response.text: + raise APIError('not-found') + + response_html = lxml.html.fromstring(response.content) + td_contents = [text_content(td).strip() for td in response_html.xpath('//td')] + + logger.debug('got td_contents %s', td_contents) + + data = {} + for field, index in FIELD_INDEXES.items(): + try: + data[field] = td_contents[index] or '' + except IndexError: + raise RuntimeError('service has changed') + if field in ADAPTERS: + data[field] = ADAPTERS[field](data[field]) + for situation_partielle_elt in response_html.xpath('//*[@id="situationPartielle"]'): + data['situation_partielle'] = text_content(situation_partielle_elt).strip() + break + return data + + +class AvisImposition(BaseResource): + @endpoint(perm='can_access', + description=_('Get citizen\'s fiscal informations'), + parameters={ + 'numero_fiscal': { + 'description': _('fiscal identifier'), + 'example_value': '1562456789521', + }, + 'reference_avis': { + 'description': _('tax notice number'), + 'example_value': '1512456789521', + }, + }) + def verify(self, request, numero_fiscal, reference_avis): + numero_fiscal = remove_spaces(numero_fiscal) + reference_avis = remove_spaces(reference_avis) + return {'data': get_avis_imposition(numero_fiscal, reference_avis)} + + def check_status(self): + get_form() + + category = _('Business Process Connectors') + + class Meta: + verbose_name = _('API Particulier') diff --git a/passerelle/settings.py b/passerelle/settings.py index 9bf601e7..85e16338 100644 --- a/passerelle/settings.py +++ b/passerelle/settings.py @@ -129,6 +129,7 @@ INSTALLED_APPS = ( 'passerelle.apps.astregs', 'passerelle.apps.atal', 'passerelle.apps.atos_genesys', + 'passerelle.apps.avis_imposition', 'passerelle.apps.base_adresse', 'passerelle.apps.bdp', 'passerelle.apps.cartads_cs', diff --git a/setup.py b/setup.py index 3d7390a4..8768963d 100755 --- a/setup.py +++ b/setup.py @@ -110,6 +110,7 @@ setup(name='passerelle', 'httplib2', 'xmlschema', 'pytz', + 'twill>=2', ], cmdclass={ 'build': build, diff --git a/tests/data/avis-imposition.html b/tests/data/avis-imposition.html new file mode 100644 index 00000000..d802c1ef --- /dev/null +++ b/tests/data/avis-imposition.html @@ -0,0 +1,85 @@ + + + + +Impots.gouv.fr - Service de vérification en ligne des avis + + + + + + + +
+
+
+
+
+
+ + +

Le service permet de vérifier l'authenticité des avis (Impôt sur le revenu) présentés par un usager

+
+
Accès au service de vérification
+
+
Saisissez les identifiants
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+
+ aideSPI +
+
+ aideReferenceAvis +
+
+
+ +
+
+ +
+
+
+
* données obligatoires
+
+
© Ministère de l'Économie et des Finances
+
+ +
\ No newline at end of file diff --git a/tests/data/avis-imposition.json b/tests/data/avis-imposition.json new file mode 100644 index 00000000..3414ef07 --- /dev/null +++ b/tests/data/avis-imposition.json @@ -0,0 +1,52 @@ +[ + { + "numero_fiscal": "1234", + "reference_avis": "abcd", + "response": "\n\n\t\n\n\n\nImpots.gouv.fr - Service de v\u00e9rification en ligne des avis\n\n\n\n\n\n
\n
\n\t\t\t
\"\"
\n\t\t\t
\"\"
\n
\n
\n
\nL'administration fiscale certifie l'authenticit\u00e9 du document pr\u00e9sent\u00e9 pour les donn\u00e9es suivantes :\n
\n\n
\nImp\u00f4t 2019 sur les revenus de l'ann\u00e9e 2018 \n\n
\t\t\n\t\t\n\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\n\n\t\t\t
\n\t\t\t\t\tD\u00e9clarant 1\n\t\t\t\t\tD\u00e9clarant 2\n\t\t\t\t\t
Nom\n\t\t\t\t\tDOE\n\t\t\t\t\tDOE\n\t\t\t\t\t
Nom de naissance\n\t\t\t\t\tDOE\n\t\t\t\t\tDOE\n\t\t\t\t\t
Pr\u00e9nom(s)\n\t\t\t\t\tJOHN\n\t\t\t\t\tJANE\n\t\t\t\t\t
Date de naissance\n\t\t\t\t\t01/01/1970\n\t\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\t\tAdresse d\u00e9clar\u00e9e au 1er janvier 2019\n\t\t\t\t\tRÉSIDENCE DU CALVAIRE\n\t\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\tRUE VICTOR HUGO\n\t\t\t\t\t
\n\t\t\t\t\t75014 PARIS\n\t\t\t\t\t
Date de mise en recouvrement de l'avis d'imp\u00f4t\n\t\t\t\t\t31/12/2019\n\t\t\t\t\t
Date d'\u00e9tablissement\n\t\t\t\t\t09/12/2019\n\t\t\t\t\t
Nombre de part(s)\n\t\t\t\t\t4.00\n\t\t\t\t\t
Situation de famille\n\t\t\t\t\tPacs\u00e9(e)s\n\t\t\t\t\t
Nombre de personne(s) \u00e0 charge\n\t\t\t\t\t4\n\t\t\t\t\t
Revenu brut global\n\t\t\t\t\t48\u00a0473 \u20ac\n\t\t\t\t\t
Revenu imposable\n\t\t\t\t\t48\u00a0473 \u20ac\n\t\t\t\t\t
Imp\u00f4t sur le revenu net avant corrections\n\t\t\t\t\t112 \u20ac\n\t\t\t\t\t
Montant de l'imp\u00f4t\n\t\t\t\t\tNon imposable\n\t\t\t\t\t
Revenu fiscal de r\u00e9f\u00e9rence\n\t\t\t\t\t48\u00a0473 \u20ac\n\t\t\t\t\t
\n\t\t\t\n\t\t\t
\n\t\t\t
\n\t\t\t\t\n\t\t\t\n\n\t\t
\n\t\t
\u00a9 Minist\u00e8re de l'\u00c9conomie et des Finances
\"\"\n\t
\n\n", + "result": { + "adresse_ligne_1": "RÉSIDENCE DU CALVAIRE", + "adresse_ligne_2": "RUE VICTOR HUGO", + "adresse_ligne_3": "75014 PARIS", + "date_de_naissance_declarant_1": "01/01/1970", + "date_de_naissance_declarant_2": "", + "impot_avant_correction": 112, + "nom_de_naissance_declarant_1": "DOE", + "nom_de_naissance_declarant_2": "DOE", + "nom_declarant_1": "DOE", + "nom_declarant_2": "DOE", + "nombre_de_parts": "4.00", + "prenom_declarant_1": "JOHN", + "prenom_declarant_2": "JANE", + "revenu_brut_global": 48473, + "revenu_fiscal_de_reference": 48473, + "revenu_imposable": 48473, + "situation_familiale": "pacs", + "situation_partielle": "" + } + }, + { + "numero_fiscal": "1234", + "reference_avis": "abcd", + "response": "\n\n\t\n\n\n\nImpots.gouv.fr - Service de v\u00e9rification en ligne des avis\n\n\n\n\n\n
\n
\n\t\t\t
\"\"
\n\t\t\t
\"\"
\n
\n
\n
\nL'administration fiscale certifie l'authenticit\u00e9 du document pr\u00e9sent\u00e9 pour les donn\u00e9es suivantes :\n
\n\n
\nImp\u00f4t 2019 sur les revenus de l'ann\u00e9e 2018 \n\n
\t\t\n\t\t\n\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\n\n\t\t\t
\n\t\t\t\t\tD\u00e9clarant 1\n\t\t\t\t\tD\u00e9clarant 2\n\t\t\t\t\t
Nom\n\t\t\t\t\tDOE\n\t\t\t\t\t\n\t\t\t\t\t
Nom de naissance\n\t\t\t\t\tDOE\n\t\t\t\t\t\n\t\t\t\t\t
Pr\u00e9nom(s)\n\t\t\t\t\tJOHN\n\t\t\t\t\t\n\t\t\t\t\t
Date de naissance\n\t\t\t\t\t01/01/1970\n\t\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\t\tAdresse d\u00e9clar\u00e9e au 1er janvier 2019\n\t\t\t\t\tRÉSIDENCE DU CALVAIRE\n\t\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\tRUE VICTOR HUGO\n\t\t\t\t\t
\n\t\t\t\t\t75014 PARIS\n\t\t\t\t\t
Date de mise en recouvrement de l'avis d'imp\u00f4t\n\t\t\t\t\t31/07/2019\n\t\t\t\t\t
Date d'\u00e9tablissement\n\t\t\t\t\t09/07/2019\n\t\t\t\t\t
Nombre de part(s)\n\t\t\t\t\t2.00\n\t\t\t\t\t
Situation de famille\n\t\t\t\t\tDivorc\u00e9(e)\n\t\t\t\t\t
Nombre de personne(s) \u00e0 charge\n\t\t\t\t\t2\n\t\t\t\t\t
Revenu brut global\n\t\t\t\t\t48\u00a0473 \u20ac\n\t\t\t\t\t
Revenu imposable\n\t\t\t\t\t48\u00a0473 \u20ac\n\t\t\t\t\t
Imp\u00f4t sur le revenu net avant corrections\n\t\t\t\t\t5\u00a0084 \u20ac\n\t\t\t\t\t
Montant de l'imp\u00f4t\n\t\t\t\t\tNon imposable\n\t\t\t\t\t
Revenu fiscal de r\u00e9f\u00e9rence\n\t\t\t\t\t48\u00a0473 \u20ac\n\t\t\t\t\t
\n\t\t\t\n\t\t\t
\n\t\t\t
\n\t\t\t\t\n\t\t\t\n\n\t\t
\n\t\t
\u00a9 Minist\u00e8re de l'\u00c9conomie et des Finances
\"\"\n\t
\n\n", + "result": { + "adresse_ligne_1": "RÉSIDENCE DU CALVAIRE", + "adresse_ligne_2": "RUE VICTOR HUGO", + "adresse_ligne_3": "75014 PARIS", + "date_de_naissance_declarant_1": "01/01/1970", + "date_de_naissance_declarant_2": "", + "impot_avant_correction": 5084, + "nom_de_naissance_declarant_1": "DOE", + "nom_de_naissance_declarant_2": "", + "nom_declarant_1": "DOE", + "nom_declarant_2": "", + "nombre_de_parts": "2.00", + "prenom_declarant_1": "JOHN", + "prenom_declarant_2": "", + "revenu_brut_global": 48473, + "revenu_fiscal_de_reference": 48473, + "revenu_imposable": 48473, + "situation_familiale": "divorce", + "situation_partielle": "" + } + } +] diff --git a/tests/test_avis_imposition.py b/tests/test_avis_imposition.py new file mode 100644 index 00000000..97e7eff8 --- /dev/null +++ b/tests/test_avis_imposition.py @@ -0,0 +1,116 @@ +# passerelle - uniform access to multiple data sources and services +# Copyright (C) 2016 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 __future__ import unicode_literals + +import json + +import requests + +import httmock + +import pytest + +from passerelle.apps.avis_imposition.models import AvisImposition + +import utils + + +# Content from the form page +with open('tests/data/avis-imposition.html') as fd: + html = fd.read() + +# Contents from the submit result page +with open('tests/data/avis-imposition.json') as fd: + data = json.load(fd) + + +@pytest.fixture +def avis_imposition(db): + return utils.make_resource(AvisImposition, slug='test') + + +@pytest.mark.parametrize('data', data) +def test_ok(avis_imposition, data, app): + @httmock.urlmatch() + def http_response(url, request): + if request.method == 'GET': + return html + else: + return data['response'] + + with httmock.HTTMock(http_response): + response = utils.endpoint_get( + expected_url='/avis-imposition/test/verify', + app=app, + resource=avis_imposition, + endpoint='verify', + params={ + 'numero_fiscal': data['numero_fiscal'], + 'reference_avis': data['reference_avis'], + }) + assert {key: value for key, value in response.json['data'].items()} == data['result'] + + +def test_not_found(avis_imposition, app): + @httmock.urlmatch() + def http_response(url, request): + return html + + with httmock.HTTMock(http_response): + response = utils.endpoint_get( + expected_url='/avis-imposition/test/verify', + app=app, + resource=avis_imposition, + endpoint='verify', + params={ + 'numero_fiscal': '1234', + 'reference_avis': 'abcd', + }) + assert response.json['err_desc'] == 'not-found' + + +@pytest.mark.parametrize('error', [ + 'exception-on-get', + '500-on-get', + 'exception-on-post', + '500-on-post', +]) +def test_request_error(avis_imposition, app, error): + @httmock.urlmatch() + def http_response(url, request): + if error == 'exception-on-get': + raise requests.RequestException('boom') + if error == '500-on-get': + return {'status_code': 500} + if request.method == 'GET': + return html + if error == 'exception-on-post': + raise requests.RequestException('boom') + if error == '500-on-post': + return {'status_code': 500} + + with httmock.HTTMock(http_response): + response = utils.endpoint_get( + expected_url='/avis-imposition/test/verify', + app=app, + resource=avis_imposition, + endpoint='verify', + params={ + 'numero_fiscal': '1234', + 'reference_avis': 'abcd', + }) + assert response.json['err_desc'] == 'service-is-down' -- 2.26.2