Projet

Général

Profil

0001-add-actesweb-connector-22395.patch

Josué Kouka, 14 septembre 2018 14:55

Télécharger (21,4 ko)

Voir les différences:

Subject: [PATCH] add actesweb connector (#22395)

 passerelle/apps/actesweb/__init__.py          |   0
 .../apps/actesweb/migrations/0001_initial.py  |  28 +++
 .../apps/actesweb/migrations/__init__.py      |   0
 passerelle/apps/actesweb/models.py            |  79 ++++++++
 .../actesweb/templates/actesweb/demand.txt    |  46 +++++
 passerelle/settings.py                        |   1 +
 tests/data/actesweb/payload_birth.json        |  50 +++++
 tests/data/actesweb/payload_death.json        |  37 ++++
 tests/data/actesweb/payload_mariage.json      |  68 +++++++
 tests/test_actesweb.py                        | 171 ++++++++++++++++++
 10 files changed, 480 insertions(+)
 create mode 100644 passerelle/apps/actesweb/__init__.py
 create mode 100644 passerelle/apps/actesweb/migrations/0001_initial.py
 create mode 100644 passerelle/apps/actesweb/migrations/__init__.py
 create mode 100644 passerelle/apps/actesweb/models.py
 create mode 100644 passerelle/apps/actesweb/templates/actesweb/demand.txt
 create mode 100644 tests/data/actesweb/payload_birth.json
 create mode 100644 tests/data/actesweb/payload_death.json
 create mode 100644 tests/data/actesweb/payload_mariage.json
 create mode 100644 tests/test_actesweb.py
passerelle/apps/actesweb/migrations/0001_initial.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4
from django.db import migrations, models
5

  
6

  
7
class Migration(migrations.Migration):
8

  
9
    dependencies = [
10
        ('base', '0007_auto_20180914_0753'),
11
    ]
12

  
13
    operations = [
14
        migrations.CreateModel(
15
            name='ActesWeb',
16
            fields=[
17
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
18
                ('title', models.CharField(max_length=50, verbose_name='Title')),
19
                ('description', models.TextField(verbose_name='Description')),
20
                ('slug', models.SlugField(unique=True)),
21
                ('log_level', models.CharField(default=b'INFO', max_length=10, verbose_name='Log Level', choices=[(b'NOTSET', b'NOTSET'), (b'DEBUG', b'DEBUG'), (b'INFO', b'INFO'), (b'WARNING', b'WARNING'), (b'ERROR', b'ERROR'), (b'CRITICAL', b'CRITICAL')])),
22
                ('users', models.ManyToManyField(to='base.ApiUser', blank=True)),
23
            ],
24
            options={
25
                'verbose_name': "ActesWeb - Demande d'acte d'\xe9tat civil",
26
            },
27
        ),
28
    ]
passerelle/apps/actesweb/models.py
1
# -*- coding: utf-8 -*-
2
# Copyright (C) 2018  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
from __future__ import unicode_literals
17

  
18
import json
19
import os
20
import tempfile
21

  
22
from django.core.files.storage import default_storage
23
from django.template.loader import get_template
24
from django.utils.dateparse import parse_date
25
from django.utils.timezone import now
26
from django.utils.translation import ugettext_lazy as _
27

  
28
from passerelle.base.models import BaseResource
29
from passerelle.utils.api import endpoint
30
from passerelle.utils.jsonresponse import APIError
31

  
32

  
33
class ActesWeb(BaseResource):
34
    category = _('Civil Status Connectors')
35

  
36
    class Meta:
37
        verbose_name = u"ActesWeb - Demande d'acte d'état civil"
38

  
39
    @property
40
    def basepath(self):
41
        return os.path.join(
42
            default_storage.path('actesweb'), self.slug)
43

  
44
    @endpoint(perm='can_access', methods=['post'], description=_('Create demand'))
45
    def create(self, request, *args, **kwargs):
46
        try:
47
            payload = json.loads(request.body)
48
        except (ValueError,):
49
            raise APIError('Invalid payload format: json expected')
50

  
51
        if payload.get('certificate_type') not in ('NA', 'DE', 'MA'):
52
            raise APIError("Invalid <certificate_type>: expected ('NA', 'DE', 'MA')")
53
        payload['event_date_start'] = parse_date(payload['event_date_start']).strftime('%Y%m%d')
54
        template_name = 'actesweb/demand.txt'
55
        demand_content = get_template(template_name).render(payload)
56
        application_id = payload['application_id']
57
        # create tmp dir
58
        tmp_dir = os.path.join(self.basepath, 'tmp')
59
        if not os.path.exists(tmp_dir):
60
            if default_storage.directory_permissions_mode:
61
                d_umask = os.umask(0)
62
                try:
63
                    os.makedirs(tmp_dir, mode=default_storage.directory_permissions_mode)
64
                except OSError:
65
                    pass
66
                finally:
67
                    os.umask(d_umask)
68
            else:
69
                os.makedirs(tmp_dir)
70

  
71
        filename = '%s.DEM' % now().strftime('%Y-%m-%d_%H-%M-%S_%f')
72
        filepath = os.path.join(self.basepath, filename)
73
        with tempfile.NamedTemporaryFile(dir=tmp_dir, suffix='.DEM', delete=False) as tpf:
74
            tpf.write(demand_content)
75
            tpf.flush()
76
            os.fsync(tpf.file.fileno())
77
            os.rename(tpf.name, filepath)
78
        demand_id = '%s_%s' % (application_id, os.path.basename(filepath))
79
        return {'data': {'demand_id': demand_id}}
passerelle/apps/actesweb/templates/actesweb/demand.txt
1
CODAGE=TXT
2
TYPE=DEMANDE
3
VERSION=03
4
TYPE_DEMANDEUR={{applicant_type}}
5
PRIORITE={{application_priority}}
6
DEMANDEUR_CIVILITE={{applicant_title_label}}
7
DEMANDEUR_NOM={{application_priority}}
8
DEMANDEUR_NOM_USAGE={{applicant_usual_name}}
9
DEMANDEUR_PRENOMS={{applicant_firstnames}}
10
DEMANDEUR_ADRESSE1={{applicant_address_street}}
11
DEMANDEUR_ADRESSE2={{applicant_address_complement}}
12
DEMANDEUR_VILLE={{applicant_address_city}}
13
DEMANDEUR_PAYS={{applicant_address_country}}
14
DEMANDEUR_TEL={{applicant_phone}}
15
DEMANDEUR_ADR={{applicant_email}}
16
DEMANDE_NOM={{concerned_lastname}}
17
DEMANDE_PRENOMS={{concerned_firstnames}}
18
DEMANDE_DATE_EVENEMENT={{event_date_start}}
19
TYPE_DEMANDE={{document_type_label}}
20
ACTE={{certificate_type|default:"particulier"}}
21
NB={{document_copies}}
22
LIEN={{applicant_status}}
23
MANDANT_NOM=
24
MANDANT_PRENOMS=
25
LIEU_EVENEMENT={{event_city}}
26
REF_ACTE={{document_ref|default:"inconnu"}}
27
PERE_NOM={{concerned_parent1_lastname}}
28
PERE_PRENOMS={{concerned_parent1_firstnames}}
29
MERE_NOM={{concerned_parent2_lastname}}
30
MERE_PRENOMS={{concerned_parent2_firstnames}}
31
CONJOINT_NOM={{partner_lastname}}
32
CONJOINT_PRENOMS={{partner_firstnames}}
33
CONJOINT_PERE_NOM={{partner_parent1_lastname}}
34
CONJOINT_PERE_PRENOMS={{partner_parent1_firstnames}}
35
CONJOINT_MERE_NOM={{partner_parent2_lastname}}
36
CONJOINT_MERE_PRENOMS={{partner_parent2_firstnames}}
37
MOTIF={{application_reason}}
38
DEMANDE_SEXE={{concerned_sex}}
39
DPERE_SEXE={{concerned_parent1_sex}}
40
DMERE_SEXE={{concerned_parent2_sex}}
41
CONJOINT_SEXE={{partner_sex}}
42
CPERE_SEXE={{partner_parent1_sex}}
43
CMERE_SEXE={{partner_parent2_sex}}
44
{% spaceless %}
45
COMMENTAIRE={{application_comment}}
46
{% endspaceless %}
passerelle/settings.py
115 115
    'passerelle.base',
116 116
    'passerelle.datasources',
117 117
    # connectors
118
    'passerelle.apps.actesweb',
118 119
    'passerelle.apps.airquality',
119 120
    'passerelle.apps.api_particulier',
120 121
    'passerelle.apps.base_adresse',
tests/data/actesweb/payload_birth.json
1
{
2
    "applicant_address_city": "Nancy",
3
    "applicant_address_complement": "Bat A",
4
    "applicant_address_country": "France",
5
    "applicant_address_county": "Meurthe-et-Moselle",
6
    "applicant_address_street": "37 Rue du Cheval Blanc",
7
    "applicant_address_zipcode": "54000",
8
    "applicant_email": "chelsea@whatever.com",
9
    "applicant_firstnames": "Kim Chelsea",
10
    "applicant_lastname": "Whatever",
11
    "applicant_name_usage": "nom d'epouse",
12
    "applicant_phone": "+33 6 55 44 22 11",
13
    "applicant_status": "concerne",
14
    "applicant_title": "Mme",
15
    "applicant_title_label": "Madame",
16
    "applicant_usual_name": "Whatever",
17
    "application_id": "N201610154",
18
    "application_origin": "internet",
19
    "application_reason": "They are just messy",
20
    "application_time": "2016-10-20T14:41:20Z",
21
    "certificate_type": "NA",
22
    "certificate_type_label": "Acte de naissance",
23
    "concerned_birth_city": "Harare",
24
    "concerned_birth_country": "Zimbabwe",
25
    "concerned_birth_county": "",
26
    "concerned_birth_date": "1980-02-29",
27
    "concerned_firstnames": "Kevin",
28
    "concerned_lastname": "Whatever",
29
    "concerned_name_usage": "",
30
    "concerned_parent1_firstnames": "John Oliver",
31
    "concerned_parent1_lastname": "Smith",
32
    "concerned_parent1_name_usage": "Smith",
33
    "concerned_parent1_title": "M",
34
    "concerned_parent1_title_label": "Monsieur",
35
    "concerned_parent1_usual_name": "Smith",
36
    "concerned_parent2_firstnames": "Kim",
37
    "concerned_parent2_lastname": "Smith",
38
    "concerned_parent2_name_usage": "nom d'\u00e9pouse",
39
    "concerned_parent2_title": "Mme",
40
    "concerned_parent2_usual_name": "Smith",
41
    "concerned_sex": "m",
42
    "concerned_title": "M",
43
    "concerned_usual_name": "Whatever",
44
    "document_copies": "1",
45
    "document_type": "CPI",
46
    "document_type_label": "Copie Integrale",
47
    "event_city": "Nancy",
48
    "event_date_end": "",
49
    "event_date_start": "2012-07-14"
50
}
tests/data/actesweb/payload_death.json
1
{
2
    "applicant_address_city": "Nancy",
3
    "applicant_address_complement": "Bat A",
4
    "applicant_address_country": "France",
5
    "applicant_address_county": "Meurthe-et-Moselle",
6
    "applicant_email": "chelsea@whatever.com",
7
    "applicant_phone": "+33 6 55 44 22 11",
8
    "applicant_address_street": "37 Rue du Cheval Blanc",
9
    "applicant_address_zipcode": "54000",
10
    "applicant_firstnames": "Kim Chelsea",
11
    "applicant_lastname": "Whatever",
12
    "applicant_name_usage": "nom d'epouse",
13
    "applicant_status": "concerne",
14
    "applicant_title": "Mme",
15
    "applicant_title_label": "Madame",
16
    "applicant_usual_name": "Whatever",
17
    "application_id": "D201610171",
18
    "application_origin": "internet",
19
    "application_reason": "",
20
    "application_time": "2016-10-20T14:41:20Z",
21
    "certificate_type": "DE",
22
    "certificate_type_label": "Acte de d\u00e9c\u00e8s",
23
    "concerned_birth_city": "Harare",
24
    "concerned_birth_country": "Zimbabwe",
25
    "concerned_birth_county": "",
26
    "concerned_birth_date": "1980-02-29",
27
    "concerned_firstnames": "Kevin",
28
    "concerned_lastname": "Whatever",
29
    "concerned_sex": "m",
30
    "concerned_title": "M",
31
    "concerned_usual_name": "Whatever",
32
    "document_copies": "1",
33
    "document_type": "EXTSF",
34
    "document_type_label": "Extrait sans filiation",
35
    "event_city": "Nancy",
36
    "event_date_start": "2012-07-14"
37
}
tests/data/actesweb/payload_mariage.json
1
{
2
    "applicant_address_city": "Nancy",
3
    "applicant_address_complement": "Bat A",
4
    "applicant_address_country": "France",
5
    "applicant_address_county": "Meurthe-et-Moselle",
6
    "applicant_email": "chelsea@whatever.com",
7
    "applicant_phone": "+33 6 55 44 22 11",
8
    "applicant_address_street": "37 Rue du Cheval Blanc",
9
    "applicant_address_zipcode": "54000",
10
    "applicant_firstnames": "Kim Chelsea",
11
    "applicant_lastname": "Whatever",
12
    "applicant_name_usage": "nom d'epouse",
13
    "applicant_status": "concerne",
14
    "applicant_title": "Mme",
15
    "applicant_title_label": "Madame",
16
    "applicant_usual_name": "Whatever",
17
    "application_id": "M201610161",
18
    "application_origin": "internet",
19
    "application_reason": "Happy mariage",
20
    "application_time": "2016-10-20T14:41:20Z",
21
    "certificate_type": "MA",
22
    "certificate_type_label": "Acte de naissance",
23
    "concerned_birth_city": "Harare",
24
    "concerned_birth_country": "Zimbabwe",
25
    "concerned_birth_county": "",
26
    "concerned_birth_date": "1980-02-29",
27
    "concerned_firstnames": "Kevin",
28
    "concerned_lastname": "Whatever",
29
    "concerned_name_usage": "",
30
    "concerned_parent1_firstnames": "John Oliver",
31
    "concerned_parent1_lastname": "Smith",
32
    "concerned_parent1_name_usage": "Smith",
33
    "concerned_parent1_title": "M",
34
    "concerned_parent1_title_label": "Monsieur",
35
    "concerned_parent1_usual_name": "Smith",
36
    "concerned_parent2_firstnames": "Kim",
37
    "concerned_parent2_lastname": "Smith",
38
    "concerned_parent2_name_usage": "nom d'\u00e9pouse",
39
    "concerned_parent2_title": "Mme",
40
    "concerned_parent2_usual_name": "Smith",
41
    "concerned_sex": "m",
42
    "concerned_title": "M",
43
    "document_copies": "1",
44
    "document_type": "CPI",
45
    "document_type_label": "Copie Integrale",
46
    "event_city": "Nancy",
47
    "event_date_end": "",
48
    "event_date_start": "2012-07-14",
49
    "partner_birth_city": "Harare",
50
    "partner_birth_country": "Zimbabwe",
51
    "partner_birth_county": "",
52
    "partner_birth_date": "1984-02-29",
53
    "partner_firstnames": "Chelsea",
54
    "partner_lastname": "Contrao",
55
    "partner_name_usage": "",
56
    "partner_parent1_firstnames": "Antonio",
57
    "partner_parent1_lastname": "Scaramucci",
58
    "partner_parent1_title": "M",
59
    "partner_parent1_title_label": "Monsieur",
60
    "partner_parent2_firstnames": "Marguerite",
61
    "partner_parent2_lastname": "Scaramucci",
62
    "partner_parent2_name_usage": "nom d'\u00e9pouse",
63
    "partner_parent2_title": "Mme",
64
    "partner_parent2_usual_name": "Gaye",
65
    "partner_sex": "F",
66
    "partner_title": "Mme",
67
    "partner_usual_name": "Scaramucci"
68
}
tests/test_actesweb.py
1
# -*- coding: utf-8 -*-
2
# Passerelle - uniform access to data and services
3
# Copyright (C) 2018  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; exclude 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.deepcopy of the GNU Affero General Public License
16
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
from __future__ import unicode_literals
18

  
19
import json
20
import io
21
import os
22
import shutil
23

  
24
import pytest
25

  
26
import utils
27
from passerelle.apps.actesweb.models import ActesWeb
28

  
29

  
30
def get_test_base_dir(name):
31
    return os.path.join(os.path.dirname(__file__), 'data', name)
32

  
33

  
34
def get_file_from_test_base_dir(filename):
35
    path = os.path.join(get_test_base_dir('actesweb'), filename)
36
    with open(path, 'rb') as fd:
37
        return fd.read()
38

  
39

  
40
@pytest.fixture
41
def actesweb(db):
42
    return utils.make_resource(ActesWeb, **{'slug': 'test'})
43

  
44

  
45
@pytest.fixture(autouse=True)
46
def media_dir(tmpdir, settings):
47
    tmp_dir = tmpdir.mkdir('actesweb').dirname
48
    settings.MEDIA_ROOT = tmp_dir
49
    yield tmp_dir
50
    shutil.rmtree(tmp_dir, ignore_errors=True)
51

  
52

  
53
PAYLOAD = [
54
    {
55
        'birth': json.loads(get_file_from_test_base_dir('payload_birth.json'))
56
    },
57
    {
58
        'mariage': json.loads(get_file_from_test_base_dir('payload_mariage.json'))
59
    },
60
    {
61
        'death': json.loads(get_file_from_test_base_dir('payload_death.json'))
62
    }
63
]
64

  
65

  
66
@pytest.fixture(params=PAYLOAD)
67
def payload(request):
68
    return request.param
69

  
70

  
71
def get_demand_filepath(con, demand_id):
72
    filename = '_'.join(demand_id.split('_')[1:])
73
    return os.path.join(con.basepath, filename)
74

  
75

  
76
def assert_file_content_values(filename, expectations):
77
    with io.open(filename, 'rb') as fp:
78
        for line in fp.readlines():
79
            field, value = line.split('=')
80
            if field in expectations:
81
                assert value.strip() == expectations[field]
82

  
83

  
84
def test_demand_creation(app, payload, actesweb):
85
    url = '/actesweb/test/create/'
86
    if 'birth' in payload:
87
        response = app.post_json(url, params=payload['birth'])
88
        demand_id = response.json['data']['demand_id']
89
        demfile = get_demand_filepath(actesweb, demand_id)
90
        assert_file_content_values(
91
            demfile, dict(
92
                DEMANDEUR_CIVILITE="Madame",
93
                DEMANDEUR_NOM_USAGE="Whatever",
94
                DEMANDEUR_PRENOMS="Kim Chelsea",
95
                DEMANDEUR_ADRESSE1="37 Rue du Cheval Blanc",
96
                DEMANDEUR_VILLE="Nancy",
97
                DEMANDEUR_PAYS="France",
98
                DEMANDEUR_TEL="+33 6 55 44 22 11",
99
                DEMANDEUR_ADR="chelsea@whatever.com",
100
                DEMANDE_NOM="Whatever",
101
                DEMANDE_PRENOMS="Kevin",
102
                DEMANDE_DATE_EVENEMENT="20120714",
103
                TYPE_DEMANDE="Copie Integrale",
104
                ACTE="NA",
105
                NB="1",
106
                LIEU_EVENEMENT="Nancy",
107
                PERE_NOM="Smith",
108
                PERE_PRENOMS="John Oliver",
109
                MERE_NOM="Smith",
110
                MERE_PRENOM="Kim",
111
                DEMANDE_SEXE="m"
112
            )
113
        )
114
    elif 'mariage' in payload:
115
        response = app.post_json(url, params=payload['mariage'])
116
        demand_id = response.json['data']['demand_id']
117
        demfile = get_demand_filepath(actesweb, demand_id)
118
        assert_file_content_values(
119
            demfile, dict(
120
                DEMANDEUR_CIVILITE="Madame",
121
                DEMANDEUR_NOM_USAGE="Whatever",
122
                DEMANDEUR_PRENOMS="Kim Chelsea",
123
                DEMANDEUR_ADRESSE1="37 Rue du Cheval Blanc",
124
                DEMANDEUR_VILLE="Nancy",
125
                DEMANDEUR_PAYS="France",
126
                DEMANDEUR_TEL="+33 6 55 44 22 11",
127
                DEMANDEUR_ADR="chelsea@whatever.com",
128
                DEMANDE_NOM="Whatever",
129
                DEMANDE_PRENOMS="Kevin",
130
                DEMANDE_DATE_EVENEMENT="20120714",
131
                TYPE_DEMANDE="Copie Integrale",
132
                ACTE="MA",
133
                NB="1",
134
                LIEU_EVENEMENT="Nancy",
135
                PERE_NOM="Smith",
136
                PERE_PRENOMS="John Oliver",
137
                MERE_NOM="Smith",
138
                MERE_PRENOM="Kim",
139
                DEMANDE_SEXE="m",
140
                CONJOINT_NOM="Contrao",
141
                CONJOIN_PRENOMS="Chelsea",
142
                CONJOINT_PERE_NOM="Scaramucci",
143
                CONJOINT_PERE_PRENOMS="Antonio",
144
                CONJOINT_MERE_NOM="Scaramucci",
145
                CONJOINT_MERE_PRENOMS="Marguerite",
146
            )
147
        )
148
    else:
149
        response = app.post_json(url, params=payload['death'])
150
        demand_id = response.json['data']['demand_id']
151
        demfile = get_demand_filepath(actesweb, demand_id)
152
        assert_file_content_values(
153
            demfile, dict(
154
                DEMANDEUR_CIVILITE="Madame",
155
                DEMANDEUR_NOM_USAGE="Whatever",
156
                DEMANDEUR_PRENOMS="Kim Chelsea",
157
                DEMANDEUR_ADRESSE1="37 Rue du Cheval Blanc",
158
                DEMANDEUR_VILLE="Nancy",
159
                DEMANDEUR_PAYS="France",
160
                DEMANDEUR_TEL="+33 6 55 44 22 11",
161
                DEMANDEUR_ADR="chelsea@whatever.com",
162
                DEMANDE_NOM="Whatever",
163
                DEMANDE_PRENOMS="Kevin",
164
                DEMANDE_DATE_EVENEMENT="20120714",
165
                TYPE_DEMANDE="Extrait sans filiation",
166
                ACTE="DE",
167
                NB="1",
168
                LIEU_EVENEMENT="Nancy",
169
                DEMANDE_SEXE="m"
170
            )
171
        )
0
-