274 lines
12 KiB
Python
Executable File
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
|
|
)
|