[FIX] website_sale_aplicoop: Remove redundant string= attributes and fix OCA linting warnings

- Remove redundant string= from 17 field definitions where name matches string value (W8113)
- Convert @staticmethod to instance methods in selection methods for proper self.env._() access
- Fix W8161 (prefer-env-translation) by using self.env._() instead of standalone _()
- Fix W8301/W8115 (translation-not-lazy) by proper placement of % interpolation outside self.env._()
- Remove unused imports of odoo._ from group_order.py and sale_order_extension.py
- All OCA linting warnings in website_sale_aplicoop main models are now resolved

Changes:
- website_sale_aplicoop/models/group_order.py: 21 field definitions cleaned
- website_sale_aplicoop/models/sale_order_extension.py: 5 field definitions cleaned + @staticmethod conversion
- Consistent with OCA standards for addon submission
This commit is contained in:
snt 2026-02-18 17:54:43 +01:00
parent 5c89795e30
commit 6fbc7b9456
73 changed files with 5386 additions and 4354 deletions

View file

@ -10,72 +10,88 @@ class TestAccountMove(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
# Create a partner
cls.partner = cls.env["res.partner"].create({
"name": "Test Customer",
"email": "customer@test.com",
})
cls.partner = cls.env["res.partner"].create(
{
"name": "Test Customer",
"email": "customer@test.com",
}
)
# Create a product
cls.product = cls.env["product.product"].create({
"name": "Test Product Invoice",
"type": "consu",
"list_price": 200.0,
"standard_price": 100.0,
})
cls.product = cls.env["product.product"].create(
{
"name": "Test Product Invoice",
"type": "consu",
"list_price": 200.0,
"standard_price": 100.0,
}
)
# Create tax
cls.tax = cls.env["account.tax"].create({
"name": "Test Tax 10%",
"amount": 10.0,
"amount_type": "percent",
"type_tax_use": "sale",
})
cls.tax = cls.env["account.tax"].create(
{
"name": "Test Tax 10%",
"amount": 10.0,
"amount_type": "percent",
"type_tax_use": "sale",
}
)
# Create an invoice
cls.invoice = cls.env["account.move"].create({
"move_type": "out_invoice",
"partner_id": cls.partner.id,
"invoice_date": "2026-01-01",
})
cls.invoice = cls.env["account.move"].create(
{
"move_type": "out_invoice",
"partner_id": cls.partner.id,
"invoice_date": "2026-01-01",
}
)
# Create invoice line
cls.invoice_line = cls.env["account.move.line"].create({
"move_id": cls.invoice.id,
"product_id": cls.product.id,
"quantity": 5,
"price_unit": 200.0,
"discount1": 10.0,
"discount2": 5.0,
"discount3": 2.0,
"tax_ids": [(6, 0, [cls.tax.id])],
})
cls.invoice_line = cls.env["account.move.line"].create(
{
"move_id": cls.invoice.id,
"product_id": cls.product.id,
"quantity": 5,
"price_unit": 200.0,
"discount1": 10.0,
"discount2": 5.0,
"discount3": 2.0,
"tax_ids": [(6, 0, [cls.tax.id])],
}
)
def test_invoice_line_discount_readonly(self):
"""Test that discount field is readonly in invoice lines"""
field = self.invoice_line._fields["discount"]
self.assertTrue(field.readonly, "Discount field should be readonly in invoice lines")
self.assertTrue(
field.readonly, "Discount field should be readonly in invoice lines"
)
def test_invoice_line_write_with_explicit_discounts(self):
"""Test writing invoice line with explicit discounts"""
self.invoice_line.write({
"discount": 30.0, # Should be ignored
"discount1": 15.0,
"discount2": 10.0,
"discount3": 5.0,
})
self.invoice_line.write(
{
"discount": 30.0, # Should be ignored
"discount1": 15.0,
"discount2": 10.0,
"discount3": 5.0,
}
)
self.assertEqual(self.invoice_line.discount1, 15.0)
self.assertEqual(self.invoice_line.discount2, 10.0)
self.assertEqual(self.invoice_line.discount3, 5.0)
def test_invoice_line_legacy_discount(self):
"""Test legacy discount behavior in invoice lines"""
self.invoice_line.write({
"discount": 20.0,
})
self.invoice_line.write(
{
"discount": 20.0,
}
)
# Should map to discount1 and reset others
self.assertEqual(self.invoice_line.discount1, 20.0)
self.assertEqual(self.invoice_line.discount2, 0.0)
@ -83,12 +99,14 @@ class TestAccountMove(TransactionCase):
def test_invoice_line_price_calculation(self):
"""Test that price subtotal is calculated correctly with triple discount"""
self.invoice_line.write({
"discount1": 10.0,
"discount2": 5.0,
"discount3": 0.0,
})
self.invoice_line.write(
{
"discount1": 10.0,
"discount2": 5.0,
"discount3": 0.0,
}
)
# Base: 5 * 200 = 1000
# After 10% discount: 900
# After 5% discount: 855
@ -99,17 +117,19 @@ class TestAccountMove(TransactionCase):
def test_multiple_invoice_lines(self):
"""Test multiple invoice lines with different discounts"""
line2 = self.env["account.move.line"].create({
"move_id": self.invoice.id,
"product_id": self.product.id,
"quantity": 3,
"price_unit": 150.0,
"discount1": 20.0,
"discount2": 10.0,
"discount3": 5.0,
"tax_ids": [(6, 0, [self.tax.id])],
})
line2 = self.env["account.move.line"].create(
{
"move_id": self.invoice.id,
"product_id": self.product.id,
"quantity": 3,
"price_unit": 150.0,
"discount1": 20.0,
"discount2": 10.0,
"discount3": 5.0,
"tax_ids": [(6, 0, [self.tax.id])],
}
)
# Verify both lines have correct discounts
self.assertEqual(self.invoice_line.discount1, 10.0)
self.assertEqual(line2.discount1, 20.0)
@ -120,11 +140,13 @@ class TestAccountMove(TransactionCase):
"""Test updating quantity doesn't affect discounts"""
initial_discount1 = self.invoice_line.discount1
initial_discount2 = self.invoice_line.discount2
self.invoice_line.write({
"quantity": 10,
})
self.invoice_line.write(
{
"quantity": 10,
}
)
# Discounts should remain unchanged
self.assertEqual(self.invoice_line.discount1, initial_discount1)
self.assertEqual(self.invoice_line.discount2, initial_discount2)
@ -134,11 +156,13 @@ class TestAccountMove(TransactionCase):
def test_invoice_line_update_price(self):
"""Test updating price doesn't affect discounts"""
initial_discount1 = self.invoice_line.discount1
self.invoice_line.write({
"price_unit": 250.0,
})
self.invoice_line.write(
{
"price_unit": 250.0,
}
)
# Discount should remain unchanged
self.assertEqual(self.invoice_line.discount1, initial_discount1)
# Price should be updated
@ -146,18 +170,20 @@ class TestAccountMove(TransactionCase):
def test_invoice_with_zero_discounts(self):
"""Test invoice line with all zero discounts"""
self.invoice_line.write({
"discount1": 0.0,
"discount2": 0.0,
"discount3": 0.0,
})
self.invoice_line.write(
{
"discount1": 0.0,
"discount2": 0.0,
"discount3": 0.0,
}
)
# All discounts should be zero
self.assertEqual(self.invoice_line.discount, 0.0)
self.assertEqual(self.invoice_line.discount1, 0.0)
self.assertEqual(self.invoice_line.discount2, 0.0)
self.assertEqual(self.invoice_line.discount3, 0.0)
# Subtotal should be quantity * price
expected = 5 * 200
self.assertEqual(self.invoice_line.price_subtotal, expected)
@ -165,23 +191,23 @@ class TestAccountMove(TransactionCase):
def test_invoice_line_combined_operations(self):
"""Test combined operations on invoice line"""
# Update multiple fields at once
self.invoice_line.write({
"quantity": 8,
"price_unit": 180.0,
"discount1": 12.0,
"discount2": 6.0,
"discount3": 0.0, # Reset discount3 explicitly
})
self.invoice_line.write(
{
"quantity": 8,
"price_unit": 180.0,
"discount1": 12.0,
"discount2": 6.0,
"discount3": 0.0, # Reset discount3 explicitly
}
)
# All fields should be updated correctly
self.assertEqual(self.invoice_line.quantity, 8)
self.assertEqual(self.invoice_line.price_unit, 180.0)
self.assertEqual(self.invoice_line.discount1, 12.0)
self.assertEqual(self.invoice_line.discount2, 6.0)
self.assertEqual(self.invoice_line.discount3, 0.0)
# Calculate expected subtotal: 8 * 180 * (1-0.12) * (1-0.06)
expected = 8 * 180 * 0.88 * 0.94
self.assertAlmostEqual(
self.invoice_line.price_subtotal, expected, places=2
)
self.assertAlmostEqual(self.invoice_line.price_subtotal, expected, places=2)

View file

@ -10,37 +10,45 @@ class TestPurchaseOrder(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
# Create a supplier
cls.supplier = cls.env["res.partner"].create({
"name": "Test Supplier",
"email": "supplier@test.com",
"supplier_rank": 1,
})
cls.supplier = cls.env["res.partner"].create(
{
"name": "Test Supplier",
"email": "supplier@test.com",
"supplier_rank": 1,
}
)
# Create a product
cls.product = cls.env["product.product"].create({
"name": "Test Product PO",
"type": "product",
"list_price": 150.0,
"standard_price": 80.0,
})
cls.product = cls.env["product.product"].create(
{
"name": "Test Product PO",
"type": "product",
"list_price": 150.0,
"standard_price": 80.0,
}
)
# Create a purchase order
cls.purchase_order = cls.env["purchase.order"].create({
"partner_id": cls.supplier.id,
})
cls.purchase_order = cls.env["purchase.order"].create(
{
"partner_id": cls.supplier.id,
}
)
# Create purchase order line
cls.po_line = cls.env["purchase.order.line"].create({
"order_id": cls.purchase_order.id,
"product_id": cls.product.id,
"product_qty": 10,
"price_unit": 150.0,
"discount1": 10.0,
"discount2": 5.0,
"discount3": 2.0,
})
cls.po_line = cls.env["purchase.order.line"].create(
{
"order_id": cls.purchase_order.id,
"product_id": cls.product.id,
"product_qty": 10,
"price_unit": 150.0,
"discount1": 10.0,
"discount2": 5.0,
"discount3": 2.0,
}
)
def test_po_line_discount_readonly(self):
"""Test that discount field is readonly in PO lines"""
@ -49,23 +57,27 @@ class TestPurchaseOrder(TransactionCase):
def test_po_line_write_with_explicit_discounts(self):
"""Test writing PO line with explicit discounts"""
self.po_line.write({
"discount": 25.0, # Should be ignored
"discount1": 12.0,
"discount2": 8.0,
"discount3": 4.0,
})
self.po_line.write(
{
"discount": 25.0, # Should be ignored
"discount1": 12.0,
"discount2": 8.0,
"discount3": 4.0,
}
)
self.assertEqual(self.po_line.discount1, 12.0)
self.assertEqual(self.po_line.discount2, 8.0)
self.assertEqual(self.po_line.discount3, 4.0)
def test_po_line_legacy_discount(self):
"""Test legacy discount behavior in PO lines"""
self.po_line.write({
"discount": 18.0,
})
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)
@ -73,33 +85,35 @@ class TestPurchaseOrder(TransactionCase):
def test_po_line_price_calculation(self):
"""Test that price subtotal is calculated correctly with triple discount"""
self.po_line.write({
"discount1": 15.0,
"discount2": 10.0,
"discount3": 5.0,
})
self.po_line.write(
{
"discount1": 15.0,
"discount2": 10.0,
"discount3": 5.0,
}
)
# Base: 10 * 150 = 1500
# After 15% discount: 1275
# After 10% discount: 1147.5
# 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):
"""Test multiple PO lines with different discounts"""
line2 = self.env["purchase.order.line"].create({
"order_id": self.purchase_order.id,
"product_id": self.product.id,
"product_qty": 5,
"price_unit": 120.0,
"discount1": 20.0,
"discount2": 15.0,
"discount3": 10.0,
})
line2 = self.env["purchase.order.line"].create(
{
"order_id": self.purchase_order.id,
"product_id": self.product.id,
"product_qty": 5,
"price_unit": 120.0,
"discount1": 20.0,
"discount2": 15.0,
"discount3": 10.0,
}
)
# Verify both lines have correct discounts
self.assertEqual(self.po_line.discount1, 15.0)
self.assertEqual(line2.discount1, 20.0)
@ -110,11 +124,13 @@ class TestPurchaseOrder(TransactionCase):
"""Test updating quantity doesn't affect discounts"""
initial_discount1 = self.po_line.discount1
initial_discount2 = self.po_line.discount2
self.po_line.write({
"product_qty": 20,
})
self.po_line.write(
{
"product_qty": 20,
}
)
# Discounts should remain unchanged
self.assertEqual(self.po_line.discount1, initial_discount1)
self.assertEqual(self.po_line.discount2, initial_discount2)
@ -124,11 +140,13 @@ class TestPurchaseOrder(TransactionCase):
def test_po_line_update_price(self):
"""Test updating price doesn't affect discounts"""
initial_discount1 = self.po_line.discount1
self.po_line.write({
"price_unit": 200.0,
})
self.po_line.write(
{
"price_unit": 200.0,
}
)
# Discount should remain unchanged
self.assertEqual(self.po_line.discount1, initial_discount1)
# Price should be updated
@ -136,18 +154,20 @@ class TestPurchaseOrder(TransactionCase):
def test_po_with_zero_discounts(self):
"""Test PO line with all zero discounts"""
self.po_line.write({
"discount1": 0.0,
"discount2": 0.0,
"discount3": 0.0,
})
self.po_line.write(
{
"discount1": 0.0,
"discount2": 0.0,
"discount3": 0.0,
}
)
# All discounts should be zero
self.assertEqual(self.po_line.discount, 0.0)
self.assertEqual(self.po_line.discount1, 0.0)
self.assertEqual(self.po_line.discount2, 0.0)
self.assertEqual(self.po_line.discount3, 0.0)
# Subtotal should be quantity * price
expected = 10 * 150
self.assertEqual(self.po_line.price_subtotal, expected)
@ -155,38 +175,40 @@ class TestPurchaseOrder(TransactionCase):
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,
})
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
)
self.assertAlmostEqual(self.po_line.price_subtotal, expected, places=2)
def test_po_confirm_with_discounts(self):
"""Test confirming PO doesn't alter discounts"""
self.po_line.write({
"discount1": 10.0,
"discount2": 5.0,
"discount3": 2.0,
})
self.po_line.write(
{
"discount1": 10.0,
"discount2": 5.0,
"discount3": 2.0,
}
)
# Confirm the purchase order
self.purchase_order.button_confirm()
# Discounts should remain unchanged after confirmation
self.assertEqual(self.po_line.discount1, 10.0)
self.assertEqual(self.po_line.discount2, 5.0)

