Revertir cambio: eliminar cálculo duplicado de impuestos
El método _get_price() del addon OCA ya maneja correctamente los impuestos según la configuración de Odoo. El cálculo adicional con compute_all() estaba duplicando los impuestos cuando price_include estaba activado. Cambios: - Eliminado método _compute_price_with_taxes() - Revertido eskaera_shop() para usar directamente _get_price() - Revertido add_to_eskaera_cart() para usar directamente _get_price() El precio mostrado ahora respeta la configuración de impuestos de Odoo sin duplicación.
This commit is contained in:
parent
3cb0af6a7b
commit
4d23e98f7b
30 changed files with 3611 additions and 1004 deletions
File diff suppressed because it is too large
Load diff
425
website_sale_aplicoop/tests/test_price_with_taxes_included.py
Normal file
425
website_sale_aplicoop/tests/test_price_with_taxes_included.py
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
# Copyright 2025 Criptomart
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
|
||||
"""
|
||||
Test suite for price calculations WITH taxes included.
|
||||
|
||||
This test verifies that the _compute_price_with_taxes method correctly
|
||||
calculates prices including taxes for display in the online shop.
|
||||
"""
|
||||
|
||||
from odoo.tests import tagged
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
@tagged("post_install", "-at_install")
|
||||
class TestPriceWithTaxesIncluded(TransactionCase):
|
||||
"""Test that prices displayed include taxes."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
# Create test company
|
||||
self.company = self.env["res.company"].create(
|
||||
{
|
||||
"name": "Test Company Tax Included",
|
||||
}
|
||||
)
|
||||
|
||||
# Get or create default tax group
|
||||
tax_group = self.env["account.tax.group"].search(
|
||||
[("company_id", "=", self.company.id)], limit=1
|
||||
)
|
||||
if not tax_group:
|
||||
tax_group = self.env["account.tax.group"].create(
|
||||
{
|
||||
"name": "IVA",
|
||||
"company_id": self.company.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Get default country (Spain)
|
||||
country_es = self.env.ref("base.es")
|
||||
|
||||
# Create tax (21% IVA) - price_include=False (default)
|
||||
self.tax_21 = self.env["account.tax"].create(
|
||||
{
|
||||
"name": "IVA 21%",
|
||||
"amount": 21.0,
|
||||
"amount_type": "percent",
|
||||
"type_tax_use": "sale",
|
||||
"price_include": False, # Explicit: tax NOT included in price
|
||||
"company_id": self.company.id,
|
||||
"country_id": country_es.id,
|
||||
"tax_group_id": tax_group.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Create tax (10% IVA reducido)
|
||||
self.tax_10 = self.env["account.tax"].create(
|
||||
{
|
||||
"name": "IVA 10%",
|
||||
"amount": 10.0,
|
||||
"amount_type": "percent",
|
||||
"type_tax_use": "sale",
|
||||
"price_include": False,
|
||||
"company_id": self.company.id,
|
||||
"country_id": country_es.id,
|
||||
"tax_group_id": tax_group.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Create tax with price_include=True for comparison
|
||||
self.tax_21_included = self.env["account.tax"].create(
|
||||
{
|
||||
"name": "IVA 21% Incluido",
|
||||
"amount": 21.0,
|
||||
"amount_type": "percent",
|
||||
"type_tax_use": "sale",
|
||||
"price_include": True, # Tax IS included in price
|
||||
"company_id": self.company.id,
|
||||
"country_id": country_es.id,
|
||||
"tax_group_id": tax_group.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Create product category
|
||||
self.category = self.env["product.category"].create(
|
||||
{
|
||||
"name": "Test Category Tax Included",
|
||||
}
|
||||
)
|
||||
|
||||
# Create test products with different tax configurations
|
||||
self.product_21 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product With 21% Tax",
|
||||
"list_price": 100.0,
|
||||
"categ_id": self.category.id,
|
||||
"taxes_id": [(6, 0, [self.tax_21.id])],
|
||||
"company_id": self.company.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.product_10 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product With 10% Tax",
|
||||
"list_price": 100.0,
|
||||
"categ_id": self.category.id,
|
||||
"taxes_id": [(6, 0, [self.tax_10.id])],
|
||||
"company_id": self.company.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.product_no_tax = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product Without Tax",
|
||||
"list_price": 100.0,
|
||||
"categ_id": self.category.id,
|
||||
"taxes_id": False,
|
||||
"company_id": self.company.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.product_tax_included = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product With Tax Included",
|
||||
"list_price": 121.0, # 100 + 21% = 121
|
||||
"categ_id": self.category.id,
|
||||
"taxes_id": [(6, 0, [self.tax_21_included.id])],
|
||||
"company_id": self.company.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Create pricelist
|
||||
self.pricelist = self.env["product.pricelist"].create(
|
||||
{
|
||||
"name": "Test Pricelist",
|
||||
"company_id": self.company.id,
|
||||
}
|
||||
)
|
||||
|
||||
def test_price_with_21_percent_tax(self):
|
||||
"""Test that 21% tax is correctly added to base price."""
|
||||
# Base price: 100.0
|
||||
# Expected with 21% tax: 121.0
|
||||
|
||||
taxes = self.product_21.taxes_id.filtered(
|
||||
lambda t: t.company_id == self.company
|
||||
)
|
||||
|
||||
base_price = 100.0
|
||||
tax_result = taxes.compute_all(
|
||||
base_price,
|
||||
currency=self.env.company.currency_id,
|
||||
quantity=1.0,
|
||||
product=self.product_21,
|
||||
)
|
||||
|
||||
price_with_tax = tax_result["total_included"]
|
||||
|
||||
self.assertAlmostEqual(
|
||||
price_with_tax, 121.0, places=2, msg="100 + 21% should equal 121.0"
|
||||
)
|
||||
|
||||
def test_price_with_10_percent_tax(self):
|
||||
"""Test that 10% tax is correctly added to base price."""
|
||||
# Base price: 100.0
|
||||
# Expected with 10% tax: 110.0
|
||||
|
||||
taxes = self.product_10.taxes_id.filtered(
|
||||
lambda t: t.company_id == self.company
|
||||
)
|
||||
|
||||
base_price = 100.0
|
||||
tax_result = taxes.compute_all(
|
||||
base_price,
|
||||
currency=self.env.company.currency_id,
|
||||
quantity=1.0,
|
||||
product=self.product_10,
|
||||
)
|
||||
|
||||
price_with_tax = tax_result["total_included"]
|
||||
|
||||
self.assertAlmostEqual(
|
||||
price_with_tax, 110.0, places=2, msg="100 + 10% should equal 110.0"
|
||||
)
|
||||
|
||||
def test_price_without_tax(self):
|
||||
"""Test that product without tax returns base price unchanged."""
|
||||
# Base price: 100.0
|
||||
# Expected with no tax: 100.0
|
||||
|
||||
taxes = self.product_no_tax.taxes_id.filtered(
|
||||
lambda t: t.company_id == self.company
|
||||
)
|
||||
|
||||
# No taxes, so tax_result would be empty
|
||||
self.assertFalse(taxes, "Product should have no taxes")
|
||||
|
||||
# Without taxes, price should remain base price
|
||||
base_price = 100.0
|
||||
expected_price = 100.0
|
||||
|
||||
self.assertEqual(
|
||||
base_price,
|
||||
expected_price,
|
||||
msg="Product without tax should have unchanged price",
|
||||
)
|
||||
|
||||
def test_oca_get_price_returns_base_without_tax(self):
|
||||
"""Test that OCA _get_price returns base price WITHOUT taxes by default."""
|
||||
# This verifies our understanding of OCA behavior
|
||||
|
||||
price_info = self.product_21._get_price(
|
||||
qty=1.0,
|
||||
pricelist=self.pricelist,
|
||||
fposition=False,
|
||||
)
|
||||
|
||||
# OCA should return base price (100.0) WITHOUT tax
|
||||
self.assertAlmostEqual(
|
||||
price_info["value"],
|
||||
100.0,
|
||||
places=2,
|
||||
msg="OCA _get_price should return base price without tax",
|
||||
)
|
||||
|
||||
# tax_included should be False for price_include=False taxes
|
||||
self.assertFalse(
|
||||
price_info.get("tax_included", False),
|
||||
msg="tax_included should be False when price_include=False",
|
||||
)
|
||||
|
||||
def test_oca_get_price_with_included_tax(self):
|
||||
"""Test OCA behavior with price_include=True tax."""
|
||||
|
||||
price_info = self.product_tax_included._get_price(
|
||||
qty=1.0,
|
||||
pricelist=self.pricelist,
|
||||
fposition=False,
|
||||
)
|
||||
|
||||
# With price_include=True, the price should already include tax
|
||||
# list_price is 121.0 (100 + 21%)
|
||||
self.assertAlmostEqual(
|
||||
price_info["value"],
|
||||
121.0,
|
||||
places=2,
|
||||
msg="Price with included tax should be 121.0",
|
||||
)
|
||||
|
||||
# tax_included should be True
|
||||
self.assertTrue(
|
||||
price_info.get("tax_included", False),
|
||||
msg="tax_included should be True when price_include=True",
|
||||
)
|
||||
|
||||
def test_compute_all_with_multiple_taxes(self):
|
||||
"""Test tax calculation with multiple taxes."""
|
||||
# Create product with both 21% and 10% taxes
|
||||
product_multi = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product With Multiple Taxes",
|
||||
"list_price": 100.0,
|
||||
"categ_id": self.category.id,
|
||||
"taxes_id": [(6, 0, [self.tax_21.id, self.tax_10.id])],
|
||||
"company_id": self.company.id,
|
||||
}
|
||||
)
|
||||
|
||||
taxes = product_multi.taxes_id.filtered(lambda t: t.company_id == self.company)
|
||||
|
||||
base_price = 100.0
|
||||
tax_result = taxes.compute_all(
|
||||
base_price,
|
||||
currency=self.env.company.currency_id,
|
||||
quantity=1.0,
|
||||
product=product_multi,
|
||||
)
|
||||
|
||||
price_with_taxes = tax_result["total_included"]
|
||||
|
||||
# 100 + 21% + 10% = 100 + 21 + 10 = 131.0
|
||||
self.assertAlmostEqual(
|
||||
price_with_taxes, 131.0, places=2, msg="100 + 21% + 10% should equal 131.0"
|
||||
)
|
||||
|
||||
def test_compute_all_with_fiscal_position(self):
|
||||
"""Test tax calculation with fiscal position mapping."""
|
||||
# Create fiscal position that maps 21% to 10%
|
||||
fiscal_position = self.env["account.fiscal.position"].create(
|
||||
{
|
||||
"name": "Test Fiscal Position",
|
||||
"company_id": self.company.id,
|
||||
}
|
||||
)
|
||||
self.env["account.fiscal.position.tax"].create(
|
||||
{
|
||||
"position_id": fiscal_position.id,
|
||||
"tax_src_id": self.tax_21.id,
|
||||
"tax_dest_id": self.tax_10.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Get taxes and apply fiscal position
|
||||
taxes = self.product_21.taxes_id.filtered(
|
||||
lambda t: t.company_id == self.company
|
||||
)
|
||||
mapped_taxes = fiscal_position.map_tax(taxes)
|
||||
|
||||
# Should be mapped to 10% tax
|
||||
self.assertEqual(len(mapped_taxes), 1)
|
||||
self.assertEqual(mapped_taxes[0].id, self.tax_10.id)
|
||||
|
||||
base_price = 100.0
|
||||
tax_result = mapped_taxes.compute_all(
|
||||
base_price,
|
||||
currency=self.env.company.currency_id,
|
||||
quantity=1.0,
|
||||
product=self.product_21,
|
||||
)
|
||||
|
||||
price_with_tax = tax_result["total_included"]
|
||||
|
||||
# Should be 110.0 (10% instead of 21%)
|
||||
self.assertAlmostEqual(
|
||||
price_with_tax, 110.0, places=2, msg="Fiscal position should map to 10% tax"
|
||||
)
|
||||
|
||||
def test_tax_amount_details(self):
|
||||
"""Test that compute_all provides detailed tax breakdown."""
|
||||
taxes = self.product_21.taxes_id.filtered(
|
||||
lambda t: t.company_id == self.company
|
||||
)
|
||||
|
||||
base_price = 100.0
|
||||
tax_result = taxes.compute_all(
|
||||
base_price,
|
||||
currency=self.env.company.currency_id,
|
||||
quantity=1.0,
|
||||
product=self.product_21,
|
||||
)
|
||||
|
||||
# Verify structure of tax_result
|
||||
self.assertIn("total_included", tax_result)
|
||||
self.assertIn("total_excluded", tax_result)
|
||||
self.assertIn("taxes", tax_result)
|
||||
|
||||
# total_excluded should be base price
|
||||
self.assertAlmostEqual(tax_result["total_excluded"], 100.0, places=2)
|
||||
|
||||
# total_included should be base + tax
|
||||
self.assertAlmostEqual(tax_result["total_included"], 121.0, places=2)
|
||||
|
||||
# taxes should contain tax details
|
||||
self.assertEqual(len(tax_result["taxes"]), 1)
|
||||
tax_detail = tax_result["taxes"][0]
|
||||
self.assertAlmostEqual(tax_detail["amount"], 21.0, places=2)
|
||||
|
||||
def test_zero_price_with_tax(self):
|
||||
"""Test tax calculation on free product."""
|
||||
free_product = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Free Product With Tax",
|
||||
"list_price": 0.0,
|
||||
"categ_id": self.category.id,
|
||||
"taxes_id": [(6, 0, [self.tax_21.id])],
|
||||
"company_id": self.company.id,
|
||||
}
|
||||
)
|
||||
|
||||
taxes = free_product.taxes_id.filtered(lambda t: t.company_id == self.company)
|
||||
|
||||
base_price = 0.0
|
||||
tax_result = taxes.compute_all(
|
||||
base_price,
|
||||
currency=self.env.company.currency_id,
|
||||
quantity=1.0,
|
||||
product=free_product,
|
||||
)
|
||||
|
||||
price_with_tax = tax_result["total_included"]
|
||||
|
||||
# 0 + 21% = 0
|
||||
self.assertAlmostEqual(
|
||||
price_with_tax,
|
||||
0.0,
|
||||
places=2,
|
||||
msg="Free product with tax should still be free",
|
||||
)
|
||||
|
||||
def test_high_precision_price_with_tax(self):
|
||||
"""Test tax calculation with high precision prices."""
|
||||
precise_product = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Precise Price Product",
|
||||
"list_price": 99.99,
|
||||
"categ_id": self.category.id,
|
||||
"taxes_id": [(6, 0, [self.tax_21.id])],
|
||||
"company_id": self.company.id,
|
||||
}
|
||||
)
|
||||
|
||||
taxes = precise_product.taxes_id.filtered(
|
||||
lambda t: t.company_id == self.company
|
||||
)
|
||||
|
||||
base_price = 99.99
|
||||
tax_result = taxes.compute_all(
|
||||
base_price,
|
||||
currency=self.env.company.currency_id,
|
||||
quantity=1.0,
|
||||
product=precise_product,
|
||||
)
|
||||
|
||||
price_with_tax = tax_result["total_included"]
|
||||
|
||||
# 99.99 + 21% = 120.9879 ≈ 120.99
|
||||
expected = 99.99 * 1.21
|
||||
self.assertAlmostEqual(
|
||||
price_with_tax,
|
||||
expected,
|
||||
places=2,
|
||||
msg=f"Expected {expected}, got {price_with_tax}",
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue