Projet

Général

Profil

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

Serghei Mihai, 22 mars 2019 21:17

Télécharger (27,8 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      | 236 ++++++++++
 passerelle/settings.py                        |   1 +
 passerelle/static/css/style.css               |   4 +
 tests/test_api_entreprise.py                  | 402 ++++++++++++++++++
 7 files changed, 678 insertions(+)
 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 - uniform access to multiple data sources and services
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 six.moves.urllib_parse import urljoin
22
import requests
23

  
24

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

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

  
36
DOCUMENT_SIGNATURE_MAX_AGE = timedelta(days=7)
37

  
38
def normalize_dates(data):
39
    for key in data:
40
        if isinstance(data[key], dict):
41
            normalize_dates(data[key])
42
        if isinstance(data[key], list):
43
            for item in data[key]:
44
                normalize_dates(item)
45
        if key.startswith('date_'):
46
            # try to parse isoformatted dates
47
            try:
48
                data[key] = datetime.fromtimestamp(int(data[key])).date()
49
            except (ValueError, TypeError):
50
                pass
51
        if key.endswith('_timestamp'):
52
            # timestamps can be integers or strings
53
            try:
54
                data[key] = make_aware(datetime.fromtimestamp(int(data[key])))
55
            except (ValueError, TypeError):
56
                pass
57

  
58

  
59
class APIEntreprise(BaseResource):
60

  
61
    url = models.URLField(_('API URL'), max_length=256, default='https://entreprise.api.gouv.fr/v2/')
62
    token = models.CharField(max_length=1024, verbose_name=_('API token'))
63
    recipient = models.CharField(max_length=256, verbose_name=_('Call recipient'),
64
                                 help_text=_('ex: siret, institution_id, waldec, etc...'))
65
    context = models.CharField(max_length=256, verbose_name=_('Call context'),
66
                                 help_text=_('ex: APS, MPS, etc...'))
67
    obj = models.CharField(max_length=49, verbose_name=_('Calls object'))
68

  
69
    category = _('Business Process Connectors')
70

  
71
    class Meta:
72
        verbose_name = _('API Entreprise')
73

  
74
    def get(self, path, **kwargs):
75
        params = {'token': self.token,
76
            'context': kwargs.get('context', self.context),
77
            'object': kwargs.get('object', self.obj),
78
            'recipient': kwargs.get('recipient', self.recipient)
79
        }
80
        url = urljoin(self.url, path)
81
        try:
82
            response = self.requests.get(url, data=params)
83
        except requests.RequestException as e:
84
            raise APIError(u'API-entreprise connection error: %s' %
85
                           response.status_code,
86
                           data={'error': unicode(e)})
87
        try:
88
            data = response.json()
89
        except ValueError as e:
90
            content = repr(response.content[:1000])
91
            raise APIError(
92
                u'API-entreprise returned non-JSON content with status %s: %s' %
93
                (response.status_code, content),
94
                data={'status_code': response.status_code,
95
                      'exception': unicode(e),
96
                      'content': content,
97
                })
98
        if response.status_code != 200:
99
            if data.get('error') == 'not_found':
100
                return {
101
                    'err': 1,
102
                    'err_desc': data.get('message', 'not-found'),
103
                }
104
            raise APIError(
105
                u'API-entreprise returned a non 200 status %s: %s' %
106
                (response.status_code, data),
107
                data={
108
                    'status_code': response.status_code,
109
                    'content': data,
110
                })
111
        normalize_dates(data)
112
        return {
113
            'err': 0,
114
            'data': data,
115
        }
116

  
117

  
118
    @endpoint(perm='can_access',
119
              pattern='(?P<institution_id>\w+)/$',
120
              example_pattern='{institution_id}/',
121
              description=_('Get association\'s documents'),
122
              parameters={
123
                  'institution_id': {
124
                      'description': _('association id'),
125
                      'example_value': '44317013900036',
126
                }
127
              }
128
    )
129
    def documents_associations(self, request, institution_id, **kwargs):
130
        data = []
131
        resp = self.get('documents_associations/%s/' % institution_id)
132
        for item in resp['data'].get('documents', []):
133
            # ignore documents with no type
134
            if not item.get('type'):
135
                continue
136
            signature = signing.dumps({'type': item['type'], 'timestamp': item['timestamp']})
137
            document_url = request.build_absolute_uri(reverse('generic-endpoint', kwargs={'connector': self.get_connector_slug(),
138
                                        'slug': self.slug,
139
                                        'endpoint': 'document',
140
                                        'rest': '%s/%s/' % (institution_id, signature)}))
141
            data.append({'id': item['timestamp'],
142
                         'text': item['type'],
143
                         'datetime': datetime.fromtimestamp(int(item['timestamp'])),
144
                         'type': item['type'],
145
                         'url': document_url})
146
        # sort data by date
147
        data.sort(key=lambda i: i['datetime'])
148
        return {'err': 0, 'data': data}
149

  
150

  
151
    @endpoint(perm='can_access',
152
              pattern='(?P<institution_id>\w+)/(?P<document_id>[\:\w-]+)/$',
153
              example_pattern='{institution_id}/{document_id}/',
154
              description=_('Get institution\'s document'),
155
              parameters={
156
                  'institution_id': {
157
                      'description': _('institution id'),
158
                      'example_value': '44317013900036',
159
                  },
160
                  'document_id': {
161
                      'description': _('document id'),
162
                      'example_value': 'A1500660325',
163
                  }
164
              }
165
    )
166
    def document(self, request, institution_id, document_id, **kwargs):
167
        resp = self.get('documents_associations/%s/' % institution_id)
168
        for item in resp['data'].get('documents', []):
169
            # ignore documents with no type
170
            if not item.get('type'):
171
                continue
172
            try:
173
                r = signing.loads(document_id, max_age=DOCUMENT_SIGNATURE_MAX_AGE)
174
                print r
175
            except signing.BadSignature:
176
                continue
177
            return HttpResponse(self.requests.get(item['url']),
178
                                content_type='application/pdf')
179
        raise Http404('document not found')
180

  
181

  
182
    @endpoint(perm='can_access',
183
              pattern='(?P<institution_id>\w+)/$',
184
              example_pattern='{institution_id}/',
185
              description=_('Get institution\'s data from Infogreffe'),
186
              parameters={
187
                  'institution_id': {
188
                      'description': _('institution id'),
189
                      'example_value': '44317013900036',
190
                }
191
              }
192
    )
193
    def extraits_rcs(self, request, institution_id, **kwargs):
194
        return self.get('extraits_rcs_infogreffe/%s/' % institution_id)
195

  
196
    @endpoint(perm='can_access',
197
              pattern='(?P<institution_id>\w+)/$',
198
              example_pattern='{institution_id}/',
199
              description=_('Get institution\'s related informations'),
200
              parameters={
201
                  'institution_id': {
202
                      'description': _('institution id'),
203
                      'example_value': '44317013900036',
204
                }
205
              }
206
    )
207
    def associations(self, request, institution_id, **kwargs):
208
        return self.get('associations/%s/' % institution_id)
209

  
210
    @endpoint(perm='can_access',
211
              pattern='(?P<institution_id>\w+)/$',
212
              example_pattern='{institution_id}/',
213
              description=_('Get institution\'s related informations'),
214
              parameters={
215
                  'institution_id': {
216
                      'description': _('association id'),
217
                      'example_value': '44317013900036',
218
                }
219
              }
220
    )
221
    def entreprises(self, request, institution_id, **kwargs):
222
        return self.get('entreprises/%s/' % institution_id)
223

  
224
    @endpoint(perm='can_access',
225
              pattern='(?P<institution_id>\w+)/$',
226
              example_pattern='{institution_id}/',
227
              description=_('Get institution\'s related informations'),
228
              parameters={
229
                  'institution_id': {
230
                      'description': _('institution id'),
231
                      'example_value': '44317013900036',
232
                }
233
              }
234
    )
235
    def etablissements(self, request, institution_id, **kwargs):
236
        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
168 168
	content: "\f2c3";  /* id-card-o */
169 169
}
170 170

  
171
li.connector.apientreprise a::before {
172
	content: "\f1ad";  /* fa-building-o */
173
}
174

  
171 175
li.connector.dpark a::before {
172 176
	content: "\f1b9";  /* car */
173 177
}
tests/test_api_entreprise.py
1
# -*- coding: utf-8 -*-
2

  
3
# tests/test_api_entreprise.py
4
# Copyright (C) 2019  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
from django.utils import timezone
25

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

  
28
from utils import make_resource, endpoint_get
29

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

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

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

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

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

  
218
DOCUMENT_ASSOCIATION_RESPONSE = "binary content"
219

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

  
225

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

  
231

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

  
237

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

  
243

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

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

  
254

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

  
259

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

  
264

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

  
272

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

  
279

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

  
291

  
292
def test_entreprises_endpoint(app, resource, mock_api_entreprise):
293
    response = app.get('/api-entreprise/test/entreprises/443170139/')
