Projet

Général

Profil

0001-api_entreprise-add-initial-connector-30010.patch

Serghei Mihai, 20 mars 2019 12:05

Télécharger (26,5 ko)

Voir les différences:

Subject: [PATCH] api_entreprise: add initial connector (#30010)

 passerelle/apps/api_entreprise/__init__.py    |   0
 .../api_entreprise/migrations/0001_initial.py |  35 ++
 .../api_entreprise/migrations/__init__.py     |   0
 passerelle/apps/api_entreprise/models.py      | 214 ++++++++++
 passerelle/settings.py                        |   1 +
 passerelle/static/css/style.css               |   3 +-
 tests/test_api_entreprise.py                  | 393 ++++++++++++++++++
 7 files changed, 645 insertions(+), 1 deletion(-)
 create mode 100644 passerelle/apps/api_entreprise/__init__.py
 create mode 100644 passerelle/apps/api_entreprise/migrations/0001_initial.py
 create mode 100644 passerelle/apps/api_entreprise/migrations/__init__.py
 create mode 100644 passerelle/apps/api_entreprise/models.py
 create mode 100644 tests/test_api_entreprise.py
passerelle/apps/api_entreprise/migrations/0001_initial.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.20 on 2019-03-15 09:38
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', '0012_job'),
14
    ]
15

  
16
    operations = [
17
        migrations.CreateModel(
18
            name='APIEntreprise',
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
                ('description', models.TextField(verbose_name='Description')),
23
                ('slug', models.SlugField(unique=True, verbose_name='Identifier')),
24
                ('url', models.URLField(default=b'https://entreprise.api.gouv.fr/v2/', max_length=256, verbose_name='API URL')),
25
                ('token', models.CharField(max_length=1024, verbose_name='API token')),
26
                ('recipient', models.CharField(help_text='ex: siret, siren, waldec, etc...', max_length=256, verbose_name='Call recipient')),
27
                ('context', models.CharField(help_text='ex: APS, MPS, etc...', max_length=256, verbose_name='Call context')),
28
                ('obj', models.CharField(max_length=49, verbose_name='Calls object')),
29
                ('users', models.ManyToManyField(blank=True, to='base.ApiUser')),
30
            ],
31
            options={
32
                'verbose_name': 'API Entreprise',
33
            },
34
        ),
35
    ]
passerelle/apps/api_entreprise/models.py
1
# passerelle.apps.api_entreprise
2
# Copyright (C) 2019  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
'''Gateway to API-Entreprise web-service from SGMAP:
18
   https://entreprise.api.gouv.fr
19
'''
20

  
21
from urlparse import urljoin
22
import requests
23

  
24
from django.db import models
25
from django.utils.translation import ugettext_lazy as _
26
from django.utils.timezone import datetime
27
from django.http import HttpResponse, Http404
28
from django.core.signing import Signer, BadSignature
29
from django.core.urlresolvers import reverse
30

  
31
from passerelle.base.models import BaseResource
32
from passerelle.utils.api import endpoint
33
from passerelle.utils.jsonresponse import APIError
34

  
35

  
36
class APIEntreprise(BaseResource):
37

  
38
    url = models.URLField(_('API URL'), max_length=256, default='https://entreprise.api.gouv.fr/v2/')
39
    token = models.CharField(max_length=1024, verbose_name=_('API token'))
40
    recipient = models.CharField(max_length=256, verbose_name=_('Call recipient'),
41
                                 help_text=_('ex: siret, institution_id, waldec, etc...'))
42
    context = models.CharField(max_length=256, verbose_name=_('Call context'),
43
                                 help_text=_('ex: APS, MPS, etc...'))
44
    obj = models.CharField(max_length=49, verbose_name=_('Calls object'))
45

  
46
    category = _('Business Process Connectors')
47

  
48
    class Meta:
49
        verbose_name = _('API Entreprise')
50

  
51
    def get(self, path, **kwargs):
52
        params = {'token': self.token,
53
            'context': kwargs.get('context', self.context),
54
            'object': kwargs.get('object', self.obj),
55
            'recipient': kwargs.get('recipient', self.recipient)
56
        }
57
        url = urljoin(self.url, path)
58
        try:
59
            response = self.requests.get(url, data=params)
60
        except requests.RequestException as e:
61
            raise APIError(u'API-entreprise connection error: %s' %
62
                           response.status_code,
63
                           data={'error': unicode(e)})
64
        try:
65
            data = response.json()
66
        except ValueError as e:
