From 20311740a28645076c07e0ae8e8d55448e41de3f Mon Sep 17 00:00:00 2001 From: GitHub Copilot Date: Fri, 7 Aug 2026 16:51:42 +0200 Subject: [PATCH] limpieza addon oca --- product_get_price_helper/README.md | 124 ----- product_get_price_helper/README.rst | 90 ---- product_get_price_helper/__init__.py | 1 - product_get_price_helper/__manifest__.py | 14 - product_get_price_helper/demo/account.xml | 36 -- product_get_price_helper/demo/pricelist.xml | 29 -- product_get_price_helper/i18n/it.po | 47 -- .../i18n/product_get_price_helper.pot | 44 -- product_get_price_helper/models/__init__.py | 1 - .../models/product_product.py | 120 ----- product_get_price_helper/pyproject.toml | 3 - .../readme/CONTRIBUTORS.md | 3 - .../readme/DESCRIPTION.md | 13 - .../static/description/icon.png | Bin 9455 -> 0 bytes .../static/description/index.html | 435 ------------------ product_get_price_helper/tests/__init__.py | 1 - .../tests/test_product.py | 275 ----------- product_get_price_helper/utils.py | 13 - 18 files changed, 1249 deletions(-) delete mode 100644 product_get_price_helper/README.md delete mode 100644 product_get_price_helper/README.rst delete mode 100644 product_get_price_helper/__init__.py delete mode 100644 product_get_price_helper/__manifest__.py delete mode 100644 product_get_price_helper/demo/account.xml delete mode 100644 product_get_price_helper/demo/pricelist.xml delete mode 100644 product_get_price_helper/i18n/it.po delete mode 100644 product_get_price_helper/i18n/product_get_price_helper.pot delete mode 100644 product_get_price_helper/models/__init__.py delete mode 100644 product_get_price_helper/models/product_product.py delete mode 100644 product_get_price_helper/pyproject.toml delete mode 100644 product_get_price_helper/readme/CONTRIBUTORS.md delete mode 100644 product_get_price_helper/readme/DESCRIPTION.md delete mode 100644 product_get_price_helper/static/description/icon.png delete mode 100644 product_get_price_helper/static/description/index.html delete mode 100644 product_get_price_helper/tests/__init__.py delete mode 100644 product_get_price_helper/tests/test_product.py delete mode 100644 product_get_price_helper/utils.py diff --git a/product_get_price_helper/README.md b/product_get_price_helper/README.md deleted file mode 100644 index 52980d8..0000000 --- a/product_get_price_helper/README.md +++ /dev/null @@ -1,124 +0,0 @@ -# Product Get Price Helper - -## Summary - -Provides a helper utility function to compute product prices with taxes, discounts, and unit of measure conversions. - -## Features - -- **Price Calculation Utility**: Helper method `get_product_price_for_pricelist` -- **Tax Handling**: Automatically computes prices with or without taxes -- **Discount Support**: Handles single and multiple discounts -- **UoM Conversion**: Converts prices between different units of measure -- **Reusable**: Can be used by other modules for price calculations - -## Technical Details - -### Utility Function - -Located in `utils.py`: - -```python -def get_product_price_for_pricelist( - product, - qty, - pricelist, - partner=None, - uom=None, - date=None, - include_tax=False -) -``` - -**Parameters**: -- `product`: Product record (product.product or product.template) -- `qty`: Quantity -- `pricelist`: Pricelist to use for calculation -- `partner`: Partner record (optional) -- `uom`: Unit of measure (optional, uses product default if not provided) -- `date`: Date for pricelist rules (optional, uses today if not provided) -- `include_tax`: Boolean, whether to include taxes in the result - -**Returns**: Decimal price - -### How It Works - -1. Gets base price from pricelist -2. Applies any applicable discounts -3. Converts price if different UoM is specified -4. Adds taxes if `include_tax=True` - -## Dependencies - -- `account` (Odoo core) -- `product` (Odoo core) - -## Installation - -```bash -docker-compose exec odoo odoo -d odoo -u product_get_price_helper --stop-after-init -``` - -## Usage - -### Example: Calculate Price with Tax - -```python -from odoo.addons.product_get_price_helper.utils import get_product_price_for_pricelist - -price = get_product_price_for_pricelist( - product=product_record, - qty=10, - pricelist=pricelist_record, - partner=partner_record, - include_tax=True -) -``` - -### Example: Calculate Price with Different UoM - -```python -price = get_product_price_for_pricelist( - product=product_record, - qty=1, - pricelist=pricelist_record, - uom=kg_uom, # Different from product's default UoM - include_tax=False -) -``` - -## OCA Source - -- **Repository**: [product-attribute](https://github.com/OCA/product-attribute) -- **Original Author**: ACSONE SA/NV -- **License**: AGPL-3 - -## Modifications for Kidekoop - -None - Used as-is from OCA. - -## Used By - -This helper is used by other modules in the project: -- `product_sale_price_from_pricelist` - For automatic price calculations -- `product_price_category` - For category-based pricing - -## Demo Data - -Includes demo data with: -- Sample accounts -- Sample pricelists - -Located in `demo/` directory. - -## Translations - -- ✅ Spanish (es) -- ✅ Euskera (eu) - -Located in `i18n/` directory. - ---- - -**Version**: 18.0.1.1.0 -**License**: AGPL-3 diff --git a/product_get_price_helper/README.rst b/product_get_price_helper/README.rst deleted file mode 100644 index 0c2ef4b..0000000 --- a/product_get_price_helper/README.rst +++ /dev/null @@ -1,90 +0,0 @@ -======================== -Product Get Price Helper -======================== - -.. - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! This file is generated by oca-gen-addon-readme !! - !! changes will be overwritten. !! - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:5fb33150c2c1ee21fd7bc337113f150dccba97ee06c9dfd5a01d2f17ce567509 - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png - :target: https://odoo-community.org/page/development-status - :alt: Beta -.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png - :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html - :alt: License: AGPL-3 -.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fproduct--attribute-lightgray.png?logo=github - :target: https://github.com/OCA/product-attribute/tree/18.0/product_get_price_helper - :alt: OCA/product-attribute -.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/product-attribute-18-0/product-attribute-18-0-product_get_price_helper - :alt: Translate me on Weblate -.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/builds?repo=OCA/product-attribute&target_branch=18.0 - :alt: Try me on Runboat - -|badge1| |badge2| |badge3| |badge4| |badge5| - -Adds a helper function \_get_price() on product.product to compute the -product price based on pricelist, fiscal position, company and date. - -The method returns a dict such as: - -.. code:: python - - { - "value": 600.0, - "tax_included": True, - "discount": 20.0, - "original_value": 750.0, - } - -**Table of contents** - -.. contents:: - :local: - -Bug Tracker -=========== - -Bugs are tracked on `GitHub Issues `_. -In case of trouble, please check there if your issue has already been reported. -If you spotted it first, help us to smash it by providing a detailed and welcomed -`feedback `_. - -Do not contact contributors directly about support or help with technical issues. - -Credits -======= - -Authors -------- - -* ACSONE SA/NV - -Contributors ------------- - -- Sébastien BEAU -- Simone Orsi -- Quentin Groulard - -Maintainers ------------ - -This module is maintained by the OCA. - -.. image:: https://odoo-community.org/logo.png - :alt: Odoo Community Association - :target: https://odoo-community.org - -OCA, or the Odoo Community Association, is a nonprofit organization whose -mission is to support the collaborative development of Odoo features and -promote its widespread use. - -This module is part of the `OCA/product-attribute `_ project on GitHub. - -You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/product_get_price_helper/__init__.py b/product_get_price_helper/__init__.py deleted file mode 100644 index 0650744..0000000 --- a/product_get_price_helper/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import models diff --git a/product_get_price_helper/__manifest__.py b/product_get_price_helper/__manifest__.py deleted file mode 100644 index 1ad048c..0000000 --- a/product_get_price_helper/__manifest__.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright 2023 ACSONE SA/NV -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -{ - "name": "Product Get Price Helper", - "summary": """ - This module provides a helper function to compute product prices.""", - "version": "18.0.1.1.0", - "license": "AGPL-3", - "author": "ACSONE SA/NV,Odoo Community Association (OCA)", - "website": "https://github.com/OCA/product-attribute", - "depends": ["account", "product"], - "demo": ["demo/account.xml", "demo/pricelist.xml"], -} diff --git a/product_get_price_helper/demo/account.xml b/product_get_price_helper/demo/account.xml deleted file mode 100644 index ed91dd4..0000000 --- a/product_get_price_helper/demo/account.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - Tax inc demo - - percent - sale - - - - - Tax exc demo - - percent - sale - - - - Default - - - - - - Business - - - - - - - - - - - diff --git a/product_get_price_helper/demo/pricelist.xml b/product_get_price_helper/demo/pricelist.xml deleted file mode 100644 index e3f3cd4..0000000 --- a/product_get_price_helper/demo/pricelist.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - Business Pricelist - - - - - list_price - - Default Business Pricelist Line - - percentage - - - - - - - diff --git a/product_get_price_helper/i18n/it.po b/product_get_price_helper/i18n/it.po deleted file mode 100644 index f013fca..0000000 --- a/product_get_price_helper/i18n/it.po +++ /dev/null @@ -1,47 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * product_get_price_helper -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 16.0\n" -"Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2025-03-24 10:06+0000\n" -"Last-Translator: mymage \n" -"Language-Team: none\n" -"Language: it\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: \n" -"Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.10.2\n" - -#. module: product_get_price_helper -#: model:account.fiscal.position,name:product_get_price_helper.fiscal_position_1 -msgid "Business" -msgstr "Impresa" - -#. module: product_get_price_helper -#: model:product.pricelist,name:product_get_price_helper.pricelist_1 -msgid "Business Pricelist" -msgstr "Listino commerciale" - -#. module: product_get_price_helper -#: model:account.fiscal.position,name:product_get_price_helper.fiscal_position_0 -msgid "Default" -msgstr "Predefinito" - -#. module: product_get_price_helper -#: model:ir.model,name:product_get_price_helper.model_product_product -msgid "Product Variant" -msgstr "Variante prodotto" - -#. module: product_get_price_helper -#: model:account.tax,name:product_get_price_helper.tax_2 -msgid "Tax exc demo" -msgstr "Demo imposta esclusa" - -#. module: product_get_price_helper -#: model:account.tax,name:product_get_price_helper.tax_1 -msgid "Tax inc demo" -msgstr "Demo imposta inclusa" diff --git a/product_get_price_helper/i18n/product_get_price_helper.pot b/product_get_price_helper/i18n/product_get_price_helper.pot deleted file mode 100644 index a271d94..0000000 --- a/product_get_price_helper/i18n/product_get_price_helper.pot +++ /dev/null @@ -1,44 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * product_get_price_helper -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 18.0\n" -"Report-Msgid-Bugs-To: \n" -"Last-Translator: \n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: \n" -"Plural-Forms: \n" - -#. module: product_get_price_helper -#: model:account.fiscal.position,name:product_get_price_helper.fiscal_position_1 -msgid "Business" -msgstr "" - -#. module: product_get_price_helper -#: model:product.pricelist,name:product_get_price_helper.pricelist_1 -msgid "Business Pricelist" -msgstr "" - -#. module: product_get_price_helper -#: model:account.fiscal.position,name:product_get_price_helper.fiscal_position_0 -msgid "Default" -msgstr "" - -#. module: product_get_price_helper -#: model:ir.model,name:product_get_price_helper.model_product_product -msgid "Product Variant" -msgstr "" - -#. module: product_get_price_helper -#: model:account.tax,name:product_get_price_helper.tax_2 -msgid "Tax exc demo" -msgstr "" - -#. module: product_get_price_helper -#: model:account.tax,name:product_get_price_helper.tax_1 -msgid "Tax inc demo" -msgstr "" diff --git a/product_get_price_helper/models/__init__.py b/product_get_price_helper/models/__init__.py deleted file mode 100644 index 5c74c8c..0000000 --- a/product_get_price_helper/models/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import product_product diff --git a/product_get_price_helper/models/product_product.py b/product_get_price_helper/models/product_product.py deleted file mode 100644 index 9b0697c..0000000 --- a/product_get_price_helper/models/product_product.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2017 Akretion (http://www.akretion.com). -# @author Sébastien BEAU -# Copyright 2021 Camptocamp (http://www.camptocamp.com). -# @author Simone Orsi -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo import models -from odoo.tools import float_compare -from odoo.tools import float_is_zero - -from ..utils import float_round - - -class ProductProduct(models.Model): - _inherit = "product.product" - - def _get_price( - self, - qty=1.0, - pricelist=None, - fposition=None, - company=None, - date=None, - price_unit=None, - ): - """Computes the product prices - - :param qty: The product quantity, used to apply pricelist rules. - :param pricelist: Optional. Get prices for a specific pricelist. - :param fposition: Optional. Apply fiscal position to product taxes. - :param company: Optional. - :param date: Optional. - - :returns: dict with the following keys: - - The product unitary price - True if product taxes are included in . - - If the pricelist.discount_policy is "without_discount": - The original price (before pricelist is applied). - The discounted percentage. - """ - self.ensure_one() - AccountTax = self.env["account.tax"] - # Apply company - product = self.with_company(company) if company else self - company = company or self.env.company - # Always filter taxes by the company - taxes = product.taxes_id.filtered(lambda tax: tax.company_id == company) - # Apply fiscal position - taxes = fposition.map_tax(taxes) if fposition else taxes - # Set context. Some of the methods used here depend on these values - product_context = dict( - self.env.context, - quantity=qty, - pricelist=pricelist.id if pricelist else None, - fiscal_position=fposition, - date=date, - ) - product = product.with_context(**product_context) - pricelist = pricelist.with_context(**product_context) if pricelist else None - if price_unit is None: - price_unit = ( - pricelist._get_product_price(product, qty, date=date) - if pricelist - else product.lst_price - ) - price_unit = AccountTax._fix_tax_included_price_company( - price_unit, product.taxes_id, taxes, company - ) - price_dp = self.env["decimal.precision"].precision_get("Product Price") - price_unit = float_round(price_unit, price_dp) - res = { - "value": price_unit, - "tax_included": any(tax.price_include for tax in taxes), - # Default values in case price.discount_policy != "without_discount" - "original_value": price_unit, - "discount": 0.0, - } - if pricelist: - rule_id = pricelist._get_product_rule(product, qty, date=date) - pl_item = self.env["product.pricelist.item"].browse(rule_id) - if not pl_item.exists(): - return res - original_price_unit = product.lst_price - if not pl_item._show_discount(): - # If the pricelist does not show the discount, we return the price as is - if float_is_zero(original_price_unit, precision_digits=price_dp): - res["original_value"] = 0.0 - return res - # Get the price rule - price_unit, _ = pricelist._get_product_price_rule(product, qty, date=date) - # Get the price before applying the pricelist - price_dp = self.env["decimal.precision"].precision_get("Product Price") - # Compute discount - if not float_is_zero( - original_price_unit, precision_digits=price_dp - ) and float_compare( - original_price_unit, price_unit, precision_digits=price_dp - ): - discount = ( - (original_price_unit - price_unit) / original_price_unit * 100 - ) - # Apply the right precision on discount - discount_dp = self.env["decimal.precision"].precision_get("Discount") - discount = float_round(discount, discount_dp) - else: - discount = 0.00 - # Compute prices - original_price_unit = AccountTax._fix_tax_included_price_company( - original_price_unit, product.taxes_id, taxes, company - ) - original_price_unit = float_round(original_price_unit, price_dp) - res.update( - { - "original_value": original_price_unit, - "discount": discount, - } - ) - return res diff --git a/product_get_price_helper/pyproject.toml b/product_get_price_helper/pyproject.toml deleted file mode 100644 index 4231d0c..0000000 --- a/product_get_price_helper/pyproject.toml +++ /dev/null @@ -1,3 +0,0 @@ -[build-system] -requires = ["whool"] -build-backend = "whool.buildapi" diff --git a/product_get_price_helper/readme/CONTRIBUTORS.md b/product_get_price_helper/readme/CONTRIBUTORS.md deleted file mode 100644 index 816b23b..0000000 --- a/product_get_price_helper/readme/CONTRIBUTORS.md +++ /dev/null @@ -1,3 +0,0 @@ -- Sébastien BEAU \<\> -- Simone Orsi \<\> -- Quentin Groulard \<\> diff --git a/product_get_price_helper/readme/DESCRIPTION.md b/product_get_price_helper/readme/DESCRIPTION.md deleted file mode 100644 index 2eafbe6..0000000 --- a/product_get_price_helper/readme/DESCRIPTION.md +++ /dev/null @@ -1,13 +0,0 @@ -Adds a helper function \_get_price() on product.product to compute the -product price based on pricelist, fiscal position, company and date. - -The method returns a dict such as: - -``` python -{ - "value": 600.0, - "tax_included": True, - "discount": 20.0, - "original_value": 750.0, -} -``` diff --git a/product_get_price_helper/static/description/icon.png b/product_get_price_helper/static/description/icon.png deleted file mode 100644 index 3a0328b516c4980e8e44cdb63fd945757ddd132d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I diff --git a/product_get_price_helper/static/description/index.html b/product_get_price_helper/static/description/index.html deleted file mode 100644 index cc91949..0000000 --- a/product_get_price_helper/static/description/index.html +++ /dev/null @@ -1,435 +0,0 @@ - - - - - -Product Get Price Helper - - - -
-