294
    data = response.json['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'] == '1998-03-31'
301
    assert data['entreprise']['mandataires_sociaux'][0]['date_naissance'] == '1965-01-27'
302

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

  
313

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

  
319
    assert 'etablissement' in data
320
    assert data['etablissement']['siret'] == '41816609600051'
321
    assert data['etablissement']['naf'] == '6202A'
322
    assert data['etablissement']['date_mise_a_jour'] == '2015-12-03'
323
    assert data['etablissement']['date_creation_etablissement'] == '2005-02-16'
324

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

  
330

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

  
336
    assert 'association' in data
337
    assert data['association']['id'] == 'W751135389'
338
    assert data['association']['siret'] == '42135938100025'
339
    assert data['association']['date_creation'] == '1993-02-11'
340
    assert data['association']['date_declaration'] == '2013-06-28'
341
    assert data['association']['date_publication'] == '1993-03-03'
342

  
343
    assert 'adresse_siege' in data['association']
344
    assert data['association']['adresse_siege']['code_postal'] == '75014'
345
    assert data['association']['adresse_siege']['code_insee'] == '75120'
346

  
347

  
348

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

  
361

  
362
def test_document_association(app, resource, mock_api_entreprise, freezer):
363
    response = app.get('/api-entreprise/test/documents_associations/443170139/')