67
            content = repr(response.content[:1000])
68
            raise APIError(
69
                u'API-entreprise returned non-JSON content with status %s: %s' %
70
                (response.status_code, content),
71
                data={'status_code': response.status_code,
72
                      'exception': unicode(e),
73
                      'content': content,
74
                })
75
        if response.status_code != 200:
76
            if data.get('error') == 'not_found':
77
                return {
78
                    'err': 1,
79
                    'err_desc': data.get('message', 'not-found'),
80
                }
81
            raise APIError(
82
                u'API-entreprise returned a non 200 status %s: %s' %
83
                (response.status_code, data),
84
                data={
85
                    'status_code': response.status_code,
86
                    'content': data,
87
                })
88
        return {
89
            'err': 0,
90
            'data': data,
91
        }
92

  
93

  
94
    @endpoint(perm='can_access',
95
              pattern='(?P<institution_id>\w+)/$',
96
              example_pattern='{institution_id}/',
97
              description=_('Get association\'s documents'),
98
              parameters={
99
                  'institution_id': {
100
                      'description': _('association id'),
101
                      'example_value': '44317013900036',
102
                }
103
              }
104
    )
105
    def documents_associations(self, request, institution_id, **kwargs):
106
        data = []
107
        signer = Signer()
108
        resp = self.get('documents_associations/%s/' % institution_id)
109
        for item in resp['data'].get('documents', []):
110
            # ignore documents with no type
111
            if not item.get('type'):
112
                continue
113
            dt = datetime.fromtimestamp(int(item['timestamp']))
114
            signature = signer.signature('%s-%s' % (item['type'], item['timestamp']))
115
            document_url = request.build_absolute_uri(reverse('generic-endpoint', kwargs={'connector': self.get_connector_slug(),
116
                                        'slug': self.slug,
117
                                        'endpoint': 'document',
118
                                        'rest': '%s/%s/' % (institution_id, signature)}))
119
            data.append({'id': item['timestamp'],
120
                         'text': item['type'],
121
                         'datetime': dt,
122
                         'type': item['type'],
123
                         'url': document_url})
124
        # sort data by date
125
        data.sort(key=lambda i: i['datetime'])
126
        return {'err': 0, 'data': data}
127

  
128

  
129
    @endpoint(perm='can_access',
130
              pattern='(?P<institution_id>\w+)/(?P<document_id>[\w-]+)/$',
131
              example_pattern='{institution_id}/{document_id}/',
132
              description=_('Get institution\'s document'),
133
              parameters={
134
                  'institution_id': {
135
                      'description': _('institution id'),
136
                      'example_value': '44317013900036',
137
                  },
138
                  'document_id': {
139
                      'description': _('document id'),
140
                      'example_value': 'A1500660325',
141
                  }
142
              }
143
    )
144
    def document(self, request, institution_id, document_id, **kwargs):
145
        signer = Signer()
146
        resp = self.get('documents_associations/%s/' % institution_id)
147
        for item in resp['data'].get('documents', []):
148
            # ignore documents with no type
149
            if not item.get('type'):
150
                continue
151
            try:
152
                signer.unsign('%s-%s:%s' % (item['type'], item['timestamp'], document_id))
153
            except BadSignature:
154
                continue
155
            return HttpResponse(self.requests.get(item['url']),
156
                                content_type='application/pdf')
157
        raise Http404('document not found')
158

  
159

  
160
    @endpoint(perm='can_access',
161
              pattern='(?P<institution_id>\w+)/$',
162
              example_pattern='{institution_id}/',
163
              description=_('Get institution\'s data from Infogreffe'),
164
              parameters={
165
                  'institution_id': {
166
                      'description': _('institution id'),
167
                      'example_value': '44317013900036',
168
                }
169
              }
170
    )
171
    def extraits_rcs(self, request, institution_id, **kwargs):
172
        return self.get('extraits_rcs_infogreffe/%s/' % institution_id)
173

  
174
    @endpoint(perm='can_access',
175
              pattern='(?P<institution_id>\w+)/$',
176
              example_pattern='{institution_id}/',
177
              description=_('Get association\'s related informations'),
178
              parameters={
179
                  'institution_id': {
180
                      'description': _('institution id'),
181
                      'example_value': '44317013900036',
182
                }
183
              }
184
    )
185
    def associations(self, request, institution_id, **kwargs):
186
        return self.get('associations/%s/' % institution_id)
