From b0afaf9d9802e7cacd18d834d1633d07c4ac9393 Mon Sep 17 00:00:00 2001 From: "German Loredo [Vauxoo]" Date: Thu, 25 Apr 2024 04:39:08 +0000 Subject: [PATCH 1/2] [IMP] sale_margin_percentage: separate one model per file To follow our good practices each model should be in its own file with the same name as the model. --- sale_margin_percentage/models/__init__.py | 1 + sale_margin_percentage/models/sale_order.py | 38 ------------------ .../models/sale_order_line.py | 39 +++++++++++++++++++ 3 files changed, 40 insertions(+), 38 deletions(-) create mode 100644 sale_margin_percentage/models/sale_order_line.py diff --git a/sale_margin_percentage/models/__init__.py b/sale_margin_percentage/models/__init__.py index 212bb5f2daf..a475b71bd4e 100644 --- a/sale_margin_percentage/models/__init__.py +++ b/sale_margin_percentage/models/__init__.py @@ -1,3 +1,4 @@ from . import res_company from . import res_config_settings from . import sale_order +from . import sale_order_line diff --git a/sale_margin_percentage/models/sale_order.py b/sale_margin_percentage/models/sale_order.py index 3bfd407e610..05dc0f4ef2c 100644 --- a/sale_margin_percentage/models/sale_order.py +++ b/sale_margin_percentage/models/sale_order.py @@ -21,41 +21,3 @@ def _compute_margin_percentage(self): order.margin_percentage = 0.0 continue order.margin_percentage = margin_sum * (100.0 / subtotal) - - -class SaleOrderLine(models.Model): - _inherit = "sale.order.line" - - margin_threshold = fields.Float( - default=lambda self: self.env.user.company_id.margin_threshold, help="Limit margin set in sales configuration" - ) - margin_percentage = fields.Float( - compute="_compute_margin_percentage", - digits="Product Price", - store=True, - help="Margin percentage compute based on price unit", - ) - purchase_price = fields.Float(readonly=True, help="Price purchase of product") - - @api.depends("product_id", "purchase_price", "product_uom_qty", "price_unit", "price_subtotal") - def _compute_margin_percentage(self): - """Same margin but we return a percentage from the purchase price.""" - for line in self: - currency = line.order_id.pricelist_id.currency_id - - if not line.product_uom_qty: - line.margin_percentage = 0.0 - continue - - if currency.is_zero(line.price_unit) or currency.is_zero(line.price_subtotal): - line.margin_percentage = -100.0 - continue - - purchase_price = line.purchase_price or line.product_id.standard_price - if currency.is_zero(purchase_price): - line.margin_percentage = 100.0 - continue - - line.margin_percentage = currency.round( - (line.price_subtotal - purchase_price * line.product_uom_qty) * 100.0 / line.price_subtotal - ) diff --git a/sale_margin_percentage/models/sale_order_line.py b/sale_margin_percentage/models/sale_order_line.py new file mode 100644 index 00000000000..6b708e493be --- /dev/null +++ b/sale_margin_percentage/models/sale_order_line.py @@ -0,0 +1,39 @@ +from odoo import api, fields, models + + +class SaleOrderLine(models.Model): + _inherit = "sale.order.line" + + margin_threshold = fields.Float( + default=lambda self: self.env.user.company_id.margin_threshold, help="Limit margin set in sales configuration" + ) + margin_percentage = fields.Float( + compute="_compute_margin_percentage", + digits="Product Price", + store=True, + help="Margin percentage compute based on price unit", + ) + purchase_price = fields.Float(readonly=True, help="Price purchase of product") + + @api.depends("product_id", "purchase_price", "product_uom_qty", "price_unit", "price_subtotal") + def _compute_margin_percentage(self): + """Same margin but we return a percentage from the purchase price.""" + for line in self: + currency = line.order_id.pricelist_id.currency_id + + if not line.product_uom_qty: + line.margin_percentage = 0.0 + continue + + if currency.is_zero(line.price_unit) or currency.is_zero(line.price_subtotal): + line.margin_percentage = -100.0 + continue + + purchase_price = line.purchase_price or line.product_id.standard_price + if currency.is_zero(purchase_price): + line.margin_percentage = 100.0 + continue + + line.margin_percentage = currency.round( + (line.price_subtotal - purchase_price * line.product_uom_qty) * 100.0 / line.price_subtotal + ) From 3ed0c76cd1a082cfd09e1e19e6d4d1e885fca26a Mon Sep 17 00:00:00 2001 From: "German Loredo [Vauxoo]" Date: Thu, 11 Apr 2024 21:51:53 +0000 Subject: [PATCH 2/2] [REM] sale_margin_percentage: remove margin_percentage field in favor of native one The field margin_percentage is no longer needed since native module sale_margin have the field margin_percent that serve the same propose. Also the field margin_threshold must be updated since it was used as a percentage but the native field margin_percent is a ration so we must follow the same pattern. --- sale_margin_percentage/__manifest__.py | 2 +- sale_margin_percentage/i18n/es.po | 17 ------------- .../migrations/15.0.1.0.1/post-migration.py | 25 +++++++++++++++++++ sale_margin_percentage/models/__init__.py | 1 - sale_margin_percentage/models/res_company.py | 2 +- sale_margin_percentage/models/sale_order.py | 23 ----------------- .../models/sale_order_line.py | 23 ++++++----------- .../tests/test_sale_order.py | 17 +++++++------ .../views/res_config_settings_views.xml | 2 +- .../views/sale_order_views.xml | 9 ++----- 10 files changed, 46 insertions(+), 75 deletions(-) create mode 100644 sale_margin_percentage/migrations/15.0.1.0.1/post-migration.py delete mode 100644 sale_margin_percentage/models/sale_order.py diff --git a/sale_margin_percentage/__manifest__.py b/sale_margin_percentage/__manifest__.py index 8d654e62fa1..eb411eccc05 100644 --- a/sale_margin_percentage/__manifest__.py +++ b/sale_margin_percentage/__manifest__.py @@ -1,6 +1,6 @@ { "name": "Sale Order Gross Margin Percentage", - "version": "15.0.1.0.0", + "version": "15.0.1.0.1", "author": "Vauxoo", "category": "Sales/Sales", "website": "https://www.vauxoo.com/", diff --git a/sale_margin_percentage/i18n/es.po b/sale_margin_percentage/i18n/es.po index fd17eb05ec8..f4b3e866be1 100644 --- a/sale_margin_percentage/i18n/es.po +++ b/sale_margin_percentage/i18n/es.po @@ -48,17 +48,6 @@ msgstr "Coste" msgid "Limit margin set in sales configuration" msgstr "Límite de margen establecido en la configuración de ventas" -#. module: sale_margin_percentage -#: model_terms:ir.ui.view,arch_db:sale_margin_percentage.view_order_form -msgid "Margin %" -msgstr "Margen %" - -#. module: sale_margin_percentage -#: model:ir.model.fields,field_description:sale_margin_percentage.field_sale_order__margin_percentage -#: model:ir.model.fields,field_description:sale_margin_percentage.field_sale_order_line__margin_percentage -msgid "Margin Percentage" -msgstr "Porcentaje de margen" - #. module: sale_margin_percentage #: model:ir.model.fields,field_description:sale_margin_percentage.field_res_company__margin_threshold #: model:ir.model.fields,field_description:sale_margin_percentage.field_res_config_settings__margin_threshold @@ -73,12 +62,6 @@ msgstr "Límite de margen" msgid "Margin Threshold for product in order lines" msgstr "Límite de margen para productos en líneas de pedido" -#. module: sale_margin_percentage -#: model:ir.model.fields,help:sale_margin_percentage.field_sale_order__margin_percentage -#: model:ir.model.fields,help:sale_margin_percentage.field_sale_order_line__margin_percentage -msgid "Margin percentage compute based on price unit" -msgstr "Porcentaje de margen calculado según la unidad de precio" - #. module: sale_margin_percentage #: model_terms:ir.ui.view,arch_db:sale_margin_percentage.res_config_settings_view_form msgid "Minimun margin percentage allowed" diff --git a/sale_margin_percentage/migrations/15.0.1.0.1/post-migration.py b/sale_margin_percentage/migrations/15.0.1.0.1/post-migration.py new file mode 100644 index 00000000000..2eeb3a6ccdc --- /dev/null +++ b/sale_margin_percentage/migrations/15.0.1.0.1/post-migration.py @@ -0,0 +1,25 @@ +import logging + +from odoo import SUPERUSER_ID, api + +_logger = logging.getLogger(__name__) + + +def migrate(cr, version): + env = api.Environment(cr, SUPERUSER_ID, {}) + update_margin_threshold(env) + recompute_margin_percent(env) + + +def update_margin_threshold(env): + companies = env["res.company"].search([]) + for company in companies: + company.write({"margin_threshold": company.margin_threshold / 100.0}) + + _logger.info("The margin threshold for %s companies have been updated.", len(companies)) + + +def recompute_margin_percent(env): + order_lines = env["sale.order.line"].search([]) + order_lines._compute_margin() + _logger.info("The margin percentage of %s records have been recomputed.", len(order_lines)) diff --git a/sale_margin_percentage/models/__init__.py b/sale_margin_percentage/models/__init__.py index a475b71bd4e..75c8003a10f 100644 --- a/sale_margin_percentage/models/__init__.py +++ b/sale_margin_percentage/models/__init__.py @@ -1,4 +1,3 @@ from . import res_company from . import res_config_settings -from . import sale_order from . import sale_order_line diff --git a/sale_margin_percentage/models/res_company.py b/sale_margin_percentage/models/res_company.py index a6f58eab581..3717e00d2fe 100644 --- a/sale_margin_percentage/models/res_company.py +++ b/sale_margin_percentage/models/res_company.py @@ -4,4 +4,4 @@ class ResCompany(models.Model): _inherit = "res.company" - margin_threshold = fields.Float(digits=(16, 2), help="Margin Threshold for product in order lines") + margin_threshold = fields.Float(help="Margin Threshold for product in order lines") diff --git a/sale_margin_percentage/models/sale_order.py b/sale_margin_percentage/models/sale_order.py deleted file mode 100644 index 05dc0f4ef2c..00000000000 --- a/sale_margin_percentage/models/sale_order.py +++ /dev/null @@ -1,23 +0,0 @@ -from odoo import api, fields, models - - -class SaleOrder(models.Model): - _inherit = "sale.order" - - margin_percentage = fields.Float( - compute="_compute_margin_percentage", - digits="Product Price", - store=True, - help="Margin percentage compute based on price unit", - ) - - @api.depends("order_line.margin_percentage") - def _compute_margin_percentage(self): - for order in self: - lines = order.order_line.filtered(lambda r: r.state != "cancel") - margin_sum = sum(lines.mapped("margin")) - subtotal = order.amount_untaxed - if not subtotal or not margin_sum: - order.margin_percentage = 0.0 - continue - order.margin_percentage = margin_sum * (100.0 / subtotal) diff --git a/sale_margin_percentage/models/sale_order_line.py b/sale_margin_percentage/models/sale_order_line.py index 6b708e493be..c53a3a61c0c 100644 --- a/sale_margin_percentage/models/sale_order_line.py +++ b/sale_margin_percentage/models/sale_order_line.py @@ -7,33 +7,24 @@ class SaleOrderLine(models.Model): margin_threshold = fields.Float( default=lambda self: self.env.user.company_id.margin_threshold, help="Limit margin set in sales configuration" ) - margin_percentage = fields.Float( - compute="_compute_margin_percentage", - digits="Product Price", - store=True, - help="Margin percentage compute based on price unit", - ) purchase_price = fields.Float(readonly=True, help="Price purchase of product") - @api.depends("product_id", "purchase_price", "product_uom_qty", "price_unit", "price_subtotal") - def _compute_margin_percentage(self): - """Same margin but we return a percentage from the purchase price.""" + @api.depends("price_subtotal", "product_uom_qty", "purchase_price") + def _compute_margin(self): + res = super()._compute_margin() for line in self: currency = line.order_id.pricelist_id.currency_id - if not line.product_uom_qty: - line.margin_percentage = 0.0 + line.margin_percent = 0.0 continue if currency.is_zero(line.price_unit) or currency.is_zero(line.price_subtotal): - line.margin_percentage = -100.0 + line.margin_percent = -1.0 continue purchase_price = line.purchase_price or line.product_id.standard_price if currency.is_zero(purchase_price): - line.margin_percentage = 100.0 + line.margin_percent = 1.0 continue - line.margin_percentage = currency.round( - (line.price_subtotal - purchase_price * line.product_uom_qty) * 100.0 / line.price_subtotal - ) + return res diff --git a/sale_margin_percentage/tests/test_sale_order.py b/sale_margin_percentage/tests/test_sale_order.py index 84092f73bf6..766ff7628e8 100644 --- a/sale_margin_percentage/tests/test_sale_order.py +++ b/sale_margin_percentage/tests/test_sale_order.py @@ -37,37 +37,37 @@ def test_01_margin_cost_0(self): """Margin and Margin Percentage when cost is 0""" sale = self.create_so(quantity=4, price=12) self.assertEqual(sale.order_line.margin, 48) - self.assertEqual(sale.order_line.margin_percentage, 100) + self.assertEqual(sale.order_line.margin_percent, 1.0) def test_02_margin_sale_price_0(self): """Margin and Margin Percentage when sale price is 0""" sale = self.create_so(product=self.product_cost_15, quantity=4, price=0) self.assertEqual(sale.order_line.margin, -60) - self.assertEqual(sale.order_line.margin_percentage, -100) + self.assertEqual(sale.order_line.margin_percent, -1.0) def test_03_margin_sale_qty_0(self): """Margin and Margin Percentage when product qty is 0""" sale = self.create_so(product=self.product_cost_10, quantity=0, price=15) self.assertEqual(sale.order_line.margin, 0.0) - self.assertEqual(sale.order_line.margin_percentage, 0.0) + self.assertEqual(sale.order_line.margin_percent, 0.0) def test_04_margin_positive(self): """Margin and Margin Percentage when purchase price < sale cost""" sale = self.create_so(product=self.product_cost_10, quantity=4, price=12) self.assertEqual(sale.order_line.margin, 8.0) - self.assertAlmostEqual(sale.order_line.margin_percentage, 16.66, places=1) + self.assertAlmostEqual(sale.order_line.margin_percent, 0.1666, places=3) def test_05_margin_negative(self): """Margin and Margin Percentage when purchase price > sale cost""" sale = self.create_so(product=self.product_cost_15, quantity=4, price=12) self.assertEqual(sale.order_line.margin, -12) - self.assertAlmostEqual(sale.order_line.margin_percentage, -25, places=1) + self.assertAlmostEqual(sale.order_line.margin_percent, -0.25, places=3) def test_06_margin_balanced(self): """Margin and Margin Percentage when purchase price = sale cost""" sale = self.create_so(product=self.product_cost_15, quantity=4, price=15) self.assertEqual(sale.order_line.margin, 0.0) - self.assertEqual(sale.order_line.margin_percentage, 0.0) + self.assertEqual(sale.order_line.margin_percent, 0.0) def test_07_margin_total(self): """Margin Percentage of the sale order.""" @@ -81,7 +81,8 @@ def test_07_margin_total(self): self.create_so_line(sale, product=self.product_cost_10, quantity=5, price=12) self.assertEqual(sale.order_line.mapped("margin"), [48.0, -60.0, -12.0, 8.0, 0.0, 0.0, 32.0, 10.0]) self.assertEqual( - sale.order_line.mapped("margin_percentage"), [100.0, -100.0, -25.0, 16.67, 0.0, 0.0, 61.54, 16.67] + list(map(lambda x: round(x, 4), sale.order_line.mapped("margin_percent"))), + [1.0, -1.0, -0.25, 0.1667, 0.0, 0.0, 0.6154, 0.1667], ) self.assertEqual(sale.margin, 26) - self.assertAlmostEqual(sale.margin_percentage, 8.55, places=1) + self.assertAlmostEqual(sale.margin_percent, 0.0855, places=3) diff --git a/sale_margin_percentage/views/res_config_settings_views.xml b/sale_margin_percentage/views/res_config_settings_views.xml index baf95a1f412..4bc556459dc 100644 --- a/sale_margin_percentage/views/res_config_settings_views.xml +++ b/sale_margin_percentage/views/res_config_settings_views.xml @@ -20,7 +20,7 @@ Minimun margin percentage allowed
- +
diff --git a/sale_margin_percentage/views/sale_order_views.xml b/sale_margin_percentage/views/sale_order_views.xml index 5bc9c0e6c99..9b71908f33a 100644 --- a/sale_margin_percentage/views/sale_order_views.xml +++ b/sale_margin_percentage/views/sale_order_views.xml @@ -9,22 +9,17 @@ base.group_system - - - - - - margin_percentage <= 0.0 + margin_percent <= 0.0 margin_percentage <= margin_threshold and margin_percentage > 0.0 + >margin_percent <= margin_threshold and margin_percent > 0.0