From a6d1c3ec64d22a137452bbb186d00a38e5bb4b82 Mon Sep 17 00:00:00 2001 From: "Paolo (pgi)" Date: Tue, 1 Jun 2021 12:39:19 +0000 Subject: [PATCH] [FIX] l10n_it_edi: The imported e-invoice was submitted to the wrong company, and the original XML wasn't attached - The context used to create the Form used 'with_context' instead of 'with_company'. - An additional message has been posted to the chatter with the original E-invoice XML from the email. - Some code clarification were due where the e-invoice company is determined. opw-2460485 closes odoo/odoo#71626 X-original-commit: db25a9d02c2fd836e05632ef1e27b73cfdd863e3 Signed-off-by: Josse Colpaert Signed-off-by: Paolo Gatti --- .../l10n_it_edi/models/account_edi_format.py | 40 ++++++++----------- addons/l10n_it_edi/models/ir_mail_server.py | 16 +++++--- .../l10n_it_edi/tests/test_ir_mail_server.py | 5 ++- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/addons/l10n_it_edi/models/account_edi_format.py b/addons/l10n_it_edi/models/account_edi_format.py index 58abd2ad12d..d81719b1de2 100644 --- a/addons/l10n_it_edi/models/account_edi_format.py +++ b/addons/l10n_it_edi/models/account_edi_format.py @@ -109,6 +109,18 @@ class AccountEdiFormat(models.Model): invoice = self.env['account.move'] first_run = False + # Type must be present in the context to get the right behavior of the _default_journal method (account.move). + # journal_id must be present in the context to get the right behavior of the _default_account method (account.move.line). + elements = tree.xpath('//CessionarioCommittente//IdCodice') + company = elements and self.env['res.company'].search([('vat', 'ilike', elements[0].text)], limit=1) + if not company: + elements = tree.xpath('//CessionarioCommittente//CodiceFiscale') + company = elements and self.env['res.company'].search([('l10n_it_codice_fiscale', 'ilike', elements[0].text)], limit=1) + if not company: + # Only invoices with a correct VAT or Codice Fiscale can be imported + _logger.warning('No company found with VAT or Codice Fiscale like %r.', elements[0].text) + continue + # Refund type. # TD01 == invoice # TD02 == advance/down payment on invoice @@ -123,32 +135,14 @@ class AccountEdiFormat(models.Model): move_type = 'in_refund' elif elements and elements[0].text and elements[0].text != 'TD01': _logger.info('Document type not managed: %s. Invoice type is set by default.', elements[0].text) - invoice_ctx = invoice.with_context(default_move_type=move_type) - # type must be present in the context to get the right behavior of the _default_journal method (account.move). - # journal_id must be present in the context to get the right behavior of the _default_account method (account.move.line). - - elements = tree.xpath('//CessionarioCommittente//IdCodice') - company = elements and self.env['res.company'].search([('vat', 'ilike', elements[0].text)], limit=1) - if not company: - elements = tree.xpath('//CessionarioCommittente//CodiceFiscale') - company = elements and self.env['res.company'].search([('l10n_it_codice_fiscale', 'ilike', elements[0].text)], limit=1) - - if company: - invoice_ctx = invoice_ctx.with_context(company_id=company.id) - else: - company = self.env.company - if elements: - _logger.info('No company found with codice fiscale: %s. The user\'s company is set by default.', elements[0].text) - else: - _logger.info('Company not found. The user\'s company is set by default.') - - if not self.env.is_superuser(): - if self.env.company != company: - raise UserError(_("You can only import invoice concern your current company: %s", self.env.company.display_name)) + # Setup the context for the Invoice Form + invoice_ctx = invoice.with_company(company) \ + .with_context(default_move_type=move_type, + account_predictive_bills_disable_prediction=True) # move could be a single record (editing) or be empty (new). - with Form(invoice_ctx.with_context(account_predictive_bills_disable_prediction=True)) as invoice_form: + with Form(invoice_ctx) as invoice_form: message_to_log = [] # Partner (first step to avoid warning 'Warning! You must first select a partner.'). <1.2> diff --git a/addons/l10n_it_edi/models/ir_mail_server.py b/addons/l10n_it_edi/models/ir_mail_server.py index 0cadb51a6d8..c9780d8f005 100644 --- a/addons/l10n_it_edi/models/ir_mail_server.py +++ b/addons/l10n_it_edi/models/ir_mail_server.py @@ -135,7 +135,8 @@ class FetchmailServer(models.Model): # we have a receipt self._message_receipt_invoice(split_underscore[1], attachment) else: - match = re.search("([A-Z]{2}[A-Za-z0-9]{2,28}_[A-Za-z0-9]{0,5}.(xml.p7m|xml))", attachment.fname) + att_filename = attachment.fname + match = re.search("([A-Z]{2}[A-Za-z0-9]{2,28}_[A-Za-z0-9]{0,5}.(xml.p7m|xml))", att_filename) # If match, we have an invoice. if match: # If it's signed, the content has a bytes type and we just remove the signature's envelope @@ -143,12 +144,13 @@ class FetchmailServer(models.Model): att_content_data = remove_signature(attachment.content) # If the envelope cannot be removed, the remove_signature returns None, so we skip if not att_content_data: - _logger.warning("E-invoice couldn't be read: %s", attachment.fname) + _logger.warning("E-invoice couldn't be read: %s", att_filename) continue - # Otherwise, it should be an utf-8 encoded XML string + att_filename = att_filename.replace('.xml.p7m', '.xml') else: + # Otherwise, it should be an utf-8 encoded XML string att_content_data = attachment.content.encode() - self._create_invoice_from_mail(att_content_data, attachment.fname, from_address) + self._create_invoice_from_mail(att_content_data, att_filename, from_address) else: if split_underscore[1] == 'AT': # Attestazione di avvenuta trasmissione della fattura con impossibilità di recapito @@ -174,7 +176,7 @@ class FetchmailServer(models.Model): return invoices # Create the new attachment for the file - self.env['ir.attachment'].create({ + attachment = self.env['ir.attachment'].create({ 'name': att_name, 'raw': att_content_data, 'res_model': 'account.move', @@ -195,6 +197,10 @@ class FetchmailServer(models.Model): invoices.l10n_it_send_state = 'new' invoices.invoice_source_email = from_address + for invoice in invoices: + invoice.with_context(no_new_invoice=True, default_res_id=invoice.id) \ + .message_post(body=(_("Original E-invoice XML file")), attachment_ids=[attachment.id]) + self._cr.commit() _logger.info('New E-invoices (%s), ids: %s', att_name, [x.id for x in invoices]) diff --git a/addons/l10n_it_edi/tests/test_ir_mail_server.py b/addons/l10n_it_edi/tests/test_ir_mail_server.py index 8e803d9ad56..ca06adb88b3 100644 --- a/addons/l10n_it_edi/tests/test_ir_mail_server.py +++ b/addons/l10n_it_edi/tests/test_ir_mail_server.py @@ -44,8 +44,10 @@ class PecMailServerTests(AccountEdiTestCommon): super().setUpClass(chart_template_ref='l10n_it.l10n_it_chart_template_generic', edi_format_ref='l10n_it_edi.edi_fatturaPA') + # Use the company_data_2 to test that the e-invoice is imported for the right company + cls.company = cls.company_data_2['company'] + # Initialize the company's codice fiscale - cls.company = cls.company_data['company'] cls.company.l10n_it_codice_fiscale = 'IT01234560157' # Build test data. @@ -108,6 +110,7 @@ class PecMailServerTests(AccountEdiTestCommon): """ Test a signed (P7M) sample e-invoice file from https://www.fatturapa.gov.it/export/documenti/fatturapa/v1.2/IT01234567890_FPR01.xml """ invoices = self._create_invoice(self.signed_invoice_content, self.signed_invoice_filename) self.assertRecordValues(invoices, [{ + 'company_id': self.company.id, 'name': 'BILL/2014/12/0001', 'date': datetime.date(2014, 12, 18), 'ref': '01234567890',