Projet

Général

Profil

0001-avis_imposition-mimic-avis-imposition-API-particulie.patch

Benjamin Dauvergne, 04 juin 2020 21:41

Télécharger (38,6 ko)

Voir les différences:

Subject: [PATCH] avis_imposition: mimic avis-imposition API particulier
 endpoint (#43479)

Return value is the same as API particulier for the avis-imposition
endpoint, except for some data massaging put into alternative keys:
* dates are converted to ISO format and put in keys with @_iso@ suffix,
* family situation is simplified to ASCII and put in key with @_simple@
suffix,
* addresse is returned as oneline joined with newlines as in API
particulier, but also with individual lines separated into 3 keys :
adresse1, adresse2, adresse3.
 passerelle/apps/avis_imposition/__init__.py   |   0
 .../migrations/0001_initial.py                |  30 ++
 .../avis_imposition/migrations/__init__.py    |   0
 passerelle/apps/avis_imposition/models.py     | 264 ++++++++++++++++++
 passerelle/settings.py                        |   1 +
 tests/data/avis-imposition.html               |  85 ++++++
 tests/data/avis-imposition.json               | 128 +++++++++
 tests/test_avis_imposition.py                 | 118 ++++++++
 8 files changed, 626 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/migrations/__init__.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
passerelle/apps/avis_imposition/migrations/0001_initial.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.20 on 2020-05-28 19:49
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations, models
6

  
7

  
8
class Migration(migrations.Migration):
9

  
10
    initial = True
11

  
12
    dependencies = [
13
        ('base', '0020_auto_20200515_1923'),
14
    ]
15

  
16
    operations = [
17
        migrations.CreateModel(
18
            name='AvisImposition',
19
            fields=[
20
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21
                ('title', models.CharField(max_length=50, verbose_name='Title')),
22
                ('slug', models.SlugField(unique=True, verbose_name='Identifier')),
23
                ('description', models.TextField(verbose_name='Description')),
24
                ('users', models.ManyToManyField(blank=True, related_name='_avisimposition_users_+', related_query_name='+', to='base.ApiUser')),
25
            ],
26
            options={
27
                'verbose_name': 'API Particulier',
28
            },
29
        ),
30
    ]
passerelle/apps/avis_imposition/models.py
1
# coding: utf-8
2
# passerelle - uniform access to multiple data sources and services
3
# Copyright (C) 2017  Entr'ouvert
4
#
5
# This program is free software: you can redistribute it and/or modify it
6
# under the terms of the GNU Affero General Public License as published
7
# by the Free Software Foundation, either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU Affero General Public License for more details.
14
#
15
# You should have received a copy of the GNU Affero General Public License
16
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17

  
18
'''Interface with "Service de vérification des avis" of impots.gouv.fr
19
'''
20

  
21
from __future__ import unicode_literals
22

  
23
import datetime
24
import logging
25
import re
26

  
27
import lxml.html
28
import requests
29

  
30
from django.utils.translation import ugettext_lazy as _
31
from django.utils.six.moves.urllib_parse import urljoin
32

  
33
from passerelle.base.models import BaseResource
34
from passerelle.utils.api import endpoint
35
from passerelle.utils.jsonresponse import APIError
36
from passerelle.utils.xml import text_content
37
from passerelle.utils.json import unflatten
38

  
39
AVIS_IMPOSITION_GOUV_FR_URL = 'https://cfsmsp.impots.gouv.fr/secavis/'
40

  
41

  
42
def remove_spaces(value):
43
    return re.sub(r'\s', '', value, flags=re.U)
44

  
45

  
46
def simplify_spaces(value):
47
    return re.sub(r'\s+', ' ', value, flags=re.U)
48

  
49

  
50
# Map fields by tr/td indexes
51
FIELD_INDEXES = {
52
    'declarant1/nom': (1, 1),
53
    'declarant2/nom': (1, 2),
54
    'declarant1/nomNaissance': (2, 1),
55
    'declarant2/nomNaissance': (2, 2),
56
    'declarant1/prenom': (3, 1),
57
    'declarant2/prenom': (3, 2),
58
    'declarant1/dateNaissance': (4, 1),
59
    'declarant2/dateNaissance': (4, 2),
60
    'declarant1/dateNaissance_iso': (4, 1),
61
    'declarant2/dateNaissance_iso': (4, 2),
62
    'foyerFiscal/adresse1': (5, 1),
63
    'foyerFiscal/adresse2': (6, 1),
64
    'foyerFiscal/adresse3': (7, 1),
65
    'dateRecouvrement': (9, 1),
66
    'dateEtablissement': (10, 1),
67
    'dateRecouvrement_iso': (9, 1),
68
    'dateEtablissement_iso': (10, 1),
69
    'nombreParts': (11, 1),
70
    'situationFamille': (12, 1),
71
    'situationFamille_simple': (12, 1),
72
    'nombrePersonnesCharge': (13, 1),
73
    'revenuBrutGlobal': (14, 1),
74
    'revenuImposable': (15, 1),
75
    'impotRevenuNetAvantCorrections': (16, 1),
76
    'montantImpot': (17, 1),
77
    'revenuFiscalReference': (18, 1),
78
}
79

  
80

  
81
def get_field(name, td_contents, tr_length):
82
    # adjust tr/td indexes based on the number of address lines deduced from
83
    # the number of tr elements
84
    i, j = FIELD_INDEXES[name]
85
    # address has 3 lines
86
    if tr_length == 19:
87
        return td_contents[(i, j)]
88
    # address has 2 lines
89
    if tr_length == 18:
90
        if i < 5:
91
            return td_contents[(i, j)]
92
        if i == 5:
93
            return ''
94
        if i > 5:
95
            return td_contents[(i - 1, j)]
96
    # address has 1 line
97
    if tr_length == 17:
98
        if i < 5:
99
            return td_contents[(i, j)]
100
        if i in (5, 6):
101
            return ''
102
        if i > 6:
103
            return td_contents[(i - 2, j)]
104
    raise NotImplementedError
105

  
106

  
107
def nombre_de_parts(value):
108
    try:
109
        return float(value)
110
    except (ValueError, TypeError):
111
        return None
112

  
113

  
114
def euros(value):
115
    if not value:
116
        return value
117
    value = remove_spaces(value)
118
    value = value.rstrip('€')
119
    try:
120
        return int(value)
121
    except ValueError:
122
        return value
123

  
124

  
125
def situation_familiale(value):
126
    if value == 'Pacs\xe9(e)s':
127
        return 'pacs/mariage'
128
    if value == 'Mari\xe9(e)s':
129
        return 'pacs/mariage'
130
    if value == 'Divorc\xe9(e)':
131
        return 'divorce'
132
    if value == 'C\xe9libataire':
133
        return 'celibataire'
134
    raise NotImplementedError(value)
135

  
136

  
137
def date(value):
138
    if not value:
139
        return ''
140
    try:
141
        return datetime.datetime.strptime(value, '%d/%m/%Y').date()
142
    except (ValueError, TypeError):
143
        return ''
144

  
145
ADAPTERS = {
146
    'nombreParts': nombre_de_parts,
147
    'revenuBrutGlobal': euros,
148
    'revenuImposable': euros,
149
    'impotRevenuNetAvantCorrections': euros,
150
    'revenuFiscalReference': euros,
151
    'montantImpot': euros,
152
    'situationFamille_simple': situation_familiale,
153
    'dateEtablissement_iso': date,
154
    'dateRecouvrement_iso': date,
155
    'declarant1/dateNaissance_iso': date,
156
    'declarant2/dateNaissance_iso': date,
157
    'nombrePersonnesCharge': nombre_de_parts,
158
}
159

  
160

  
161
def get_form(logger=None):
162
    logger = logger or logging
163
    try:
164
        response = requests.get(AVIS_IMPOSITION_GOUV_FR_URL)
165
        response.raise_for_status()
166
    except requests.RequestException as e:
167
        raise APIError('service-is-down', data=str(e))
168

  
169
    if 'Saisissez les identifiants' not in response.text:
170
        raise RuntimeError('service has changed')
171

  
172
    html = lxml.html.fromstring(response.content)
173
    data = {}
174
    for form_elt in html.xpath('//form'):
175
        if 'action' not in form_elt.attrib:
176
            continue
177
        action_url = form_elt.attrib['action']
178
        break
179
    else:
180
        raise RuntimeError('service has changed')
181
    logger.debug('using found action_url %s', action_url)
182

  
183
    for input_elt in html.xpath('//input'):
184
        if 'value' in input_elt.attrib:
185
            data[input_elt.attrib['name']] = input_elt.attrib['value']
186

  
187
    return action_url, data
188

  
189

  
190
def get_avis_imposition(numero_fiscal, reference_avis, logger=None):
191
    logger = logger or logging
192

  
193
    action_url, data = get_form()
194
    data['j_id_7:spi'] = numero_fiscal
195
    data['j_id_7:num_facture'] = reference_avis
196

  
197
    logger.debug('sending data %s', data)
198

  
199
    try:
200
        response = requests.post(urljoin(AVIS_IMPOSITION_GOUV_FR_URL, action_url), params=data)
201
        response.raise_for_status()
202
    except requests.RequestException as e:
203
        raise APIError('service-is-down', data=str(e))
204

  
205
    if 'Saisissez les identifiants' in response.text:
206
        raise APIError('not-found')
207

  
208
    response_html = lxml.html.fromstring(response.content)
209
    td_contents = {}
210
    tr_elements = list(response_html.xpath('//tr'))
211
    for i, tr_element in enumerate(tr_elements):
212
        for j, td_element in enumerate(tr_element.xpath('td')):
213
            td_contents[(i, j)] = simplify_spaces(text_content(td_element).strip())
214

  
215
    logger.debug('got td_contents %s', td_contents)
216

  
217
    data = {
218
        # https://github.com/betagouv/svair-api/blob/master/utils/year.js
219
        'foyerFiscal/year': int('20' + reference_avis[:2]),
220
    }
221
    for field in FIELD_INDEXES:
222
        try:
223
            data[field] = get_field(field, td_contents, len(tr_elements))
224
        except IndexError:
225
            raise RuntimeError('service has changed')
226
        if field in ADAPTERS:
227
            data[field] = ADAPTERS[field](data[field])
228
    for situation_partielle_elt in response_html.xpath('//*[@id="situationPartielle"]'):
229
        data['situationPartielle'] = text_content(situation_partielle_elt).strip()
230
        break
231
    return data
232

  
233

  
234
class AvisImposition(BaseResource):
235
    @endpoint(perm='can_access',
236
              description=_('Get citizen\'s fiscal informations'),
237
              parameters={
238
                  'numero_fiscal': {
239
                      'description': _('fiscal identifier'),
240
                      'example_value': '1562456789521',
241
                  },
242
                  'reference_avis': {
243
                      'description': _('tax notice number'),
244
                      'example_value': '1512456789521',
245
                  },
246
              })
247
    def verify(self, request, numero_fiscal, reference_avis):
248
        numero_fiscal = remove_spaces(numero_fiscal)
249
        reference_avis = remove_spaces(reference_avis)
250
        data = get_avis_imposition(numero_fiscal, reference_avis)
251
        unflattened = unflatten(data)
252
        foyer_fiscal = unflattened['foyerFiscal']
253
        foyer_fiscal['adresse'] = ' '.join(
254
            value for key, value in sorted(foyer_fiscal.items()) if key.startswith('adresse') and value
255
        )
256
        return {'data': unflattened}
257

  
258
    def check_status(self):
259
        get_form()
260

  
261
    category = _('Business Process Connectors')
262

  
263
    class Meta:
264
        verbose_name = _('French tax notice validator on impots.gouv.fr')
passerelle/settings.py
129 129
    'passerelle.apps.astregs',
130 130
    'passerelle.apps.atal',
131 131
    'passerelle.apps.atos_genesys',
132
    'passerelle.apps.avis_imposition',
132 133
    'passerelle.apps.base_adresse',
133 134
    'passerelle.apps.bdp',
134 135
    'passerelle.apps.cartads_cs',
tests/data/avis-imposition.html
1
<!DOCTYPE html>
2
<html xmlns="http://www.w3.org/1999/xhtml"><head>
3
<meta http-equiv="Content-type" content="text/html; charset=UTF-8">
4

  
5
<title>Impots.gouv.fr - Service de vérification en ligne des avis</title>
6

  
7
<link href="coin_fichiers/style.css" rel="styleSheet" type="text/css">
8

  
9
<script type="text/javascript" src="coin_fichiers/fonctions.js"></script>
10

  
11
</head>
12
<body>
13
<div id="conteneur">
14
<div id="barre_haut">
15
			<div style="float: left;"><img src="coin_fichiers/bo_seule-2.gif" alt=""></div>
16
			<div style="float: right;"><img src="coin_fichiers/bo_seule-3.gif" alt=""></div>
17
</div>
18
<div id="principal">
19
<div id="nav_pro">
20
<b>Bienvenue sur le service de vérification des avis</b>
21
</div>
22

  
23
<div id="infoService"><p>Le service permet de vérifier l'authenticité des avis (Impôt sur le revenu) présentés par un usager</p></div>
24
<br>
25
<div class="titre"><span>Accès au service de vérification</span></div>
26
<br>
27
<div class="titre2">Saisissez les identifiants</div><form id="j_id_7" name="j_id_7" method="post" action="/secavis/faces/commun/index.jsf" enctype="application/x-www-form-urlencoded">
28
	<table>
29
		<tbody>
30
			<tr>
31
				<td width="290"> 
32
					<br><br>
33
				</td>
34
			</tr>		
35
			<tr>
36
				<td> 
37
					<label>Numéro fiscal *</label><a href="#" onclick="win = ouvrePopup('/secavis/faces/commun/aideSpi.jsf', 523, 375); win.focus();" tabindex="4"><img src="coin_fichiers/pic_aide_pro.gif" alt="aideSPI" style="vertical-align:middle"></a>					
38
				</td>
39
			</tr>
40
			<tr>
41
				<td><input id="j_id_7:spi" name="j_id_7:spi" type="text" maxlength="13" size="15" tabindex="1" autocomplete="off">
42
				</td>
43
				
44
			</tr>
45
			<tr>
46
				<td></td>
47
			</tr>
48
			<tr>
49
				<td>
50
				 <label>Référence de l'avis *</label><a href="#" onclick="win = ouvrePopup('/secavis/faces/commun/aideNumFacture.jsf', 520, 375); win.focus();" tabindex="5"><img src="coin_fichiers/pic_aide_pro.gif" alt="aideReferenceAvis" style="vertical-align:middle"></a>	
51
				</td>
52
			</tr>
53
			<tr>
54
				<td><input id="j_id_7:num_facture" name="j_id_7:num_facture" type="text" maxlength="13" size="15" tabindex="2" autocomplete="off">
55
				</td>
56
				
57
			</tr>
58
			
59

  
60
			<tr>
61
				<td></td>
62
			</tr>
63
			<tr>
64
				<td></td>
65
				<td></td>
66

  
67
				<td>
68
				<div align="right">
69
					
70
					<div class="bloc_boutons"><input id="j_id_7:j_id_l" name="j_id_7:j_id_l" type="submit" value="Valider" title="Vérifier les informations d'avis" class="valider" tabindex="3">
71
					</div>
72

  
73
			 	</div>
74
				</td>
75
			</tr>
76

  
77
		</tbody>
78
	</table><input type="hidden" name="j_id_7_SUBMIT" value="1"><input type="hidden" name="javax.faces.ViewState" id="j_id__v_0:javax.faces.ViewState:1" value="RxJe/1JKTJSr3aiM3H9DqZq0DrwqEXsY7Rw4eLRgEBsCF1IALJGqVgWTaQkiKbbdcGDWW774BWUCa/+j2CDznhw1/3bxJteY6ZCui66yNevhkej4xuyrFMte5KQnKORt9JZrOQ=="></form>
79
<br>
80
<div id="donneesObligatoires">* données obligatoires</div>
81
</div>
82
<div id="bas_page">© Ministère de l'Économie et des Finances</div><img src="coin_fichiers/hit.gif" alt="" width="1" height="1">
83
</div>
84

  
85
<div id="grammalecte_menu_main_button_shadow_host" style="width: 0px; height: 0px;"></div></body><script src="coin_fichiers/api.js"></script></html>
tests/data/avis-imposition.json
1
[
2
  {
3
    "numero_fiscal": "1234",
4
    "reference_avis": "18abcd",
5
    "response": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n\t\n<head>\n<meta http-equiv=\"Content-type\" content=\"text/html; charset=UTF-8\" />\n\n<title>Impots.gouv.fr - Service de v\u00e9rification en ligne des avis</title>\n<link href=\"/secavis/css/style.css\" rel=\"styleSheet\" type=\"text/css\" />\n</head>\n\n<body>\n\n<div id=\"conteneur\">\n<div id=\"barre_haut\">\n\t\t\t<div style=\"float: left;\"><img src=\"/secavis/img/bo_seule-2.gif\" alt=\"\" /></div>\n\t\t\t<div style=\"float: right;\"><img src=\"/secavis/img/bo_seule-3.gif\" alt=\"\" /></div>\n</div>\n<div id=\"principal\">\n<div id=\"nav_pro\">\n<b>L'administration fiscale certifie l'authenticit\u00e9 du document pr\u00e9sent\u00e9 pour les donn\u00e9es suivantes :</b>\n</div>\n\n<div class=\"titre_affiche_avis\">\n<span>Imp\u00f4t   2019 sur les revenus de l'ann\u00e9e  2018  \n</span>\n</div>\t\t\n\t\t\n\n\t\t\t<table>\n\t\t\t\t<tbody>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"label\">\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"label\">D\u00e9clarant 1\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"label\">D\u00e9clarant 2\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\">Nom\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelPair\">DOE\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelPair\">DOE\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelImpair\">Nom de naissance\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelImpair\">DOE\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelImpair\">DOE\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\">Pr\u00e9nom(s)\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelPair\">JOHN\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelPair\">JANE\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelImpair\">Date de naissance\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelImpair\">01/01/1970\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelImpair\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\">\n\t\t\t\t\t\tAdresse d\u00e9clar\u00e9e au 1<sup>er</sup> janvier  2019\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelPair\">R\u00c9SIDENCE DU CALVAIRE\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelPair\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\">\n\t\t\t\t\t</td>\n\t\t\t\t\t<td colspan=\"2\" class=\"labelPair\">RUE VICTOR HUGO\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\">\n\t\t\t\t\t</td>\n\t\t\t\t\t<td colspan=\"2\" class=\"labelPair\">75014 PARIS\n\t\t\t\t\t</td>\n\t\t\t\t\t</tr>\t\t\t\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"espace\"></td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\" colspan=\"2\">Date de mise en recouvrement de l'avis d'imp\u00f4t\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textPair\">31/12/2019\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\t\t\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelImpair\" colspan=\"2\">Date d'\u00e9tablissement\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textImpair\">09/12/2019\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\" colspan=\"2\">Nombre de part(s)\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textPair\">4.00\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelImpair\" colspan=\"2\">Situation de famille\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textImpair\">Pacs\u00e9(e)s\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\" colspan=\"2\">Nombre de personne(s) \u00e0 charge\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textPair\">4\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelImpair\" colspan=\"2\">Revenu brut global\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textImpair\">48\u00a0473 \u20ac\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\" colspan=\"2\">Revenu imposable\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textPair\">48\u00a0473 \u20ac\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelImpair\" colspan=\"2\">Imp\u00f4t sur le revenu net avant corrections\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textImpair\">112 \u20ac\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\" colspan=\"2\">Montant de l'imp\u00f4t\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textPair\">Non imposable\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\t\t\t\t\t\t\t\t\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelImpair\" colspan=\"2\">Revenu fiscal de r\u00e9f\u00e9rence\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textImpair\">48\u00a0473 \u20ac\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\t\t\t\t\t\t\t\n\n\t\t\t</tbody></table>\n\t\t\t\n\t\t\t<div id=\"situationPartielle\">\n\t\t\t</div>\n\t\t\t\t\n\t\t\t<div id=\"boutonsAvis\">\t\t\n\t\t\t\t<a class=\"nouvelle_recherche\" href=\"/secavis/\">\t\t\t\n\t\t\t\t\tNouvelle recherche\t\t\t\t\n\t\t\t\t</a>\n\t\t\t </div>\n\n\t\t</div>\n\t\t<div id=\"bas_page\">\u00a9 Minist\u00e8re de l'\u00c9conomie et des Finances</div><img src=\"https://logs1279.xiti.com/hit.xiti?s=532158&amp;s2=3&amp;p=AFFICHAGE::Avis_Sans_Correctif_erreur_pas_javascript&amp;\" alt=\"\" height=\"1\" width=\"1\" />\n\t</div>\n</body>\n</html>",
6
    "result": {
7
      "dateEtablissement": "09/12/2019",
8
      "dateEtablissement_iso": "2019-12-09",
9
      "dateRecouvrement": "31/12/2019",
10
      "dateRecouvrement_iso": "2019-12-31",
11
      "declarant1": {
12
        "dateNaissance": "01/01/1970",
13
        "dateNaissance_iso": "1970-01-01",
14
        "nom": "DOE",
15
        "nomNaissance": "DOE",
16
        "prenom": "JOHN"
17
      },
18
      "declarant2": {
19
        "dateNaissance": "",
20
        "dateNaissance_iso": "",
21
        "nom": "DOE",
22
        "nomNaissance": "DOE",
23
        "prenom": "JANE"
24
      },
25
      "foyerFiscal": {
26
        "adresse": "R\u00c9SIDENCE DU CALVAIRE RUE VICTOR HUGO 75014 PARIS",
27
        "adresse1": "R\u00c9SIDENCE DU CALVAIRE",
28
        "adresse2": "RUE VICTOR HUGO",
29
        "adresse3": "75014 PARIS",
30
        "year": 2018
31
      },
32
      "impotRevenuNetAvantCorrections": 112,
33
      "montantImpot": "Nonimposable",
34
      "nombreParts": 4.0,
35
      "nombrePersonnesCharge": 4.0,
36
      "revenuBrutGlobal": 48473,
37
      "revenuFiscalReference": 48473,
38
      "revenuImposable": 48473,
39
      "situationFamille": "Pacs\u00e9(e)s",
40
      "situationFamille_simple": "pacs/mariage",
41
      "situationPartielle": ""
42
    }
43
  },
44
  {
45
    "numero_fiscal": "1234",
46
    "reference_avis": "18abcd",
47
    "response": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n\t\n<head>\n<meta http-equiv=\"Content-type\" content=\"text/html; charset=UTF-8\" />\n\n<title>Impots.gouv.fr - Service de v\u00e9rification en ligne des avis</title>\n<link href=\"/secavis/css/style.css\" rel=\"styleSheet\" type=\"text/css\" />\n</head>\n\n<body>\n\n<div id=\"conteneur\">\n<div id=\"barre_haut\">\n\t\t\t<div style=\"float: left;\"><img src=\"/secavis/img/bo_seule-2.gif\" alt=\"\" /></div>\n\t\t\t<div style=\"float: right;\"><img src=\"/secavis/img/bo_seule-3.gif\" alt=\"\" /></div>\n</div>\n<div id=\"principal\">\n<div id=\"nav_pro\">\n<b>L'administration fiscale certifie l'authenticit\u00e9 du document pr\u00e9sent\u00e9 pour les donn\u00e9es suivantes :</b>\n</div>\n\n<div class=\"titre_affiche_avis\">\n<span>Imp\u00f4t   2019 sur les revenus de l'ann\u00e9e  2018  \n</span>\n</div>\t\t\n\t\t\n\n\t\t\t<table>\n\t\t\t\t<tbody>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"label\">\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"label\">D\u00e9clarant 1\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"label\">D\u00e9clarant 2\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\">Nom\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelPair\">DOE\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelPair\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelImpair\">Nom de naissance\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelImpair\">DOE\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelImpair\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\">Pr\u00e9nom(s)\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelPair\">JACK\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelPair\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelImpair\">Date de naissance\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelImpair\">01/01/1970\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelImpair\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\">\n\t\t\t\t\t\tAdresse d\u00e9clar\u00e9e au 1<sup>er</sup> janvier  2019\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelPair\">R\u00c9SIDENCE DU CALVAIRE\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelPair\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\">\n\t\t\t\t\t</td>\n\t\t\t\t\t<td colspan=\"2\" class=\"labelPair\">RUE VICTOR HUGO\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\">\n\t\t\t\t\t</td>\n\t\t\t\t\t<td colspan=\"2\" class=\"labelPair\">75014 PARIS\n\t\t\t\t\t</td>\n\t\t\t\t\t</tr>\t\t\t\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"espace\"></td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\" colspan=\"2\">Date de mise en recouvrement de l'avis d'imp\u00f4t\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textPair\">31/07/2019\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\t\t\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelImpair\" colspan=\"2\">Date d'\u00e9tablissement\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textImpair\">09/07/2019\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\" colspan=\"2\">Nombre de part(s)\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textPair\">2.00\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelImpair\" colspan=\"2\">Situation de famille\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textImpair\">Divorc\u00e9(e)\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\" colspan=\"2\">Nombre de personne(s) \u00e0 charge\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textPair\">2\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelImpair\" colspan=\"2\">Revenu brut global\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textImpair\">48\u00a0473 \u20ac\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\" colspan=\"2\">Revenu imposable\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textPair\">48\u00a0473 \u20ac\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelImpair\" colspan=\"2\">Imp\u00f4t sur le revenu net avant corrections\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textImpair\">5\u00a0084 \u20ac\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\" colspan=\"2\">Montant de l'imp\u00f4t\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textPair\">Non imposable\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\t\t\t\t\t\t\t\t\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelImpair\" colspan=\"2\">Revenu fiscal de r\u00e9f\u00e9rence\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textImpair\">48\u00a0473 \u20ac\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\t\t\t\t\t\t\t\n\n\t\t\t</tbody></table>\n\t\t\t\n\t\t\t<div id=\"situationPartielle\">\n\t\t\t</div>\n\t\t\t\t\n\t\t\t<div id=\"boutonsAvis\">\t\t\n\t\t\t\t<a class=\"nouvelle_recherche\" href=\"/secavis/\">\t\t\t\n\t\t\t\t\tNouvelle recherche\t\t\t\t\n\t\t\t\t</a>\n\t\t\t </div>\n\n\t\t</div>\n\t\t<div id=\"bas_page\">\u00a9 Minist\u00e8re de l'\u00c9conomie et des Finances</div><img src=\"https://logs1279.xiti.com/hit.xiti?s=532158&amp;s2=3&amp;p=AFFICHAGE::Avis_Sans_Correctif_erreur_pas_javascript&amp;\" alt=\"\" height=\"1\" width=\"1\" />\n\t</div>\n</body>\n</html>",
48
    "result": {
49
      "dateEtablissement": "09/07/2019",
50
      "dateEtablissement_iso": "2019-07-09",
51
      "dateRecouvrement": "31/07/2019",
52
      "dateRecouvrement_iso": "2019-07-31",
53
      "declarant1": {
54
        "dateNaissance": "01/01/1970",
55
        "dateNaissance_iso": "1970-01-01",
56
        "nom": "DOE",
57
        "nomNaissance": "DOE",
58
        "prenom": "JACK"
59
      },
60
      "declarant2": {
61
        "dateNaissance": "",
62
        "dateNaissance_iso": "",
63
        "nom": "",
64
        "nomNaissance": "",
65
        "prenom": ""
66
      },
67
      "foyerFiscal": {
68
        "adresse": "R\u00c9SIDENCE DU CALVAIRE RUE VICTOR HUGO 75014 PARIS",
69
        "adresse1": "R\u00c9SIDENCE DU CALVAIRE",
70
        "adresse2": "RUE VICTOR HUGO",
71
        "adresse3": "75014 PARIS",
72
        "year": 2018
73
      },
74
      "impotRevenuNetAvantCorrections": 5084,
75
      "montantImpot": "Nonimposable",
76
      "nombreParts": 2.0,
77
      "nombrePersonnesCharge": 2.0,
78
      "revenuBrutGlobal": 48473,
79
      "revenuFiscalReference": 48473,
80
      "revenuImposable": 48473,
81
      "situationFamille": "Divorc\u00e9(e)",
82
      "situationFamille_simple": "divorce",
83
      "situationPartielle": ""
84
    }
85
  },
86
  {
87
    "numero_fiscal": "1234",
88
    "reference_avis": "18abcd",
89
    "response": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n\t\n<head>\n<meta http-equiv=\"Content-type\" content=\"text/html; charset=UTF-8\" />\n\n<title>Impots.gouv.fr - Service de v\u00e9rification en ligne des avis</title>\n<link href=\"/secavis/css/style.css\" rel=\"styleSheet\" type=\"text/css\" />\n</head>\n\n<body>\n\n<div id=\"conteneur\">\n<div id=\"barre_haut\">\n\t\t\t<div style=\"float: left;\"><img src=\"/secavis/img/bo_seule-2.gif;jsessionid=F02B3A77814BD226080DC0F4D73C27A1.secavis-02-01\" alt=\"\" /></div>\n\t\t\t<div style=\"float: right;\"><img src=\"/secavis/img/bo_seule-3.gif;jsessionid=F02B3A77814BD226080DC0F4D73C27A1.secavis-02-01\" alt=\"\" /></div>\n</div>\n<div id=\"principal\">\n<div id=\"nav_pro\">\n<b>L'administration fiscale certifie l'authenticit\u00e9 du document pr\u00e9sent\u00e9 pour les donn\u00e9es suivantes :</b>\n</div>\n\n<div class=\"titre_affiche_avis\">\n<span>Imp\u00f4t   2018 sur les revenus de l'ann\u00e9e  2017  \n</span>\n</div>\t\t\n\t\t\n\n\t\t\t<table>\n\t\t\t\t<tbody>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"label\">\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"label\">D\u00e9clarant 1\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"label\">D\u00e9clarant 2\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\">Nom\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelPair\">JOHNSON\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelPair\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelImpair\">Nom de naissance\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelImpair\">JOHNSON\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelImpair\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\">Pr\u00e9nom(s)\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelPair\">ROBERT\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelPair\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelImpair\">Date de naissance\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelImpair\">11/05/1978\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelImpair\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\">\n\t\t\t\t\t\tAdresse d\u00e9clar\u00e9e au 1<sup>er</sup> janvier  2018\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelPair\">13 RUE ALEXANDRE FLEMING\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"labelPair\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\">\n\t\t\t\t\t</td>\n\t\t\t\t\t<td colspan=\"2\" class=\"labelPair\">99999 SAINT-HENRI-LES-COQUILLAGES\n\t\t\t\t\t</td>\n\t\t\t\t\t</tr>\t\t\t\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"espace\"></td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\" colspan=\"2\">Date de mise en recouvrement de l'avis d'imp\u00f4t\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textPair\">31/07/2018\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\t\t\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelImpair\" colspan=\"2\">Date d'\u00e9tablissement\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textImpair\">02/08/2018\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\" colspan=\"2\">Nombre de part(s)\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textPair\">1.00\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelImpair\" colspan=\"2\">Situation de famille\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textImpair\">C\u00e9libataire\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\" colspan=\"2\">Nombre de personne(s) \u00e0 charge\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textPair\">0\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelImpair\" colspan=\"2\">Revenu brut global\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textImpair\">30\u00a0317 \u20ac\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\" colspan=\"2\">Revenu imposable\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textPair\">30\u00a0317 \u20ac\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelImpair\" colspan=\"2\">Imp\u00f4t sur le revenu net avant corrections\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textImpair\">3\u00a0388 \u20ac\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelPair\" colspan=\"2\">Montant de l'imp\u00f4t\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textPair\">3\u00a0388 \u20ac\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\t\t\t\t\t\t\t\t\n\t\t\t\t<tr>\n\t\t\t\t\t<td class=\"labelImpair\" colspan=\"2\">Revenu fiscal de r\u00e9f\u00e9rence\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class=\"textImpair\">30\u00a0317 \u20ac\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\t\t\t\t\t\t\t\n\n\t\t\t</tbody></table>\n\t\t\t\n\t\t\t<div id=\"situationPartielle\">\n\t\t\t</div>\n\t\t\t\t\n\t\t\t<div id=\"boutonsAvis\">\t\t\n\t\t\t\t<a class=\"nouvelle_recherche\" href=\"/secavis/\">\t\t\t\n\t\t\t\t\tNouvelle recherche\t\t\t\t\n\t\t\t\t</a>\n\t\t\t </div>\n\n\t\t</div>\n\t\t<div id=\"bas_page\">\u00a9 Minist\u00e8re de l'\u00c9conomie et des Finances</div><img src=\"https://logs1279.xiti.com/hit.xiti?s=532158&amp;s2=3&amp;p=AFFICHAGE::Avis_Sans_Correctif_erreur_pas_javascript&amp;\" alt=\"\" height=\"1\" width=\"1\" />\n\t</div>\n</body>\n</html>",
90
    "result": {
91
      "dateEtablissement": "02/08/2018",
92
      "dateEtablissement_iso": "2018-08-02",
93
      "dateRecouvrement": "31/07/2018",
94
      "dateRecouvrement_iso": "2018-07-31",
95
      "declarant1": {
96
        "dateNaissance": "11/05/1978",
97
        "dateNaissance_iso": "1978-05-11",
98
        "nom": "JOHNSON",
99
        "nomNaissance": "JOHNSON",
100
        "prenom": "ROBERT"
101
      },
102
      "declarant2": {
103
        "dateNaissance": "",
104
        "dateNaissance_iso": "",
105
        "nom": "",
106
        "nomNaissance": "",
107
        "prenom": ""
108
      },
109
      "foyerFiscal": {
110
        "adresse": "13 RUE ALEXANDRE FLEMING 99999 SAINT-HENRI-LES-COQUILLAGES",
111
        "adresse1": "",
112
        "adresse2": "13 RUE ALEXANDRE FLEMING",
113
        "adresse3": "99999 SAINT-HENRI-LES-COQUILLAGES",
114
        "year": 2018
115
      },
116
      "impotRevenuNetAvantCorrections": 3388,
117
      "montantImpot": 3388,
118
      "nombreParts": 1.0,
119
      "nombrePersonnesCharge": 0.0,
120
      "revenuBrutGlobal": 30317,
121
      "revenuFiscalReference": 30317,
122
      "revenuImposable": 30317,
123
      "situationFamille": "C\u00e9libataire",
124
      "situationFamille_simple": "celibataire",
125
      "situationPartielle": ""
126
    }
127
  }
128
]
tests/test_avis_imposition.py
1
# passerelle - uniform access to multiple data sources and services
2
# Copyright (C) 2016 Entr'ouvert
3
#
4
# This program is free software: you can redistribute it and/or modify it
5
# under the terms of the GNU Affero General Public License as published
6
# by the Free Software Foundation, either version 3 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU Affero General Public License for more details.
13
#
14
# You should have received a copy of the GNU Affero General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

  
17
from __future__ import unicode_literals
18

  
19
import json
20

  
21
import requests
22

  
23
import httmock
24

  
25
import pytest
26

  
27
from passerelle.apps.avis_imposition.models import AvisImposition
28

  
29
import utils
30

  
31

  
32
# Content from the form page
33
with open('tests/data/avis-imposition.html') as fd:
34
    html = fd.read()
35

  
36
# Contents from the submit result page
37
with open('tests/data/avis-imposition.json') as fd:
38
    cases = json.load(fd)
39

  
40

  
41
@pytest.fixture
42
def avis_imposition(db):
43
    return utils.make_resource(AvisImposition, slug='test')
44

  
45

  
46
@pytest.mark.parametrize(
47
    'data', cases, ids=[
48
        ''.join([data['result']['declarant1']['prenom'], data['result']['declarant1']['nom']]) for data in cases])
49
def test_ok(avis_imposition, data, app):
50
    @httmock.urlmatch()
51
    def http_response(url, request):
52
        if request.method == 'GET':
53
            return html
54
        else:
55
            return data['response']
56

  
57
    with httmock.HTTMock(http_response):
58
        response = utils.endpoint_get(
59
            expected_url='/avis-imposition/test/verify',
60
            app=app,
61
            resource=avis_imposition,
62
            endpoint='verify',
63
            params={
64
                'numero_fiscal': data['numero_fiscal'],
65
                'reference_avis': data['reference_avis'],
66
            })
67
    assert {key: value for key, value in response.json['data'].items()} == data['result']
68

  
69

  
70
def test_not_found(avis_imposition, app):
71
    @httmock.urlmatch()
72
    def http_response(url, request):
73
        return html
74

  
75
    with httmock.HTTMock(http_response):
76
        response = utils.endpoint_get(
77
            expected_url='/avis-imposition/test/verify',
78
            app=app,
79
            resource=avis_imposition,
80
            endpoint='verify',
81
            params={
82
                'numero_fiscal': '1234',
83
                'reference_avis': 'abcd',
84
            })
85
    assert response.json['err_desc'] == 'not-found'
86

  
87

  
88
@pytest.mark.parametrize('error', [
89
    'exception-on-get',
90
    '500-on-get',
91
    'exception-on-post',
92
    '500-on-post',
93
])
94
def test_request_error(avis_imposition, app, error):
95
    @httmock.urlmatch()
96
    def http_response(url, request):
97
        if error == 'exception-on-get':
98
            raise requests.RequestException('boom')
99
        if error == '500-on-get':
100
            return {'status_code': 500}
101
        if request.method == 'GET':
102
            return html
103
        if error == 'exception-on-post':
104
            raise requests.RequestException('boom')
105
        if error == '500-on-post':
106
            return {'status_code': 500}
107

  
108
    with httmock.HTTMock(http_response):
109
        response = utils.endpoint_get(
110
            expected_url='/avis-imposition/test/verify',
111
            app=app,
112
            resource=avis_imposition,
113
            endpoint='verify',
114
            params={
115
                'numero_fiscal': '1234',
116
                'reference_avis': 'abcd',
117
            })
118
    assert response.json['err_desc'] == 'service-is-down'
0
-