187

  
188
    @endpoint(perm='can_access',
189
              pattern='(?P<institution_id>\w+)/$',
190
              example_pattern='{institution_id}/',
191
              description=_('Get firm\'s related informations'),
192
              parameters={
193
                  'institution_id': {
194
                      'description': _('association id'),
195
                      'example_value': '44317013900036',
196
                }
197
              }
198
    )
199
    def entreprises(self, request, institution_id, **kwargs):
200
        return self.get('entreprises/%s/' % institution_id)
201

  
202
    @endpoint(perm='can_access',
203
              pattern='(?P<institution_id>\w+)/$',
204
              example_pattern='{institution_id}/',
205
              description=_('Get institution\'s related informations'),
206
              parameters={
207
                  'institution_id': {
208
                      'description': _('institution id'),
209
                      'example_value': '44317013900036',
210
                }
211
              }
212
    )
213
    def etablissements(self, request, institution_id, **kwargs):
214
        return self.get('etablissements/%s/' % institution_id)
passerelle/settings.py
145 145
    'passerelle.apps.solis',
146 146
    'passerelle.apps.arpege_ecp',
147 147
    'passerelle.apps.vivaticket',
148
    'passerelle.apps.api_entreprise',
148 149
    # backoffice templates and static
149 150
    'gadjo',
150 151
)
passerelle/static/css/style.css
164 164
	content: "\f15b"; /* file */
