[IMP] account(_edi): Detect when an invoice is ready to be sent

In some flow like subscription, invoices are sent by mail automatically to the customer.
Sometimes, the invoice must be approved by the government before sending the mail like the Mexican EDI.
This commit aims to add a custom method to detect when an invoice is ready to be sent to the customer.

PR (community): https://github.com/odoo/odoo/pull/78714
PR (enterprise): https://github.com/odoo/enterprise/pull/21809

closes odoo/odoo#79504

X-original-commit: 3a29371eb70309f46e3b8938434287fefc23b351
Related: odoo/enterprise#22171
Signed-off-by: William André (wan) <wan@odoo.com>
This commit is contained in:
Laurent Smet
2021-11-09 14:45:57 +00:00
committed by william-andre
parent 346dcd7ac1
commit 85f2ae03d3
4 changed files with 105 additions and 2 deletions
+25
View File
@@ -7,6 +7,7 @@ from odoo.tools.misc import formatLang, format_date, get_lang
from datetime import date, timedelta
from collections import defaultdict
from contextlib import contextmanager
from itertools import zip_longest
from hashlib import sha256
from json import dumps
@@ -2758,6 +2759,30 @@ class AccountMove(models.Model):
return reverse_moves
def _action_invoice_ready_to_be_sent(self):
""" Hook allowing custom code when an invoice becomes ready to be sent by mail to the customer.
For example, when an EDI document must be sent to the government and be signed by it.
"""
def _is_ready_to_be_sent(self):
""" Helper telling if a journal entry is ready to be sent by mail to the customer.
:return: True if the invoice is ready, False otherwise.
"""
self.ensure_one()
return True
@contextmanager
def _send_only_when_ready(self):
moves_not_ready = self.filtered(lambda x: not x._is_ready_to_be_sent())
try:
yield
finally:
moves_now_ready = moves_not_ready.filtered(lambda x: x._is_ready_to_be_sent())
if moves_now_ready:
moves_now_ready._action_invoice_ready_to_be_sent()
def open_reconcile_view(self):
return self.line_ids.open_reconcile_view()
@@ -161,8 +161,10 @@ class AccountEdiDocument(models.Model):
state = documents[0].state
if doc_type == 'invoice':
if state == 'to_send':
edi_result = edi_format._post_invoice_edi(documents.move_id)
_postprocess_post_edi_results(documents, edi_result)
invoices = documents.move_id
with invoices._send_only_when_ready():
edi_result = edi_format._post_invoice_edi(invoices)
_postprocess_post_edi_results(documents, edi_result)
elif state == 'to_cancel':
edi_result = edi_format._cancel_invoice_edi(documents.move_id)
_postprocess_cancel_edi_results(documents, edi_result)
+11
View File
@@ -429,6 +429,17 @@ class AccountMove(models.Model):
self.env['account.edi.document'].create(edi_document_vals_list)
self.edi_document_ids._process_documents_no_web_services()
def _is_ready_to_be_sent(self):
# OVERRIDE
# Prevent a mail to be sent to the customer if the EDI document is not sent.
res = super()._is_ready_to_be_sent()
if not res:
return False
edi_documents_to_send = self.edi_document_ids.filtered(lambda x: x.state == 'to_send')
return not bool(edi_documents_to_send)
def _post(self, soft=True):
# OVERRIDE
# Set the electronic document to be posted and post immediately for synchronous formats.
+65
View File
@@ -227,3 +227,68 @@ class TestAccountEdi(AccountEdiTestCommon, CronMixinCase):
self.env.ref('account_edi.ir_cron_edi_network').method_direct_trigger()
self.assertEqual(len(capt.records), 2, "Not all records have been processed in this run, the cron should "
"re-trigger itself to process some more later")
def test_prepare_edi_vals_to_export(self):
"""
Test _prepare_edi_vals_to_export return values
in the proper format
tag_ids should be a set of id and tags a proper recordset
"""
account_tag = self.env['account.account.tag'].create({
"applicability": "taxes",
"country_id": self.env.ref('base.us').id,
"name": "Test Tag",
})
tax = self.env['account.tax'].create({
"amount": 15,
"amount_type": "percent",
"description": "15%",
"country_id": self.env.ref('base.us').id,
"invoice_repartition_line_ids": [
Command.create({
"factor_percent": 100,
"repartition_type": "base",
"sequence": 1,
}),
Command.create({
"factor_percent": 100,
"repartition_type": "tax",
"sequence": 1,
"tag_ids": [Command.link(account_tag.id)]
})
],
"name": "Test",
"tax_exigibility": "on_invoice",
"type_tax_use": "sale"
})
invoices = self.env['account.move'].create({
'move_type': 'out_invoice',
'invoice_date': '2019-01-01',
'date': '2019-01-01',
'partner_id': self.partner_a.id,
'invoice_line_ids': [Command.create({
'product_id': self.product_a.id,
'tax_ids': [Command.link(tax.id)]
})],
})
vals = invoices._prepare_edi_vals_to_export()
self.assertEqual(
vals['invoice_line_vals_list'][0]['tax_detail_vals_list'][0]['tag_ids'], set(account_tag.ids))
self.assertEqual(
vals['invoice_line_vals_list'][0]['tax_detail_vals_list'][0]['tags'].name, "Test Tag")
def test_invoice_ready_to_be_sent(self):
def _is_needed_for_invoice(edi_format, invoice):
return True
with self.mock_edi(
_needs_web_services_method=_generate_mocked_needs_web_services(True),
_is_required_for_invoice_method=_is_needed_for_invoice,
):
self.invoice.action_post()
doc = self.invoice._get_edi_document(self.edi_format)
self.assertFalse(self.invoice._is_ready_to_be_sent())
doc._process_documents_web_services(with_commit=False)
self.assertTrue(self.invoice._is_ready_to_be_sent())