sp_fr: implement response flow (#33838)

This commit is contained in:
Benjamin Dauvergne 2019-06-11 17:19:23 +02:00
parent a6b7df1192
commit 2497cab25e
1 changed files with 128 additions and 5 deletions

View File

@ -170,16 +170,20 @@ class Resource(BaseResource):
try:
move, error = handler()
except Exception:
count -= 1
self.logger.exception('handling of file "%s" failed', filename)
# sftp.rename(filename, 'FAILED/' + filename)
sftp.rename(filename, 'FAILED/' + filename)
else:
if move and error:
count -= 1
self.logger.error('handling of file "%s" failed: %s', filename, error)
# sftp.rename(filename, 'FAILED/' + filename)
sftp.rename(filename, 'FAILED/' + filename)
else:
if error:
count -= 1
self.logger.warning('handling of file "%s" failed: %s', filename, error)
elif move:
count -= 1
sftp.rename(filename, 'DONE/' + filename)
if not count:
break
@ -226,6 +230,7 @@ class Resource(BaseResource):
return False, 'error during response to service-public.fr %r' % e
self.request.state = Request.STATE_RETURNED
self.request.save()
self.resource.logger.info('%s responded, closed', self.request.filename)
return True, None
def process(self, fd):
@ -330,7 +335,18 @@ class Resource(BaseResource):
return submitter.result.backoffice_url
def response(self):
raise NotImplementedError
with self.resource.output_sftp.client() as client:
with client.open(self.request.response_zip_filename, mode='w') as fd:
self.request.build_response_zip(
fd,
etat='100',
commentaire=u'Demande transmise à la collectivité')
with self.resource.input_sftp.client() as client:
with client.open('DONE/' + self.request.response_zip_filename, mode='w') as fd:
self.request.build_response_zip(
fd,
etat='100',
commentaire=u'Demande transmise à la collectivité')
def get_data(self, data, name):
# prevent error in manual mapping
@ -626,8 +642,8 @@ class Request(models.Model):
STATE_ERROR = 'error'
STATES = [
(STATE_RECEIVED, _('Received')),
(STATE_TRANSFERED, _('Transfered')),
(STATE_ERROR, _('Transfered')),
(STATE_TRANSFERED, _('Transferred')),
(STATE_ERROR, _('Error')),
(STATE_RETURNED, _('Returned')),
]
@ -668,6 +684,113 @@ class Request(models.Model):
self.resource.logger.error('could not delete %s', self.archive)
return super(Request, self).delete(*args, **kwargs)
@property
def message_xml(self):
# FileField can be closed, or open, you never know, and used as a
# contextmanager, __enter__ does not re-open/re-seek(0) it :/
self.archive.open()
with self.archive as fd:
with zipfile.ZipFile(fd) as archive:
with archive.open('message.xml') as message_xml_fd:
s = message_xml_fd.read()
return ET.fromstring(s)
@property
def id_enveloppe(self):
message_xml = self.message_xml
ns = {
'pec': 'http://finances.gouv.fr/dgme/pec/message/v1',
'mdel': 'http://finances.gouv.fr/dgme/gf/composants/teledemarchexml/donnee/metier'
}
return message_xml.find('.//{%(pec)s}MessageId' % ns).text.split()[1]
def build_message_xml_retour(self, etat, commentaire):
message_xml = self.message_xml
ns = {
'pec': 'http://finances.gouv.fr/dgme/pec/message/v1',
'mdel': 'http://finances.gouv.fr/dgme/gf/composants/teledemarchexml/donnee/metier'
}
template = '''<ns2:Message xmlns:ns2="http://finances.gouv.fr/dgme/pec/message/v1" xmlns="http://finances.gouv.fr/dgme/gf/composants/teledemarchexml/donnee/metier">
<ns2:Header>
<ns2:Routing>
<ns2:MessageId/>
<ns2:RefToMessageId/>
<ns2:FlowType/>
<ns2:Sender/>
<ns2:Recipients>
<ns2:Recipient/>
</ns2:Recipients>
</ns2:Routing>
<ns2:Security>
<ns2:Horodatage>false</ns2:Horodatage>
</ns2:Security>
</ns2:Header>
<ns2:Body>
<ns2:Content><ns2:Retour>
<ns2:Enveloppe>
<ns2:NumeroTeledemarche/>
<ns2:MotDePasse/>
</ns2:Enveloppe>
<ns2:Instruction>
<ns2:Maj>
<ns2:Etat/>
<ns2:Commentaire/>
</ns2:Maj>
</ns2:Instruction>
</ns2:Retour>
</ns2:Content>
</ns2:Body>
</ns2:Message>''' # NOQA E501
response = ET.XML(template)
message_id = message_xml.find('.//{%(pec)s}MessageId' % ns).text
# maybe could work with str(uuid.uuid4().hex), which would be more unique, we will never know
response.find('.//{%(pec)s}MessageId' % ns).text = 'RET-1-' + message_id
response.find('.//{%(pec)s}RefToMessageId' % ns).text = message_id
response.find('.//{%(pec)s}FlowType' % ns).text = message_xml.find('.//{%(pec)s}FlowType' % ns).text
response.find('.//{%(pec)s}Sender' % ns).extend(
message_xml.find('.//{%(pec)s}Recipient' % ns))
response.find('.//{%(pec)s}Recipient' % ns).extend(
message_xml.find('.//{%(pec)s}Sender' % ns))
response.find('.//{%(pec)s}FlowType' % ns).text = message_xml.find('.//{%(pec)s}FlowType' % ns).text
# Strangely the same node in the response does not have the same
# namespace as the node in the request, whatever...
response.find('.//{%(pec)s}NumeroTeledemarche' % ns).text = message_xml.find(
'.//{%(mdel)s}NumeroTeledemarche' % ns).text
response.find('.//{%(pec)s}MotDePasse' % ns).text = message_xml.find('.//{%(mdel)s}MotDePasse' % ns).text
response.find('.//{%(pec)s}Etat' % ns).text = '100'
response.find('.//{%(pec)s}Commentaire' % ns).text = u'Dossier transmis à la collectivité'
return response
def build_response_zip(self, fd_or_filename, etat, commentaire):
with zipfile.ZipFile(fd_or_filename, 'w') as archive:
message_xml = self.build_message_xml_retour(
etat=etat, commentaire=commentaire)
archive.writestr('message.xml',
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
+ ET.tostring(message_xml, encoding='utf-8'))
@property
def response_zip_filename(self):
m = FILE_PATTERN.match(self.filename)
numero_teledossier = m.group('identifier')
code_demarche = m.group('procedure')
id_enveloppe = self.id_enveloppe
numero_sequence = '1'
return '%s-%s-%s-%s.zip' % (
numero_teledossier,
code_demarche,
id_enveloppe,
numero_sequence)
class Meta:
verbose_name = _('MDEL request')
verbose_name_plural = _('MDEL requests')