Projet

Général

Profil

0001-api_entreprise-add-match_mandataire_social-endpoint-.patch

Paul Marillonnet, 11 mai 2022 15:05

Télécharger (6,39 ko)

Voir les différences:

Subject: [PATCH] api_entreprise: add match_mandataire_social endpoint (#64687)

 passerelle/apps/api_entreprise/models.py | 41 +++++++++++++++++++++++
 passerelle/apps/api_entreprise/utils.py  | 34 +++++++++++++++++++
 tests/test_api_entreprise.py             | 42 ++++++++++++++++++++++++
 3 files changed, 117 insertions(+)
 create mode 100644 passerelle/apps/api_entreprise/utils.py
passerelle/apps/api_entreprise/models.py
33 33
from passerelle.utils.jsonresponse import APIError, exception_to_text
34 34
from passerelle.views import WrongParameter
35 35

  
36
from .utils import simple_match
37

  
36 38
DOCUMENT_SIGNATURE_MAX_AGE = timedelta(days=7)
37 39

  
38 40

  
......
170 172
        'example_value': '2019',
171 173
    }
172 174

  
175
    FIRST_NAME_PARAM = {'description': _('matched user\'s first name'), 'example_value': 'John'}
176

  
177
    LAST_NAME_PARAM = {'description': _('matched user\'s last name'), 'example_value': 'Doe'}
178

  
179
    BIRTHDATE_PARAM = {'description': _('matched user\'s YYYYDDMM birthdate'), 'example_value': '19700131'}
180

  
181
    METHOD_PARAM = {'description': _('method used for user identity matching'), 'example_value': 'simple'}
182

  
173 183
    @endpoint(
174 184
        perm='can_access',
175 185
        pattern=r'(?P<association_id>\w+)/$',
......
403 413
        return self.get(
404 414
            'effectifs_mensuels_acoss_covid/%s/%s/etablissement/%s/' % (year, month, siret), **kwargs
405 415
        )
416

  
417
    @endpoint(
418
        perm='can_access',
419
        pattern=r'(?P<siren>\w+)/$',
420
        description=_(
421
            'Match firm\'s society representative against local FranceConnect identity information'
422
        ),
423
        parameters={
424
            'siren': SIREN_PARAM,
425
            'first_name': FIRST_NAME_PARAM,
426
            'last_name': LAST_NAME_PARAM,
427
            'birthdate': BIRTHDATE_PARAM,
428
            'method': METHOD_PARAM,
429
            'object': OBJECT_PARAM,
430
            'context': CONTEXT_PARAM,
431
            'recipient': RECIPIENT_PARAM,
432
        },
433
    )
434
    def match_mandataire_social(
435
        self, request, siren, first_name, last_name, birthdate, method='simple', **kwargs
436
    ):
437
        entreprise = self.get(
438
            'entreprises/%s/' % siren,
439
            **kwargs,
440
        )
441
        if method not in ('simple',):
442
            return {'err': 1, 'err_desc': 'method %s not implemented' % method}
443
        for mandataire in entreprise['data'].get('entreprise', {}).get('mandataires_sociaux', []):
444
            if method == 'simple' and simple_match(mandataire, first_name, last_name, birthdate):
445
                return {'err': 0, 'data': mandataire}
446
        return {'err': 0, 'data': {}}
passerelle/apps/api_entreprise/utils.py
1
# passerelle - uniform access to multiple data sources and services
2
# Copyright (C) 2022  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 unicodedata import category
18
from unicodedata import normalize as unormalize
19

  
20

  
21
def normalize(s):
22
    return ''.join(c for c in unormalize('NFKD', s).casefold() if category(c) not in ('Mn', 'Zs'))
23

  
24

  
25
def simple_match(mandataire, first_name, last_name, birthdate):
26
    if any([attr not in mandataire for attr in ['prenom', 'nom', 'date_naissance']]):
27
        return False
28
    if normalize(mandataire['prenom'].split(',')[0]) != normalize(first_name):
29
        return False
30
    if normalize(mandataire['nom']) != normalize(last_name):
31
        return False
32
    if mandataire['date_naissance'].replace('-', '') != birthdate:
33
        return False
34
    return True
tests/test_api_entreprise.py
386 386
    assert data['etablissement_siege']['date_mise_a_jour'] == '2015-12-03'
387 387

  
388 388

  
389
def test_match_mandataire_social(app, resource, mock_api_entreprise):
390
    params = {
391
        'first_name': 'françois',
392
        'last_name': 'hIsQuIn',
393
        'birthdate': '19650127',
394
        'method': 'simple',
395
    }
396
    params.update(REQUEST_PARAMS)
397

  
398
    url = '/api-entreprise/test/match_mandataire_social/443170139/'
399
    response = app.get(url, params=params)
400

  
401
    # successful matching
402
    data = response.json['data']
403
    assert data['nom'] == 'HISQUIN'
404
    assert data['prenom'] == 'FRANCOIS'
405
    assert data['date_naissance'] == '1965-01-27'
406
    assert data['type'] == 'PP'
407

  
408
    params['method'] = 'unkwown'
409
    response = app.get(url, params=params)
410

  
411
    # unsupported method
412
    assert response.json['err']
413
    assert 'data' not in response.json
414

  
415
    params['method'] = 'simple'
416
    params.pop('first_name')
417
    response = app.get(url, params=params, status=400)
418

  
419
    # missing parameter
420
    assert not response.json['data']
421
    assert 'missing parameter' in response.json['err_desc']
422

  
423
    params['first_name'] = 'JOHN'
424
    response = app.get(url, params=params)
425

  
426
    # matching failed
427
    assert not response.json['err']
428
    assert not response.json['data']
429

  
430

  
389 431
@mock.patch('passerelle.utils.Request.get')
390 432
def test_entreprises_endpoint_include_private(mocked_get, app, resource, mock_api_entreprise):
391 433
    mocked_get.return_value = FakedResponse(content='{}', status_code=200)
392
-