add connector for Cart@DS CS (#27144)

This commit is contained in:
Frédéric Péters 2018-10-09 19:10:36 +02:00
parent 8fc099421f
commit 81690434be
7 changed files with 727 additions and 1 deletions

View File

View File

@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.12 on 2019-02-20 10:38
from __future__ import unicode_literals
from django.db import migrations, models
import passerelle.apps.cartads_cs.models
class Migration(migrations.Migration):
initial = True
dependencies = [
('base', '0012_job'),
]
operations = [
migrations.CreateModel(
name='CartaDSCS',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=50, verbose_name='Title')),
('description', models.TextField(verbose_name='Description')),
('slug', models.SlugField(unique=True, verbose_name='Identifier')),
('wsdl_base_url', models.URLField(help_text='ex: https://example.net/adscs/webservices/', verbose_name='WSDL Base URL')),
('username', models.CharField(max_length=64, verbose_name='Username')),
('password', models.CharField(max_length=64, verbose_name='Password')),
('iv', models.CharField(max_length=16, verbose_name='Initialisation Vector')),
('secret_key', models.CharField(max_length=16, verbose_name='Secret Key')),
('ftp_server', models.CharField(max_length=128, verbose_name='FTP Server')),
('ftp_username', models.CharField(max_length=64, verbose_name='FTP Username')),
('ftp_password', models.CharField(max_length=64, verbose_name='FTP Password')),
('ftp_client_name', models.CharField(max_length=64, verbose_name='FTP Client Name')),
('users', models.ManyToManyField(blank=True, to='base.ApiUser')),
],
options={
'verbose_name': 'Cart@DS CS',
},
),
migrations.CreateModel(
name='CartaDSDossier',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('email', models.CharField(max_length=256)),
('tracking_code', models.CharField(max_length=20)),
('commune_id', models.CharField(max_length=20)),
('type_dossier_id', models.CharField(max_length=20)),
('objet_demande_id', models.CharField(max_length=20, null=True)),
('zip_ready', models.BooleanField(default=False)),
('zip_sent', models.BooleanField(default=False)),
('zip_ack_response', models.CharField(max_length=20, null=True)),
('notification_url', models.URLField(null=True)),
('notification_message', models.TextField(null=True)),
('cartads_id_dossier', models.CharField(max_length=50, null=True)),
('cartads_numero_dossier', models.CharField(max_length=50, null=True)),
('last_update_datetime', models.DateTimeField(auto_now=True)),
],
),
migrations.CreateModel(
name='CartaDSFile',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('tracking_code', models.CharField(max_length=20)),
('id_piece', models.CharField(max_length=20)),
('uploaded_file', models.FileField(upload_to=passerelle.apps.cartads_cs.models.cartads_file_location)),
('last_update_datetime', models.DateTimeField(auto_now=True)),
],
),
]

View File

