[FIX] account_invoice_triple_discount_readonly: tests for 18.0 purchases
In 18.0 purchase.order.line uses purchase.triple.discount.mixin, not the triple.discount.mixin this addon patches, so the purchase tests checked 16.0 behaviour. test_purchase_order now checks the 18.0 one plus what matters here: the bill created from the PO keeps discount1..3, and editing one of them on the bill keeps the others. test_triple_discount_mixin runs on an invoice line, and no longer expects the values of the previous test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
9e05a279d7
commit
ca526d55cc
2 changed files with 117 additions and 115 deletions
|
|
@ -7,6 +7,16 @@ from odoo.tests.common import TransactionCase
|
||||||
|
|
||||||
@tagged("post_install", "-at_install")
|
@tagged("post_install", "-at_install")
|
||||||
class TestPurchaseOrder(TransactionCase):
|
class TestPurchaseOrder(TransactionCase):
|
||||||
|
"""Purchase lines and the vendor bills created from them.
|
||||||
|
|
||||||
|
In 18.0 ``purchase.order.line`` does not use ``triple.discount.mixin`` but
|
||||||
|
``purchase.triple.discount.mixin`` (purchase_triple_discount), where the
|
||||||
|
total discount is a stored compute of discount1..3: the accumulation bug
|
||||||
|
this addon fixes does not happen there. What matters on the purchase side
|
||||||
|
is that the three discounts reach the bill untouched, and the bill lines do
|
||||||
|
use the mixin this addon patches.
|
||||||
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
super().setUpClass()
|
super().setUpClass()
|
||||||
|
|
@ -20,13 +30,15 @@ class TestPurchaseOrder(TransactionCase):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create a product template first, then get the variant
|
# Create a product template first, then get the variant. Billed on
|
||||||
|
# ordered quantities, so the bill can be created without a receipt.
|
||||||
cls.product_template = cls.env["product.template"].create(
|
cls.product_template = cls.env["product.template"].create(
|
||||||
{
|
{
|
||||||
"name": "Test Product PO",
|
"name": "Test Product PO",
|
||||||
"type": "consu",
|
"type": "consu",
|
||||||
"list_price": 150.0,
|
"list_price": 150.0,
|
||||||
"standard_price": 80.0,
|
"standard_price": 80.0,
|
||||||
|
"purchase_method": "purchase",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
# Get the auto-created product variant
|
# Get the auto-created product variant
|
||||||
|
|
@ -52,16 +64,24 @@ class TestPurchaseOrder(TransactionCase):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_po_line_discount_readonly(self):
|
def _create_bill_line(self):
|
||||||
"""Test that discount field is readonly in PO lines"""
|
self.purchase_order.button_confirm()
|
||||||
|
self.purchase_order.action_create_invoice()
|
||||||
|
return self.purchase_order.invoice_ids.invoice_line_ids.filtered(
|
||||||
|
lambda line: line.product_id == self.product
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_po_line_discount_is_computed(self):
|
||||||
|
"""The total discount of a PO line is computed from discount1..3"""
|
||||||
field = self.po_line._fields["discount"]
|
field = self.po_line._fields["discount"]
|
||||||
self.assertTrue(field.readonly, "Discount field should be readonly in PO lines")
|
self.assertTrue(field.compute)
|
||||||
|
expected = 100 - (100 * 0.90 * 0.95 * 0.98)
|
||||||
|
self.assertAlmostEqual(self.po_line.discount, expected, places=2)
|
||||||
|
|
||||||
def test_po_line_write_with_explicit_discounts(self):
|
def test_po_line_write_with_explicit_discounts(self):
|
||||||
"""Test writing PO line with explicit discounts"""
|
"""Test writing PO line with explicit discounts"""
|
||||||
self.po_line.write(
|
self.po_line.write(
|
||||||
{
|
{
|
||||||
"discount": 25.0, # Should be ignored
|
|
||||||
"discount1": 12.0,
|
"discount1": 12.0,
|
||||||
"discount2": 8.0,
|
"discount2": 8.0,
|
||||||
"discount3": 4.0,
|
"discount3": 4.0,
|
||||||
|
|
@ -71,22 +91,11 @@ class TestPurchaseOrder(TransactionCase):
|
||||||
self.assertEqual(self.po_line.discount1, 12.0)
|
self.assertEqual(self.po_line.discount1, 12.0)
|
||||||
self.assertEqual(self.po_line.discount2, 8.0)
|
self.assertEqual(self.po_line.discount2, 8.0)
|
||||||
self.assertEqual(self.po_line.discount3, 4.0)
|
self.assertEqual(self.po_line.discount3, 4.0)
|
||||||
|
expected = 100 - (100 * 0.88 * 0.92 * 0.96)
|
||||||
def test_po_line_legacy_discount(self):
|
self.assertAlmostEqual(self.po_line.discount, expected, places=2)
|
||||||
"""Test legacy discount behavior in PO lines"""
|
|
||||||
self.po_line.write(
|
|
||||||
{
|
|
||||||
"discount": 18.0,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Should map to discount1 and reset others
|
|
||||||
self.assertEqual(self.po_line.discount1, 18.0)
|
|
||||||
self.assertEqual(self.po_line.discount2, 0.0)
|
|
||||||
self.assertEqual(self.po_line.discount3, 0.0)
|
|
||||||
|
|
||||||
def test_po_line_price_calculation(self):
|
def test_po_line_price_calculation(self):
|
||||||
"""Test that price subtotal is calculated correctly with triple discount"""
|
"""The PO subtotal applies the total discount"""
|
||||||
self.po_line.write(
|
self.po_line.write(
|
||||||
{
|
{
|
||||||
"discount1": 15.0,
|
"discount1": 15.0,
|
||||||
|
|
@ -95,11 +104,9 @@ class TestPurchaseOrder(TransactionCase):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Base: 10 * 150 = 1500
|
# The PO line keeps the total discount with the "Discount" precision
|
||||||
# After 15% discount: 1275
|
# (27.33 %, not 27.3325 %), so the subtotal is computed from it.
|
||||||
# After 10% discount: 1147.5
|
expected_subtotal = 10 * 150 * (1 - self.po_line.discount / 100)
|
||||||
# After 5% discount: 1090.125
|
|
||||||
expected_subtotal = 10 * 150 * 0.85 * 0.90 * 0.95
|
|
||||||
self.assertAlmostEqual(self.po_line.price_subtotal, expected_subtotal, places=2)
|
self.assertAlmostEqual(self.po_line.price_subtotal, expected_subtotal, places=2)
|
||||||
|
|
||||||
def test_multiple_po_lines(self):
|
def test_multiple_po_lines(self):
|
||||||
|
|
@ -117,7 +124,7 @@ class TestPurchaseOrder(TransactionCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Verify both lines have correct discounts
|
# Verify both lines have correct discounts
|
||||||
self.assertEqual(self.po_line.discount1, 15.0)
|
self.assertEqual(self.po_line.discount1, 10.0)
|
||||||
self.assertEqual(line2.discount1, 20.0)
|
self.assertEqual(line2.discount1, 20.0)
|
||||||
self.assertEqual(line2.discount2, 15.0)
|
self.assertEqual(line2.discount2, 15.0)
|
||||||
self.assertEqual(line2.discount3, 10.0)
|
self.assertEqual(line2.discount3, 10.0)
|
||||||
|
|
@ -174,40 +181,8 @@ class TestPurchaseOrder(TransactionCase):
|
||||||
expected = 10 * 150
|
expected = 10 * 150
|
||||||
self.assertEqual(self.po_line.price_subtotal, expected)
|
self.assertEqual(self.po_line.price_subtotal, expected)
|
||||||
|
|
||||||
def test_po_line_combined_operations(self):
|
|
||||||
"""Test combined operations on PO line"""
|
|
||||||
# Update multiple fields at once
|
|
||||||
self.po_line.write(
|
|
||||||
{
|
|
||||||
"product_qty": 15,
|
|
||||||
"price_unit": 175.0,
|
|
||||||
"discount1": 18.0,
|
|
||||||
"discount2": 12.0,
|
|
||||||
"discount3": 6.0,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
# All fields should be updated correctly
|
|
||||||
self.assertEqual(self.po_line.product_qty, 15)
|
|
||||||
self.assertEqual(self.po_line.price_unit, 175.0)
|
|
||||||
self.assertEqual(self.po_line.discount1, 18.0)
|
|
||||||
self.assertEqual(self.po_line.discount2, 12.0)
|
|
||||||
self.assertEqual(self.po_line.discount3, 6.0)
|
|
||||||
|
|
||||||
# Calculate expected subtotal
|
|
||||||
expected = 15 * 175 * 0.82 * 0.88 * 0.94
|
|
||||||
self.assertAlmostEqual(self.po_line.price_subtotal, expected, places=2)
|
|
||||||
|
|
||||||
def test_po_confirm_with_discounts(self):
|
def test_po_confirm_with_discounts(self):
|
||||||
"""Test confirming PO doesn't alter discounts"""
|
"""Test confirming PO doesn't alter discounts"""
|
||||||
self.po_line.write(
|
|
||||||
{
|
|
||||||
"discount1": 10.0,
|
|
||||||
"discount2": 5.0,
|
|
||||||
"discount3": 2.0,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Confirm the purchase order
|
# Confirm the purchase order
|
||||||
self.purchase_order.button_confirm()
|
self.purchase_order.button_confirm()
|
||||||
|
|
||||||
|
|
@ -215,3 +190,25 @@ class TestPurchaseOrder(TransactionCase):
|
||||||
self.assertEqual(self.po_line.discount1, 10.0)
|
self.assertEqual(self.po_line.discount1, 10.0)
|
||||||
self.assertEqual(self.po_line.discount2, 5.0)
|
self.assertEqual(self.po_line.discount2, 5.0)
|
||||||
self.assertEqual(self.po_line.discount3, 2.0)
|
self.assertEqual(self.po_line.discount3, 2.0)
|
||||||
|
|
||||||
|
def test_bill_keeps_the_three_discounts(self):
|
||||||
|
"""The bill line gets discount1..3 of the PO line, not their sum"""
|
||||||
|
bill_line = self._create_bill_line()
|
||||||
|
|
||||||
|
self.assertEqual(len(bill_line), 1)
|
||||||
|
self.assertEqual(bill_line.discount1, 10.0)
|
||||||
|
self.assertEqual(bill_line.discount2, 5.0)
|
||||||
|
self.assertEqual(bill_line.discount3, 2.0)
|
||||||
|
# The bill line computes the total discount without rounding it.
|
||||||
|
expected = 10 * 150 * 0.90 * 0.95 * 0.98
|
||||||
|
self.assertAlmostEqual(bill_line.price_subtotal, expected, places=2)
|
||||||
|
|
||||||
|
def test_bill_line_edit_keeps_the_other_discounts(self):
|
||||||
|
"""Editing one discount on the bill keeps the other two"""
|
||||||
|
bill_line = self._create_bill_line()
|
||||||
|
|
||||||
|
bill_line.write({"discount": 50.0, "discount2": 12.0})
|
||||||
|
|
||||||
|
self.assertEqual(bill_line.discount1, 10.0)
|
||||||
|
self.assertEqual(bill_line.discount2, 12.0)
|
||||||
|
self.assertEqual(bill_line.discount3, 2.0)
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,11 @@ from odoo.tests.common import TransactionCase
|
||||||
|
|
||||||
@tagged("post_install", "-at_install")
|
@tagged("post_install", "-at_install")
|
||||||
class TestTripleDiscountMixin(TransactionCase):
|
class TestTripleDiscountMixin(TransactionCase):
|
||||||
|
"""The patched ``triple.discount.mixin``, through an invoice line.
|
||||||
|
|
||||||
|
Purchase lines do not use this mixin in 18.0 (see test_purchase_order).
|
||||||
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
super().setUpClass()
|
super().setUpClass()
|
||||||
|
|
@ -30,19 +35,21 @@ class TestTripleDiscountMixin(TransactionCase):
|
||||||
# Get the auto-created product variant
|
# Get the auto-created product variant
|
||||||
cls.product = cls.product_template.product_variant_ids[0]
|
cls.product = cls.product_template.product_variant_ids[0]
|
||||||
|
|
||||||
# Create a purchase order
|
# Create an invoice
|
||||||
cls.purchase_order = cls.env["purchase.order"].create(
|
cls.invoice = cls.env["account.move"].create(
|
||||||
{
|
{
|
||||||
|
"move_type": "out_invoice",
|
||||||
"partner_id": cls.partner.id,
|
"partner_id": cls.partner.id,
|
||||||
|
"invoice_date": "2026-01-01",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create a purchase order line
|
# Create an invoice line
|
||||||
cls.po_line = cls.env["purchase.order.line"].create(
|
cls.line = cls.env["account.move.line"].create(
|
||||||
{
|
{
|
||||||
"order_id": cls.purchase_order.id,
|
"move_id": cls.invoice.id,
|
||||||
"product_id": cls.product.id,
|
"product_id": cls.product.id,
|
||||||
"product_qty": 10,
|
"quantity": 10,
|
||||||
"price_unit": 100.0,
|
"price_unit": 100.0,
|
||||||
"discount1": 10.0,
|
"discount1": 10.0,
|
||||||
"discount2": 5.0,
|
"discount2": 5.0,
|
||||||
|
|
@ -52,13 +59,13 @@ class TestTripleDiscountMixin(TransactionCase):
|
||||||
|
|
||||||
def test_discount_field_is_readonly(self):
|
def test_discount_field_is_readonly(self):
|
||||||
"""Test that the discount field is readonly"""
|
"""Test that the discount field is readonly"""
|
||||||
field = self.po_line._fields["discount"]
|
field = self.line._fields["discount"]
|
||||||
self.assertTrue(field.readonly, "Discount field should be readonly")
|
self.assertTrue(field.readonly, "Discount field should be readonly")
|
||||||
|
|
||||||
def test_write_with_explicit_discounts(self):
|
def test_write_with_explicit_discounts(self):
|
||||||
"""Test writing with explicit discount1, discount2, discount3"""
|
"""Test writing with explicit discount1, discount2, discount3"""
|
||||||
# Write with explicit discounts
|
# Write with explicit discounts
|
||||||
self.po_line.write(
|
self.line.write(
|
||||||
{
|
{
|
||||||
"discount": 20.0, # This should be ignored
|
"discount": 20.0, # This should be ignored
|
||||||
"discount1": 15.0,
|
"discount1": 15.0,
|
||||||
|
|
@ -68,18 +75,18 @@ class TestTripleDiscountMixin(TransactionCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Verify explicit discounts were applied
|
# Verify explicit discounts were applied
|
||||||
self.assertEqual(self.po_line.discount1, 15.0)
|
self.assertEqual(self.line.discount1, 15.0)
|
||||||
self.assertEqual(self.po_line.discount2, 10.0)
|
self.assertEqual(self.line.discount2, 10.0)
|
||||||
self.assertEqual(self.po_line.discount3, 5.0)
|
self.assertEqual(self.line.discount3, 5.0)
|
||||||
|
|
||||||
# The computed discount field should reflect the combined discounts
|
# The computed discount field should reflect the combined discounts
|
||||||
# Formula: 100 - (100 * (1 - 0.15) * (1 - 0.10) * (1 - 0.05))
|
# Formula: 100 - (100 * (1 - 0.15) * (1 - 0.10) * (1 - 0.05))
|
||||||
expected_discount = 100 - (100 * 0.85 * 0.90 * 0.95)
|
expected_discount = 100 - (100 * 0.85 * 0.90 * 0.95)
|
||||||
self.assertAlmostEqual(self.po_line.discount, expected_discount, places=2)
|
self.assertAlmostEqual(self.line.discount, expected_discount, places=2)
|
||||||
|
|
||||||
def test_write_only_discount1(self):
|
def test_write_only_discount1(self):
|
||||||
"""Test writing only discount1 explicitly"""
|
"""Test writing only discount1 explicitly"""
|
||||||
self.po_line.write(
|
self.line.write(
|
||||||
{
|
{
|
||||||
"discount": 25.0, # This should be ignored
|
"discount": 25.0, # This should be ignored
|
||||||
"discount1": 20.0,
|
"discount1": 20.0,
|
||||||
|
|
@ -87,45 +94,43 @@ class TestTripleDiscountMixin(TransactionCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Only discount1 should change
|
# Only discount1 should change
|
||||||
self.assertEqual(self.po_line.discount1, 20.0)
|
self.assertEqual(self.line.discount1, 20.0)
|
||||||
# Others should remain unchanged
|
# Others should remain unchanged
|
||||||
self.assertEqual(self.po_line.discount2, 5.0)
|
self.assertEqual(self.line.discount2, 5.0)
|
||||||
self.assertEqual(self.po_line.discount3, 2.0)
|
self.assertEqual(self.line.discount3, 2.0)
|
||||||
|
|
||||||
def test_write_only_discount2(self):
|
def test_write_only_discount2(self):
|
||||||
"""Test writing only discount2 explicitly"""
|
"""Test writing only discount2 explicitly"""
|
||||||
self.po_line.write(
|
self.line.write(
|
||||||
{
|
{
|
||||||
"discount": 30.0, # This should be ignored
|
"discount": 30.0, # This should be ignored
|
||||||
"discount2": 12.0,
|
"discount2": 12.0,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Only discount2 should change
|
# Only discount2 should change; each test starts from setUpClass
|
||||||
self.assertEqual(self.po_line.discount2, 12.0)
|
self.assertEqual(self.line.discount2, 12.0)
|
||||||
# Others should remain unchanged from previous test
|
self.assertEqual(self.line.discount1, 10.0)
|
||||||
self.assertEqual(self.po_line.discount1, 20.0)
|
self.assertEqual(self.line.discount3, 2.0)
|
||||||
self.assertEqual(self.po_line.discount3, 2.0)
|
|
||||||
|
|
||||||
def test_write_only_discount3(self):
|
def test_write_only_discount3(self):
|
||||||
"""Test writing only discount3 explicitly"""
|
"""Test writing only discount3 explicitly"""
|
||||||
self.po_line.write(
|
self.line.write(
|
||||||
{
|
{
|
||||||
"discount": 35.0, # This should be ignored
|
"discount": 35.0, # This should be ignored
|
||||||
"discount3": 8.0,
|
"discount3": 8.0,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Only discount3 should change
|
# Only discount3 should change; each test starts from setUpClass
|
||||||
self.assertEqual(self.po_line.discount3, 8.0)
|
self.assertEqual(self.line.discount3, 8.0)
|
||||||
# Others should remain unchanged from previous tests
|
self.assertEqual(self.line.discount1, 10.0)
|
||||||
self.assertEqual(self.po_line.discount1, 20.0)
|
self.assertEqual(self.line.discount2, 5.0)
|
||||||
self.assertEqual(self.po_line.discount2, 12.0)
|
|
||||||
|
|
||||||
def test_write_legacy_discount_only(self):
|
def test_write_legacy_discount_only(self):
|
||||||
"""Test legacy behavior: writing only discount field"""
|
"""Test legacy behavior: writing only discount field"""
|
||||||
# Reset to known state first
|
# Reset to known state first
|
||||||
self.po_line.write(
|
self.line.write(
|
||||||
{
|
{
|
||||||
"discount1": 10.0,
|
"discount1": 10.0,
|
||||||
"discount2": 5.0,
|
"discount2": 5.0,
|
||||||
|
|
@ -134,32 +139,32 @@ class TestTripleDiscountMixin(TransactionCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Write only discount (legacy behavior)
|
# Write only discount (legacy behavior)
|
||||||
self.po_line.write(
|
self.line.write(
|
||||||
{
|
{
|
||||||
"discount": 25.0,
|
"discount": 25.0,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Should map to discount1 and reset others
|
# Should map to discount1 and reset others
|
||||||
self.assertEqual(self.po_line.discount1, 25.0)
|
self.assertEqual(self.line.discount1, 25.0)
|
||||||
self.assertEqual(self.po_line.discount2, 0.0)
|
self.assertEqual(self.line.discount2, 0.0)
|
||||||
self.assertEqual(self.po_line.discount3, 0.0)
|
self.assertEqual(self.line.discount3, 0.0)
|
||||||
|
|
||||||
def test_write_multiple_times(self):
|
def test_write_multiple_times(self):
|
||||||
"""Test writing multiple times to ensure consistency"""
|
"""Test writing multiple times to ensure consistency"""
|
||||||
# First write
|
# First write
|
||||||
self.po_line.write(
|
self.line.write(
|
||||||
{
|
{
|
||||||
"discount1": 10.0,
|
"discount1": 10.0,
|
||||||
"discount2": 10.0,
|
"discount2": 10.0,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(self.po_line.discount1, 10.0)
|
self.assertEqual(self.line.discount1, 10.0)
|
||||||
self.assertEqual(self.po_line.discount2, 10.0)
|
self.assertEqual(self.line.discount2, 10.0)
|
||||||
|
|
||||||
# Second write
|
# Second write
|
||||||
self.po_line.write(
|
self.line.write(
|
||||||
{
|
{
|
||||||
"discount": 5.0,
|
"discount": 5.0,
|
||||||
"discount3": 5.0,
|
"discount3": 5.0,
|
||||||
|
|
@ -167,13 +172,13 @@ class TestTripleDiscountMixin(TransactionCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
# discount3 should change, others remain
|
# discount3 should change, others remain
|
||||||
self.assertEqual(self.po_line.discount1, 10.0)
|
self.assertEqual(self.line.discount1, 10.0)
|
||||||
self.assertEqual(self.po_line.discount2, 10.0)
|
self.assertEqual(self.line.discount2, 10.0)
|
||||||
self.assertEqual(self.po_line.discount3, 5.0)
|
self.assertEqual(self.line.discount3, 5.0)
|
||||||
|
|
||||||
def test_write_zero_discounts(self):
|
def test_write_zero_discounts(self):
|
||||||
"""Test writing zero discounts"""
|
"""Test writing zero discounts"""
|
||||||
self.po_line.write(
|
self.line.write(
|
||||||
{
|
{
|
||||||
"discount1": 0.0,
|
"discount1": 0.0,
|
||||||
"discount2": 0.0,
|
"discount2": 0.0,
|
||||||
|
|
@ -181,15 +186,15 @@ class TestTripleDiscountMixin(TransactionCase):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(self.po_line.discount1, 0.0)
|
self.assertEqual(self.line.discount1, 0.0)
|
||||||
self.assertEqual(self.po_line.discount2, 0.0)
|
self.assertEqual(self.line.discount2, 0.0)
|
||||||
self.assertEqual(self.po_line.discount3, 0.0)
|
self.assertEqual(self.line.discount3, 0.0)
|
||||||
self.assertEqual(self.po_line.discount, 0.0)
|
self.assertEqual(self.line.discount, 0.0)
|
||||||
|
|
||||||
def test_write_combined_scenario(self):
|
def test_write_combined_scenario(self):
|
||||||
"""Test a realistic combined scenario"""
|
"""Test a realistic combined scenario"""
|
||||||
# Initial state
|
# Initial state
|
||||||
self.po_line.write(
|
self.line.write(
|
||||||
{
|
{
|
||||||
"discount1": 15.0,
|
"discount1": 15.0,
|
||||||
"discount2": 5.0,
|
"discount2": 5.0,
|
||||||
|
|
@ -198,7 +203,7 @@ class TestTripleDiscountMixin(TransactionCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
# User tries to update discount field (should be ignored if explicit discounts present)
|
# User tries to update discount field (should be ignored if explicit discounts present)
|
||||||
self.po_line.write(
|
self.line.write(
|
||||||
{
|
{
|
||||||
"discount": 50.0,
|
"discount": 50.0,
|
||||||
"discount1": 20.0,
|
"discount1": 20.0,
|
||||||
|
|
@ -206,13 +211,13 @@ class TestTripleDiscountMixin(TransactionCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
# discount1 should be updated, others unchanged
|
# discount1 should be updated, others unchanged
|
||||||
self.assertEqual(self.po_line.discount1, 20.0)
|
self.assertEqual(self.line.discount1, 20.0)
|
||||||
self.assertEqual(self.po_line.discount2, 5.0)
|
self.assertEqual(self.line.discount2, 5.0)
|
||||||
self.assertEqual(self.po_line.discount3, 0.0)
|
self.assertEqual(self.line.discount3, 0.0)
|
||||||
|
|
||||||
def test_discount_calculation_accuracy(self):
|
def test_discount_calculation_accuracy(self):
|
||||||
"""Test that discount calculation is accurate"""
|
"""Test that discount calculation is accurate"""
|
||||||
self.po_line.write(
|
self.line.write(
|
||||||
{
|
{
|
||||||
"discount1": 10.0,
|
"discount1": 10.0,
|
||||||
"discount2": 10.0,
|
"discount2": 10.0,
|
||||||
|
|
@ -222,22 +227,22 @@ class TestTripleDiscountMixin(TransactionCase):
|
||||||
|
|
||||||
# Combined discount: 100 - (100 * 0.9 * 0.9 * 0.9) = 27.1
|
# Combined discount: 100 - (100 * 0.9 * 0.9 * 0.9) = 27.1
|
||||||
expected = 100 - (100 * 0.9 * 0.9 * 0.9)
|
expected = 100 - (100 * 0.9 * 0.9 * 0.9)
|
||||||
self.assertAlmostEqual(self.po_line.discount, expected, places=2)
|
self.assertAlmostEqual(self.line.discount, expected, places=2)
|
||||||
|
|
||||||
def test_write_without_discount_field(self):
|
def test_write_without_discount_field(self):
|
||||||
"""Test writing other fields without touching discount fields"""
|
"""Test writing other fields without touching discount fields"""
|
||||||
initial_discount1 = self.po_line.discount1
|
initial_discount1 = self.line.discount1
|
||||||
|
|
||||||
# Write other fields
|
# Write other fields
|
||||||
self.po_line.write(
|
self.line.write(
|
||||||
{
|
{
|
||||||
"product_qty": 20,
|
"quantity": 20,
|
||||||
"price_unit": 150.0,
|
"price_unit": 150.0,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Discounts should remain unchanged
|
# Discounts should remain unchanged
|
||||||
self.assertEqual(self.po_line.discount1, initial_discount1)
|
self.assertEqual(self.line.discount1, initial_discount1)
|
||||||
# But other fields should be updated
|
# But other fields should be updated
|
||||||
self.assertEqual(self.po_line.product_qty, 20)
|
self.assertEqual(self.line.quantity, 20)
|
||||||
self.assertEqual(self.po_line.price_unit, 150.0)
|
self.assertEqual(self.line.price_unit, 150.0)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue