Unify export process.

Added menu for messages.

This commit refs #28106
This commit is contained in:
Sergio Morillo 2023-08-31 10:46:58 +02:00
parent 6c8f2dff5b
commit e1d0c4cdfb
9 changed files with 224 additions and 51 deletions

View File

@ -16,6 +16,8 @@ def register():
configuration.ConfigurationPath,
edocument.EdocumentMessage,
edocument.EdocumentTemplate,
edocument.EdocumentExportParams,
edocument.EdocumentExportFile,
party.Party,
party.PartyIdentifier,
stock.Configuration,

View File

@ -8,10 +8,12 @@ from trytond.pool import Pool
from trytond.transaction import Transaction
from trytond.i18n import gettext
from trytond.exceptions import UserError
from trytond.wizard import StateTransition, StateView, Button
from genshi.template import TextTemplate
from io import open
import oyaml as yaml
import os
import tempfile
KNOWN_EXTENSIONS = ['.txt', '.edi', '.pla']
@ -55,10 +57,9 @@ class EdocumentMessage(ModelView, ModelSQL):
"""EDIFACT message"""
__name__ = 'edocument.message'
code = fields.Char('Code')
message = fields.Text('Message')
sequence = fields.Many2One('ir.sequence', 'Sequence')
origin = fields.Reference('Origin', selection='get_origin')
code = fields.Char('Code', readonly=True)
message = fields.Text('Message', readonly=True)
origin = fields.Reference('Origin', selection='get_origin', readonly=True)
def get_rec_name(self, name):
return 'EW' + '{0:0>6}'.format(self.code)
@ -94,25 +95,27 @@ class EdocumentMessage(ModelView, ModelSQL):
class EdocumentMixin(object):
messages = fields.One2Many('edocument.message', 'origin', 'Message')
edocument_processed = fields.Function(
fields.Boolean('Processed'), 'get_edocument_processed',
searcher='search_edocument_processed')
edi_messages = fields.One2Many('edocument.message', 'origin',
'EDI Messages')
edi_processed = fields.Function(
fields.Boolean('EDI Processed'), 'get_edi_processed',
searcher='search_edi_processed')
edi_message = fields.Function(
fields.Char('EDI Message'), 'get_edi_message')
def get_edocument_processed(self, name=None):
return len(self.messages) > 0
def get_edi_processed(self, name=None):
return bool(self.edi_messages)
@classmethod
def search_edocument_processed(cls, name, clause):
def search_edi_processed(cls, name, clause):
exist = {
True: [('messages', '=', None)],
False: [('messages', '!=', None)]}
True: [('edi_messages', '=', None)],
False: [('edi_messages', '!=', None)]
}
return exist[bool(clause[1] == '=') ^ bool(clause[2])]
def get_edi_message(self, name=None):
return self.messages[-1].rec_name if self.messages else ''
return self.edi_messages[-1].rec_name if self.edi_messages else ''
@classmethod
def copy(cls, records, default=None):
@ -120,9 +123,16 @@ class EdocumentMixin(object):
default = {}
else:
default = default.copy()
default['messages'] = None
default['edi_messages'] = None
return super().copy(records, default=default)
@property
def edi_party(self):
return self.party
def _get_edi_message_key(self, message):
return message.rec_name
class EdocumentImportMixin(EdocumentMixin):
@ -238,32 +248,53 @@ class EdocumentFileManager(object):
class EdocumentExportMixin(object):
_message_type = ''
def _default_template_path(self, message_type):
return os.path.join(os.path.dirname(__file__),
'template', message_type.lower() + '.txt')
start = StateTransition()
params = StateView('edifact_export.params',
'edocument_edifact.export_params_view_form',
[
Button('Cancel', 'end', 'tryton-cancel'),
Button('Export', 'show_file', 'tryton-forward')
])
show_file = StateView('edifact_export.file',
'edocument_edifact.export_file_view_form', [
Button('OK', 'end', 'tryton-ok')
])
def transition_start(self):
return 'params'
@classmethod
def _default_template_path_file(cls):
pass
def _default_template_path(self):
return os.path.join(os.path.dirname(
self._default_template_path_file()),
'template',
self._message_type.lower() + '.txt')
def _write_file(self, file_path, file, encoding='utf-8'):
edi_file = open(file_path, 'w+', encoding=encoding)
edi_file.write(file)
edi_file.close()
with open(file_path, 'w+', encoding=encoding) as edi_file:
edi_file.write(file)
def _edi_template(self, message_type, party):
def _edi_template(self, party):
pool = Pool()
EdocumentTemplate = pool.get('edocument.template')
templates = EdocumentTemplate.search([
('message_type', '=', message_type),
('message_type', '=', self._message_type),
('party', '=', party)])
if templates:
return templates[0].template, templates[0].encoding
else:
template_path = self._default_template_path(message_type)
template_path = self._default_template_path()
with open(template_path) as file:
template = file.read()
return template, 'utf-8'
def generate_message(self, message_type, export_again=False):
def generate_message(self, export_again=False):
pool = Pool()
ActiveModel = self.model
Message = pool.get('edocument.message')
@ -271,7 +302,7 @@ class EdocumentExportMixin(object):
domain = [('id', 'in', Transaction().context['active_ids'])]
if not export_again:
domain.append(('edocument_processed', '=', False))
domain.append(('edi_processed', '=', False))
records = ActiveModel.search(domain)
if not records:
@ -280,13 +311,18 @@ class EdocumentExportMixin(object):
companies = set(x.company for x in records)
if len(companies) > 1:
raise UserError(gettext('edocument_edifact.msg_company_unique'))
company, = companies
edifact_sender = [x for x in company.party.identifiers
if x.type == 'EDI_sender']
if not edifact_sender:
raise UserError(gettext('edocument_edifact.msg_EDI_sender',
company=company.party.name))
parties = set(x.party for x in records)
parties = set(x.edi_party for x in records)
if len(parties) > 1:
raise UserError(
gettext('edocument_edifact.msg_party_receiver_unique'))
party, = parties
edifact_receiver = [x for x in party.identifiers
if x.type == 'EDI_receiver']
@ -294,7 +330,7 @@ class EdocumentExportMixin(object):
raise UserError(gettext('edocument_edifact.msg_party_EDI_receiver',
party=party.name))
template, encoding = self._edi_template(message_type, party)
template, encoding = self._edi_template(party)
loader = TextTemplate(template)
for record in records:
message = Message()
@ -304,16 +340,15 @@ class EdocumentExportMixin(object):
"message": message,
"sender": edifact_sender[0].code,
"receiver": edifact_receiver[0].code,
"records": [[message.code, record]],
"records": [[record._get_edi_message_key(message), record]],
"date": message.create_date.strftime("%y%m%d"),
"time": message.create_date.strftime("%H%M")
}
message.message = loader.generate(
data=data, items=[1, 2, 3]).render()
message.save()
record.save()
conf = Configuration._get_path(message_type)
conf = Configuration._get_path(self._message_type)
chars = ['.', ' ', '-', ':']
f_name = ''.join(
[c for c in str(datetime.now()) if c not in chars])
@ -322,4 +357,37 @@ class EdocumentExportMixin(object):
self._write_file(file_name, message.message, encoding=encoding)
if not message.code:
raise UserError(gettext('edocument_edifact.msg_EDI_sequence'))
return message.message, message_type + message.code + '.EDI'
return message.message, self._message_type + message.code + '.EDI'
def default_show_file(self, fields):
if not Transaction().context['active_ids']:
return {'file': None, 'file_name': None}
message, edi_file_name = self.generate_message(
export_again=self.params.export_again)
if not message:
return {}
file_no, file_name = tempfile.mkstemp('.txt', 'tryton_')
with open(file_name, 'w+') as file_p:
file_p.write(message)
file_p.close()
with open(file_name, mode='r') as file_p:
self.show_file.file = file_p.read()
self.show_file.file_name = edi_file_name
return {'file': self.show_file.file, 'file_name': edi_file_name}
class EdocumentExportParams(ModelView):
'''EDIFACT Export Params'''
__name__ = 'edifact_export.params'
export_again = fields.Boolean('Export Again')
class EdocumentExportFile(ModelView):
'''EDIFACT Export File'''
__name__ = 'edifact_export.file'
file = fields.Binary('File', readonly=True)
file_name = fields.Char('File Name')