@ -0,0 +1,445 @@
# -*- coding: utf-8 -*-
# passerelle - uniform access to multiple data sources and services
# Copyright (C) 2018 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import base64
import datetime
from ftplib import FTP
import json
import os
from xml.etree import ElementTree as etree
import zipfile
from Crypto.Cipher import AES
from django.core.files.storage import default_storage
from django.core.signing import Signer
from django.core.urlresolvers import reverse
from django.db import models
from django.http import HttpResponse
from django.utils.translation import ugettext_lazy as _
from django.utils.six.moves.urllib import parse as urlparse
from passerelle.base.models import BaseResource
from passerelle.utils.api import endpoint
def cartads_file_location(instance, filename):
return 'cartads_cs/%s/%s' % (instance.tracking_code, filename)
class CartaDSFile(models.Model):
tracking_code = models.CharField(max_length=20)
id_piece = models.CharField(max_length=20)
uploaded_file = models.FileField(upload_to=cartads_file_location)
last_update_datetime = models.DateTimeField(auto_now=True)
class CartaDSDossier(models.Model):
email = models.CharField(max_length=256)
tracking_code = models.CharField(max_length=20)
commune_id = models.CharField(max_length=20)
type_dossier_id = models.CharField(max_length=20)
objet_demande_id = models.CharField(max_length=20, null=True)
zip_ready = models.BooleanField(default=False)
zip_sent = models.BooleanField(default=False)
zip_ack_response = models.CharField(null=True, max_length=20)
notification_url = models.URLField(null=True)
notification_message = models.TextField(null=True)
cartads_id_dossier = models.CharField(max_length=50, null=True)
cartads_numero_dossier = models.CharField(max_length=50, null=True)
last_update_datetime = models.DateTimeField(auto_now=True)
class CartaDSCS(BaseResource):
category = _('Misc')
wsdl_base_url = models.URLField(_('WSDL Base URL'),
help_text=_('ex: https://example.net/adscs/webservices/'))
username = models.CharField(_('Username'), max_length=64)
password = models.CharField(_('Password'), max_length=64)
iv = models.CharField(_('Initialisation Vector'), max_length=16)
secret_key = models.CharField(_('Secret Key'), max_length=16)
ftp_server = models.CharField(_('FTP Server'), max_length=128)
ftp_username = models.CharField(_('FTP Username'), max_length=64)
ftp_password = models.CharField(_('FTP Password'), max_length=64)
ftp_client_name = models.CharField(_('FTP Client Name'), max_length=64)
class Meta:
verbose_name = 'Cart@DS CS'
@property
def wsdl_url(self):
return self.get_wsdl_url()
def get_wsdl_url(self, service_type='ServicePortail'):
return self.wsdl_base_url + service_type + '.svc?singleWsdl'
def soap_client(self, **kwargs):
client = super(CartaDSCS, self).soap_client(**kwargs)
# fix URL that should have been changed by reverse proxy
parsed_wsdl_address = urlparse.urlparse(client.service._binding_options['address'])
parsed_real_address = urlparse.urlparse(self.wsdl_base_url)
client.service._binding_options['address'] = urlparse.urlunparse(
parsed_real_address[:2] + parsed_wsdl_address[2:])
return client
def get_token(self):
token_data = {
'date': datetime.datetime.now().strftime('%d/%m/%Y %H:%M:%S'),
'login': self.username,
'password': self.password,
}
token_data_str = json.dumps(token_data)
data_pad = AES.block_size - len(token_data_str) % AES.block_size
aes = AES.new(self.secret_key, AES.MODE_CBC, self.iv)
token = aes.encrypt(token_data_str + (chr(data_pad)*data_pad))
return base64.encodestring(token).replace('\n', '').rstrip('=')
def check_status(self):
self.soap_client().service.GetCommunes(self.get_token())
# description of common endpoint parameters
COMMUNE_ID_PARAM = {
'description': _('Identifier of collectivity'),
'example_value': '2'
}
TYPE_DOSSIER_ID_PARAM = {
'description': _('Identifier of file type'),
'example_value': 'CU',
}
OBJET_DEMANDE_ID_PARAM = {
'description': _('Identifier of demand subject'),
'example_value': '1',
}
TRACKING_CODE_PARAM = {
'description': _('Unique identifier (ex: tracking code)'),
'example_value': 'XCBTFRML',
}
PIECE_ID_PARAM = {
'description': _('Identifier of single file item'),
}
UPLOAD_TOKEN_PARAM = {
'description': _('Token for upload file'),
}
@endpoint(description=_('Get list of collectivities'))
def communes(self, request):
client = self.soap_client()
resp = client.service.GetCommunes(self.get_token())
return {'data': [{'id': str(x['Key']), 'text': x['Value']} for x in resp]}
@endpoint(description=_('Get lisf of file types'),
parameters={
'commune_id': COMMUNE_ID_PARAM
})
def types_dossier(self, request, commune_id):
client = self.soap_client()
resp = client.service.GetTypesDossier(self.get_token(), int(commune_id))
return {'data': [{'id': x['Key'], 'text': x['Value']} for x in resp]}
@endpoint(description=_('Get list of demand subjects'),
parameters={'type_dossier_id': TYPE_DOSSIER_ID_PARAM},
)
def objets_demande(self, request, type_dossier_id):
client = self.soap_client()
resp = client.service.GetObjetsDemande(self.get_token(), type_dossier_id)
return {'data': [{'id': str(x['Key']), 'text': x['Value']} for x in resp]}
@endpoint(description=_('Get list of CERFA documents'),
parameters={
'type_dossier_id': TYPE_DOSSIER_ID_PARAM,
'type_compte': {'description': _('Type of account')},
})
def liste_pdf(self, request, type_dossier_id, type_compte=1):
client = self.soap_client()
resp = client.service.GetListePdf(self.get_token(), type_dossier_id,
{'TypeCompteUtilisateur': type_compte})
return {'data': [
{'id': x['Identifiant'],
'text': u'%s: %s' % (x['Nom'], x['Description']),
'url': x['UrlTelechargement'],
} for x in resp]}
@endpoint(perm='can_access',
description=_('Get list of file items'),
parameters={
'type_dossier_id': TYPE_DOSSIER_ID_PARAM,
'objet_demande_id': OBJET_DEMANDE_ID_PARAM,
'tracking_code': TRACKING_CODE_PARAM,
})
def pieces(self, request, type_dossier_id, objet_demande_id, tracking_code):
client = self.soap_client()
resp = client.service.GetPieces(self.get_token(), type_dossier_id,
objet_demande_id)
signer = Signer(salt='cart@ds_cs')
upload_token = signer.sign(tracking_code)
cerfa_pieces = [
{'id': 'cerfa-%s-%s' % (type_dossier_id, objet_demande_id),
'text': 'Cerfa rempli',
'description': '',
'codePiece': '',
'reglementaire': True,
'files': [],
'max_files': 1,
'section_start': 'Cerfa',
},
{'id': 'cerfa-autres-%s-%s' % (type_dossier_id, objet_demande_id),
'text': 'Cerfa demandeurs complémentaires',
'description': '',
'codePiece': '',
'reglementaire': False,
'files': [],
'max_files': 6,
}
]
pieces = [
{'id': str(x['IdPiece']),
'text': x['Libelle'],
'description': x['Descriptif'],
'codePiece': x['CodePiece'],
'reglementaire': x['Reglementaire'],
'files': [],
'max_files': 6,
} for x in resp]
required_pieces = [x for x in pieces if x['reglementaire']]
if required_pieces:
required_pieces[0]['section_start'] = 'Pièces réglementaires'
optional_pieces = [x for x in pieces if not x['reglementaire']]
if optional_pieces:
optional_pieces[0]['section_start'] = 'Pièces spécifiques'
pieces = cerfa_pieces + required_pieces + optional_pieces
known_files = CartaDSFile.objects.filter(tracking_code=tracking_code)
for piece in pieces:
if request:
upload_url = request.build_absolute_uri('%supload/%s/%s/' % (
self.get_absolute_url(),
piece['id'],
upload_token))
else:
upload_url = None
piece['files'] = [
{
'url': upload_url,
'name': os.path.basename(x.uploaded_file.name),
'token': signer.sign(str(x.id)),
'id': x.id,
} for x in known_files if x.id_piece == str(piece['id'])]
if len(piece['files']) < piece['max_files']:
piece['files'].append({'url': upload_url})
return {'data': pieces}
@endpoint(perm='can_access',
description=_('Check list of file items'),
parameters={
'type_dossier_id': TYPE_DOSSIER_ID_PARAM,
'objet_demande_id': OBJET_DEMANDE_ID_PARAM,
'tracking_code': TRACKING_CODE_PARAM,
})
def check_pieces(self, request, type_dossier_id, objet_demande_id, tracking_code):
pieces = self.pieces(request, type_dossier_id, objet_demande_id, tracking_code)
result = True
for piece in pieces['data']:
if not piece['reglementaire']:
continue
if not [x for x in piece['files'] if x.get('name')]:
result = False
break
return {'result': result}
@endpoint(methods=['post'],
pattern='^(?P<id_piece>[\w-]+)/(?P<token>[\w:_-]+)/$',
description=_('Upload a single document file'),
parameters={
'id_piece': PIECE_ID_PARAM,
'token': UPLOAD_TOKEN_PARAM,
})
def upload(self, request, id_piece, token, **kwargs):
signer = Signer(salt='cart@ds_cs')
tracking_code = signer.unsign(token)
file_upload = CartaDSFile(
tracking_code=tracking_code,
id_piece=id_piece,
uploaded_file=request.FILES['files[]'])
file_upload.save()
return [{'name': os.path.basename(file_upload.uploaded_file.name),
'token': signer.sign(str(file_upload.id))}]
@endpoint(methods=['post'],
name='upload',
pattern='^(?P<id_piece>[\w-]+)/(?P<token>[\w:_-]+)/(?P<file_upload>[\w:_-]+)/delete/$',
description=_('Delete a single document file'),
parameters={
'id_piece': PIECE_ID_PARAM,
'token': UPLOAD_TOKEN_PARAM,
'file_upload': {
'description': _('Signed identifier of single document upload'),
},
})
def upload_delete(self, request, id_piece, token, file_upload, **kwargs):
# this cannot be verb DELETE as we have no way to set
# Access-Control-Allow-Methods
signer = Signer(salt='cart@ds_cs')
tracking_code = signer.unsign(token)
CartaDSFile.objects.filter(id=signer.unsign(file_upload)).delete()
return {'err': 0}
@endpoint(perm='can_access',
description=_('Validate and send a file'),
parameters={
'commune_id': COMMUNE_ID_PARAM,
'type_dossier_id': TYPE_DOSSIER_ID_PARAM,
'objet_demande_id': OBJET_DEMANDE_ID_PARAM,
'tracking_code': TRACKING_CODE_PARAM,
'email': {
'description': _('Email of requester'),
},
})
def send(self, request, commune_id, type_dossier_id, objet_demande_id, tracking_code, email):
dossier = CartaDSDossier(
commune_id=commune_id,
type_dossier_id=type_dossier_id,
objet_demande_id=objet_demande_id,
tracking_code=tracking_code,
email=email,
)
dossier.save()
signer = Signer(salt='cart@ds_cs/dossier')
dossier.notification_url = request.build_absolute_uri(
reverse('generic-endpoint', kwargs={
'connector': 'cartads-cs',
'slug': self.slug,
'endpoint': 'notification'})) + '/%s/' % signer.sign(str(dossier.id))
dossier.save()
self.add_job('pack', dossier_id=dossier.id)
return {'err': 0, 'dossier_id': dossier.id}
def pack(self, dossier_id):
dossier = CartaDSDossier.objects.get(id=dossier_id)
zip_filename = os.path.join(default_storage.path('cartads_cs'), '%s.zip' % dossier.tracking_code)
zip_file = zipfile.ZipFile(zip_filename, mode='w')
liste_pdf = self.liste_pdf(None, dossier.type_dossier_id)
cerfa_id = liste_pdf['data'][0]['id'].replace('*', '-')
pieces = self.pieces(None, dossier.type_dossier_id, dossier.objet_demande_id, dossier.tracking_code)
for piece in pieces['data']:
cnt = 1
for file in piece['files']:
if not file.get('id'):
continue
cartads_file = CartaDSFile.objects.get(id=file['id'])
if piece['id'] == 'cerfa-%s-%s' % (dossier.type_dossier_id, dossier.objet_demande_id):
zip_file.write(
cartads_file.uploaded_file.path,
'%s.pdf' % cerfa_id)
elif piece['id'].startswith('cerfa-autres-'):
zip_file.write(
cartads_file.uploaded_file.path,
'Fiches_complementaires/Cerfa_autres_demandeurs_%d.pdf' % cnt)
else:
zip_file.write(
cartads_file.uploaded_file.path,
'Pieces/%s-%s%s%s' % (
piece['id'],
piece['codePiece'],
cnt,
os.path.splitext(cartads_file.uploaded_file.path)[-1]))
cnt += 1
zip_file.close()
dossier.zip_ready = True
dossier.save()
self.add_job('send_to_cartads', dossier_id=dossier.id)
def send_to_cartads(self, dossier_id):
dossier = CartaDSDossier.objects.get(id=dossier_id)
zip_filename = os.path.join(default_storage.path('cartads_cs'), '%s.zip' % dossier.tracking_code)
ftp = FTP(self.ftp_server)
ftp.login(self.ftp_username, self.ftp_password)
ftp.cwd(self.ftp_client_name)
ftp.storbinary(
'STOR %s' % os.path.basename(zip_filename),
open(zip_filename))
ftp.quit()
def key_value_of_stringstring(d):
return {'KeyValueOfstringstring': [{'Key': x, 'Value': y} for x, y in d.items()]}
client = self.soap_client()
resp = client.service.NotifierDepotDossier(
self.get_token(),
dossier.commune_id,
dossier.type_dossier_id,
os.path.basename(zip_filename),
dossier.email,
key_value_of_stringstring(
{
'TraitementImmediat': 1,
'UrlNotification': dossier.notification_url,
}))
dossier.zip_sent = True
dossier.zip_ack_response = str(resp)
dossier.save()
@endpoint(pattern='^(?P<signed_dossier_id>[\w:_-]+)/$',
methods=['post'],
description=_('Notification of file processing by Cart@DS CS'),
parameters={
'signed_dossier_id': {
'description': _('Signed identifier of file')
},
})
def notification(self, request, signed_dossier_id):
signer = Signer(salt='cart@ds_cs/dossier')
dossier_id = signer.unsign(signed_dossier_id)
dossier = CartaDSDossier.objects.get(id=dossier_id)
dossier.notification_message = request.body
notification = etree.fromstring(request.POST['notification'])
dossier.cartads_id_dossier = notification.find('InformationsComplementaires/IdDossierCartads').text
dossier.cartads_numero_dossier = notification.find('InformationsComplementaires/NumeroDossier').text
dossier.save()
return HttpResponse('ok', content_type='text/plain')
@endpoint(perm='can_access',
description=_('Get status of file'),
parameters={
'dossier_id': {
'description': _('Identifier of file'),
}
})
def status(self, request, dossier_id):
dossier = CartaDSDossier.objects.get(id=dossier_id)
extra = None
if dossier.cartads_id_dossier:
client = self.soap_client(wsdl_url=self.get_wsdl_url('ServiceEtapeDossier'))
resp = client.service.GetEtapesDossier(self.get_token(),
dossier.cartads_id_dossier, [])
steps = []
for step in resp:
steps.append(step)
steps.sort(key=lambda x: x['DateReference'])
status_id = 'cartads-%s' % steps[-1]['IdEtape']
status_label = steps[-1]['LibelleEtape']
extra = {}
for key in steps[-1].keys():
extra[key] = steps[-1][key]
elif dossier.zip_sent:
status_id = 'zip-sent'
status_label = _('File sent')
elif dossier.zip_ready:
status_id = _('File ready to be sent')
else:
status_label = 'pending'
return {'status_id': status_id, 'status_label': status_label, 'extra': extra}

