Skip to content

Commit

Permalink
[MIG] sale_pricelist_global_rule: Migration to 16.0
Browse files Browse the repository at this point in the history
  • Loading branch information
LuciaMarchalFactorLibre committed Jan 15, 2025
1 parent 27a1770 commit 423ca3c
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 41 deletions.
10 changes: 5 additions & 5 deletions sale_pricelist_global_rule/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ Sale pricelist global rule
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fsale--workflow-lightgray.png?logo=github
:target: https://github.com/OCA/sale-workflow/tree/15.0/sale_pricelist_global_rule
:target: https://github.com/OCA/sale-workflow/tree/16.0/sale_pricelist_global_rule
:alt: OCA/sale-workflow
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/sale-workflow-15-0/sale-workflow-15-0-sale_pricelist_global_rule
:target: https://translation.odoo-community.org/projects/sale-workflow-16-0/sale-workflow-16-0-sale_pricelist_global_rule
: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/sale-workflow&target_branch=15.0
:target: https://runboat.odoo-community.org/builds?repo=OCA/sale-workflow&target_branch=16.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|
Expand Down Expand Up @@ -80,7 +80,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues <https://github.com/OCA/sale-workflow/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 <https://github.com/OCA/sale-workflow/issues/new?body=module:%20sale_pricelist_global_rule%0Aversion:%2015.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
`feedback <https://github.com/OCA/sale-workflow/issues/new?body=module:%20sale_pricelist_global_rule%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

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

Expand Down Expand Up @@ -113,6 +113,6 @@ 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/sale-workflow <https://github.com/OCA/sale-workflow/tree/15.0/sale_pricelist_global_rule>`_ project on GitHub.
This module is part of the `OCA/sale-workflow <https://github.com/OCA/sale-workflow/tree/16.0/sale_pricelist_global_rule>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
2 changes: 1 addition & 1 deletion sale_pricelist_global_rule/__manifest__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Sale pricelist global rule",
"version": "15.0.1.0.3",
"version": "16.0.1.0.0",
"summary": "Apply a global rule to all sale order",
"author": "Tecnativa, Odoo Community Association (OCA)",
"category": "Sales Management",
Expand Down
77 changes: 61 additions & 16 deletions sale_pricelist_global_rule/models/product_pricelist.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,50 @@
from odoo.exceptions import ValidationError


def get_family_category(category):
subcategories = set(category.child_id)
all_subcategories = subcategories.copy()
for subcategory in subcategories:
all_subcategories |= get_family_category(subcategory)

Check warning on line 9 in sale_pricelist_global_rule/models/product_pricelist.py

View check run for this annotation

Codecov / codecov/patch

sale_pricelist_global_rule/models/product_pricelist.py#L9

Added line #L9 was not covered by tests
return all_subcategories


class ProductPricelist(models.Model):
_inherit = "product.pricelist"

def _compute_price_rule_get_items(
self, products_qty_partner, date, uom_id, prod_tmpl_ids, prod_ids, categ_ids
):
items = super()._compute_price_rule_get_items(
products_qty_partner, date, uom_id, prod_tmpl_ids, prod_ids, categ_ids
self.ensure_one()

Check warning on line 19 in sale_pricelist_global_rule/models/product_pricelist.py

View check run for this annotation

Codecov / codecov/patch

sale_pricelist_global_rule/models/product_pricelist.py#L19

Added line #L19 was not covered by tests
# Load all rules
self.env["product.pricelist.item"].flush(

Check warning on line 21 in sale_pricelist_global_rule/models/product_pricelist.py

View check run for this annotation

Codecov / codecov/patch

sale_pricelist_global_rule/models/product_pricelist.py#L21

Added line #L21 was not covered by tests
["price", "currency_id", "company_id", "active"]
)
# ignore new global rules on Odoo standard
self.env.cr.execute(

Check warning on line 24 in sale_pricelist_global_rule/models/product_pricelist.py

View check run for this annotation

Codecov / codecov/patch

sale_pricelist_global_rule/models/product_pricelist.py#L24

Added line #L24 was not covered by tests
"""
SELECT
item.id
FROM
product_pricelist_item AS item
LEFT JOIN product_category AS categ ON item.categ_id = categ.id
WHERE
(item.product_tmpl_id IS NULL OR item.product_tmpl_id = any(%s))
AND (item.product_id IS NULL OR item.product_id = any(%s))
AND (item.categ_id IS NULL OR item.categ_id = any(%s))
AND (item.pricelist_id = %s)
AND (item.date_start IS NULL OR item.date_start<=%s)
AND (item.date_end IS NULL OR item.date_end>=%s)
AND (item.active = TRUE)
ORDER BY
item.applied_on, item.min_quantity desc, categ.complete_name desc, item.id desc
""",
(prod_tmpl_ids, prod_ids, categ_ids, self.id, date, date),
)
# NOTE: if you change `order by` on that query, make sure it matches
# _order from model to avoid inconstencies and undeterministic issues.

item_ids = [x[0] for x in self.env.cr.fetchall()]
items = self.env["product.pricelist.item"].browse(item_ids)
return items.filtered(

Check warning on line 49 in sale_pricelist_global_rule/models/product_pricelist.py

View check run for this annotation

Codecov / codecov/patch

sale_pricelist_global_rule/models/product_pricelist.py#L47-L49

Added lines #L47 - L49 were not covered by tests
lambda item: item.applied_on
not in ["4_global_product_template", "5_global_product_category"]
Expand Down Expand Up @@ -82,6 +116,7 @@ def _compute_price_rule_global(self, sale):
"by_template": {},
"by_categ": {},
}

for line in sale.order_line.filtered(lambda x: not x.display_type):
qty_in_product_uom = line.product_uom_qty
# Final unit price is computed according to `qty` in the default `uom_id`.
Expand Down Expand Up @@ -111,10 +146,10 @@ def _compute_price_rule_global(self, sale):
# need to call price_compute.
price = product.price_compute("list_price")[product.id]

price_uom = product.uom_id
for rule in items:
if not rule._is_applicable_for_sale(product.product_tmpl_id, qty_data):
continue

if rule.base == "pricelist" and rule.base_pricelist_id:
# first, try compute the price for global rule
# otherwise, fallback to regular computation
Expand All @@ -125,9 +160,7 @@ def _compute_price_rule_global(self, sale):
) = rule.base_pricelist_id._compute_price_rule_global(sale)[line.id]
if not rule_applied:
price = rule.base_pricelist_id._compute_price_rule(
[(product, line.product_uom_qty, sale.partner_id)],
date,
line.product_uom.id,
product, line.product_uom_qty
)[product.id][0]
src_currency = rule.base_pricelist_id.currency_id
else:
Expand All @@ -143,9 +176,15 @@ def _compute_price_rule_global(self, sale):
price = src_currency._convert(

Check warning on line 176 in sale_pricelist_global_rule/models/product_pricelist.py

View check run for this annotation

Codecov / codecov/patch

sale_pricelist_global_rule/models/product_pricelist.py#L176

Added line #L176 was not covered by tests
price, self.currency_id, self.env.company, date, round=False
)

# import pdb; pdb.set_trace()
if price is not False:
price = rule._compute_price(price, price_uom, product)
price = rule._compute_price(
product,
line.product_uom_qty,
product.uom_id,
date,
self.currency_id,
)
suitable_rule = rule
break

Expand Down Expand Up @@ -231,8 +270,8 @@ def _check_product_consistency(self):
"price_discount",
"price_surcharge",
)
def _get_pricelist_item_name_price(self):
res = super()._get_pricelist_item_name_price()
def _compute_name_and_price(self):
res = super()._compute_name_and_price()
for item in self:
if item.global_categ_id and item.applied_on == "5_global_product_category":
item.name = _("Global category: %s") % (

Check warning on line 277 in sale_pricelist_global_rule/models/product_pricelist.py

View check run for this annotation

Codecov / codecov/patch

sale_pricelist_global_rule/models/product_pricelist.py#L277

Added line #L277 was not covered by tests
Expand Down Expand Up @@ -318,11 +357,17 @@ def _is_applicable_for_sale(self, product_template, qty_data):
elif self.global_product_tmpl_id != product_template:
is_applicable = False
elif self.applied_on == "5_global_product_category":
total_qty = qty_data["by_categ"].get(product_template.categ_id, 0.0)
category = product_template.categ_id
total_qty = qty_data["by_categ"].get(category, 0.0)
if self.min_quantity and total_qty < self.min_quantity:
is_applicable = False
elif not product_template.categ_id.parent_path.startswith(
self.global_categ_id.parent_path
):
is_applicable = False
else:
rule_family_categories = get_family_category(self.global_categ_id)
rule_family_categories.add(self.global_categ_id)

product_family_categories = get_family_category(category)
product_family_categories.add(category)

if not rule_family_categories.intersection(product_family_categories):
is_applicable = False
return is_applicable
16 changes: 8 additions & 8 deletions sale_pricelist_global_rule/models/sale_order.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import math

from odoo import api, fields, models
from odoo.tools import float_compare

Expand Down Expand Up @@ -47,6 +49,7 @@ def button_compute_pricelist_global_rule(self):
fiscal_position=self.env.context.get("fiscal_position"),
)
price, suitable_rule = prices_data[line.id]
price = math.trunc(price * 100) / 100
if is_discount_visible:
product_context = dict(
self.env.context,
Expand All @@ -55,15 +58,10 @@ def button_compute_pricelist_global_rule(self):
uom=line.product_uom.id,
)

base_price, currency = line.with_context(
currency = self.pricelist_id.currency_id
base_price = line.with_context(
**product_context
)._get_real_price_currency(
product,
suitable_rule,
line.product_uom_qty,
line.product_uom,
self.pricelist_id.id,
)
).product_id.uom_id._compute_price(product.lst_price, line.product_uom)
if base_price != 0:
if self.pricelist_id.currency_id != currency:
# we need new_list_price in the same currency as price,
Expand All @@ -75,6 +73,7 @@ def button_compute_pricelist_global_rule(self):
self.date_order or fields.Date.context_today(self),
)
discount = (base_price - price) / base_price * 100

if (discount > 0 and base_price > 0) or (
discount < 0 and base_price < 0
):
Expand All @@ -84,5 +83,6 @@ def button_compute_pricelist_global_rule(self):
if float_compare(price, line.price_unit, precision_digits=digits) != 0:
vals_to_write["price_unit"] = price
if vals_to_write:

line.write(vals_to_write)
self.need_recompute_pricelist_global = False
6 changes: 3 additions & 3 deletions sale_pricelist_global_rule/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ <h1 class="title">Sale pricelist global rule</h1>
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:b93829a100ce8864f9f399ba2bf2c998544d9a7b00d3555405045eaebe3f4cd4
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/sale-workflow/tree/15.0/sale_pricelist_global_rule"><img alt="OCA/sale-workflow" src="https://img.shields.io/badge/github-OCA%2Fsale--workflow-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/sale-workflow-15-0/sale-workflow-15-0-sale_pricelist_global_rule"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/sale-workflow&amp;target_branch=15.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/sale-workflow/tree/16.0/sale_pricelist_global_rule"><img alt="OCA/sale-workflow" src="https://img.shields.io/badge/github-OCA%2Fsale--workflow-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/sale-workflow-16-0/sale-workflow-16-0-sale_pricelist_global_rule"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/sale-workflow&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module allows configured pricelists to be applied to a sales order by considering cumulative quantities across all lines.</p>
<p><strong>Global by Product Template</strong></p>
<p>If a pricelist rule has a <cite>min_quantity = 15</cite>, and a sales order contains:</p>
Expand Down Expand Up @@ -430,7 +430,7 @@ <h1><a class="toc-backref" href="#toc-entry-4">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/sale-workflow/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/sale-workflow/issues/new?body=module:%20sale_pricelist_global_rule%0Aversion:%2015.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<a class="reference external" href="https://github.com/OCA/sale-workflow/issues/new?body=module:%20sale_pricelist_global_rule%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
Expand Down Expand Up @@ -460,7 +460,7 @@ <h2><a class="toc-backref" href="#toc-entry-8">Maintainers</a></h2>
<p>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.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/sale-workflow/tree/15.0/sale_pricelist_global_rule">OCA/sale-workflow</a> project on GitHub.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/sale-workflow/tree/16.0/sale_pricelist_global_rule">OCA/sale-workflow</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
Expand Down
16 changes: 8 additions & 8 deletions sale_pricelist_global_rule/tests/test_pricelist_global.py
Original file line number Diff line number Diff line change
Expand Up @@ -683,14 +683,14 @@ def test_pricelist_visible_discount(self):
- Based on other pricelist
- Global pricelist discount policy: without_discount
- base pricelist discount_policy: with_discount
- product_m_red: price=80, discount=10
- product_m_black: price=80, discount=10
- product_m_red: price=100, discount=28
- product_m_black: price=100, discount=28
Case 5:
- Based on other pricelist
- Global pricelist discount policy: with_discount
- base pricelist discount_policy: without_discount
- product_m_red: price=80, discount=10
- product_m_black: price=80, discount=10
- product_m_red: price=72, discount=0
- product_m_black: price=72, discount=0
Case 6:
- Based on other pricelist
- Global pricelist discount policy: without_discount
Expand Down Expand Up @@ -744,10 +744,10 @@ def test_pricelist_visible_discount(self):
self.pricelist_global.write({"discount_policy": "without_discount"})
self.pricelist_base.write({"discount_policy": "with_discount"})
self.sale_order1.button_compute_pricelist_global_rule()
self.assertEqual(self.sale_line_m_red.price_unit, 80)
self.assertEqual(self.sale_line_m_red.discount, 10)
self.assertEqual(self.sale_line_m_black.price_unit, 80)
self.assertEqual(self.sale_line_m_black.discount, 10)
self.assertEqual(self.sale_line_m_red.price_unit, 100)
self.assertEqual(self.sale_line_m_red.discount, 28)
self.assertEqual(self.sale_line_m_black.price_unit, 100)
self.assertEqual(self.sale_line_m_black.discount, 28)
self.assertEqual(self.sale_line_2.price_unit, 200)
self.assertEqual(self.sale_line_2.discount, 0)
self.assertEqual(self.sale_line_3.price_unit, 300)
Expand Down
6 changes: 6 additions & 0 deletions setup/sale_pricelist_global_rule/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import setuptools

setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)

0 comments on commit 423ca3c

Please sign in to comment.