165 165
}
166 166

  
167
li.connector.apiparticulier a::before {
167
li.connector.apiparticulier a::before,
168
li.connector.apientreprise a::before {
168 169
	content: "\f2c3";  /* id-card-o */
169 170
}
170 171

  
tests/test_api_entreprise.py
1
# -*- coding: utf-8 -*-
2

  
3
# tests/test_api_entreprise.py
4
# Copyright (C) 2018  Entr'ouvert
5
#
6
# This program is free software: you can redistribute it and/or modify it
7
# under the terms of the GNU Affero General Public License as published
8
# by the Free Software Foundation, either version 3 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
# GNU Affero General Public License for more details.
15
#
16
# You should have received a copy of the GNU Affero General Public License
17
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
18

  
19
import pytest
20

  
21
from httmock import urlmatch, HTTMock, response
22

  
23
from django.core.urlresolvers import reverse
24

  
25
from passerelle.apps.api_entreprise.models import APIEntreprise
26

  
27
from utils import make_resource, endpoint_get
28

  
29
ETABLISSEMENTS_RESPONSE = {
30
  "etablissement": {
31
    "siege_social": True,
32
    "siret": "41816609600051",
33
    "naf": "6202A",
34
    "libelle_naf": "Conseil en systèmes et logiciels informatiques",
35
    "date_mise_a_jour": 1449183600,
36
    "tranche_effectif_salarie_etablissement": {
37
      "de": 200,
38
      "a": 249,
39
      "code": "31",
40
      "date_reference": "2014",
41
      "intitule": "200 à 249 salariés"
42
    },
43
    "date_creation_etablissement": 1108594800,
44
    "region_implantation": {
45
      "code": "11",
46
      "value": "Île-de-France"
47
    },
48
    "commune_implantation": {
49
      "code": "75108",
50
      "value": "PARIS 8"
51
    },
52
    "adresse": {
53
      "l1": "OCTO TECHNOLOGY",
54
      "l4": "50 AVENUE DES CHAMPS ELYSEES",
55
      "l6": "75008 PARIS",
56
      "l7": "FRANCE",
57
      "numero_voie": "50",
58
      "type_voie": "AV",
59
      "nom_voie": "DES CHAMPS ELYSEES",
60
      "code_postal": "75008",
61
      "localite": "PARIS 8",
62
      "code_insee_localite": "75108",
63
    },
64
    "etat_administratif": {
65
      "value": "F",
66
      "date_fermeture": 1315173600
67
    }
68
  },
69
  "gateway_error": False
70
}
71

  
72
ENTREPRISES_RESPONSE = {
73
  "entreprise": {
74
    "siren": "418166096",
75
    "capital_social": 459356,
76
    "numero_tva_intracommunautaire": "FR16418166096",
77
    "forme_juridique": "SA à directoire (s.a.i.)",
78
    "forme_juridique_code": "5699",
79
    "nom_commercial": "OCTO-TECHNOLOGY",
80
    "procedure_collective": False,
81
    "naf_entreprise": "6202A",
82
    "libelle_naf_entreprise": "Conseil en systèmes et logiciels informatiques",
83
    "raison_sociale": "OCTO-TECHNOLOGY",
84
    "siret_siege_social": "41816609600051",
85
    "code_effectif_entreprise": "31",
86
    "date_creation": 891381600,
87
    "categorie_entreprise": "PME",
88
    "tranche_effectif_salarie_entreprise": {
89
      "de": 200,
90
      "a": 249,
91
      "code": "31",
92
      "date_reference": "2014",
93
      "intitule": "200 à 249 salariés"
94
    },
95
    "mandataires_sociaux": [{
96
      "nom": "HISQUIN",
97
      "prenom": "FRANCOIS",
98
      "fonction": "PRESIDENT DU DIRECTOIRE",
99
      "dirigeant": True,
100
      "date_naissance": "1965-01-27",
101
      "raison_sociale": "",
102
      "identifiant": "",
103
      "type": "PP"
104
    }, {
105
        "nom": "",
106
        "prenom": "",
107
        "fonction": "COMMISSAIRE AUX COMPTES SUPPLEANT",
108
        "dirigeant": True,
109
        "date_naissance": "",
110
        "date_naissance_timestamp": 0,
111
        "raison_sociale": "BCRH & ASSOCIES - SOCIETE A RESPONSABILITE LIMITEE A ASSOCIE UNIQUE",
112
        "identifiant": "490092574",
113
        "type": "PM"
114
      }
115
    ],
116
    "etat_administratif": {
117
      "value": "C", # A (actif) ou C (cessé)
118
      "date_cessation": 1315173600 # null quand actif (A), un timestamp (un entier) quand cessé (C )
119
    }
120
  },
121
  "etablissement_siege": {
122
    "siege_social": True,
123
    "siret": "41816609600051",
124
    "naf": "6202A",
125
    "libelle_naf": "Conseil en systèmes et logiciels informatiques",
126
    "date_mise_a_jour": 1449183600,
127
    "tranche_effectif_salarie_etablissement": {
128
      "de": 200,
129
      "a": 249,
130
      "code": "31",
131
      "date_reference": "2014",
132
      "intitule": "200 à 249 salariés"
133
    },
134
    "date_creation_etablissement": 1108594800,
135
    "region_implantation": {
136
      "code": "11",
137
      "value": "Île-de-France"
138
    },
139
    "commune_implantation": {
140
      "code": "75108",
141
      "value": "PARIS 8"
142
    },
143
    "adresse": {
144
      "l1": "OCTO TECHNOLOGY",
145
      "l4": "50 AVENUE DES CHAMPS ELYSEES",
146
      "l6": "75008 PARIS",
147
      "l7": "FRANCE",
148
      "numero_voie": "50",
149
      "type_voie": "AV",
150
      "nom_voie": "DES CHAMPS ELYSEES",
151
      "code_postal": "75008",
152
      "localite": "PARIS 8",
153
      "code_insee_localite": "75108",
154
    },
155
    "etat_administratif": {
156
        "value": "F",
157
        "date_fermeture": 1315173600
158
    }
159
  },
160
  "gateway_error": False
161
}
162

  
163
EXTRAITS_RCS_RESPONSE = {
164
  "siren": "418166096",
165
  "date_immatriculation": "1998-03-27",
166
  "date_immatriculation_timestamp": 890953200,
167
  "date_extrait": "21 AVRIL 2017",
168
  "observations": [
169
    {
170
      "date": "2000-02-23",
171
      "date_timestamp": 951260400,
172
      "numero": "12197",
173
      "libelle": " LA SOCIETE NE CONSERVE AUCUNE ACTIVITE A SON ANCIEN SIEGE "
174
    }
175
  ]
176
}
177

  
178
ASSOCIATIONS_RESPONSE = {
179
  "association" : {
180
    "id": "W751135389",
181
    "titre": "ALLIANCE DU COEUR: UNION NATIONALE DES FEDERATIONS ET ASSOCIATIONS DE MALADES CARDIOVASCULAIRES",
182
    "objet": "information, soutien, solidarité et accompagnement psycho médico social des personnes malades cardiovasculaires et de leurs proches...",
183
    "siret": "42135938100025",
184
    "siret_siege_social": "42135938100033",
185
    "date_creation": "1993-02-11",
186
    "date_declaration": "2013-06-28",
187
    "date_publication": "1993-03-03",
188
    "adresse_siege": {
189
      "numero_voie": "10",
190
      "type_voie": "RUE",
191
      "libelle_voie": "Lebouis",
192
      "code_insee": "75120",
193
      "code_postal": "75014",
194
      "commune": "Paris"
195
    },
196
    "groupement": "Simple",
197
    "mise_a_jour": "2013-06-28"
198
  }
199
}
200

  
201
DOCUMENTS_ASSOCIATION_RESPONSE = {
202
  "nombre_documents": 2,
203
  "documents": [
204
    {
205
      "type": "Statuts",
206
      "url": "https://apientreprise.fr/attestations/40ab0b07d434d0417e8997ce7c5afbef/attestation_document_association.pdf",
207
      "timestamp": "1500660325"
208
    },
209
    {
210
      "type": "Récépissé",
211
      "url": "https://apientreprise.fr/attestations/40ab0b07d434d0417e8997ce7c5afbef/recepisse_association.pdf",
212
      "timestamp": "1500667325"
213
    },
214
  ]
215
}
216

  
217
DOCUMENT_ASSOCIATION_RESPONSE = "binary content"
218

  
219
@urlmatch(netloc='^entreprise.api.gouv.fr$',
220
          path='^/v2/etablissements/')
221
def api_entreprise_etablissements(url, request):
222
    return response(200, ETABLISSEMENTS_RESPONSE, request=request)
223

  
224

  
225
@urlmatch(netloc='^entreprise.api.gouv.fr$',
226
          path='^/v2/entreprises/')
227
def api_entreprise_entreprises(url, request):
228
    return response(200, ENTREPRISES_RESPONSE, request=request)
229

  
230

  
231
@urlmatch(netloc='^entreprise.api.gouv.fr$',
232
          path='^/v2/associations/')
233
def api_entreprise_associations(url, request):
234
    return response(200, ASSOCIATIONS_RESPONSE, request=request)
235

  
236

  
237
@urlmatch(netloc='^entreprise.api.gouv.fr$',
238
          path='^/v2/extraits_rcs_infogreffe/')
239
def api_entreprise_extraits_rcs(url, request):
240
    return response(200, EXTRAITS_RCS_RESPONSE, request=request)
241

  
242

  
243
@urlmatch(netloc='^entreprise.api.gouv.fr$',
244
          path='^/v2/documents_associations/')
245
def api_entreprise_documents_associations(url, request):
246
    return response(200, DOCUMENTS_ASSOCIATION_RESPONSE, request=request)
247

  
248
@urlmatch(netloc='^apientreprise.fr$',
249
          path='^/attestations/')
250
def api_entreprise_document_association(url, request):
251
    return response(200, DOCUMENT_ASSOCIATION_RESPONSE, request=request)
252

  
253

  
254
@urlmatch(netloc='^entreprise.api.gouv.fr$')
255
def api_entreprise_error_500(url, request):
256
    return response(500, 'bad error happened', request=request)
257

  
258

  
259
@urlmatch(netloc='^entreprise.api.gouv.fr$')
260
def api_entreprise_error_not_json(url, request):
261
    return response(200, 'simple text', request=request)
262

  
263

  
264
@urlmatch(netloc='^entreprise.api.gouv.fr$')
265
def api_entreprise_error_not_found(url, request):
266
    return response(404, {
267
        'error': 'not_found',
268
        'message': u'Page not found'
269
    }, request=request)
270

  
271

  
272
@pytest.yield_fixture
273
def mock_api_entreprise():
274
    with HTTMock(api_entreprise_etablissements, api_entreprise_entreprises, api_entreprise_associations, api_entreprise_extraits_rcs,
275
                 api_entreprise_associations, api_entreprise_documents_associations, api_entreprise_document_association):
276
        yield None
277

  
278

  
279
@pytest.fixture
280
def resource(db):
281
    return make_resource(
282
        APIEntreprise,
283
        slug='test',
284
        title='API Entreprise',
285
        description='API Entreprise',
286
        token='83c68bf0b6013c4daf3f8213f7212aa5',
287
        recipient='Test', context='Test',
288
        obj='Test')
289

  
290

  
291
def test_entreprises_endpoint(app, resource, mock_api_entreprise):
292
    response = app.get('/api-entreprise/test/entreprises/443170139/')
293
    data = response.json['data']
294
    assert 'entreprise' in data
295
    assert data['entreprise']['categorie_entreprise'] == 'PME'
296
    assert data['entreprise']['numero_tva_intracommunautaire'] == 'FR16418166096'
297
    assert data['entreprise']['siret_siege_social'] == '41816609600051'
298
    assert data['entreprise']['forme_juridique_code'] == '5699'
299
    assert data['entreprise']['siren'] == '418166096'
300
    assert data['entreprise']['date_creation'] == 891381600
301

  
302
    assert 'etablissement_siege' in data
303
    assert data['etablissement_siege']['siret'] == '41816609600051'
304
    assert data['etablissement_siege']['adresse']['numero_voie'] == '50'
305
    assert data['etablissement_siege']['adresse']['type_voie'] == 'AV'
306
    assert data['etablissement_siege']['adresse']['nom_voie'] == 'DES CHAMPS ELYSEES'
307
    assert data['etablissement_siege']['adresse']['code_postal'] == '75008'
308
    assert data['etablissement_siege']['adresse']['localite'] == 'PARIS 8'
309
    assert data['etablissement_siege']['adresse']['code_insee_localite'] == '75108'
310

  
311

  
312
def test_etablissements_endpoint(app, resource, mock_api_entreprise):
313
    response = app.get('/api-entreprise/test/etablissements/44317013900036/')
314
    assert 'data' in response.json
315
    data = response.json['data']
316

  
317
    assert 'etablissement' in data
318
    assert data['etablissement']['siret'] == '41816609600051'
319
    assert data['etablissement']['naf'] == '6202A'
320
    assert data['etablissement']['date_mise_a_jour'] == 1449183600
321
    assert data['etablissement']['date_creation_etablissement'] == 1108594800
322

  
323
    assert 'adresse' in data['etablissement']
324
    assert data['etablissement']['adresse']['code_postal'] == '75008'
325
    assert data['etablissement']['adresse']['localite'] == 'PARIS 8'
326
    assert data['etablissement']['adresse']['code_insee_localite'] == '75108'
327

  
328

  
329
def test_associations_endpoint(app, resource, mock_api_entreprise):
330
    response = app.get('/api-entreprise/test/associations/443170139/')
331
    assert 'data' in response.json
332
    data = response.json['data']
333

  
334
    assert 'association' in data
335
    assert data['association']['id'] == 'W751135389'
336
    assert data['association']['siret'] == '42135938100025'
337

  
338
    assert 'adresse_siege' in data['association']
339
    assert data['association']['adresse_siege']['code_postal'] == '75014'
340
    assert data['association']['adresse_siege']['code_insee'] == '75120'
341

  
342

  
343

  
344
def test_documents_associations_endpoint(app, resource, mock_api_entreprise):
345
    response = app.get('/api-entreprise/test/documents_associations/443170139/')
346
    assert 'data' in response.json
347
    data = response.json['data']
348
    assert len(data) == 2
349
    for document in data:
350
        assert 'id' in document
351
        assert 'text' in document
352
        assert 'url' in document
353
        assert 'datetime' in document
354
        assert 'type' in document
355

  
356

  
357
def test_document_association(app, resource, mock_api_entreprise):
358
    response = app.get('/api-entreprise/test/documents_associations/443170139/')
359
    assert 'data' in response.json
360
    data = response.json['data']
361
    assert len(data) == 2
362
    for document in data:
363
        assert 'url' in document
364
        resp = app.get(document['url'], status=200)
365
        # try to get document with wrong signature
366
        url = document['url']
367
        wrong_url = document['url'] + "wrong/"
368
        resp = app.get(wrong_url, status=404)
369

  
370

  
371
def test_error_500(app, resource, mock_api_entreprise):
372
    with HTTMock(api_entreprise_error_500):
373
        response = app.get('/api-entreprise/test/entreprises/443170139/')
374
        assert response.status_code == 200
375
        assert response.json['err'] == 1
376
        assert response.json['data']['status_code'] == 500
377
        assert 'error happened' in response.json['err_desc']
378

  
379

  
380
def test_no_json_error(app, resource, mock_api_entreprise):
381
    with HTTMock(api_entreprise_error_not_json):
382
        response = app.get('/api-entreprise/test/entreprises/443170139/')
383
        assert response.status_code == 200
384
        assert response.json['err'] == 1
385
        assert response.json['err_desc'] == "API-entreprise returned non-JSON content with status 200: 'simple text'"
386

  
387

  
388
def test_error_404(app, resource, mock_api_entreprise):
389
    with HTTMock(api_entreprise_error_not_found):
390
        response = app.get('/api-entreprise/test/entreprises/443170139/')
391
        assert response.status_code == 200
392
        assert response.json['err'] == 1
393
        assert response.json['err_desc'] == 'Page not found'
0
-