Product Get Price Helper

- - -

Beta License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

-

Adds a helper function _get_price() on product.product to compute the -product price based on pricelist, fiscal position, company and date.

-

The method returns a dict such as:

-
-{
-    "value": 600.0,
-    "tax_included": True,
-    "discount": 20.0,
-    "original_value": 750.0,
-}
-
-

Table of contents

- -
-

Bug Tracker

-

Bugs are tracked on GitHub Issues. -In case of trouble, please check there if your issue has already been reported. -If you spotted it first, help us to smash it by providing a detailed and welcomed -feedback.

-

Do not contact contributors directly about support or help with technical issues.

-
-
-

Credits

-
-

Authors

-
    -
  • ACSONE SA/NV
  • -
-
-
-

Contributors

- -
-
-

Maintainers

-

This module is maintained by the OCA.

- -Odoo Community Association - -

OCA, or the Odoo Community Association, is a nonprofit organization whose -mission is to support the collaborative development of Odoo features and -promote its widespread use.

-

This module is part of the OCA/product-attribute project on GitHub.

-

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

-
-
-
- - diff --git a/product_get_price_helper/tests/__init__.py b/product_get_price_helper/tests/__init__.py deleted file mode 100644 index 626580e..0000000 --- a/product_get_price_helper/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import test_product diff --git a/product_get_price_helper/tests/test_product.py b/product_get_price_helper/tests/test_product.py deleted file mode 100644 index a177bc6..0000000 --- a/product_get_price_helper/tests/test_product.py +++ /dev/null @@ -1,275 +0,0 @@ -# Copyright 2017 Akretion (http://www.akretion.com). -# @author Benoît GUILLOT -# Copyright 2025 Camptocamp (http://www.camptocamp.com). -# @author Simone Orsi -# 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, - }, - ) diff --git a/product_get_price_helper/utils.py b/product_get_price_helper/utils.py deleted file mode 100644 index fca7e31..0000000 --- a/product_get_price_helper/utils.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2021 Camptocamp (http://www.camptocamp.com). -# @author Simone Orsi -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo.tools import float_repr - - -def float_round(value, dp): - # be carefull odoo rounding implementation do not return the shortest - # representation of a float this mean if the price_unit is 211.70 - # you will have 211.70000000000002 - # Odony exemple: https://gist.github.com/odony/5269a695545902e7e23e761e20a9ec8c - return float(float_repr(value, dp))