364
    assert 'data' in response.json
365
    data = response.json['data']
366
    assert len(data) == 2
367
    document = data[0]
368
    assert 'url' in document
369
    resp = app.get(document['url'], status=200)
370
    # try to get document with wrong signature
371
    url = document['url']
372
    wrong_url = document['url'] + "wrong/"
373
    resp = app.get(wrong_url, status=404)
374
    # try expired url
375
    freezer.move_to(timezone.now() + timezone.timedelta(days=8))
376
    resp = app.get(document['url'], status=404)
377

  
378

  
379

  
380
def test_error_500(app, resource, mock_api_entreprise):
381
    with HTTMock(api_entreprise_error_500):
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['data']['status_code'] == 500
386
        assert 'error happened' in response.json['err_desc']
387

  
388

  
389
def test_no_json_error(app, resource, mock_api_entreprise):
390
    with HTTMock(api_entreprise_error_not_json):
391
        response = app.get('/api-entreprise/test/entreprises/443170139/')
392
        assert response.status_code == 200
393
        assert response.json['err'] == 1
394
        assert response.json['err_desc'] == "API-entreprise returned non-JSON content with status 200: 'simple text'"
395

  
396

  
397
def test_error_404(app, resource, mock_api_entreprise):
398
    with HTTMock(api_entreprise_error_not_found):
399
        response = app.get('/api-entreprise/test/entreprises/443170139/')
400
        assert response.status_code == 200
401
        assert response.json['err'] == 1
402
        assert response.json['err_desc'] == 'Page not found'
0
-