From 64a559295c8a08febfbffd9632a5e235854327ab Mon Sep 17 00:00:00 2001 From: Edilio Escalona Almira Date: Thu, 10 Jul 2025 10:44:57 -0500 Subject: [PATCH] [ADD] product_margin_report_sale_margin: Add new fields for sales margin in the Product Margins report [IMP] product_margin_report_sale_margin: Add tests --- product_margin_report_sale_margin/README.rst | 108 +++++ product_margin_report_sale_margin/__init__.py | 4 + .../__manifest__.py | 15 + .../models/__init__.py | 5 + .../models/product_product.py | 25 + .../pyproject.toml | 3 + .../readme/CONTRIBUTORS.md | 2 + .../readme/DESCRIPTION.md | 1 + .../readme/USAGE.md | 19 + .../static/description/index.html | 459 ++++++++++++++++++ .../static/img/readme/FIELDS_VIEW_FORM.png | Bin 0 -> 14569 bytes .../static/img/readme/FIELDS_VIEW_TREE.png | Bin 0 -> 37706 bytes .../tests/__init__.py | 6 + .../tests/test_common.py | 11 + .../tests/test_product.py | 43 ++ .../views/product_product_views.xml | 39 ++ 16 files changed, 740 insertions(+) create mode 100644 product_margin_report_sale_margin/README.rst create mode 100644 product_margin_report_sale_margin/__init__.py create mode 100644 product_margin_report_sale_margin/__manifest__.py create mode 100644 product_margin_report_sale_margin/models/__init__.py create mode 100644 product_margin_report_sale_margin/models/product_product.py create mode 100644 product_margin_report_sale_margin/pyproject.toml create mode 100644 product_margin_report_sale_margin/readme/CONTRIBUTORS.md create mode 100644 product_margin_report_sale_margin/readme/DESCRIPTION.md create mode 100644 product_margin_report_sale_margin/readme/USAGE.md create mode 100644 product_margin_report_sale_margin/static/description/index.html create mode 100644 product_margin_report_sale_margin/static/img/readme/FIELDS_VIEW_FORM.png create mode 100644 product_margin_report_sale_margin/static/img/readme/FIELDS_VIEW_TREE.png create mode 100644 product_margin_report_sale_margin/tests/__init__.py create mode 100644 product_margin_report_sale_margin/tests/test_common.py create mode 100644 product_margin_report_sale_margin/tests/test_product.py create mode 100644 product_margin_report_sale_margin/views/product_product_views.xml diff --git a/product_margin_report_sale_margin/README.rst b/product_margin_report_sale_margin/README.rst new file mode 100644 index 000000000..9bd831991 --- /dev/null +++ b/product_margin_report_sale_margin/README.rst @@ -0,0 +1,108 @@ +========================== +Product report sale margin +========================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:5b02242f5dbe90213a92d0d2632daa7f4c6b7553a8057302a5ab4f1f79657f90 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Fmargin--analysis-lightgray.png?logo=github + :target: https://github.com/OCA/margin-analysis/tree/17.0/product_margin_report_sale_margin + :alt: OCA/margin-analysis +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/margin-analysis-17-0/margin-analysis-17-0-product_margin_report_sale_margin + :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/margin-analysis&target_branch=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds 2 new fields for calculating the Sales margin. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +Sales margin fields +------------------- + +1. Go to *Invoicing* > *Reporting* -> Product Margins + +2. Select the values you want to filter by. + +3. Click on the *Open margins* button. + +4. When the new view is displayed, the two new fields are visible; + similarly, if you select an element, they will be visible in the form + view. + + |FIELDS_VIEW_TREE| + + |FIELDS_VIEW_FORM| + +Field calculations +------------------ + +- Sales margin = Turnover - (# Invoiced in Sale \* Avg. Unit Price + [Purchases]) +- Sales margin rate = (Sales margin - \* 100) / Turnover + +.. |FIELDS_VIEW_TREE| image:: https://raw.githubusercontent.com/OCA/margin-analysis/17.0/product_margin_report_sale_margin/static/img/readme/FIELDS_VIEW_TREE.png +.. |FIELDS_VIEW_FORM| image:: https://raw.githubusercontent.com/OCA/margin-analysis/17.0/product_margin_report_sale_margin/static/img/readme/FIELDS_VIEW_FORM.png + +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 +------- + +* Binhex + +Contributors +------------ + +- [Binhex Cloud] (https://www.binhex.cloud): + + - Edilio Escalona Almira e.escalona@binhex.cloud + +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/margin-analysis `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/product_margin_report_sale_margin/__init__.py b/product_margin_report_sale_margin/__init__.py new file mode 100644 index 000000000..0077c8866 --- /dev/null +++ b/product_margin_report_sale_margin/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2025 Binhex +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import models diff --git a/product_margin_report_sale_margin/__manifest__.py b/product_margin_report_sale_margin/__manifest__.py new file mode 100644 index 000000000..8312de724 --- /dev/null +++ b/product_margin_report_sale_margin/__manifest__.py @@ -0,0 +1,15 @@ +# Copyright 2025 Binhex +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Product report sale margin", + "summary": """Add new fields for sales margin in the Product Margins report.""", + "version": "17.0.1.0.0", + "license": "AGPL-3", + "author": "Binhex,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/margin-analysis", + "depends": [ + "product_margin", + ], + "data": ["views/product_product_views.xml"], +} diff --git a/product_margin_report_sale_margin/models/__init__.py b/product_margin_report_sale_margin/models/__init__.py new file mode 100644 index 000000000..57112ab7f --- /dev/null +++ b/product_margin_report_sale_margin/models/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2025 Binhex +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + + +from . import product_product diff --git a/product_margin_report_sale_margin/models/product_product.py b/product_margin_report_sale_margin/models/product_product.py new file mode 100644 index 000000000..c32baedad --- /dev/null +++ b/product_margin_report_sale_margin/models/product_product.py @@ -0,0 +1,25 @@ +# Copyright 2025 Binhex +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ProductProduct(models.Model): + _inherit = "product.product" + + sales_margin = fields.Float(compute="_compute_product_margin_fields_values") + sales_margin_rate = fields.Float(compute="_compute_product_margin_fields_values") + + def _compute_product_margin_fields_values(self): + res = super()._compute_product_margin_fields_values() + for product in self: + product_values = res[product.id] + product_values["sales_margin"] = product_values["turnover"] - ( + product_values["sale_num_invoiced"] + * product_values["purchase_avg_price"] + ) + product_values["sales_margin_rate"] = ( + product_values["sales_margin"] * 100 + ) / (product_values["turnover"] or 1) + product.update(res[product.id]) + return res diff --git a/product_margin_report_sale_margin/pyproject.toml b/product_margin_report_sale_margin/pyproject.toml new file mode 100644 index 000000000..4231d0ccc --- /dev/null +++ b/product_margin_report_sale_margin/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/product_margin_report_sale_margin/readme/CONTRIBUTORS.md b/product_margin_report_sale_margin/readme/CONTRIBUTORS.md new file mode 100644 index 000000000..0bfe91dd4 --- /dev/null +++ b/product_margin_report_sale_margin/readme/CONTRIBUTORS.md @@ -0,0 +1,2 @@ +- [Binhex Cloud] (https://www.binhex.cloud): + - Edilio Escalona Almira diff --git a/product_margin_report_sale_margin/readme/DESCRIPTION.md b/product_margin_report_sale_margin/readme/DESCRIPTION.md new file mode 100644 index 000000000..d99fbcab4 --- /dev/null +++ b/product_margin_report_sale_margin/readme/DESCRIPTION.md @@ -0,0 +1 @@ +This module adds 2 new fields for calculating the Sales margin. diff --git a/product_margin_report_sale_margin/readme/USAGE.md b/product_margin_report_sale_margin/readme/USAGE.md new file mode 100644 index 000000000..153ea96df --- /dev/null +++ b/product_margin_report_sale_margin/readme/USAGE.md @@ -0,0 +1,19 @@ +Sales margin fields +------------------ + +1. Go to *Invoicing* > *Reporting* -> Product Margins +2. Select the values you want to filter by. +3. Click on the *Open margins* button. +4. When the new view is displayed, the two new fields are visible; similarly, + if you select an element, they will be visible in the form view. + + ![FIELDS_VIEW_TREE](../static/img/readme/FIELDS_VIEW_TREE.png) + + ![FIELDS_VIEW_FORM](../static/img/readme/FIELDS_VIEW_FORM.png) + + +Field calculations +------------------ +* Sales margin = Turnover - (# Invoiced in Sale * Avg. Unit Price [Purchases]) +* Sales margin rate = (Sales margin - * 100) / Turnover + diff --git a/product_margin_report_sale_margin/static/description/index.html b/product_margin_report_sale_margin/static/description/index.html new file mode 100644 index 000000000..eada62019 --- /dev/null +++ b/product_margin_report_sale_margin/static/description/index.html @@ -0,0 +1,459 @@ + + + + + +Product report sale margin + + + +
+

