[FIX] account_edi: a failed import of an attachment with account_edi now allows OCR to run automatically.
Before this commit, account_invoice_extract and account_edi where independent in parsing files uploaded or added as attachment in an invoice. Some tricks where used to avoid clash, but they were not perfect and some bugs appeared like the OCR not triggering automatically or an attachment being parsed twice by account_edi when parsing failed. The goal of this commit is to unify the import of files between the two features and ensure that they will not clash. For more information about potential problems that appeared before : See https://github.com/odoo/odoo/pull/61169 See https://github.com/odoo/enterprise/pull/15124/ closes odoo/odoo#65660 X-original-commit: 8435d0e8990509ee67425977f970ab27bea8133a Related: odoo/enterprise#16172 Signed-off-by: Laurent Smet <smetl@users.noreply.github.com> Signed-off-by: bfr-o <bfr-o@users.noreply.github.com>
This commit is contained in:
@@ -613,7 +613,16 @@ class AccountJournal(models.Model):
|
||||
invoices = self.env['account.move']
|
||||
for attachment in attachments:
|
||||
attachment.write({'res_model': 'mail.compose.message'})
|
||||
invoices += self._create_invoice_from_single_attachment(attachment)
|
||||
decoders = self.env['account.move']._get_create_invoice_from_attachment_decoders()
|
||||
invoice = False
|
||||
for decoder in sorted(decoders, key=lambda d: d[0]):
|
||||
invoice = decoder[1](attachment)
|
||||
if invoice:
|
||||
break
|
||||
if not invoice:
|
||||
invoice = self.env['account.move'].create({})
|
||||
invoice.with_context(no_new_invoice=True).message_post(attachment_ids=[attachment.id])
|
||||
invoices += invoice
|
||||
|
||||
action_vals = {
|
||||
'name': _('Generated Documents'),
|
||||
@@ -638,12 +647,11 @@ class AccountJournal(models.Model):
|
||||
def _create_invoice_from_single_attachment(self, attachment):
|
||||
""" Creates an invoice and post the attachment. If the related modules
|
||||
are installed, it will trigger OCR or the import from the EDI.
|
||||
DEPRECATED : use create_invoice_from_attachment instead
|
||||
|
||||
:returns: the created invoice.
|
||||
"""
|
||||
invoice = self.env['account.move'].create({})
|
||||
invoice.message_post(attachment_ids=[attachment.id])
|
||||
return invoice
|
||||
return self.create_invoice_from_attachment(attachment.ids)
|
||||
|
||||
def _create_secure_sequence(self, sequence_fields):
|
||||
"""This function creates a no_gap sequence on each journal in self that will ensure
|
||||
|
||||
@@ -2887,6 +2887,57 @@ class AccountMove(models.Model):
|
||||
|
||||
return rslt
|
||||
|
||||
@api.returns('mail.message', lambda value: value.id)
|
||||
def message_post(self, **kwargs):
|
||||
# OVERRIDE
|
||||
# When posting a message, check the attachment to see if it's an invoice and update with the imported data.
|
||||
res = super().message_post(**kwargs)
|
||||
|
||||
attachment_ids = kwargs.get('attachment_ids', [])
|
||||
if len(self) != 1 or not attachment_ids or self.env.context.get('no_new_invoice') or not self.is_invoice(include_receipts=True):
|
||||
return res
|
||||
|
||||
attachments = self.env['ir.attachment'].browse(attachment_ids)
|
||||
odoobot = self.env.ref('base.partner_root')
|
||||
if attachments and self.state != 'draft':
|
||||
self.message_post(body='The invoice is not a draft, it was not updated from the attachment.',
|
||||
message_type='comment',
|
||||
subtype_xmlid='mail.mt_note',
|
||||
author_id=odoobot.id)
|
||||
return res
|
||||
if attachments and self.line_ids:
|
||||
self.message_post(body='The invoice already contains lines, it was not updated from the attachment.',
|
||||
message_type='comment',
|
||||
subtype_xmlid='mail.mt_note',
|
||||
author_id=odoobot.id)
|
||||
return res
|
||||
|
||||
decoders = self.env['account.move']._get_update_invoice_from_attachment_decoders(self)
|
||||
for decoder in sorted(decoders, key=lambda d: d[0]):
|
||||
# start with message_main_attachment_id, that way if OCR is installed, only that one will be parsed.
|
||||
# this is based on the fact that the ocr will be the last decoder.
|
||||
for attachment in attachments.sorted(lambda x: x != self.message_main_attachment_id):
|
||||
invoice = decoder[1](attachment, self)
|
||||
if invoice:
|
||||
break
|
||||
|
||||
return res
|
||||
|
||||
def _get_create_invoice_from_attachment_decoders(self):
|
||||
""" Returns a list of method that are able to create an invoice from an attachment and a priority.
|
||||
|
||||
:returns: A list of tuples (priority, method) where method takes an attachment as parameter.
|
||||
"""
|
||||
return []
|
||||
|
||||
def _get_update_invoice_from_attachment_decoders(self, invoice):
|
||||
""" Returns a list of method that are able to create an invoice from an attachment and a priority.
|
||||
|
||||
:param invoice: The invoice on which to update the data.
|
||||
:returns: A list of tuples (priority, method) where method takes an attachment as parameter.
|
||||
"""
|
||||
return []
|
||||
|
||||
class AccountMoveLine(models.Model):
|
||||
_name = "account.move.line"
|
||||
_description = "Journal Item"
|
||||
|
||||
@@ -65,7 +65,7 @@ class AccountTourUploadBill(models.TransientModel):
|
||||
'res_model': 'mail.compose.message',
|
||||
'datas': self.sample_bill_preview,
|
||||
})
|
||||
bill = purchase_journal.with_context(default_journal_id=purchase_journal.id, default_move_type='in_invoice')._create_invoice_from_single_attachment(attachment)
|
||||
bill = purchase_journal.with_context(default_journal_id=purchase_journal.id, default_move_type='in_invoice').create_invoice_from_attachment(attachment.ids)
|
||||
if self.selection == 'sample':
|
||||
bill.write({
|
||||
'partner_id': self.env.ref('base.main_partner').id,
|
||||
|
||||
@@ -51,12 +51,3 @@ class AccountJournal(models.Model):
|
||||
|
||||
for journal in self:
|
||||
journal.edi_format_ids += edi_formats.filtered(lambda e: e._is_compatible_with_journal(journal))
|
||||
|
||||
def _create_invoice_from_single_attachment(self, attachment):
|
||||
# OVERRIDE
|
||||
invoice = self.env['account.edi.format'].search([])._create_invoice_from_attachment(attachment)
|
||||
if invoice:
|
||||
# with_context: we don't want to import the attachment since the invoice was just created from it.
|
||||
invoice.with_context(no_new_invoice=True).message_post(attachment_ids=attachment.ids)
|
||||
return invoice
|
||||
return super(AccountJournal, self.with_context(no_new_invoice=True))._create_invoice_from_single_attachment(attachment)
|
||||
|
||||
@@ -216,37 +216,16 @@ class AccountMove(models.Model):
|
||||
# Import Electronic Document
|
||||
####################################################
|
||||
|
||||
@api.returns('mail.message', lambda value: value.id)
|
||||
def message_post(self, **kwargs):
|
||||
def _get_create_invoice_from_attachment_decoders(self):
|
||||
# OVERRIDE
|
||||
# When posting a message, analyse the attachment to check if it is an EDI document and update the invoice
|
||||
# with the imported data.
|
||||
res = super().message_post(**kwargs)
|
||||
|
||||
if len(self) != 1 or self.env.context.get('no_new_invoice') or not self.is_invoice(include_receipts=True):
|
||||
return res
|
||||
|
||||
attachments = self.env['ir.attachment'].browse(kwargs.get('attachment_ids', []))
|
||||
odoobot = self.env.ref('base.partner_root')
|
||||
if attachments and self.state != 'draft':
|
||||
self.message_post(body='The invoice is not a draft, it was not updated from the attachment.',
|
||||
message_type='comment',
|
||||
subtype_xmlid='mail.mt_note',
|
||||
author_id=odoobot.id)
|
||||
return res
|
||||
if attachments and self.line_ids:
|
||||
self.message_post(body='The invoice already contains lines, it was not updated from the attachment.',
|
||||
message_type='comment',
|
||||
subtype_xmlid='mail.mt_note',
|
||||
author_id=odoobot.id)
|
||||
return res
|
||||
|
||||
edi_formats = self.env['account.edi.format'].search([])
|
||||
for attachment in attachments:
|
||||
invoice = edi_formats._update_invoice_from_attachment(attachment, self)
|
||||
if invoice:
|
||||
break
|
||||
res = super()._get_create_invoice_from_attachment_decoders()
|
||||
res.append((10, self.env['account.edi.format'].search([])._create_invoice_from_attachment))
|
||||
return res
|
||||
|
||||
def _get_update_invoice_from_attachment_decoders(self, invoice):
|
||||
# OVERRIDE
|
||||
res = super()._get_update_invoice_from_attachment_decoders(invoice)
|
||||
res.append((10, self.env['account.edi.format'].search([])._update_invoice_from_attachment))
|
||||
return res
|
||||
|
||||
####################################################
|
||||
|
||||
@@ -67,7 +67,7 @@ class AccountEdiTestCommon(AccountTestInvoicingCommon):
|
||||
})
|
||||
|
||||
journal_id = self.company_data['default_journal_sale']
|
||||
journal_id.with_context(default_move_type='in_invoice')._create_invoice_from_single_attachment(attachment)
|
||||
journal_id.with_context(default_move_type='in_invoice').create_invoice_from_attachment(attachment.ids)
|
||||
|
||||
def assert_generated_file_equal(self, invoice, expected_values, applied_xpath=None):
|
||||
invoice.action_post()
|
||||
|
||||
Reference in New Issue
Block a user