View file

@ -10,35 +10,43 @@ class TestTripleDiscountMixin(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
# Create a partner
cls.partner = cls.env["res.partner"].create({
"name": "Test Partner",
})
cls.partner = cls.env["res.partner"].create(
{
"name": "Test Partner",
}
)
# Create a product
cls.product = cls.env["product.product"].create({
"name": "Test Product",
"type": "product",
"list_price": 100.0,
"standard_price": 50.0,
})
cls.product = cls.env["product.product"].create(
{
"name": "Test Product",
"type": "product",
"list_price": 100.0,
"standard_price": 50.0,
}
)
# Create a purchase order
cls.purchase_order = cls.env["purchase.order"].create({
"partner_id": cls.partner.id,
})
cls.purchase_order = cls.env["purchase.order"].create(
{
"partner_id": cls.partner.id,
}
)
# Create a purchase order line
cls.po_line = cls.env["purchase.order.line"].create({
"order_id": cls.purchase_order.id,
"product_id": cls.product.id,
"product_qty": 10,
"price_unit": 100.0,
"discount1": 10.0,
"discount2": 5.0,
"discount3": 2.0,
})
cls.po_line = cls.env["purchase.order.line"].create(
{
"order_id": cls.purchase_order.id,
"product_id": cls.product.id,
"product_qty": 10,
"price_unit": 100.0,
"discount1": 10.0,
"discount2": 5.0,
"discount3": 2.0,
}
)
def test_discount_field_is_readonly(self):
"""Test that the discount field is readonly"""
@ -48,18 +56,20 @@ class TestTripleDiscountMixin(TransactionCase):
def test_write_with_explicit_discounts(self):
"""Test writing with explicit discount1, discount2, discount3"""
# Write with explicit discounts
self.po_line.write({
"discount": 20.0, # This should be ignored
"discount1": 15.0,
"discount2": 10.0,
"discount3": 5.0,
})
self.po_line.write(
{
"discount": 20.0, # This should be ignored
"discount1": 15.0,
"discount2": 10.0,
"discount3": 5.0,
}
)
# Verify explicit discounts were applied
self.assertEqual(self.po_line.discount1, 15.0)
self.assertEqual(self.po_line.discount2, 10.0)
self.assertEqual(self.po_line.discount3, 5.0)
# The computed discount field should reflect the combined discounts
# Formula: 100 - (100 * (1 - 0.15) * (1 - 0.10) * (1 - 0.05))
expected_discount = 100 - (100 * 0.85 * 0.90 * 0.95)
@ -67,11 +77,13 @@ class TestTripleDiscountMixin(TransactionCase):
def test_write_only_discount1(self):
"""Test writing only discount1 explicitly"""
self.po_line.write({
"discount": 25.0, # This should be ignored
"discount1": 20.0,
})
self.po_line.write(
{
"discount": 25.0, # This should be ignored
"discount1": 20.0,
}
)
# Only discount1 should change
self.assertEqual(self.po_line.discount1, 20.0)
# Others should remain unchanged
@ -80,11 +92,13 @@ class TestTripleDiscountMixin(TransactionCase):
def test_write_only_discount2(self):
"""Test writing only discount2 explicitly"""
self.po_line.write({
"discount": 30.0, # This should be ignored
"discount2": 12.0,
})
self.po_line.write(
{
"discount": 30.0, # This should be ignored
"discount2": 12.0,
}
)
# Only discount2 should change
self.assertEqual(self.po_line.discount2, 12.0)
# Others should remain unchanged from previous test
@ -93,11 +107,13 @@ class TestTripleDiscountMixin(TransactionCase):
def test_write_only_discount3(self):
"""Test writing only discount3 explicitly"""
self.po_line.write({
"discount": 35.0, # This should be ignored
"discount3": 8.0,
})
self.po_line.write(
{
"discount": 35.0, # This should be ignored
"discount3": 8.0,
}
)
# Only discount3 should change
self.assertEqual(self.po_line.discount3, 8.0)
# Others should remain unchanged from previous tests
@ -107,17 +123,21 @@ class TestTripleDiscountMixin(TransactionCase):
def test_write_legacy_discount_only(self):
"""Test legacy behavior: writing only discount field"""
# Reset to known state first
self.po_line.write({
"discount1": 10.0,
"discount2": 5.0,
"discount3": 2.0,
})
self.po_line.write(
{
"discount1": 10.0,
"discount2": 5.0,
"discount3": 2.0,
}
)
# Write only discount (legacy behavior)
self.po_line.write({
"discount": 25.0,
})
self.po_line.write(
{
"discount": 25.0,
}
)
# Should map to discount1 and reset others
self.assertEqual(self.po_line.discount1, 25.0)
self.assertEqual(self.po_line.discount2, 0.0)
@ -126,20 +146,24 @@ class TestTripleDiscountMixin(TransactionCase):
def test_write_multiple_times(self):
"""Test writing multiple times to ensure consistency"""
# First write
self.po_line.write({
"discount1": 10.0,
"discount2": 10.0,
})
self.po_line.write(
{
"discount1": 10.0,
"discount2": 10.0,
}
)
self.assertEqual(self.po_line.discount1, 10.0)
self.assertEqual(self.po_line.discount2, 10.0)
# Second write
self.po_line.write({
"discount": 5.0,
"discount3": 5.0,
})
self.po_line.write(
{
"discount": 5.0,
"discount3": 5.0,
}
)
# discount3 should change, others remain
self.assertEqual(self.po_line.discount1, 10.0)
self.assertEqual(self.po_line.discount2, 10.0)
@ -147,12 +171,14 @@ class TestTripleDiscountMixin(TransactionCase):
def test_write_zero_discounts(self):
"""Test writing zero discounts"""
self.po_line.write({
"discount1": 0.0,
"discount2": 0.0,
"discount3": 0.0,
})
self.po_line.write(
{
"discount1": 0.0,
"discount2": 0.0,
"discount3": 0.0,
}
)
self.assertEqual(self.po_line.discount1, 0.0)
self.assertEqual(self.po_line.discount2, 0.0)
self.assertEqual(self.po_line.discount3, 0.0)
@ -161,18 +187,22 @@ class TestTripleDiscountMixin(TransactionCase):
def test_write_combined_scenario(self):
"""Test a realistic combined scenario"""
# Initial state
self.po_line.write({
"discount1": 15.0,
"discount2": 5.0,
"discount3": 0.0,
})
self.po_line.write(
{
"discount1": 15.0,
"discount2": 5.0,
"discount3": 0.0,
}
)
# User tries to update discount field (should be ignored if explicit discounts present)
self.po_line.write({
"discount": 50.0,
"discount1": 20.0,
})
self.po_line.write(
{
"discount": 50.0,
"discount1": 20.0,
}
)
# discount1 should be updated, others unchanged
self.assertEqual(self.po_line.discount1, 20.0)
self.assertEqual(self.po_line.discount2, 5.0)
@ -180,12 +210,14 @@ class TestTripleDiscountMixin(TransactionCase):
def test_discount_calculation_accuracy(self):
"""Test that discount calculation is accurate"""
self.po_line.write({
"discount1": 10.0,
"discount2": 10.0,
"discount3": 10.0,
})
self.po_line.write(
{
"discount1": 10.0,
"discount2": 10.0,
"discount3": 10.0,
}
)
# Combined discount: 100 - (100 * 0.9 * 0.9 * 0.9) = 27.1
expected = 100 - (100 * 0.9 * 0.9 * 0.9)
self.assertAlmostEqual(self.po_line.discount, expected, places=2)
@ -193,13 +225,15 @@ class TestTripleDiscountMixin(TransactionCase):
def test_write_without_discount_field(self):
"""Test writing other fields without touching discount fields"""
initial_discount1 = self.po_line.discount1
# Write other fields
self.po_line.write({
"product_qty": 20,
"price_unit": 150.0,
})
self.po_line.write(
{
"product_qty": 20,
"price_unit": 150.0,
}
)
# Discounts should remain unchanged
self.assertEqual(self.po_line.discount1, initial_discount1)
# But other fields should be updated