[IMP] product_pricelist_total_margin: Add global_margin_type for min/max limits
- Add global_margin_type field in res.config.settings * Options: 'markup' (default) or 'margin' (commercial margin) * Determines how global min/max percentages are interpreted - Refactor _apply_global_margin_limits(): * Now receives price instead of margin percentage * Calculates min/max prices based on global_margin_type * Returns adjusted price instead of adjusted margin * Supports both markup and commercial margin formulas - Update _compute_price() to apply limits after price calculation - Update res_config_settings_views.xml to show global_margin_type selector - Update help texts with examples for both calculation methods - Add 2 new tests to validate global limits with commercial margin type: * test_global_minimum_with_commercial_margin_type * test_global_maximum_with_commercial_margin_type - All 13 tests passing (11 existing + 2 new) Example with global min 25%: - Markup: Min price = Cost × 1.25 - Commercial Margin: Min price = Cost / 0.75 (ensures 25% margin on PVP)
This commit is contained in:
parent
07cc0eb517
commit
449bb75bb6
4 changed files with 180 additions and 25 deletions
|
|
@ -411,3 +411,97 @@ class TestTotalMargin(TransactionCase):
|
|||
places=4,
|
||||
msg=f"Commercial margin should be 20%, got {commercial_margin * 100}%",
|
||||
)
|
||||
|
||||
def test_global_minimum_with_commercial_margin_type(self):
|
||||
"""Test global minimum margin with commercial margin calculation."""
|
||||
# Set global minimum to 25% and type to commercial margin
|
||||
self.env["ir.config_parameter"].sudo().set_param(
|
||||
"product_pricelist_total_margin.min_percent", "25.0"
|
||||
)
|
||||
self.env["ir.config_parameter"].sudo().set_param(
|
||||
"product_pricelist_total_margin.global_margin_type", "margin"
|
||||
)
|
||||
|
||||
# Enable total margin (calculated: -5% + 25% = 20%, below min 25%)
|
||||
self.item_chained.use_total_margin = True
|
||||
self.item_chained.margin_type = "markup" # Item uses markup
|
||||
|
||||
price = self.pricelist_chained._get_product_price(
|
||||
product=self.product,
|
||||
quantity=1.0,
|
||||
)
|
||||
|
||||
# Expected: Global limit is interpreted as commercial margin
|
||||
# Min 25% commercial margin: PVP = Cost / (1 - 0.25) = 4.68 / 0.75 = 6.24
|
||||
# Item calculates 20% markup: 4.68 * 1.20 = 5.616, but global min forces 6.24
|
||||
expected_price = 4.68 / 0.75
|
||||
self.assertAlmostEqual(
|
||||
price,
|
||||
expected_price,
|
||||
places=2,
|
||||
msg=f"Global minimum (commercial margin 25%) should give {expected_price}, got {price}",
|
||||
)
|
||||
|
||||
# Verify the actual commercial margin is 25%
|
||||
commercial_margin = (price - 4.68) / price
|
||||
self.assertAlmostEqual(
|
||||
commercial_margin,
|
||||
0.25,
|
||||
places=4,
|
||||
msg=f"Commercial margin should be 25%, got {commercial_margin * 100}%",
|
||||
)
|
||||
|
||||
# Clean up
|
||||
self.env["ir.config_parameter"].sudo().set_param(
|
||||
"product_pricelist_total_margin.min_percent", "0.0"
|
||||
)
|
||||
self.env["ir.config_parameter"].sudo().set_param(
|
||||
"product_pricelist_total_margin.global_margin_type", "markup"
|
||||
)
|
||||
|
||||
def test_global_maximum_with_commercial_margin_type(self):
|
||||
"""Test global maximum margin with commercial margin calculation."""
|
||||
# Set global maximum to 15% and type to commercial margin
|
||||
self.env["ir.config_parameter"].sudo().set_param(
|
||||
"product_pricelist_total_margin.max_percent", "15.0"
|
||||
)
|
||||
self.env["ir.config_parameter"].sudo().set_param(
|
||||
"product_pricelist_total_margin.global_margin_type", "margin"
|
||||
)
|
||||
|
||||
# Enable total margin (calculated: -5% + 25% = 20%, above max 15%)
|
||||
self.item_chained.use_total_margin = True
|
||||
self.item_chained.margin_type = "margin" # Item uses commercial margin
|
||||
|
||||
price = self.pricelist_chained._get_product_price(
|
||||
product=self.product,
|
||||
quantity=1.0,
|
||||
)
|
||||
|
||||
# Expected: Global limit is interpreted as commercial margin
|
||||
# Max 15% commercial margin: PVP = Cost / (1 - 0.15) = 4.68 / 0.85 = 5.506
|
||||
# Item calculates 20% margin: 4.68 / 0.80 = 5.85, but global max limits to 5.506
|
||||
expected_price = 4.68 / 0.85
|
||||
self.assertAlmostEqual(
|
||||
price,
|
||||
expected_price,
|
||||
places=2,
|
||||
msg=f"Global maximum (commercial margin 15%) should give {expected_price}, got {price}",
|
||||
)
|
||||
|
||||
# Verify the actual commercial margin is 15%
|
||||
commercial_margin = (price - 4.68) / price
|
||||
self.assertAlmostEqual(
|
||||
commercial_margin,
|
||||
0.15,
|
||||
places=4,
|
||||
msg=f"Commercial margin should be 15%, got {commercial_margin * 100}%",
|
||||
)
|
||||
|
||||
# Clean up
|
||||
self.env["ir.config_parameter"].sudo().set_param(
|
||||
"product_pricelist_total_margin.max_percent", "0.0"
|
||||
)
|
||||
self.env["ir.config_parameter"].sudo().set_param(
|
||||
"product_pricelist_total_margin.global_margin_type", "markup"
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue