Files
Odoo-18.0-20251222/sale_invoice_policy/tests/test_sale_invoice_policy.py
tocmo0nlord adbe430761
Some checks failed
pre-commit / pre-commit (push) Has been cancelled
tests / Detect unreleased dependencies (push) Has been cancelled
tests / test with OCB (push) Has been cancelled
tests / test with Odoo (push) Has been cancelled
Initial commit: Odoo 18.0-20251222 extra-addons
2026-03-13 20:43:25 +00:00

189 lines
7.2 KiB
Python
Executable File

# Copyright 2017 Acsone SA/NV (http://www.acsone.eu)
# Copyright 2025 Jacques-Etienne Baudoux (BCIM) <je@bcim.be>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import odoo.tests.common as common
class TestSaleOrderInvoicePolicy(common.TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.product_obj = cls.env["product.product"]
cls.sale_obj = cls.env["sale.order"]
cls.partner = cls.env.ref("base.res_partner_2")
cls.product = cls.product_obj.create(
{"name": "Test", "type": "consu", "list_price": 20.0}
)
cls.product2 = cls.product_obj.create(
{"name": "Test 2", "type": "consu", "list_price": 45.0}
)
cls.product3 = cls.product_obj.create(
{
"name": "Test 3 (service)",
"type": "service",
"list_price": 850.5,
}
)
def test_sale_order_invoice_order(self):
"""Test invoicing based on ordered quantities"""
so = self.env["sale.order"].create(
{
"partner_id": self.env.ref("base.res_partner_2").id,
"order_line": [
(0, 0, {"product_id": self.product.id, "product_uom_qty": 2.0}),
(0, 0, {"product_id": self.product2.id, "product_uom_qty": 3.0}),
],
"invoice_policy": "order",
}
)
self.assertEqual(so.invoice_policy, "order")
# SO is not confirmed yet
self.assertEqual([0.0, 0.0], so.order_line.mapped("untaxed_amount_to_invoice"))
so.action_confirm()
self.assertEqual(len(so.picking_ids), 1)
picking = so.picking_ids
picking.action_assign()
self.assertEqual(picking.state, "assigned")
so_line = so.order_line[0]
self.assertEqual(so_line.qty_to_invoice, 2)
self.assertEqual(so_line.invoice_status, "to invoice")
self.assertEqual(so_line.product_id.invoice_policy, "order")
so_line = so.order_line[1]
self.assertEqual(so_line.qty_to_invoice, 3)
self.assertEqual(so_line.invoice_status, "to invoice")
self.assertEqual(so_line.product_id.invoice_policy, "order")
def test_sale_order_invoice_deliver(self):
"""Test invoicing based on delivered quantities"""
self.assertEqual("order", self.product.invoice_policy)
so = self.env["sale.order"].create(
{
"partner_id": self.env.ref("base.res_partner_2").id,
"invoice_policy": "delivery",
"order_line": [
(0, 0, {"product_id": self.product.id, "product_uom_qty": 2.0}),
(0, 0, {"product_id": self.product2.id, "product_uom_qty": 3.0}),
],
}
)
self.assertEqual(so.invoice_policy, "delivery")
# SO is not confirmed yet
self.assertEqual([0.0, 0.0], so.order_line.mapped("untaxed_amount_to_invoice"))
so.action_confirm()
# SO is not delivered
self.assertEqual([0.0, 0.0], so.order_line.mapped("untaxed_amount_to_invoice"))
self.assertEqual(len(so.picking_ids), 1)
picking = so.picking_ids
picking.action_assign()
self.assertEqual(picking.state, "assigned")
so_line = so.order_line[0]
self.assertEqual(so_line.qty_to_invoice, 0)
self.assertEqual(so_line.invoice_status, "no")
so_line = so.order_line[1]
self.assertEqual(so_line.qty_to_invoice, 0)
self.assertEqual(so_line.invoice_status, "no")
for mv in picking.move_line_ids:
mv.quantity = mv.quantity_product_uom
picking.button_validate()
self.assertEqual(picking.state, "done")
so_line = so.order_line[0]
self.assertEqual(so_line.qty_to_invoice, 2)
self.assertEqual(so_line.invoice_status, "to invoice")
self.assertEqual(40.0, so_line.untaxed_amount_to_invoice)
# Check that product has still its original invoice policy
self.assertEqual("order", self.product.invoice_policy)
so_line = so.order_line[1]
self.assertEqual(so_line.qty_to_invoice, 3)
self.assertEqual(so_line.invoice_status, "to invoice")
self.assertEqual(135.0, so_line.untaxed_amount_to_invoice)
def test_settings(self):
# delivery policy is the default
settings = self.env["res.config.settings"].create({})
settings.sale_default_invoice_policy = "delivery"
settings.execute()
so = self.env["sale.order"].create(
{"partner_id": self.env.ref("base.res_partner_2").id}
)
self.assertEqual(so.invoice_policy, "delivery")
# order policy is the default
settings.sale_default_invoice_policy = "order"
settings.execute()
so = self.env["sale.order"].create(
{"partner_id": self.env.ref("base.res_partner_2").id}
)
self.assertEqual(so.invoice_policy, "order")
def test_context_manager_exception(self):
"""Check the exception is well managed when called with several
invoice policies"""
self.assertEqual("order", self.product.invoice_policy)
so = self.env["sale.order"].create(
{
"partner_id": self.env.ref("base.res_partner_2").id,
"invoice_policy": "delivery",
"order_line": [
(0, 0, {"product_id": self.product.id, "product_uom_qty": 2.0}),
(0, 0, {"product_id": self.product2.id, "product_uom_qty": 3.0}),
],
}
)
so2 = self.env["sale.order"].create(
{
"partner_id": self.env.ref("base.res_partner_2").id,
"invoice_policy": "order",
"order_line": [
(0, 0, {"product_id": self.product.id, "product_uom_qty": 2.0}),
(0, 0, {"product_id": self.product2.id, "product_uom_qty": 3.0}),
],
}
)
lines = (so | so2).order_line
with self.assertRaises(Exception) as exc:
with self.env["sale.order.line"]._sale_invoice_policy(
lines
): # pragma: no cover
pass
self.assertEqual(
"The method _sale_invoice_policy() must be called with lines sharing "
"the same invoice policy",
exc.exception.args[0],
)
def test_force_lines_to_invoice_policy_order(self):
"""Check when a SO is fully paid by a payment transaction and the automatic
invoicing is enabled, that the policy is changed on order."""
so = self.env["sale.order"].create(
{
"partner_id": self.env.ref("base.res_partner_2").id,
"order_line": [
(0, 0, {"product_id": self.product.id, "product_uom_qty": 2.0}),
(0, 0, {"product_id": self.product2.id, "product_uom_qty": 3.0}),
],
"invoice_policy": "delivery",
}
)
so.action_confirm()
self.assertEqual(so.invoice_policy, "delivery")
so._force_lines_to_invoice_policy_order()
self.assertEqual(so.invoice_policy, "order")