Files
Odoo-18.0-20251222/sale_global_discount/tests/test_sale_global_discount.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

274 lines
12 KiB
Python
Executable File

# Copyright 2020 Tecnativa - David Vidal
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import exceptions
from odoo.tests import Form, tagged
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
@tagged("post_install", "-at_install")
class TestSaleGlobalDiscount(AccountTestInvoicingCommon):
@classmethod
def setUpClass(cls, chart_template_ref=None):
super().setUpClass()
cls.chart_template = chart_template_ref
cls.env.ref("base_global_discount.group_global_discount").write(
{"users": [(4, cls.env.user.id)]}
)
cls.main_company = cls.env.ref("base.main_company")
cls.account = cls.env["account.account"].create(
{
"name": "Test account Global Discount",
"code": "TEST99999",
"account_type": "asset_current",
"reconcile": True,
}
)
cls.global_discount_obj = cls.env["global.discount"]
cls.global_discount_1 = cls.global_discount_obj.create(
{
"name": "Test Discount 1",
"sequence": 1,
"discount_scope": "sale",
"discount": 20,
"account_id": cls.account.id,
}
)
cls.global_discount_2 = cls.global_discount_obj.create(
{
"name": "Test Discount 2",
"sequence": 2,
"discount_scope": "sale",
"discount": 30,
"account_id": cls.account.id,
}
)
cls.global_discount_3 = cls.global_discount_obj.create(
{
"name": "Test Discount 3",
"sequence": 3,
"discount_scope": "sale",
"discount": 50,
"account_id": cls.account.id,
}
)
cls.pricelist = cls.env["product.pricelist"].create(
{"name": "Public Pricelist", "sequence": 1}
)
cls.partner_1 = cls.env["res.partner"].create(
{"name": "Mr. Odoo", "property_product_pricelist": cls.pricelist.id}
)
cls.partner_2 = cls.env["res.partner"].create(
{"name": "Mrs. Odoo", "property_product_pricelist": cls.pricelist.id}
)
cls.partner_2.customer_global_discount_ids = (
cls.global_discount_2 + cls.global_discount_3
)
cls.product_1 = cls.env["product.product"].create(
{"name": "Test Product 1", "type": "service"}
)
cls.product_2 = cls.env["product.product"].create(
{"name": "Test Product 2", "type": "service"}
)
cls.tax_group_5pc = cls.env["account.tax.group"].create(
{"name": "Test Tax Group 5%", "sequence": 1}
)
cls.tax_group_15pc = cls.env["account.tax.group"].create(
{"name": "Test Tax Group 15%", "sequence": 2}
)
cls.tax_1 = cls.tax_sale_a
cls.tax_1.amount = 15.0
cls.tax_2 = cls.tax_sale_b
cls.tax_2.amount = 5.0
cls.sale_journal0 = cls.env["account.journal"].create(
{
"name": "Sale Journal",
"type": "sale",
"code": "SJT0",
}
)
sale_form = Form(cls.env["sale.order"])
sale_form.partner_id = cls.partner_1
with sale_form.order_line.new() as order_line:
order_line.product_id = cls.product_1
order_line.tax_id.clear()
order_line.tax_id.add(cls.tax_1)
order_line.tax_id.add(cls.tax_2)
order_line.product_uom_qty = 2
order_line.price_unit = 75
with sale_form.order_line.new() as order_line:
order_line.product_id = cls.product_2
order_line.tax_id.clear()
order_line.tax_id.add(cls.tax_1)
order_line.tax_id.add(cls.tax_2)
order_line.product_uom_qty = 3
order_line.price_unit = 33.33
cls.sale = sale_form.save()
@staticmethod
def get_taxes_widget_total_tax(order):
tax_amount_total = 0.0
for subtotal in order.tax_totals["subtotals"]:
tax_amount_total = sum(
tax_group["tax_amount"] for tax_group in subtotal["tax_groups"]
)
return tax_amount_total
def test_01_global_sale_successive_discounts(self):
"""Add global discounts to the sale order"""
self.assertAlmostEqual(self.sale.amount_total, 299.99)
self.assertAlmostEqual(self.sale.amount_tax, 50)
self.assertAlmostEqual(
self.get_taxes_widget_total_tax(self.sale), self.sale.amount_tax
)
self.assertAlmostEqual(self.sale.amount_untaxed, 249.99)
# Apply a single 20% global discount
self.sale.global_discount_ids = self.global_discount_1
self.sale._compute_tax_totals()
# Discount is computed over the base and global taxes are computed
# according to it line by line with the core method
self.assertAlmostEqual(self.sale.amount_global_discount, 50)
self.assertAlmostEqual(self.sale.amount_untaxed, 199.99)
self.assertAlmostEqual(self.sale.amount_untaxed_before_global_discounts, 249.99)
self.assertAlmostEqual(self.sale.amount_total, 239.99)
self.assertAlmostEqual(self.sale.amount_total_before_global_discounts, 299.99)
self.assertAlmostEqual(self.sale.amount_tax, 40)
self.assertAlmostEqual(
self.get_taxes_widget_total_tax(self.sale), self.sale.amount_tax
)
# Apply an additional 30% global discount
self.sale.global_discount_ids += self.global_discount_2
self.sale._compute_tax_totals()
self.assertAlmostEqual(self.sale.amount_global_discount, 110)
self.assertAlmostEqual(self.sale.amount_untaxed, 139.99)
self.assertAlmostEqual(self.sale.amount_untaxed_before_global_discounts, 249.99)
self.assertAlmostEqual(self.sale.amount_total, 167.99)
self.assertAlmostEqual(self.sale.amount_total_before_global_discounts, 299.99)
self.assertAlmostEqual(self.sale.amount_tax, 28)
self.assertAlmostEqual(
self.get_taxes_widget_total_tax(self.sale), self.sale.amount_tax
)
# The account move should look like this
# credit debit name
# ======== ======= ===============================================
# 150 0 Test Product 1
# 99.99 0 Test Product 2
# 13.13 0 Test TAX 15%
# 4.38 0 TAX 5%
# 0 105.01
# 0 75 Test Discount 2 (30.00%) - Test TAX 15%, TAX 5%
# 0 87.49 Test Discount 3 (50.00%) - Test TAX 15%, TAX 5%
# ======== ======= ===============================================
def test_02_global_sale_discounts_from_partner(self):
"""Change the partner and his global discounts go to the invoice"""
# (30% then 50%)
self.sale.partner_id = self.partner_2
self.sale._compute_tax_totals()
self.assertAlmostEqual(self.sale.amount_global_discount, 162.49)
self.assertAlmostEqual(self.sale.amount_untaxed, 87.5)
self.assertAlmostEqual(self.sale.amount_untaxed_before_global_discounts, 249.99)
self.assertAlmostEqual(self.sale.amount_total, 105.01)
self.assertAlmostEqual(self.sale.amount_total_before_global_discounts, 299.99)
self.assertAlmostEqual(self.sale.amount_tax, 17.51)
self.assertAlmostEqual(
self.get_taxes_widget_total_tax(self.sale), self.sale.amount_tax
)
def test_03_global_sale_discounts_to_invoice(self):
"""All the discounts go to the invoice"""
self.sale.partner_id = self.partner_2
self.sale._compute_tax_totals()
self.sale.order_line.mapped("product_id").write({"invoice_policy": "order"})
self.sale.action_confirm()
move = self.sale._create_invoices()
# Check the invoice relevant fields
self.assertEqual(len(move.invoice_global_discount_ids), 2)
discount_amount = sum(
move.invoice_global_discount_ids.mapped("discount_amount")
)
self.assertAlmostEqual(discount_amount, 162.49)
self.assertAlmostEqual(move.amount_untaxed_before_global_discounts, 249.99)
self.assertAlmostEqual(move.amount_untaxed, 87.5)
self.assertAlmostEqual(move.amount_total, 105.01)
# Expected Journal Entry
# credit debit account
# ======== ======= =========
# 150 0 400000 (line 1)
# 99.99 0 400000 (line 2)
# 13.13 0 400000 (line_tax_1)
# 4.38 0 400000 (line_tax_2)
# 0 105.01 121000 (Base)
# 0 75 TEST99999 (Global discount 1)
# 0 87.49 TEST99999 (Global discount 2)
# 267.50 267.50 <- Balance
line_tax_1 = move.line_ids.filtered(lambda x: x.tax_line_id == self.tax_1)
line_tax_2 = move.line_ids.filtered(lambda x: x.tax_line_id == self.tax_2)
self.assertAlmostEqual(line_tax_1.credit, 13.13)
self.assertAlmostEqual(line_tax_2.credit, 4.38)
term_line = move.line_ids.filtered(
lambda x: x.account_id.account_type == "asset_receivable"
)
self.assertAlmostEqual(term_line.debit, 105.01)
discount_lines = move.line_ids.filtered("invoice_global_discount_id")
self.assertEqual(len(discount_lines), 2)
self.assertAlmostEqual(sum(discount_lines.mapped("debit")), 162.49)
def test_04_incompatible_taxes(self):
# Line 1 with tax 1 and tax 2
# Line 2 with only tax 2
self.sale.order_line[1].tax_id = [(6, 0, self.tax_1.ids)]
with self.assertRaises(exceptions.UserError):
self.sale.global_discount_ids = self.global_discount_1
self.sale._compute_amounts()
def test_05_no_taxes(self):
self.sale.order_line[1].tax_id = False
with self.assertRaises(exceptions.UserError):
self.sale.global_discount_ids = self.global_discount_1
self.sale._compute_amounts()
def test_06_discounted_line(self):
self.sale.global_discount_ids = self.global_discount_1
line = self.sale.order_line[0]
line.discount = 10
self.assertAlmostEqual(line.price_subtotal, 135)
self.assertAlmostEqual(self.sale.amount_untaxed_before_global_discounts, 234.99)
self.assertAlmostEqual(self.sale.amount_untaxed, 187.99)
def test_07_bypass_global_discounts(self):
self.sale.global_discount_ids = self.global_discount_2 + self.global_discount_3
self.sale.order_line[0].product_id.bypass_global_discount = True
self.assertAlmostEqual(self.sale.amount_untaxed_before_global_discounts, 249.99)
self.assertAlmostEqual(self.sale.amount_untaxed, 185.00)
self.assertAlmostEqual(self.sale.amount_total, 222.00)
self.assertAlmostEqual(self.sale.amount_tax, 37.00)
self.assertAlmostEqual(
self.get_taxes_widget_total_tax(self.sale), self.sale.amount_tax
)
def test_08_global_discount_with_tax_included(self):
tax_included = self.env["account.tax"].create(
{
"name": "IVA 21% included",
"amount": 21,
"amount_type": "percent",
"type_tax_use": "sale",
"price_include": True,
"include_base_amount": True,
}
)
for line in self.sale.order_line:
line.tax_id = [(6, 0, tax_included.ids)]
self.sale._compute_tax_totals()
self.sale.global_discount_ids = self.global_discount_1
self.sale._compute_tax_totals()
self.assertTrue(self.sale.amount_tax > 0)
self.assertTrue(
self.sale.amount_total < self.sale.amount_total_before_global_discounts
)
self.assertAlmostEqual(
self.get_taxes_widget_total_tax(self.sale), self.sale.amount_tax
)