View File

@ -122,6 +122,7 @@ INSTALLED_APPS = (
'passerelle.apps.arcgis',
'passerelle.apps.base_adresse',
'passerelle.apps.bdp',
'passerelle.apps.cartads_cs',
'passerelle.apps.choosit',
'passerelle.apps.cityweb',
'passerelle.apps.clicrdv',

View File

@ -105,7 +105,8 @@ setup(name='passerelle',
'Pillow',
'python-magic',
'jsonschema',
'zeep < 3.0'
'zeep < 3.0',
'pycrypto',
],
cmdclass={
'build': build,

210
tests/test_cartads_cs.py Normal file
View File

@ -0,0 +1,210 @@
# -*- coding: utf-8 -*-
import datetime
import mock
import pytest
from django.core.files.storage import default_storage
from passerelle.apps.cartads_cs.models import CartaDSCS, CartaDSFile, CartaDSDossier
from passerelle.base.models import Job
from . import utils
@pytest.fixture
def connector(db):
return utils.make_resource(CartaDSCS,
title='Test',
slug='test',
description='...',
wsdl_base_url='http://test.invalid/adscs/webservices/',
username='test',
password='test',
iv='x'*16,
secret_key='y'*16,
ftp_server='ftp.invalid',
ftp_username='test',
ftp_password='test',
ftp_client_name='test'
)
class FakeService():
def GetCommunes(self, token):
return [{'Key': 2, 'Value': 'AIGREFEUILLE SUR MAINE'}]
def GetTypesDossier(self, token, commune_id):
return [{'Key': 'CU', 'Value': "Certificat d'urbanisme"}]
def GetObjetsDemande(self, token, type_dossier_id):
return [{'Key': 1, 'Value': "CU d'information"}]
def GetListePdf(self, token, type_dossier_id, options=None):
return [{'UrlTelechargement': 'https://invalid/adscs/webservices/ServicePDF.ashx?pdf=13410*04',
'Nom': 'Cerfa 13410-04',
'Description': "Demande de Certificat d'urbanisme",
'Identifiant': '13410*04'}]
def GetPieces(self, token, type_dossier_id, objet_demande_id):
return [{'IdPiece': 1065,
'Libelle': 'DECLARATION PREALABLE INCOMPLETE',
'CodePiece': 'CU',
'Descriptif': 'Complétez la rubrique',
'Reglementaire': False,
},
{'IdPiece': 1,
'Libelle': 'Plan de situation du terrain',
'CodePiece': 'CU01',
'Descriptif': 'Un plan de situation du terrain [Art. R. 410-1 al 1 du code de l\'urbanisme]',
'Reglementaire': True,
}
]
def NotifierDepotDossier(self, token, commune_id, type_dossier_id, filename, email, infos):
return 'True'
def GetEtapesDossier(self, token, dossier_id, infos):
return [{
'DateEcheance': datetime.datetime(2019, 3, 1, 0, 0),
'DateRealisation': None,
'DateReference': datetime.datetime(2019, 2, 14, 0, 0),
'IdDossier': 135792,
'IdEtape': 1,
'IdEtapeDossier': 692232,
'LibelleEtape': 'En cours de saisie'
}]
def test_communes(connector, app):
with mock.patch('passerelle.apps.cartads_cs.models.CartaDSCS.soap_client') as client:
client.return_value = mock.Mock(service=FakeService())
resp = app.get('/cartads-cs/test/communes')
assert resp.json == {'data': [{'text': 'AIGREFEUILLE SUR MAINE', 'id': '2'}], 'err': 0}
def test_types_dossier(connector, app):
with mock.patch('passerelle.apps.cartads_cs.models.CartaDSCS.soap_client') as client:
client.return_value = mock.Mock(service=FakeService())
resp = app.get('/cartads-cs/test/types_dossier', status=400)
resp = app.get('/cartads-cs/test/types_dossier?commune_id=1')
assert resp.json == {'data': [{'id': 'CU', 'text': "Certificat d'urbanisme"}], 'err': 0}
def test_objets_demande(connector, app):
with mock.patch('passerelle.apps.cartads_cs.models.CartaDSCS.soap_client') as client:
client.return_value = mock.Mock(service=FakeService())
resp = app.get('/cartads-cs/test/objets_demande?type_dossier_id=CU')
assert resp.json == {'data': [{'id': '1', 'text': "CU d'information"}], 'err': 0}
def test_liste_pdf(connector, app):
with mock.patch('passerelle.apps.cartads_cs.models.CartaDSCS.soap_client') as client:
client.return_value = mock.Mock(service=FakeService())
resp = app.get('/cartads-cs/test/liste_pdf?type_dossier_id=CU')
assert resp.json == {'data': [{'id': '13410*04',
'text': "Cerfa 13410-04: Demande de Certificat d'urbanisme",
'url': 'https://invalid/adscs/webservices/ServicePDF.ashx?pdf=13410*04'}],
'err': 0}
def test_pieces_management(connector, app):
with mock.patch('passerelle.apps.cartads_cs.models.CartaDSCS.soap_client') as client:
client.return_value = mock.Mock(service=FakeService())
resp = app.get('/cartads-cs/test/pieces?type_dossier_id=CU&objet_demande_id=1&tracking_code=BBBBBBBB')
data = resp.json['data']
assert len(data) == 4
assert data[0]['text'] == 'Cerfa rempli'
assert data[0]['max_files'] == 1
assert data[1]['text'] == u'Cerfa demandeurs complémentaires'
assert data[1]['max_files'] == 6
assert data[2]['text'] == 'Plan de situation du terrain'
assert data[2]['max_files'] == 6
assert data[3]['text'] == 'DECLARATION PREALABLE INCOMPLETE'
assert data[3]['max_files'] == 6
for piece in data:
assert len(piece['files']) == 1
assert piece['files'][0].keys() == ['url']
resp = app.get('/cartads-cs/test/check_pieces?type_dossier_id=CU&objet_demande_id=1&tracking_code=BBBBBBBB')
assert resp.json == {'result': False, 'err': 0}
resp = app.post(data[0]['files'][0]['url'],
upload_files=[('files[]', 'test.pdf', '%PDF...')])
cerfa_token = resp.json[0]['token']
resp = app.get('/cartads-cs/test/pieces?type_dossier_id=CU&objet_demande_id=1&tracking_code=BBBBBBBB')
data = resp.json['data']
assert data[0]['files'][0]['name']
resp = app.post(data[0]['files'][0]['url'] + '%s/delete/' % cerfa_token)
assert resp.json == {'err': 0}
resp = app.get('/cartads-cs/test/pieces?type_dossier_id=CU&objet_demande_id=1&tracking_code=BBBBBBBB')
data = resp.json['data']
assert 'name' not in data[0]['files'][0]
resp = app.post(data[0]['files'][0]['url'],
upload_files=[('files[]', 'test.pdf', '%PDF...')])
resp = app.post(data[1]['files'][0]['url'],
upload_files=[('files[]', 'test.pdf', '%PDF...')])
resp = app.post(data[1]['files'][0]['url'],
upload_files=[('files[]', 'test.pdf', '%PDF...')])
resp = app.get('/cartads-cs/test/pieces?type_dossier_id=CU&objet_demande_id=1&tracking_code=BBBBBBBB')
data = resp.json['data']
assert len(data[1]['files']) == 3
resp = app.get('/cartads-cs/test/check_pieces?type_dossier_id=CU&objet_demande_id=1&tracking_code=BBBBBBBB')
assert resp.json == {'result': False, 'err': 0}
resp = app.post(data[2]['files'][0]['url'],
upload_files=[('files[]', 'test.pdf', '%PDF...')])
resp = app.get('/cartads-cs/test/check_pieces?type_dossier_id=CU&objet_demande_id=1&tracking_code=BBBBBBBB')
assert resp.json == {'result': True, 'err': 0}
def test_send(connector, app):
CartaDSFile.objects.all().delete()
Job.objects.all().delete()
test_pieces_management(connector, app)
resp = app.get('/cartads-cs/test/send?commune_id=1&type_dossier_id=CU&objet_demande_id=1&tracking_code=BBBBBBBB&email=test@invalid')
assert CartaDSDossier.objects.all().count() == 1
dossier = CartaDSDossier.objects.all().first()
assert resp.json['dossier_id'] == dossier.id
assert Job.objects.all().count() == 1
# test_pack
with mock.patch('passerelle.apps.cartads_cs.models.CartaDSCS.soap_client') as client:
client.return_value = mock.Mock(service=FakeService())
with mock.patch('passerelle.apps.cartads_cs.models.FTP') as FTP:
connector.jobs()
assert Job.objects.filter(method_name='pack', status='completed').count()
assert Job.objects.filter(method_name='send_to_cartads', status='completed').count()
dossier = CartaDSDossier.objects.get(id=dossier.id)
assert dossier.zip_ack_response == 'True'
resp = app.post(dossier.notification_url, params={'notification': '''<?xml version="1.0" encoding="utf-8"?>
<Notification xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<NomArchive>SKTJCMPD.zip</NomArchive>
<DateDepot>2019-02-14T00:00:00</DateDepot>
<EmailDemandeur>test@invalid</EmailDemandeur>
<Succes>true</Succes>
<InformationsComplementaires>
<Etape>PriseEnChargeAutoTerminee</Etape>
<MessageErreur />
<IdDossierCartads>135792</IdDossierCartads>
<NumeroDossier>CU 044 043 19 A0006</NumeroDossier>
</InformationsComplementaires>
</Notification>'''})
dossier = CartaDSDossier.objects.get(id=dossier.id)
assert dossier.cartads_id_dossier == '135792'
assert dossier.cartads_numero_dossier == 'CU 044 043 19 A0006'
def test_status(connector, app):
CartaDSDossier.objects.all().delete()
test_send(connector, app)
dossier = CartaDSDossier.objects.all()[0]
with mock.patch('passerelle.apps.cartads_cs.models.CartaDSCS.soap_client') as client:
client.return_value = mock.Mock(service=FakeService())
resp = app.get('/cartads-cs/test/status?dossier_id=%s' % dossier.id)
assert resp.json['status_label'] == 'En cours de saisie'