Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 21 additions & 23 deletions sale_order_type_automation/models/sale_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,31 +59,29 @@ def run_invoicing_atomation(self):
):
if rec.env.context.get("commit_invoice_automation"):
rec.env.cr.commit()
if rec.type_id.invoice_validate_domain:
domain = safe_eval(
rec.type_id.invoice_validate_domain,
{
"datetime": safe_eval_datetime,
"context_today": lambda: fields.Date.context_today(rec),
"relativedelta": safe_eval_dateutil.relativedelta.relativedelta,
},
)
invoices_to_validate = (invoices - invoices.filtered_domain(domain)) if domain else invoices
else:
invoices_to_validate = invoices
try:
if rec.type_id.invoice_validate_domain:
domain = safe_eval(
rec.type_id.invoice_validate_domain,
{
"datetime": safe_eval_datetime,
"context_today": lambda: fields.Date.context_today(rec),
"relativedelta": safe_eval_dateutil.relativedelta.relativedelta,
},
)
invoices_to_validate = (invoices - invoices.filtered_domain(domain)) if domain else invoices
else:
invoices_to_validate = invoices
invoices_to_validate.sudo().action_post()
for invoice in invoices_to_validate: # to avoid "expected singleton" error
if (
invoice.name
and not invoice.line_ids.mapped("move_name")
and invoice.name not in invoice.line_ids.mapped("move_name")
):
invoice.env.add_to_compute(invoice.line_ids._fields["move_name"], invoice.line_ids)
with rec.env.cr.savepoint():
invoices_to_validate.sudo().action_post()
for invoice in invoices_to_validate: # to avoid "expected singleton" error
if (
invoice.name
and not invoice.line_ids.mapped("move_name")
and invoice.name not in invoice.line_ids.mapped("move_name")
):
invoice.env.add_to_compute(invoice.line_ids._fields["move_name"], invoice.line_ids)
except Exception as error:
rec.env.cr.rollback()
if not rec.env.context.get("commit_invoice_automation"):
raise error
message = _(
"We couldn't validate the automatically created "
"invoices (ids %s), you will need to validate them"
Expand Down
1 change: 1 addition & 0 deletions sale_order_type_automation/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
##############################################################################

from . import test_sale_order_type_automation
from . import test_invoice_automation_error
74 changes: 74 additions & 0 deletions sale_order_type_automation/tests/test_invoice_automation_error.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
##############################################################################
# For copyright and license notices, see __manifest__.py file in module root
# directory
##############################################################################
from unittest.mock import patch

from odoo.addons.sale.tests.common import TestSaleCommon
from odoo.tests import tagged


@tagged("post_install", "-at_install")
class TestInvoiceAutomationError(TestSaleCommon):
@classmethod
def setup_independent_user(cls):
# Keep superuser context for setup in deployments with stricter product ACLs.
return None

@classmethod
def setUpClass(cls):
super().setUpClass()
cls.validate_invoice_type = cls.env["sale.order.type"].create(
{
"name": "Test Validate Invoice Automation",
"invoicing_atomation": "validate_invoice",
}
)
sale_exception_installed = cls.env["sale.order"]._fields.get("ignore_exception")
if sale_exception_installed:
cls.env["exception.rule"].search([("active", "=", True)]).write({"active": False})

def _create_so(self):
product = self.company_data["product_service_order"]
return self.env["sale.order"].create(
{
"partner_id": self.partner_a.id,
"type_id": self.validate_invoice_type.id,
"order_line": [
(
0,
0,
{
"product_id": product.id,
"product_uom_qty": 1.0,
"price_unit": 100.0,
},
)
],
}
)

def test_arca_timeout_keeps_invoice_and_logs_error(self):
"""Al fallar action_post (ej. timeout ARCA), la factura queda en draft y
se registra el error en el chatter de la factura y de la orden de venta."""
so = self._create_so()
AccountMove = self.env["account.move"]
with patch.object(
type(AccountMove),
"action_post",
side_effect=Exception("ARCA timeout"),
):
so.action_confirm()

self.assertEqual(len(so.invoice_ids), 1, "La factura debe haberse creado")
invoice = so.invoice_ids
self.assertTrue(invoice.exists(), "La factura no debe haberse borrado por el savepoint")
self.assertEqual(invoice.state, "draft", "La factura debe quedar en draft si action_post falla")
self.assertTrue(
any("ARCA timeout" in (m.body or "") for m in invoice.message_ids),
"Se esperaba mensaje de error en el chatter de la factura",
)
self.assertTrue(
any("ARCA timeout" in (m.body or "") for m in so.message_ids),
"Se esperaba mensaje de error en el chatter de la orden de venta",
)
Loading