View File

@ -135,5 +135,62 @@
action="act_edocument_configuration_path"
sequence="10" icon="tryton-list"
id="menu_edocument_configuration_path"/>
<!-- Edocument Message -->
<record model="ir.ui.view" id="edocument_message_view_form">
<field name="model">edocument.message</field>
<field name="type">form</field>
<field name="name">edocument_message_form</field>
</record>
<record model="ir.ui.view" id="edocument_message_view_list">
<field name="model">edocument.message</field>
<field name="type">tree</field>
<field name="name">edocument_message_list</field>
</record>
<record model="ir.action.act_window" id="act_edocument_message">
<field name="name">Edocument Messages</field>
<field name="res_model">edocument.message</field>
</record>
<record model="ir.action.act_window.view" id="act_edocument_message_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="edocument_message_view_list"/>
<field name="act_window" ref="act_edocument_message"/>
</record>
<record model="ir.action.act_window.view" id="act_edocument_message_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="edocument_message_view_form"/>
<field name="act_window" ref="act_edocument_message"/>
</record>
<record model="ir.model.access" id="access_edocument_message">
<field name="model" search="[('model', '=', 'edocument.message')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_edocument_message_group_group_admin">
<field name="model" search="[('model', '=', 'edocument.message')]"/>
<field name="group" ref="res.group_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<menuitem parent="menu_edocument" sequence="20" id="menu_edocument_message" name="Messages"
action="act_edocument_message"/>
<!-- Export views -->
<record model="ir.ui.view" id="export_file_view_form">
<field name="model">edifact_export.file</field>
<field name="type">form</field>
<field name="name">export_file_form</field>
</record>
<record model="ir.ui.view" id="export_params_view_form">
<field name="model">edifact_export.params</field>
<field name="type">form</field>
<field name="name">export_params_form</field>
</record>
</data>
</tryton>

View File

@ -26,17 +26,9 @@ msgctxt "model:ir.message,text:msg_EDI_export_path"
msgid "EDI export path is not defined in Edocument Configuration."
msgstr "Ruta de exportación EDI no está definida en Configuración de Documentación Electrónica."
msgctxt "model:ir.message,text:msg_customer_unique"
msgid "Cannot send invoices for more than 1 customer"
msgstr "No se pueden enviar facturas a más de 1 cliente."
msgctxt "model:ir.message,text:msg_shipment_customer_unique"
msgid "Cannot send shipments for more than 1 customer"
msgstr "No se pueden enviar albaranes a más de 1 cliente."
msgctxt "model:ir.message,text:msg_customer_EDI_receiver"
msgid "Customer \"%(customer)s\" lacks EDI receiver identifier"
msgstr "El cliente \"%(customer)s\" no tiene identificador de receptor EDI."
msgctxt "model:ir.message,text:msg_party_receiver_unique"
msgid "Cannot send document for more than one Party receiver."
msgstr "No se pueden enviar documentos a más de un tercero receptor."
msgctxt "model:ir.message,text:msg_message_type_unique"
msgid "Message type must be unique."
@ -381,3 +373,31 @@ msgstr "93A"
msgctxt "selection:party.party,edi_release_number:"
msgid "96A"
msgstr "96A"
msgctxt "field:edifact_export.params,export_again:"
msgid "Export Again"
msgstr "Exportar de nuevo"
msgctxt "field:edifact_export.file,file:"
msgid "File"
msgstr "Fichero"
msgctxt "field:edifact_export.file,file_name:"
msgid "File Name"
msgstr "Nombre de archivo"
msgctxt "model:edifact_export.params,name:"
msgid "EDIFACT Export Params"
msgstr "Parámetros exportar EDIFACT"
msgctxt "model:edifact_export.file,name:"
msgid "EDIFACT Export File"
msgstr "Fichero exportar EDIFACT"
msgctxt "model:ir.action,name:act_edocument_message"
msgid "Edocument Messages"
msgstr "Mensajes de Documentación Electrónica"
msgctxt "model:ir.ui.menu,name:menu_edocument_message"
msgid "Messages"
msgstr "Mensajes"

View File

@ -6,11 +6,8 @@ this repository contains the full copyright notices and license terms. -->
<record model="ir.message" id="msg_company_unique">
<field name="text">Cannot send invoices from more than 1 company.</field>
</record>
<record model="ir.message" id="msg_customer_unique">
<field name="text">Cannot send invoices for more than 1 customer.</field>
</record>
<record model="ir.message" id="msg_shipment_customer_unique">
<field name="text">Cannot send shipments for more than 1 customer.</field>
<record model="ir.message" id="msg_party_receiver_unique">
<field name="text">Cannot send document for more than one Party receiver.</field>
</record>
<record model="ir.message" id="msg_edi_party_message_type">
<field name="text">Combination of message type and party must be unique.</field>
@ -21,9 +18,6 @@ this repository contains the full copyright notices and license terms. -->
<record model="ir.message" id="msg_party_EDI_receiver">
<field name="text">Party "%(party)s" lacks EDI receiver identifier.</field>
</record>
<record model="ir.message" id="msg_customer_EDI_receiver">
<field name="text">Customer "%(customer)s" lacks EDI receiver identifier.</field>
</record>
<record model="ir.message" id="msg_EDI_sequence">
<field name="text">EDI Sequence must be defined in Edocument Configuration.</field>
</record>

View File

@ -0,0 +1,11 @@
<?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. -->
<form>
<label name="code"/>
<field name="code"/>
<label name="origin"/>
<field name="origin"/>
<separator name="message" colspan="4"/>
<field name="message" colspan="4"/>
</form>

View File

@ -0,0 +1,7 @@
<?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. -->
<tree>
<field name="rec_name"/>
<field name="origin" expand="1"/>
</tree>

View File

@ -0,0 +1,7 @@
<?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. -->
<form>
<label name="file"/>
<field name="file"/>
</form>

View File

@ -0,0 +1,7 @@
<?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. -->
<form>
<label name="export_again"/>
<field name="export_again"/>
</form>