Unify import process.

This commit refs #28045
This commit is contained in:
Sergio Morillo 2023-08-31 22:23:40 +02:00
parent e1d0c4cdfb
commit 9796367b1e
6 changed files with 165 additions and 58 deletions

View File

@ -18,8 +18,9 @@ def register():
edocument.EdocumentTemplate, edocument.EdocumentTemplate,
edocument.EdocumentExportParams, edocument.EdocumentExportParams,
edocument.EdocumentExportFile, edocument.EdocumentExportFile,
edocument.EDocumentImportResult,
party.Party, party.Party,
party.PartyIdentifier, party.PartyConfiguration,
stock.Configuration, stock.Configuration,
stock.ConfigurationSequence, stock.ConfigurationSequence,
product.Template, product.Template,

View File

@ -5,6 +5,7 @@ from trytond.model import ModelSQL, ModelView, fields, Exclude
from sql.conditionals import Coalesce from sql.conditionals import Coalesce
from sql.operators import Equal as SqlEqual from sql.operators import Equal as SqlEqual
from trytond.pool import Pool from trytond.pool import Pool
from trytond.pyson import PYSONEncoder
from trytond.transaction import Transaction from trytond.transaction import Transaction
from trytond.i18n import gettext from trytond.i18n import gettext
from trytond.exceptions import UserError from trytond.exceptions import UserError
@ -86,11 +87,11 @@ class EdocumentMessage(ModelView, ModelSQL):
default_company = Transaction().context.get('company', None) default_company = Transaction().context.get('company', None)
vlist = [x.copy() for x in vlist] vlist = [x.copy() for x in vlist]
for values in vlist: for values in vlist:
if config.edocument_sequence: if not values.get('code') and config.edocument_sequence:
values['code'] = config.get_multivalue( values['code'] = config.get_multivalue(
'edocument_sequence', 'edocument_sequence',
company=values.get('company', default_company)).get() company=values.get('company', default_company)).get()
return super(EdocumentMessage, cls).create(vlist) return super().create(vlist)
class EdocumentMixin(object): class EdocumentMixin(object):
@ -134,25 +135,20 @@ class EdocumentMixin(object):
return message.rec_name return message.rec_name
class EdocumentImportMixin(EdocumentMixin): class EdocumentImportMixin(object):
_edi_message_type = ''
@classmethod @classmethod
def _get_template_name(cls): def _get_template_name(cls):
pass pass
@classmethod @classmethod
def create_from_edi(cls, edi_info, template): def create_object_from_edi(cls, edi_content, template):
pass pass
@classmethod @classmethod
def postprocess(cls, objects): def _postprocess(cls, objects):
pass return objects
@classmethod
def _get_path(cls, message_type):
pool = Pool()
Configuration = pool.get('edocument.configuration.path')
return Configuration._get_path(message_type)
@classmethod @classmethod
def _template(cls): def _template(cls):
@ -165,56 +161,58 @@ class EdocumentImportMixin(EdocumentMixin):
return EdocumentFileManager() return EdocumentFileManager()
@classmethod @classmethod
def _create_objects_from_edi( def _create_objects_from_edi(cls, template=None):
cls, source_uri, error_uri, template=None, target_model=None):
""" """
Get objects from edi files Get objects from edi files
""" """
pool = Pool() pool = Pool()
if not target_model: Configuration = pool.get('edocument.configuration.path')
target_model = cls.__name__ ObjectModel = pool.get(cls.__name__)
Object = pool.get(target_model)
Message = pool.get('edocument.message') Message = pool.get('edocument.message')
paths = Configuration._get_path(cls._edi_message_type)
source_uri, error_uri = paths.path, paths.error_path
if not template: if not template:
template = cls._template() template = cls._template()
objects = [] records = []
error_files = []
messages = [] messages = []
imported = [] to_delete = []
manager = cls._get_document_manager() manager = cls._get_document_manager()
for name, info in manager._get_messages(source_uri, error_uri).items(): for name, info in manager._get_messages(source_uri, error_uri).items():
created, errors = cls.create_from_edi(info, template) try:
if created: record, errors = cls.create_object_from_edi(info, template)
message = Message(code=info) except RuntimeError:
messages.append(message) continue
imported.append(name) else:
for value in created: if errors:
if 'id' in value: error_files.append(manager._handle_errors(
new_object = Object(value['id']) name, errors, error_uri))
else: else:
new_object = Object() if record:
for k, v in value.items(): message = Message(
setattr(new_object, k, v) code=os.path.basename(os.path.splitext(name)[0]),
new_object.message = message message=info,
message.origin = new_object origin=record)
objects.append(new_object) messages.append(message)
if imported: records.append(record)
manager._handle_imported(imported) to_delete.append(name)
if errors:
manager._handle_errors(name, errors, error_uri) ObjectModel.save(records)
Message.save(messages) if messages:
Object.save(objects) Message.save(messages)
return objects
records = cls._postprocess(records)
if to_delete:
manager._handle_imported(to_delete)
return records, error_files
@classmethod @classmethod
def get_objects_from_edi(cls, message_type, target_model=None): def get_objects_from_edi(cls):
'''Get objects from edi''' return cls._create_objects_from_edi()
conf = cls._get_path(message_type)
results = cls._create_objects_from_edi(
conf.path,
conf.error_path,
target_model=target_model)
cls.postprocess(results)
return results
class EdocumentFileManager(object): class EdocumentFileManager(object):
@ -222,7 +220,7 @@ class EdocumentFileManager(object):
@classmethod @classmethod
def _read_file(cls, filename): def _read_file(cls, filename):
with open(filename, encoding='utf-8') as file: with open(filename, 'r', encoding='cp1252') as file:
return file.read() return file.read()
@classmethod @classmethod
@ -240,6 +238,7 @@ class EdocumentFileManager(object):
os.path.splitext(os.path.basename(fname))[0])) os.path.splitext(os.path.basename(fname))[0]))
with open(error_fname, 'w') as fp: with open(error_fname, 'w') as fp:
fp.write('\n'.join(errors)) fp.write('\n'.join(errors))
return error_fname
@classmethod @classmethod
def _handle_imported(cls, imported): def _handle_imported(cls, imported):
@ -247,6 +246,80 @@ class EdocumentFileManager(object):
os.remove(file) os.remove(file)
class EDocumentImportResult(ModelView):
"""Import EDIFACT Result"""
__name__ = 'edifact_import.result'
error_file = fields.Binary('Errors', filename='error_filename',
readonly=True)
error_filename = fields.Char('Filename')
message = fields.Text('Message', readonly=True)
def import_edocument_mixin(model_name, result_field):
class ImportEDocumentMixin(object):
start = StateTransition()
errors = StateView('edifact_import.result',
'edocument_edifact.import_result_view_form', [
Button('OK', 'pre_open', 'tryton-ok', default=True),
])
pre_open = StateTransition()
@property
def result_records(self):
return getattr(self.errors, result_field, [])
@result_records.setter
def result_records(self, value):
setattr(self.errors, result_field, [s.id for s in (value or [])])
def transition_start(self):
pool = Pool()
ActiveModel = pool.get(model_name)
Configuration = pool.get('edocument.configuration.path')
paths = Configuration._get_path(ActiveModel._edi_message_type)
results, error_files = ActiveModel.get_objects_from_edi()
self.result_records = results
if error_files:
error_file = os.path.join(paths.error_path, 'error_file')
with open(error_file, 'w') as ef:
for file in error_files:
ef.write('%s:\n' % file.split('/')[-1].split('error_')[-1])
with open(file, 'r') as f:
for line in f:
ef.write('\t- %s' % line)
ef.write('\n')
with open(error_file, mode='r') as f:
self.errors.error_file = f.read()
return 'errors'
return 'pre_open'
def default_errors(self, fields):
return {
'error_file': self.errors.error_file,
'error_filename': 'EDI_error.txt',
'message': self.errors.error_file,
result_field: [r.id for r in self.result_records]
}
def transition_pre_open(self):
return 'open_'
def do_open_(self, action):
if not self.result_records:
return
action['pyson_domain'] = PYSONEncoder().encode([
('id', 'in', [s.id for s in self.result_records])
])
return action, {}
return ImportEDocumentMixin
class EdocumentExportMixin(object): class EdocumentExportMixin(object):
_message_type = '' _message_type = ''