Product report sale margin

+ + +

Beta License: AGPL-3 OCA/margin-analysis Translate me on Weblate Try me on Runboat

+

This module adds 2 new fields for calculating the Sales margin.

+

Table of contents

+ +
+

Usage

+
+

Sales margin fields

+
    +
  1. Go to Invoicing > Reporting -> Product Margins

    +
  2. +
  3. Select the values you want to filter by.

    +
  4. +
  5. Click on the Open margins button.

    +
  6. +
  7. When the new view is displayed, the two new fields are visible; +similarly, if you select an element, they will be visible in the form +view.

    +

    FIELDS_VIEW_TREE

    +

    FIELDS_VIEW_FORM

    +
  8. +
+
+
+

Field calculations

+
    +
  • Sales margin = Turnover - (# Invoiced in Sale * Avg. Unit Price +[Purchases])
  • +
  • Sales margin rate = (Sales margin - * 100) / Turnover
  • +
+
+
+
+

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

+
    +
  • Binhex
  • +
+
+
+

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/margin-analysis project on GitHub.

+

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

+
+
+
+ + diff --git a/product_margin_report_sale_margin/static/img/readme/FIELDS_VIEW_FORM.png b/product_margin_report_sale_margin/static/img/readme/FIELDS_VIEW_FORM.png new file mode 100644 index 0000000000000000000000000000000000000000..1d7094b7ec8e4f6215d630559ea6b1bab6bf7ddf GIT binary patch literal 14569 zcmch;WmFv9z9$^P-3jh)2_D=v!CixsKyYg`xCOTm+}#}-2o8-q1eeAoG%kUuJV)-F zHFxg1XJ+2_17B)wnyO;&|4%zyMM)MNg&5`8vuEh?a#Cu~o;@!Fe(;c909Q`2;hCR3 z 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 literal 0 HcmV?d00001 diff --git a/product_margin_report_sale_margin/static/img/readme/FIELDS_VIEW_TREE.png b/product_margin_report_sale_margin/static/img/readme/FIELDS_VIEW_TREE.png new file mode 100644 index 0000000000000000000000000000000000000000..6c7c8ddc66b6ba801c23c6576bf832cbaa122732 GIT binary patch literal 37706 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 literal 0 HcmV?d00001 diff --git a/product_margin_report_sale_margin/tests/__init__.py b/product_margin_report_sale_margin/tests/__init__.py new file mode 100644 index 000000000..487088eba --- /dev/null +++ b/product_margin_report_sale_margin/tests/__init__.py @@ -0,0 +1,6 @@ +# Copyright 2025 Binhex +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + + +from . import test_common +from . import test_product diff --git a/product_margin_report_sale_margin/tests/test_common.py b/product_margin_report_sale_margin/tests/test_common.py new file mode 100644 index 000000000..dd86b7f9f --- /dev/null +++ b/product_margin_report_sale_margin/tests/test_common.py @@ -0,0 +1,11 @@ +# Copyright 2025 Binhex +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.tests import TransactionCase + + +class TestReportProductMarginCommon(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.Product = cls.env["product.product"] diff --git a/product_margin_report_sale_margin/tests/test_product.py b/product_margin_report_sale_margin/tests/test_product.py new file mode 100644 index 000000000..34b36c1c3 --- /dev/null +++ b/product_margin_report_sale_margin/tests/test_product.py @@ -0,0 +1,43 @@ +# Copyright 2025 Binhex +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from unittest.mock import patch + +from odoo.addons.product_margin.models.product_product import ProductProduct + +from .test_common import TestReportProductMarginCommon + + +class TestReportProductMargin(TestReportProductMarginCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.product = cls.Product.create( + { + "name": "Test Product", + } + ) + + def test_compute_product_margin_fields_values(self): + mocked_super_return = { + self.product.id: { + "turnover": 1000.0, + "sale_num_invoiced": 10.0, + "purchase_avg_price": 50.0, + } + } + + with patch.object( + ProductProduct, + "_compute_product_margin_fields_values", + return_value=mocked_super_return, + ): + result = self.product._compute_product_margin_fields_values() + + sales_margin = 1000.0 - (10.0 * 50.0) + sales_margin_rate = (sales_margin * 100) / 1000.0 + + self.assertEqual(result[self.product.id]["sales_margin"], sales_margin) + self.assertEqual( + result[self.product.id]["sales_margin_rate"], sales_margin_rate + ) diff --git a/product_margin_report_sale_margin/views/product_product_views.xml b/product_margin_report_sale_margin/views/product_product_views.xml new file mode 100644 index 000000000..96d129aec --- /dev/null +++ b/product_margin_report_sale_margin/views/product_product_views.xml @@ -0,0 +1,39 @@ + + + + + product.margin.form.inherit.product_margin_report_sale_margin + product.product + + + + + + + + + + + + + product.margin.tree.product_margin_report_sale_margin + product.product + + + + + + + + + + +