build: configurar herramientas de verificación OCA

- Instalar pre-commit con 25 hooks configurados
- Configurar black 26.1.0 para formateo de código Python
- Configurar isort 7.0.0 para ordenación de imports
- Configurar flake8 7.3.0 con flake8-bugbear
- Configurar pylint 3.1.1 con pylint-odoo 9.1.2
- Añadir autoflake y pyupgrade para mejoras automáticas
- Configurar prettier para formateo de XML/JSON/YAML
- Crear .editorconfig para consistencia de editor
- Crear Makefile con comandos útiles
- Crear check_addon.sh para verificación rápida de addons
- Actualizar configuración de VS Code con extensiones recomendadas
- Añadir documentación completa de uso
- Aplicar formateo automático a archivos existentes
- Deshabilitar setuptools-odoo (no soporta Odoo 18.0 aún)
- Deshabilitar fix-encoding-pragma (obsoleto, usar pyupgrade)
This commit is contained in:
snt 2026-02-11 16:09:41 +01:00
parent 5b9c6e3211
commit fe137dc265
224 changed files with 18376 additions and 0 deletions

View file

@ -0,0 +1,275 @@
# Copyright 2017 Akretion (http://www.akretion.com).
# @author Benoît GUILLOT <benoit.guillot@akretion.com>
# Copyright 2025 Camptocamp (http://www.camptocamp.com).
# @author Simone Orsi <simone.orsi@camptocamp.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from unittest import mock
from odoo.tests import TransactionCase
class ProductCase(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.template = cls.env.ref("product.product_product_4_product_template")
cls.variant = cls.env.ref("product.product_product_4b")
cls.template.taxes_id = cls.env.ref("product_get_price_helper.tax_1")
cls.env.user.company_id.currency_id = cls.env.ref("base.USD")
cls.base_pricelist = cls.env["product.pricelist"].create(
{"name": "Base Pricelist", "currency_id": cls.env.ref("base.USD").id}
)
cls.base_pricelist.currency_id = cls.env.ref("base.USD")
cls.variant.currency_id = cls.env.ref("base.USD")
def test_product_simple_get_price(self):
self.variant.taxes_id.price_include = True
self.assertEqual(
self.variant._get_price(),
{
"discount": 0.0,
"original_value": 750.0,
"tax_included": True,
"value": 750.0,
},
)
self.variant.taxes_id.price_include = False
self.assertEqual(
self.variant._get_price(),
{
"discount": 0.0,
"original_value": 750.0,
"tax_included": False,
"value": 750.0,
},
)
def test_product_price_rounding(self):
# Odony example: https://gist.github.com/odony/5269a695545902e7e23e761e20a9ec8c
self.env["product.pricelist.item"].create(
{
"pricelist_id": self.base_pricelist.id,
"product_id": self.variant.id,
"base": "list_price",
"applied_on": "0_product_variant",
"compute_price": "percentage",
"percent_price": 50,
}
)
self.variant.list_price = 423.4
self.assertEqual(
self.variant._get_price(pricelist=self.base_pricelist)["value"], 211.70
)
def test_product_get_price(self):
# self.base_pricelist doesn't define a tax mapping. We are tax included
fiscal_position_fr = self.env.ref("product_get_price_helper.fiscal_position_0")
self.variant.taxes_id.price_include = True
price = self.variant._get_price(
pricelist=self.base_pricelist, fposition=fiscal_position_fr
)
self.assertDictEqual(
price,
{
"discount": 0.0,
"original_value": 750.0,
"tax_included": True,
"value": 750.0,
},
)
# promotion price list define a discount of 20% on all product
promotion_price_list = self.env.ref("product_get_price_helper.pricelist_1")
price = self.variant._get_price(
pricelist=promotion_price_list, fposition=fiscal_position_fr
)
self.assertDictEqual(
price,
{
"discount": 0.0,
"original_value": 600.0,
"tax_included": True,
"value": 600.0,
},
)
# use a fiscal position defining a mapping from tax included to tax
# excluded
tax_exclude_fiscal_position = self.env.ref(
"product_get_price_helper.fiscal_position_1"
)
price = self.variant._get_price(
pricelist=self.base_pricelist, fposition=tax_exclude_fiscal_position
)
self.assertDictEqual(
price,
{
"discount": 0.0,
"original_value": 652.17,
"tax_included": False,
"value": 652.17,
},
)
price = self.variant._get_price(
pricelist=promotion_price_list, fposition=tax_exclude_fiscal_position
)
self.assertDictEqual(
price,
{
"discount": 0.0,
"original_value": 521.74,
"tax_included": False,
"value": 521.74,
},
)
def test_product_get_price_zero(self):
# Test that discount calculation does not fail if original price is 0
self.variant.list_price = 0
self.env["product.pricelist.item"].create(
{
"product_id": self.variant.id,
"pricelist_id": self.base_pricelist.id,
"fixed_price": 10,
}
)
fiscal_position_fr = self.env.ref("product_get_price_helper.fiscal_position_0")
self.variant.taxes_id.price_include = True
price = self.variant.with_context(foo=1)._get_price(
pricelist=self.base_pricelist, fposition=fiscal_position_fr
)
self.assertDictEqual(
price,
{
"discount": 0.0,
"original_value": 0.0,
"tax_included": True,
"value": 10.0,
},
)
# FIXME v18 we cannot use `_show_discount` method
# because it relies on `sale.group_discount_per_so_line` from sale module.
# See https://github.com/odoo/odoo/issues/202035
# The test should be updated when the issue is fixed to use
# self.env.user.groups_id |= self.env.ref("sale.group_discount_per_so_line")
@mock.patch(
"odoo.addons.product.models.product_pricelist_item.PricelistItem._show_discount"
)
def test_product_get_price_per_qty(self, show_discount):
show_discount.return_value = False
self.variant.taxes_id.price_include = True
# Define a promotion price for the product with min_qty = 10
fposition = self.env.ref("product_get_price_helper.fiscal_position_0")
pricelist = self.base_pricelist
self.env["product.pricelist.item"].create(
{
"name": "Discount on Product when Qty >= 10",
"pricelist_id": pricelist.id,
"base": "list_price",
"compute_price": "percentage",
"percent_price": "20",
"applied_on": "0_product_variant",
"product_id": self.variant.id,
"min_quantity": 10.0,
}
)
# Case 1 (qty = 1.0). No discount is applied
price = self.variant._get_price(
qty=1.0, pricelist=pricelist, fposition=fposition
)
self.assertDictEqual(
price,
{
"discount": 0.0,
"original_value": 750.0,
"tax_included": True,
"value": 750.0,
},
)
# Case 2 (qty = 10.0). Discount is applied
# promotion price list define a discount of 20% on all product
price = self.variant._get_price(
qty=10.0, pricelist=pricelist, fposition=fposition
)
self.assertDictEqual(
price,
{
"discount": 0.0,
"original_value": 600.0,
"tax_included": True,
"value": 600.0,
},
)
@mock.patch(
"odoo.addons.product.models.product_pricelist_item.PricelistItem._show_discount"
)
def test_product_get_price_discount_policy(self, show_discount):
self.variant.taxes_id.price_include = True
show_discount.return_value = False
# Ensure that discount is with 2 digits
self.env.ref("product.decimal_discount").digits = 2
# self.base_pricelist doesn't define a tax mapping. We are tax included
# Discount policy: do not show the discount.
fiscal_position_fr = self.env.ref("product_get_price_helper.fiscal_position_0")
price = self.variant._get_price(
pricelist=self.base_pricelist, fposition=fiscal_position_fr
)
self.assertDictEqual(
price,
{
"tax_included": True,
"value": 750.0,
"discount": 0.0,
"original_value": 750.0,
},
)
# promotion price list define a discount of 20% on all product
# Discount policy: show the discount.
show_discount.return_value = True
promotion_price_list = self.env.ref("product_get_price_helper.pricelist_1")
price = self.variant._get_price(
pricelist=promotion_price_list, fposition=fiscal_position_fr
)
self.assertDictEqual(
price,
{
"tax_included": True,
"value": 600.0,
"discount": 20.0,
"original_value": 750.0,
},
)
# use the fiscal position defining a mapping from tax included to tax
# excluded
# Tax mapping should not impact the computation of the discount and
# the original value
tax_exclude_fiscal_position = self.env.ref(
"product_get_price_helper.fiscal_position_1"
)
show_discount.return_value = False
price = self.variant._get_price(
pricelist=self.base_pricelist, fposition=tax_exclude_fiscal_position
)
self.assertDictEqual(
price,
{
"tax_included": False,
"value": 652.17,
"discount": 0.0,
"original_value": 652.17,
},
)
show_discount.return_value = True
price = self.variant._get_price(
pricelist=promotion_price_list, fposition=tax_exclude_fiscal_position
)
self.assertDictEqual(
price,
{
"tax_included": False,
"value": 521.74,
"discount": 20.0,
"original_value": 652.17,
},
)