View File

@ -192,5 +192,12 @@
<field name="type">form</field> <field name="type">form</field>
<field name="name">export_params_form</field> <field name="name">export_params_form</field>
</record> </record>
<!-- Import views -->
<record model="ir.ui.view" id="import_result_view_form">
<field name="model">edifact_import.result</field>
<field name="type">form</field>
<field name="name">import_result_form</field>
</record>
</data> </data>
</tryton> </tryton>

View File

@ -400,4 +400,16 @@ msgstr "Mensajes de Documentación Electrónica"
msgctxt "model:ir.ui.menu,name:menu_edocument_message" msgctxt "model:ir.ui.menu,name:menu_edocument_message"
msgid "Messages" msgid "Messages"
msgstr "Mensajes" msgstr "Mensajes"
msgctxt "model:edifact_import.result,name:"
msgid "Import EDIFACT Result"
msgstr "Resultado importar EDIFACT"
msgctxt "field:edifact_import.result,error_file:"
msgid "Errors"
msgstr "Errores"
msgctxt "view:edifact_import.result:"
msgid "The import of EDI files has encountered the following errors:"
msgstr "La importación de ficheros EDI ha encontrado los siguientes errores:"

View File

@ -29,15 +29,16 @@ class Party(metaclass=PoolMeta):
], 'Assigned Code') ], 'Assigned Code')
class PartyIdentifier(metaclass=PoolMeta): class PartyConfiguration(metaclass=PoolMeta):
__name__ = 'party.identifier' __name__ = 'party.configuration'
@classmethod @classmethod
def get_types(cls): def __setup__(cls):
return super().get_types() + [ super().__setup__()
cls.identifier_types.selection.extend([
('EDI_sender', 'EDI Sender'), ('EDI_sender', 'EDI Sender'),
('EDI_receiver', 'EDI Receiver'), ('EDI_receiver', 'EDI Receiver'),
('EDI_supplier', 'EDI Supplier'), ('EDI_supplier', 'EDI Supplier'),
('EDI_payer', 'EDI Payer'), ('EDI_payer', 'EDI Payer'),
('EDI_buyer', 'EDI Buyer'), ('EDI_buyer', 'EDI Buyer'),
('EDI_invoice', 'EDI Invoice')] ('EDI_invoice', 'EDI Invoice')])

View File

@ -0,0 +1,13 @@
<?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. -->
<form col="2">
<image name="tryton-warning" xexpand="0" xfill="0"/>
<label string="The import of EDI files has encountered the following errors:"
id="process" yalign="0.5" xalign="0.0" xexpand="1"/>
<newline/>
<label name="error_file"/>
<field name="error_file" filename="error_filename"/>
<field name="message" colspan="2"/>
<field name="error_filename" invisible="1" colspan="2"/>
</form>