0001-gesbac-initial-connector-35325.patch
passerelle/apps/gesbac/migrations/0001_initial.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
# Generated by Django 1.11.20 on 2019-09-16 16:38 |
|
3 |
from __future__ import unicode_literals |
|
4 | ||
5 |
from django.db import migrations, models |
|
6 |
import django.db.models.deletion |
|
7 |
import jsonfield.fields |
|
8 |
import passerelle.utils.sftp |
|
9 | ||
10 | ||
11 |
class Migration(migrations.Migration): |
|
12 | ||
13 |
initial = True |
|
14 | ||
15 |
dependencies = [ |
|
16 |
('base', '0014_auto_20190820_0914'), |
|
17 |
] |
|
18 | ||
19 |
operations = [ |
|
20 |
migrations.CreateModel( |
|
21 |
name='CSV', |
|
22 |
fields=[ |
|
23 |
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
|
24 |
('formdata_id', models.CharField(max_length=64, null=True)), |
|
25 |
('creation_datetime', models.DateTimeField(auto_now_add=True)), |
|
26 |
('filename', models.CharField(max_length=128)), |
|
27 |
('sequence_number', models.IntegerField(default=0)), |
|
28 |
('file_type', models.CharField(choices=[(b'D', b'Demand'), (b'R', b'Response')], default=b'D', max_length=1)), |
|
29 |
('data', jsonfield.fields.JSONField(default=dict)), |
|
30 |
], |
|
31 |
options={ |
|
32 |
'get_latest_by': 'creation_datetime', |
|
33 |
}, |
|
34 |
), |
|
35 |
migrations.CreateModel( |
|
36 |
name='Gesbac', |
|
37 |
fields=[ |
|
38 |
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
|
39 |
('title', models.CharField(max_length=50, verbose_name='Title')), |
|
40 |
('description', models.TextField(verbose_name='Description')), |
|
41 |
('slug', models.SlugField(unique=True, verbose_name='Identifier')), |
|
42 |
('outcoming_sftp', passerelle.utils.sftp.SFTPField(default=None, verbose_name='Outcoming SFTP')), |
|
43 |
('incoming_sftp', passerelle.utils.sftp.SFTPField(default=None, verbose_name='Incoming SFTP')), |
|
44 |
('output_files_prefix', models.CharField(max_length=32, verbose_name='Output files prefix')), |
|
45 |
('input_files_prefix', models.CharField(max_length=32, verbose_name='Input files prefix')), |
|
46 |
('users', models.ManyToManyField(blank=True, related_name='_gesbac_users_+', related_query_name='+', to='base.ApiUser')), |
|
47 |
], |
|
48 |
options={ |
|
49 |
'verbose_name': 'Gesbac', |
|
50 |
}, |
|
51 |
), |
|
52 |
migrations.AddField( |
|
53 |
model_name='csv', |
|
54 |
name='resource', |
|
55 |
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gesbac.Gesbac'), |
|
56 |
), |
|
57 |
] |
passerelle/apps/gesbac/models.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
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 |
import csv |
|
18 |
import os |
|
19 | ||
20 |
from django.db import models |
|
21 |
from django.utils.translation import ugettext_lazy as _ |
|
22 |
from django.utils.timezone import now, make_aware |
|
23 |
from django.core.files.storage import default_storage |
|
24 | ||
25 |
from passerelle.base.models import BaseResource |
|
26 |
from passerelle.utils.api import endpoint, APIError |
|
27 |
from passerelle.utils import SFTPField |
|
28 | ||
29 |
from jsonfield import JSONField |
|
30 | ||
31 |
CSV_DELIMITER = ';' |
|
32 | ||
33 |
DEMAND_SCHEMA = { |
|
34 |
"$schema": "http://json-schema.org/draft-03/schema#", |
|
35 |
"title": "Gesbac", |
|
36 |
"description": "", |
|
37 |
"type": "object", |
|
38 |
"properties": { |
|
39 |
"formdata_id": { |
|
40 |
"description": "formdata id", |
|
41 |
"type": "string", |
|
42 |
"required": True |
|
43 |
}, |
|
44 |
"demand_date": { |
|
45 |
"description": "demand date", |
|
46 |
"type": "string", |
|
47 |
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$", |
|
48 |
"required": True |
|
49 |
}, |
|
50 |
"demand_time": { |
|
51 |
"description": "demand time", |
|
52 |
"type": "string", |
|
53 |
"pattern": "^[0-9]{2}:[0-9]{2}:[0-9]{2}$", |
|
54 |
"required": True |
|
55 |
}, |
|
56 |
"producer_code": { |
|
57 |
"description": "producer code", |
|
58 |
"type": "integer", |
|
59 |
"required": True |
|
60 |
}, |
|
61 |
"invariant_number": { |
|
62 |
"description": "invariant number", |
|
63 |
"type": "string", |
|
64 |
"required": False, |
|
65 |
"maxLength": 10, |
|
66 |
"default": "" |
|
67 |
}, |
|
68 |
"city_insee_code": { |
|
69 |
"type": "string", |
|
70 |
"required": False, |
|
71 |
"default": "" |
|
72 |
}, |
|
73 |
"street_rivoli_code": { |
|
74 |
"type": "string", |
|
75 |
"required": False, |
|
76 |
"default": "" |
|
77 |
}, |
|
78 |
"street_name": { |
|
79 |
"type": "string", |
|
80 |
"required": False, |
|
81 |
"default": "" |
|
82 |
}, |
|
83 |
"address_complement": { |
|
84 |
"type": "string", |
|
85 |
"maxLength": 32, |
|
86 |
"required": False, |
|
87 |
"default": "" |
|
88 |
}, |
|
89 |
"street_number": { |
|
90 |
"type": "integer", |
|
91 |
"required": False, |
|
92 |
"default": 0 |
|
93 |
}, |
|
94 |
"bis_ter": { |
|
95 |
"type": "string", |
|
96 |
"maxLength": 3, |
|
97 |
"required": False, |
|
98 |
"default": "" |
|
99 |
}, |
|
100 |
"building": { |
|
101 |
"type": "string", |
|
102 |
"maxLength": 5, |
|
103 |
"required": False, |
|
104 |
"default": "" |
|
105 |
}, |
|
106 |
"hall": { |
|
107 |
"type": "string", |
|
108 |
"maxLength": 5, |
|
109 |
"required": False, |
|
110 |
"default": "" |
|
111 |
}, |
|
112 |
"appartment_number": { |
|
113 |
"type": "string", |
|
114 |
"maxLength": 5, |
|
115 |
"required": False, |
|
116 |
"default": "" |
|
117 |
}, |
|
118 |
"producer_social_reason": { |
|
119 |
"type": "string", |
|
120 |
"maxLength": 38, |
|
121 |
"required": False, |
|
122 |
"default": "" |
|
123 |
}, |
|
124 |
"producer_title_code": { |
|
125 |
"type": "integer", |
|
126 |
"required": False, |
|
127 |
"default": 0 |
|
128 |
}, |
|
129 |
"producer_last_name": { |
|
130 |
"type": "string", |
|
131 |
"maxLength": 38, |
|
132 |
"required": False, |
|
133 |
"default": "" |
|
134 |
}, |
|
135 |
"producer_first_name": { |
|
136 |
"type": "string", |
|
137 |
"maxLength": 32, |
|
138 |
"required": False, |
|
139 |
"default": "" |
|
140 |
}, |
|
141 |
"producer_phone": { |
|
142 |
"type": "string", |
|
143 |
"maxLength": 20, |
|
144 |
"required": False, |
|
145 |
"default": "" |
|
146 |
}, |
|
147 |
"producer_email": { |
|
148 |
"type": "string", |
|
149 |
"maxLength": 50, |
|
150 |
"required": False, |
|
151 |
"default": "" |
|
152 |
}, |
|
153 |
"owner_last_name": { |
|
154 |
"type": "string", |
|
155 |
"maxLength": 38, |
|
156 |
"required": False, |
|
157 |
"default": "" |
|
158 |
}, |
|
159 |
"owner_first_name": { |
|
160 |
"type": "string", |
|
161 |
"maxLength": 32, |
|
162 |
"required": False, |
|
163 |
"default": "" |
|
164 |
}, |
|
165 |
"owner_phone": { |
|
166 |
"type": "string", |
|
167 |
"maxLength": 20, |
|
168 |
"required": False, |
|
169 |
"default": "" |
|
170 |
}, |
|
171 |
"owner_email": { |
|
172 |
"type": "string", |
|
173 |
"maxLength": 50, |
|
174 |
"required": False, |
|
175 |
"default": "" |
|
176 |
}, |
|
177 |
"activity_code": { |
|
178 |
"type": "integer", |
|
179 |
"required": False, |
|
180 |
"default": 0 |
|
181 |
}, |
|
182 |
"family_members_number": { |
|
183 |
"type": "integer", |
|
184 |
"required": False, |
|
185 |
"default": 0 |
|
186 |
}, |
|
187 |
"houses_number": { |
|
188 |
"type": "integer", |
|
189 |
"required": False, |
|
190 |
"default": 0 |
|
191 |
}, |
|
192 |
"t1_flats_number": { |
|
193 |
"type": "integer", |
|
194 |
"required": False, |
|
195 |
"default": 0 |
|
196 |
}, |
|
197 |
"t2_flats_number": { |
|
198 |
"type": "integer", |
|
199 |
"required": False, |
|
200 |
"default": 0 |
|
201 |
}, |
|
202 |
"t3_flats_number": { |
|
203 |
"type": "integer", |
|
204 |
"required": False, |
|
205 |
"default": 0 |
|
206 |
}, |
|
207 |
"t4_flats_number": { |
|
208 |
"type": "integer", |
|
209 |
"required": False, |
|
210 |
"default": 0 |
|
211 |
}, |
|
212 |
"t5_flats_number": { |
|
213 |
"type": "integer", |
|
214 |
"required": False, |
|
215 |
"default": 0 |
|
216 |
}, |
|
217 |
"t6_flats_number": { |
|
218 |
"type": "integer", |
|
219 |
"required": False, |
|
220 |
"default": 0 |
|
221 |
}, |
|
222 |
"shops_number": { |
|
223 |
"type": "integer", |
|
224 |
"required": False, |
|
225 |
"default": 0 |
|
226 |
}, |
|
227 |
"garden_size": { |
|
228 |
"type": "integer", |
|
229 |
"required": False, |
|
230 |
"default": 0 |
|
231 |
}, |
|
232 |
"expected_date": { |
|
233 |
"type": "string", |
|
234 |
"pattern": "^[0-9]{8}$", |
|
235 |
"required": False, |
|
236 |
"default": "" |
|
237 |
}, |
|
238 |
"expected_time": { |
|
239 |
"type": "string", |
|
240 |
"pattern": "^[0-9]{2}$", |
|
241 |
"required": False, |
|
242 |
"default": "" |
|
243 |
}, |
|
244 |
"modification_code": { |
|
245 |
"type": "integer", |
|
246 |
"required": False, |
|
247 |
"default": 0 |
|
248 |
}, |
|
249 |
"demand_reason_label": { |
|
250 |
"type": "string", |
|
251 |
"required": False, |
|
252 |
"default": "" |
|
253 |
}, |
|
254 |
"comment": { |
|
255 |
"type": "string", |
|
256 |
"maxLength": 500, |
|
257 |
"required": False, |
|
258 |
"default": "" |
|
259 |
}, |
|
260 |
"card_subject": { |
|
261 |
"type": "integer", |
|
262 |
"required": True |
|
263 |
}, |
|
264 |
"card_type": { |
|
265 |
"type": "integer", |
|
266 |
"required": True |
|
267 |
}, |
|
268 |
"card_demand_reason": { |
|
269 |
"type": "integer", |
|
270 |
"required": True |
|
271 |
}, |
|
272 |
"cards_number": { |
|
273 |
"type": "integer", |
|
274 |
"required": True, |
|
275 |
"default": 1 |
|
276 |
}, |
|
277 |
"card_number": { |
|
278 |
"type": "string", |
|
279 |
"maxLength": 20, |
|
280 |
"required": False |
|
281 |
}, |
|
282 |
"card_bar_code": { |
|
283 |
"type": "string", |
|
284 |
"maxLength": 20, |
|
285 |
"required": False, |
|
286 |
"default": "", |
|
287 |
}, |
|
288 |
"card_code": { |
|
289 |
"type": "string", |
|
290 |
"maxLength": 20, |
|
291 |
"required": False, |
|
292 |
"default": "", |
|
293 |
}, |
|
294 |
"card_validity_start_date": { |
|
295 |
"type": "string", |
|
296 |
"required": False, |
|
297 |
"pattern": "^[0-9]{8}$", |
|
298 |
"default": "", |
|
299 |
}, |
|
300 |
"card_validity_end_date": { |
|
301 |
"type": "string", |
|
302 |
"required": False, |
|
303 |
"pattern": "^[0-9]{8}$", |
|
304 |
"default": "", |
|
305 |
}, |
|
306 |
"card_comment": { |
|
307 |
"type": "string", |
|
308 |
"required": False, |
|
309 |
"maxLength": 100, |
|
310 |
"default": "", |
|
311 |
} |
|
312 |
} |
|
313 |
} |
|
314 | ||
315 | ||
316 |
class Gesbac(BaseResource): |
|
317 |
outcoming_sftp = SFTPField(verbose_name=_('Outcoming SFTP')) |
|
318 |
incoming_sftp = SFTPField(verbose_name=_('Incoming SFTP')) |
|
319 |
output_files_prefix = models.CharField(_('Output files prefix'), |
|
320 |
blank=False, max_length=32) |
|
321 |
input_files_prefix = models.CharField(_('Input files prefix'), |
|
322 |
blank=False, max_length=32) |
|
323 | ||
324 |
category = _('Business Process Connectors') |
|
325 | ||
326 |
class Meta: |
|
327 |
verbose_name = u'Gesbac' |
|
328 | ||
329 |
def check_status(self): |
|
330 |
with self.outcoming_sftp.client() as out_sftp: |
|
331 |
out_sftp.listdir() |
|
332 |
with self.incoming_sftp.client() as in_sftp: |
|
333 |
in_sftp.listdir() |
|
334 | ||
335 |
@property |
|
336 |
def file_handler(self): |
|
337 |
return FileHandler(resource=self) |
|
338 | ||
339 |
@endpoint(name='create-demand', |
|
340 |
perm='can_access', |
|
341 |
description=_('Create demand'), |
|
342 |
post = { |
|
343 |
'description': _('Creates a demand file'), |
|
344 |
'request_body': { |
|
345 |
'schema': { |
|
346 |
'application/json': DEMAND_SCHEMA |
|
347 |
} |
|
348 |
} |
|
349 |
} |
|
350 |
) |
|
351 |
def create_demand(self, request, post_data): |
|
352 |
return {'data': self.file_handler.send(post_data['formdata_id'], post_data)} |
|
353 | ||
354 |
@endpoint(name='get-response', perm='can_access', |
|
355 |
description=_('Get response'), |
|
356 |
parameters={ |
|
357 |
'formdata_id': { |
|
358 |
'description': _('Form data identifier'), |
|
359 |
'example_value': '42-01' |
|
360 |
} |
|
361 |
} |
|
362 |
) |
|
363 |
def get_response(self, request, formdata_id): |
|
364 |
return {'data': self.file_handler.get(formdata_id)} |
|
365 | ||
366 | ||
367 |
CSV_FILE_TYPES = ( |
|
368 |
('D', 'Demand'), |
|
369 |
('R', 'Response') |
|
370 |
) |
|
371 | ||
372 | ||
373 |
class CSV(models.Model): |
|
374 |
resource = models.ForeignKey(Gesbac) |
|
375 |
formdata_id = models.CharField(max_length=64, null=True) |
|
376 |
creation_datetime = models.DateTimeField(auto_now_add=True) |
|
377 |
filename = models.CharField(max_length=128) |
|
378 |
sequence_number = models.IntegerField(default=0) |
|
379 |
file_type = models.CharField(max_length=1, choices=CSV_FILE_TYPES, default='D') |
|
380 |
data = JSONField() |
|
381 | ||
382 |
class Meta: |
|
383 |
get_latest_by = 'creation_datetime' |
|
384 | ||
385 | ||
386 |
class FileHandler(object): |
|
387 | ||
388 |
def __init__(self, resource): |
|
389 |
self.resource = resource |
|
390 | ||
391 |
def get_file_suffix(self, formdata_id, sequence_number): |
|
392 |
sequence = "%03d" % sequence_number |
|
393 |
# replace '-' from formdata id with sequence number because integer is |
|
394 |
# expected |
|
395 |
return formdata_id.replace('-', sequence) |
|
396 | ||
397 |
def get_filename(self, prefix, formdata_id, sequence_number): |
|
398 |
timestamp = now().strftime('%y%m%d-%H%M%S') |
|
399 |
suffix = self.get_file_suffix(formdata_id, sequence_number) |
|
400 |
return '%s%s-%s.csv' % (prefix, timestamp, suffix) |
|
401 | ||
402 |
def send(self, formdata_id, data): |
|
403 | ||
404 |
try: |
|
405 |
demand_file = self.resource.csv_set.filter(formdata_id=formdata_id, file_type='D').latest() |
|
406 |
sequence_number = demand_file.sequence_number + 1 |
|
407 |
except CSV.DoesNotExist: |
|
408 |
sequence_number = 0 |
|
409 | ||
410 |
filename = self.get_filename(self.resource.output_files_prefix, |
|
411 |
formdata_id, sequence_number) |
|
412 | ||
413 |
with self.resource.outcoming_sftp.client() as client: |
|
414 |
with client.open(filename, mode='w') as fd: |
|
415 |
writer = csv.writer(fd, delimiter=CSV_DELIMITER) |
|
416 |
applicant_data = ['E', formdata_id] |
|
417 |
# get applicant attributes |
|
418 |
for param in ['demand_date', 'demand_time', 'producer_code', |
|
419 |
'invariant_number', 'city_insee_code', 'street_rivoli_code', |
|
420 |
'street_name', 'address_complement', 'street_number', |
|
421 |
'bis_ter', 'building', 'hall', 'appartment_number', |
|
422 |
'producer_social_reason', 'producer_title_code', |
|
423 |
'producer_last_name', 'producer_first_name', |
|
424 |
'producer_phone', 'producer_email', 'owner_last_name', |
|
425 |
'owner_first_name', 'owner_phone', 'owner_email', |
|
426 |
'activity_code', 'family_members_number', 'houses_number', |
|
427 |
't1_flats_number', 't2_flats_number', 't3_flats_number', |
|
428 |
't4_flats_number', 't5_flats_number', 't6_flats_number', |
|
429 |
'shops_number', 'garden_size', 'expected_date', |
|
430 |
'expected_time', 'modification_code', |
|
431 |
'demand_reason_label', 'comment']: |
|
432 |
item = data.get(param) |
|
433 |
if isinstance(item, basestring): |
|
434 |
item = item.encode('utf-8') |
|
435 |
applicant_data.append(item) |
|
436 |
writer.writerow(applicant_data) |
|
437 |
# get card attributes |
|
438 |
card_data = ['CARTE', formdata_id] |
|
439 |
for param in ['card_demand_purpose', 'card_type', 'card_demand_reason', |
|
440 |
'card_demanded_number', 'card_number', 'card_bar_code', |
|
441 |
'card_code', 'card_validity_start_date', |
|
442 |
'card_validity_end_date', 'card_comment']: |
|
443 |
item = data.get(param) |
|
444 |
if isinstance(item, basestring): |
|
445 |
item = item.encode('utf-8') |
|
446 |
card_data.append(item) |
|
447 |
writer.writerow(card_data) |
|
448 | ||
449 |
CSV.objects.create(formdata_id=formdata_id, |
|
450 |
resource=self.resource, |
|
451 |
sequence_number=sequence_number, |
|
452 |
filename=filename, |
|
453 |
data=data) |
|
454 |
return {'filename': filename} |
|
455 | ||
456 |
def get(self, formdata_id): |
|
457 |
data = [] |
|
458 |
try: |
|
459 |
demand = self.resource.csv_set.filter(formdata_id=formdata_id, |
|
460 |
file_type='D').latest() |
|
461 |
except CSV.DoesNotExist: |
|
462 |
raise APIError('Unknown demand') |
|
463 | ||
464 |
try: |
|
465 |
response = self.resource.csv_set.filter(formdata_id=formdata_id, |
|
466 |
sequence_number=demand.sequence_number, |
|
467 |
file_type='R').latest() |
|
468 |
return response.data |
|
469 |
except CSV.DoesNotExist: |
|
470 |
pass |
|
471 | ||
472 |
with self.resource.incoming_sftp.client() as client: |
|
473 |
response_filename = demand.filename.replace(self.resource.output_files_prefix, |
|
474 |
self.resource.input_files_prefix) |
|
475 |
for csv_file in client.listdir(): |
|
476 |
if csv_file.endswith('%s.csv' % self.get_file_suffix(formdata_id, |
|
477 |
demand.sequence_number)): |
|
478 |
response_filename = csv_file |
|
479 |
break |
|
480 |
else: |
|
481 |
raise APIError('Response doest not exist yet') |
|
482 | ||
483 |
with client.open(response_filename, mode='r') as fd: |
|
484 |
for row in csv.reader(fd, delimiter=CSV_DELIMITER): |
|
485 |
data.append(row) |
|
486 |
CSV.objects.create(resource=self.resource, formdata_id=formdata_id, |
|
487 |
filename=response_filename, |
|
488 |
sequence_number=demand.sequence_number, |
|
489 |
file_type='R', data=data) |
|
490 |
return data |
passerelle/settings.py | ||
---|---|---|
136 | 136 |
'passerelle.apps.family', |
137 | 137 |
'passerelle.apps.feeds', |
138 | 138 |
'passerelle.apps.gdc', |
139 |
'passerelle.apps.gesbac', |
|
139 | 140 |
'passerelle.apps.jsondatastore', |
140 | 141 |
'passerelle.apps.sp_fr', |
141 | 142 |
'passerelle.apps.mobyt', |
passerelle/utils/__init__.py | ||
---|---|---|
337 | 337 |
# legacy import, other modules keep importing to_json from passerelle.utils |
338 | 338 |
from .jsonresponse import to_json |
339 | 339 |
from .soap import SOAPClient, SOAPTransport |
340 |
from .sftp import SFTPField, SFTP |
tests/test_gesbac.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | ||
3 |
# tests/test_gesbac.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 datetime |
|
20 |
import pytest |
|
21 | ||
22 |
from django.utils.timezone import now |
|
23 |
from .utils import make_resource |
|
24 | ||
25 |
from passerelle.utils import SFTP |
|
26 |
from passerelle.apps.gesbac.models import Gesbac, CSV |
|
27 | ||
28 | ||
29 |
@pytest.fixture |
|
30 |
def resource(db, sftpserver): |
|
31 |
return make_resource( |
|
32 |
Gesbac, |
|
33 |
slug='test', |
|
34 |
title='Gesbac', |
|
35 |
description='gesbac', |
|
36 |
outcoming_sftp=SFTP('sftp://foo:bar@{server.host}:{server.port}/output/'.format(server=sftpserver)), |
|
37 |
incoming_sftp=SFTP('sftp://foo:bar@{server.host}:{server.port}/input/'.format(server=sftpserver)), |
|
38 |
output_files_prefix='output-', |
|
39 |
input_files_prefix='input-') |
|
40 | ||
41 | ||
42 |
def test_check_status(app, resource, sftpserver): |
|
43 |
with sftpserver.serve_content({'input': {'test': 'content'}, |
|
44 |
'output': {'file': 'content'}}): |
|
45 |
resource.check_status() |
|
46 | ||
47 | ||
48 |
def test_create_demand(app, resource, sftpserver, freezer): |
|
49 |
assert resource.csv_set.count() == 0 |
|
50 |
timestamp = now() |
|
51 |
payload = { |
|
52 |
'formdata_id': '42-42', |
|
53 |
'demand_date': timestamp.strftime('%Y-%m-%d'), |
|
54 |
'demand_time': timestamp.strftime('%H:%M:%S'), |
|
55 |
'producer_code': 1, |
|
56 |
'city_insee_code': '75114', |
|
57 |
'street_rivoli_code': '4', |
|
58 |
'street_name': 'Château', |
|
59 |
'producer_social_reason': 'SCOP', |
|
60 |
'producer_last_name': 'Bar', |
|
61 |
'producer_first_name': 'Foo', |
|
62 |
'producer_email': 'foo@example.com', |
|
63 |
'owner_last_name': 'Bar', |
|
64 |
'owner_first_name': 'Foo', |
|
65 |
'owner_email': 'foo@example.com', |
|
66 |
'family_members_number': 5, |
|
67 |
'houses_number': 1, |
|
68 |
'card_type': 1, |
|
69 |
'card_subject': 1, |
|
70 |
'card_demand_reason': 1, |
|
71 |
'card_demand_purpose': 1, |
|
72 |
'cards_number': 1 |
|
73 |
} |
|
74 |
with sftpserver.serve_content({'output': {'file': 'content'}}): |
|
75 |
response = app.post_json('/gesbac/test/create-demand/', params=payload) |
|
76 |
assert response.json['data']['filename'] == '%s%s-4200042.csv' % (resource.output_files_prefix, |
|
77 |
timestamp.strftime('%y%m%d-%H%M%S')) |
|
78 |
assert resource.csv_set.filter(formdata_id='42-42', file_type='D').count() == 1 |
|
79 |
csv = resource.csv_set.filter(formdata_id='42-42', file_type='D').latest() |
|
80 |
assert csv.filename == 'output-' + timestamp.strftime('%y%m%d-%H%M%S') + '-4200042.csv' |
|
81 |
freezer.move_to(datetime.timedelta(seconds=5)) |
|
82 |
timestamp = now() |
|
83 |
response = app.post_json('/gesbac/test/create-demand/', params=payload) |
|
84 |
payload['cards_number'] = 2 |
|
85 |
assert resource.csv_set.filter(formdata_id='42-42', file_type='D').count() == 2 |
|
86 |
csv = resource.csv_set.filter(formdata_id='42-42', file_type='D').latest() |
|
87 |
assert csv.filename == '%s%s-4200142.csv' % (resource.output_files_prefix, |
|
88 |
timestamp.strftime('%y%m%d-%H%M%S')) |
|
89 | ||
90 | ||
91 |
def test_get_demand_response(app, resource, sftpserver): |
|
92 |
response = app.get('/gesbac/test/get-response/', params={'formdata_id': '42-42'}) |
|
93 |
assert response.json['err'] == 1 |
|
94 |
assert response.json['err_desc'] == 'Unknown demand' |
|
95 |
assert response.json['err_class'] == 'passerelle.utils.jsonresponse.APIError' |
|
96 | ||
97 |
demand_filename = '%s91001-090000-4200042.csv' % resource.output_files_prefix |
|
98 |
CSV.objects.create(resource=resource, formdata_id='42-42', |
|
99 |
filename=demand_filename) |
|
100 |
response_filename = '%s91001-090300-4200042.csv' % resource.input_files_prefix |
|
101 |
CSV.objects.create(resource=resource, formdata_id='42-42', |
|
102 |
filename=response_filename, file_type='R', data=['CARTE', '42-42']) |
|
103 |
response = app.get('/gesbac/test/get-response/', params={'formdata_id': '42-42'}) |
|
104 |
assert response.json['err'] == 0 |
|
105 |
assert response.json['data'] == ['CARTE', '42-42'] |
|
106 | ||
107 |
CSV.objects.filter(resource=resource, file_type='R').delete() |
|
108 | ||
109 |
with sftpserver.serve_content({'input': {'test': 'content'}}): |
|
110 |
response = app.get('/gesbac/test/get-response/', params={'formdata_id': '42-42'}) |
|
111 |
assert response.json['err'] == 1 |
|
112 |
assert response.json['err_desc'] == 'Response doest not exist yet' |
|
113 |
assert response.json['err_class'] == 'passerelle.utils.jsonresponse.APIError' |
|
114 | ||
115 |
with sftpserver.serve_content({'input': {response_filename: 'CARTE;42-42;3;2;;;;;;;;;'}}): |
|
116 |
response = app.get('/gesbac/test/get-response/', params={'formdata_id': '42-42'}) |
|
117 |
assert response.json['err'] == 0 |
|
118 |
assert response.json['data'] == [['CARTE', '42-42', '3', '2', '', '', '', '', '', '', '', '', '']] |
|
119 |
assert resource.csv_set.filter(file_type='R', filename=response_filename).count() == 1 |
|
0 |
- |