From cea6977a6650f023d833367003c8d723c25a3516 Mon Sep 17 00:00:00 2001 From: Quentin Groulard Date: Wed, 21 Oct 2020 11:31:13 +0200 Subject: [PATCH 1/8] [ADD] Pricelist brand --- pricelist_brand/README.rst | 85 ++++ pricelist_brand/__init__.py | 1 + pricelist_brand/__manifest__.py | 13 + pricelist_brand/models/__init__.py | 1 + pricelist_brand/models/product_pricelist.py | 130 ++++++ pricelist_brand/readme/CONTRIBUTORS.rst | 1 + pricelist_brand/readme/DESCRIPTION.rst | 1 + pricelist_brand/readme/USAGE.rst | 8 + pricelist_brand/static/description/icon.png | Bin 0 -> 9455 bytes pricelist_brand/static/description/index.html | 432 ++++++++++++++++++ pricelist_brand/tests/__init__.py | 1 + .../tests/test_product_pricelist.py | 137 ++++++ pricelist_brand/views/product_pricelist.xml | 21 + 13 files changed, 831 insertions(+) create mode 100644 pricelist_brand/README.rst create mode 100644 pricelist_brand/__init__.py create mode 100644 pricelist_brand/__manifest__.py create mode 100644 pricelist_brand/models/__init__.py create mode 100644 pricelist_brand/models/product_pricelist.py create mode 100644 pricelist_brand/readme/CONTRIBUTORS.rst create mode 100644 pricelist_brand/readme/DESCRIPTION.rst create mode 100644 pricelist_brand/readme/USAGE.rst create mode 100644 pricelist_brand/static/description/icon.png create mode 100644 pricelist_brand/static/description/index.html create mode 100644 pricelist_brand/tests/__init__.py create mode 100644 pricelist_brand/tests/test_product_pricelist.py create mode 100644 pricelist_brand/views/product_pricelist.xml diff --git a/pricelist_brand/README.rst b/pricelist_brand/README.rst new file mode 100644 index 000000000..8d2054093 --- /dev/null +++ b/pricelist_brand/README.rst @@ -0,0 +1,85 @@ +=============== +Pricelist Brand +=============== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Fbrand-lightgray.png?logo=github + :target: https://github.com/OCA/brand/tree/13.0/pricelist_brand + :alt: OCA/brand +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/brand-13-0/brand-13-0-pricelist_brand + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/284/13.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows to configure pricelist items so that they are applied on products of specific brands. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +To apply pricelist items on branded products: + +#. See 'product_brand' module to learn how to configure brands on products. +#. Go to *Sales > Pricelists* and open the pricelist of your choice or create a new one. +#. Edit the pricelist and add a new item to it. +#. Select *Brand* in the field *Applied On*. +#. Select the product brand of your choice in the field *Brand*. +#. Configure the rest of the rule the way you want, this rule will apply on any product from the brand you selected. + +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 smashing 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 +~~~~~~~~~~~~ + +* 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/brand `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/pricelist_brand/__init__.py b/pricelist_brand/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/pricelist_brand/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/pricelist_brand/__manifest__.py b/pricelist_brand/__manifest__.py new file mode 100644 index 000000000..1645144c1 --- /dev/null +++ b/pricelist_brand/__manifest__.py @@ -0,0 +1,13 @@ +# Copyright 2020 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Pricelist Brand", + "summary": """This module allows to apply pricelist items on brand""", + "version": "13.0.1.0.0", + "license": "AGPL-3", + "author": "ACSONE SA/NV,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/brand", + "depends": ["product_brand"], + "data": ["views/product_pricelist.xml"], +} diff --git a/pricelist_brand/models/__init__.py b/pricelist_brand/models/__init__.py new file mode 100644 index 000000000..9880677a7 --- /dev/null +++ b/pricelist_brand/models/__init__.py @@ -0,0 +1 @@ +from . import product_pricelist diff --git a/pricelist_brand/models/product_pricelist.py b/pricelist_brand/models/product_pricelist.py new file mode 100644 index 000000000..24f0106ed --- /dev/null +++ b/pricelist_brand/models/product_pricelist.py @@ -0,0 +1,130 @@ +# Copyright 2020 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +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 + ): + self.ensure_one() + product_tmpls = self.env["product.template"].browse(prod_tmpl_ids) + brand_ids = product_tmpls.mapped("product_brand_id").ids + # Load all rules + self.env["product.pricelist.item"].flush(["price", "currency_id", "company_id"]) + self.env.cr.execute( + """ + SELECT + item.id + FROM + product_pricelist_item AS item + LEFT JOIN product_category AS categ ON item.categ_id = categ.id + LEFT JOIN product_brand AS brand ON item.product_brand_id = brand.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.product_brand_id IS NULL OR item.product_brand_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) + ORDER BY + item.applied_on, item.min_quantity desc, + categ.complete_name desc, item.id desc + """, + (prod_tmpl_ids, prod_ids, categ_ids, brand_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()] + return self.env["product.pricelist.item"].browse(item_ids) + + +class ProductPricelistItem(models.Model): + + _inherit = "product.pricelist.item" + + product_brand_id = fields.Many2one( + comodel_name="product.brand", + string="Brand", + ondelete="cascade", + help="Specify a brand if this rule only applies to products" + "belonging to this brand. Keep empty otherwise.", + ) + applied_on = fields.Selection(selection_add=[("25_brand", "Brand")]) + + @api.constrains("product_id", "product_tmpl_id", "categ_id", "product_brand_id") + def _check_product_consistency(self): + super(ProductPricelistItem, self)._check_product_consistency() + for item in self: + if item.applied_on == "25_brand" and not item.product_brand_id: + raise ValidationError( + _("Please specify the brand for which this rule should be applied") + ) + + @api.depends( + "applied_on", + "categ_id", + "product_tmpl_id", + "product_id", + "compute_price", + "fixed_price", + "pricelist_id", + "percent_price", + "price_discount", + "price_surcharge", + "product_brand_id", + ) + def _get_pricelist_item_name_price(self): + super(ProductPricelistItem, self)._get_pricelist_item_name_price() + for item in self: + if item.product_brand_id and item.applied_on == "25_brand": + item.name = _("Brand: %s") % (item.product_brand_id.display_name) + + @api.onchange("product_id", "product_tmpl_id", "categ_id", "product_brand_id") + def _onchane_rule_content(self): + super(ProductPricelistItem, self)._onchane_rule_content() + + @api.model_create_multi + def create(self, vals_list): + for values in vals_list: + if values.get("applied_on", False): + # Ensure item consistency for later searches. + applied_on = values["applied_on"] + if applied_on == "25_brand": + values.update( + dict(product_id=None, product_tmpl_id=None, categ_id=None) + ) + elif applied_on == "3_global": + values.update(dict(product_brand_id=None)) + elif applied_on == "2_product_category": + values.update(dict(product_brand_id=None)) + elif applied_on == "1_product": + values.update(dict(product_brand_id=None)) + elif applied_on == "0_product_variant": + values.update(dict(product_brand_id=None)) + return super(ProductPricelistItem, self).create(vals_list) + + def write(self, values): + if values.get("applied_on", False): + # Ensure item consistency for later searches. + applied_on = values["applied_on"] + if applied_on == "25_brand": + values.update( + dict(product_id=None, product_tmpl_id=None, categ_id=None) + ) + elif applied_on == "3_global": + values.update(dict(product_brand_id=None)) + elif applied_on == "2_product_category": + values.update(dict(product_brand_id=None)) + elif applied_on == "1_product": + values.update(dict(product_brand_id=None)) + elif applied_on == "0_product_variant": + values.update(dict(product_brand_id=None)) + return super(ProductPricelistItem, self).write(values) diff --git a/pricelist_brand/readme/CONTRIBUTORS.rst b/pricelist_brand/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..5914f5529 --- /dev/null +++ b/pricelist_brand/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Quentin Groulard diff --git a/pricelist_brand/readme/DESCRIPTION.rst b/pricelist_brand/readme/DESCRIPTION.rst new file mode 100644 index 000000000..a6fa92014 --- /dev/null +++ b/pricelist_brand/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module allows to configure pricelist items so that they are applied on products of specific brands. diff --git a/pricelist_brand/readme/USAGE.rst b/pricelist_brand/readme/USAGE.rst new file mode 100644 index 000000000..1bffe67cf --- /dev/null +++ b/pricelist_brand/readme/USAGE.rst @@ -0,0 +1,8 @@ +To apply pricelist items on branded products: + +#. See 'product_brand' module to learn how to configure brands on products. +#. Go to *Sales > Pricelists* and open the pricelist of your choice or create a new one. +#. Edit the pricelist and add a new item to it. +#. Select *Brand* in the field *Applied On*. +#. Select the product brand of your choice in the field *Brand*. +#. Configure the rest of the rule the way you want, this rule will apply on any product from the brand you selected. diff --git a/pricelist_brand/static/description/icon.png b/pricelist_brand/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/pricelist_brand/static/description/index.html b/pricelist_brand/static/description/index.html new file mode 100644 index 000000000..8afe62118 --- /dev/null +++ b/pricelist_brand/static/description/index.html @@ -0,0 +1,432 @@ + + + + + + +Pricelist Brand + + + +
+

Pricelist Brand

+ + +

Beta License: AGPL-3 OCA/brand Translate me on Weblate Try me on Runbot

+

This module allows to configure pricelist items so that they are applied on products of specific brands.

+

Table of contents

+ +
+

Usage

+

To apply pricelist items on branded products:

+
    +
  1. See ‘product_brand’ module to learn how to configure brands on products.
  2. +
  3. Go to Sales > Pricelists and open the pricelist of your choice or create a new one.
  4. +
  5. Edit the pricelist and add a new item to it.
  6. +
  7. Select Brand in the field Applied On.
  8. +
  9. Select the product brand of your choice in the field Brand.
  10. +
  11. Configure the rest of the rule the way you want, this rule will apply on any product from the brand you selected.
  12. +
+
+
+

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 smashing 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/brand project on GitHub.

+

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

+
+
+
+ + diff --git a/pricelist_brand/tests/__init__.py b/pricelist_brand/tests/__init__.py new file mode 100644 index 000000000..48b4ef970 --- /dev/null +++ b/pricelist_brand/tests/__init__.py @@ -0,0 +1 @@ +from . import test_product_pricelist diff --git a/pricelist_brand/tests/test_product_pricelist.py b/pricelist_brand/tests/test_product_pricelist.py new file mode 100644 index 000000000..56bd87d90 --- /dev/null +++ b/pricelist_brand/tests/test_product_pricelist.py @@ -0,0 +1,137 @@ +# Copyright 2020 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.exceptions import ValidationError +from odoo.tests.common import TransactionCase +from odoo.tools import float_compare + + +class TestProductPricelist(TransactionCase): + def setUp(self): + super(TestProductPricelist, self).setUp() + self.product_brand_obj = self.env["product.brand"] + self.product_brand = self.env["product.brand"].create( + {"name": "Test Brand", "description": "Test brand description"} + ) + self.product = self.env.ref("product.product_product_4") + self.product.write({"product_brand_id": self.product_brand.id}) + self.product_2 = self.env.ref("product.product_product_5") + + self.list0 = self.ref("product.list0") + self.pricelist = self.env["product.pricelist"].create( + { + "name": "Test Pricelist", + "item_ids": [ + ( + 0, + 0, + { + "name": "Default pricelist", + "compute_price": "formula", + "base": "pricelist", + "base_pricelist_id": self.list0, + }, + ), + ( + 0, + 0, + { + "name": "10% Discount on Test Brand", + "applied_on": "25_brand", + "product_brand_id": self.product_brand.id, + "compute_price": "formula", + "base": "list_price", + "price_discount": 10, + }, + ), + ], + } + ) + + def test_ensure_pricelist_item_consistency(self): + with self.assertRaises(ValidationError): + self.env["product.pricelist.item"].create( + { + "pricelist_id": self.pricelist.id, + "base": "list_price", + "compute_price": "formula", + "applied_on": "25_brand", + } + ) + pricelist_item = self.env["product.pricelist.item"].create( + { + "pricelist_id": self.pricelist.id, + "base": "list_price", + "compute_price": "formula", + "applied_on": "25_brand", + "product_brand_id": self.product_brand.id, + } + ) + self.assertFalse( + any( + [ + pricelist_item.product_id, + pricelist_item.product_tmpl_id, + pricelist_item.categ_id, + ] + ) + ) + pricelist_item.write( + {"applied_on": "0_product_variant", "product_id": self.product.id} + ) + self.assertFalse(pricelist_item.product_brand_id) + pricelist_item.write( + {"applied_on": "25_brand", "product_brand_id": self.product_brand.id} + ) + self.assertFalse(pricelist_item.product_id) + pricelist_item.write( + { + "applied_on": "1_product", + "product_tmpl_id": self.product.product_tmpl_id.id, + } + ) + self.assertFalse(pricelist_item.product_brand_id) + pricelist_item.write( + {"applied_on": "25_brand", "product_brand_id": self.product_brand.id} + ) + self.assertFalse(pricelist_item.product_tmpl_id) + pricelist_item.write( + {"applied_on": "2_product_category", "categ_id": self.product.categ_id.id} + ) + self.assertFalse(pricelist_item.product_brand_id) + pricelist_item.write( + {"applied_on": "25_brand", "product_brand_id": self.product_brand.id} + ) + self.assertFalse(pricelist_item.categ_id) + pricelist_item.write({"applied_on": "3_global"}) + self.assertFalse(pricelist_item.product_brand_id) + + def test_calculation_price_of_products_pricelist(self): + """Test calculation of product price based on pricelist""" + context = {} + context.update({"pricelist": self.pricelist.id, "quantity": 1}) + + # Check sale price of branded product + product_with_context = self.product.with_context(context) + self.assertEqual( + float_compare( + product_with_context.price, + ( + product_with_context.lst_price + - product_with_context.lst_price * (0.10) + ), + precision_digits=2, + ), + 0, + ) + + # Check sale price of not branded product (should not change) + product_2_with_context = self.product_2.with_context(context) + self.assertEqual( + float_compare( + product_2_with_context.price, + product_2_with_context.lst_price, + precision_digits=2, + ), + 0, + ) diff --git a/pricelist_brand/views/product_pricelist.xml b/pricelist_brand/views/product_pricelist.xml new file mode 100644 index 000000000..f35812258 --- /dev/null +++ b/pricelist_brand/views/product_pricelist.xml @@ -0,0 +1,21 @@ + + + + + product.pricelist.item.form (in pricelist_brand) + product.pricelist.item + + + + + + + + From f9e113092ec49297f3e45799b654315e7fe7def7 Mon Sep 17 00:00:00 2001 From: oca-travis Date: Mon, 14 Mar 2022 18:23:00 +0000 Subject: [PATCH 2/8] [UPD] Update pricelist_brand.pot --- pricelist_brand/i18n/pricelist_brand.pot | 59 ++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 pricelist_brand/i18n/pricelist_brand.pot diff --git a/pricelist_brand/i18n/pricelist_brand.pot b/pricelist_brand/i18n/pricelist_brand.pot new file mode 100644 index 000000000..adeea94d4 --- /dev/null +++ b/pricelist_brand/i18n/pricelist_brand.pot @@ -0,0 +1,59 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * pricelist_brand +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.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: pricelist_brand +#: model:ir.model.fields,field_description:pricelist_brand.field_product_pricelist_item__applied_on +msgid "Apply On" +msgstr "" + +#. module: pricelist_brand +#: model:ir.model.fields,field_description:pricelist_brand.field_product_pricelist_item__product_brand_id +#: model:ir.model.fields.selection,name:pricelist_brand.selection__product_pricelist_item__applied_on__25_brand +msgid "Brand" +msgstr "" + +#. module: pricelist_brand +#: code:addons/pricelist_brand/models/product_pricelist.py:0 +#, python-format +msgid "Brand: %s" +msgstr "" + +#. module: pricelist_brand +#: code:addons/pricelist_brand/models/product_pricelist.py:0 +#, python-format +msgid "Please specify the brand for which this rule should be applied" +msgstr "" + +#. module: pricelist_brand +#: model:ir.model,name:pricelist_brand.model_product_pricelist +msgid "Pricelist" +msgstr "" + +#. module: pricelist_brand +#: model:ir.model.fields,help:pricelist_brand.field_product_pricelist_item__applied_on +msgid "Pricelist Item applicable on selected option" +msgstr "" + +#. module: pricelist_brand +#: model:ir.model,name:pricelist_brand.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "" + +#. module: pricelist_brand +#: model:ir.model.fields,help:pricelist_brand.field_product_pricelist_item__product_brand_id +msgid "" +"Specify a brand if this rule only applies to productsbelonging to this " +"brand. Keep empty otherwise." +msgstr "" From 39346886855cdc2aca1412c026b385b5a271af0e Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Mon, 14 Mar 2022 18:32:00 +0000 Subject: [PATCH 3/8] [UPD] README.rst --- pricelist_brand/static/description/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pricelist_brand/static/description/index.html b/pricelist_brand/static/description/index.html index 8afe62118..cae8eea1b 100644 --- a/pricelist_brand/static/description/index.html +++ b/pricelist_brand/static/description/index.html @@ -3,7 +3,7 @@ - + Pricelist Brand -
-

Pricelist Brand

+
+ + +Odoo Community Association + +
+

Pricelist Brand

-

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

-

This module allows to configure pricelist items so that they are applied on products of specific brands.

+

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

+

This module allows to configure pricelist items so that they are applied +on products of specific brands.

Table of contents

    @@ -386,41 +391,44 @@

    Pricelist Brand

-

Usage

+

Usage

To apply pricelist items on branded products:

    -
  1. See ‘product_brand’ module to learn how to configure brands on products.
  2. -
  3. Go to Sales > Pricelists and open the pricelist of your choice or create a new one.
  4. +
  5. See ‘product_brand’ module to learn how to configure brands on +products.
  6. +
  7. Go to Sales > Pricelists and open the pricelist of your choice or +create a new one.
  8. Edit the pricelist and add a new item to it.
  9. Select Brand in the field Applied On.
  10. Select the product brand of your choice in the field Brand.
  11. -
  12. Configure the rest of the rule the way you want, this rule will apply on any product from the brand you selected.
  13. +
  14. Configure the rest of the rule the way you want, this rule will apply +on any product from the brand you selected.
-

Bug Tracker

+

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.

+feedback.

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

-

Credits

+

Credits

-

Authors

+

Authors

  • ACSONE SA/NV
-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association @@ -428,10 +436,11 @@

Maintainers

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

+

This module is part of the OCA/brand project on GitHub.

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

+
From 7446e5ff6c3100bef7974e5d1dc8fc9bad6c47e9 Mon Sep 17 00:00:00 2001 From: AlexGarS73 Date: Tue, 24 Mar 2026 16:26:03 +0100 Subject: [PATCH 7/8] [MIG] pricelist_brand: Migration to 19.0 --- pricelist_brand/README.rst | 1 + pricelist_brand/__manifest__.py | 2 +- pricelist_brand/models/product_pricelist.py | 83 ++++++++++++------- pricelist_brand/readme/CONTRIBUTORS.md | 1 + pricelist_brand/static/description/index.html | 1 + .../tests/test_product_pricelist.py | 30 +++++-- pricelist_brand/views/product_pricelist.xml | 9 +- 7 files changed, 84 insertions(+), 43 deletions(-) diff --git a/pricelist_brand/README.rst b/pricelist_brand/README.rst index 64c3d7d7a..053008000 100644 --- a/pricelist_brand/README.rst +++ b/pricelist_brand/README.rst @@ -77,6 +77,7 @@ Contributors ------------ - Quentin Groulard +- Alex Garcia Maintainers ----------- diff --git a/pricelist_brand/__manifest__.py b/pricelist_brand/__manifest__.py index 49fdd4771..12b376758 100644 --- a/pricelist_brand/__manifest__.py +++ b/pricelist_brand/__manifest__.py @@ -4,7 +4,7 @@ { "name": "Pricelist Brand", "summary": """This module allows to apply pricelist items on brand""", - "version": "16.0.1.0.0", + "version": "19.0.1.0.0", "license": "AGPL-3", "author": "ACSONE SA/NV,Odoo Community Association (OCA)", "website": "https://github.com/OCA/brand", diff --git a/pricelist_brand/models/product_pricelist.py b/pricelist_brand/models/product_pricelist.py index d73009184..c57542b63 100644 --- a/pricelist_brand/models/product_pricelist.py +++ b/pricelist_brand/models/product_pricelist.py @@ -1,16 +1,16 @@ # Copyright 2020 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import _, api, fields, models +from odoo import api, fields, models from odoo.exceptions import ValidationError -from odoo.osv import expression +from odoo.fields import Domain class ProductPricelist(models.Model): _inherit = "product.pricelist" def _get_applicable_rules_domain(self, products, date, **kwargs): - res = super()._get_applicable_rules_domain(products, date) + res = super()._get_applicable_rules_domain(products, date, **kwargs) if products._name == "product.template": brand_domain = ("product_brand_id", "in", products.product_brand_id.ids) else: @@ -19,7 +19,7 @@ def _get_applicable_rules_domain(self, products, date, **kwargs): "in", products.product_tmpl_id.product_brand_id.ids, ) - res = expression.AND( + res = Domain.AND( [ res, [ @@ -45,38 +45,63 @@ class ProductPricelistItem(models.Model): applied_on = fields.Selection( selection_add=[("25_brand", "Brand")], ondelete={"25_brand": "set default"} ) + display_applied_on = fields.Selection( + selection_add=[("25_brand", "Brand")], ondelete={"25_brand": "set default"} + ) + + def _is_applicable_for(self, product, qty_in_product_uom): + res = super()._is_applicable_for(product, qty_in_product_uom) + if not res: + return False + if self.applied_on == "25_brand": + if product._name == "product.template": + return product.product_brand_id == self.product_brand_id + return product.product_tmpl_id.product_brand_id == self.product_brand_id + return res @api.constrains("product_id", "product_tmpl_id", "categ_id", "product_brand_id") def _check_product_consistency(self): for item in self: if item.applied_on == "25_brand" and not item.product_brand_id: raise ValidationError( - _("Please specify the brand for which this rule should be applied") + self.env._( + "Please specify the brand for which this rule should be applied" + ) ) return super()._check_product_consistency() @api.depends( - "applied_on", - "categ_id", - "product_tmpl_id", - "product_id", - "compute_price", - "fixed_price", - "pricelist_id", - "percent_price", - "price_discount", - "price_surcharge", + "applied_on", "categ_id", "product_tmpl_id", "product_id", "product_brand_id" ) - def _compute_name_and_price(self): - res = super()._compute_name_and_price() + def _compute_name(self): + res = super()._compute_name() for item in self: if item.product_brand_id and item.applied_on == "25_brand": - item.name = _("Brand: %s") % (item.product_brand_id.display_name) + item.name = self.env._("Brand: %s", item.product_brand_id.display_name) + return res + + @api.onchange("display_applied_on") + def _onchange_display_applied_on(self): + res = super()._onchange_display_applied_on() + for item in self: + if item.display_applied_on == "25_brand": + item.update( + { + "product_id": False, + "product_tmpl_id": False, + "categ_id": False, + "applied_on": "25_brand", + } + ) return res @api.onchange("product_id", "product_tmpl_id", "categ_id", "product_brand_id") def _onchange_rule_content(self): - return super()._onchange_rule_content() + res = super()._onchange_rule_content() + for item in self: + if item.product_brand_id: + item.applied_on = "25_brand" + return res @api.model_create_multi def create(self, vals_list): @@ -86,16 +111,16 @@ def create(self, vals_list): applied_on = values["applied_on"] if applied_on == "25_brand": values.update( - dict(product_id=None, product_tmpl_id=None, categ_id=None) + dict(product_id=False, product_tmpl_id=False, categ_id=False) ) elif applied_on == "3_global": - values.update(dict(product_brand_id=None)) + values.update(dict(product_brand_id=False)) elif applied_on == "2_product_category": - values.update(dict(product_brand_id=None)) + values.update(dict(product_brand_id=False)) elif applied_on == "1_product": - values.update(dict(product_brand_id=None)) + values.update(dict(product_brand_id=False)) elif applied_on == "0_product_variant": - values.update(dict(product_brand_id=None)) + values.update(dict(product_brand_id=False)) return super().create(vals_list) def write(self, values): @@ -104,14 +129,14 @@ def write(self, values): applied_on = values["applied_on"] if applied_on == "25_brand": values.update( - dict(product_id=None, product_tmpl_id=None, categ_id=None) + dict(product_id=False, product_tmpl_id=False, categ_id=False) ) elif applied_on == "3_global": - values.update(dict(product_brand_id=None)) + values.update(dict(product_brand_id=False)) elif applied_on == "2_product_category": - values.update(dict(product_brand_id=None)) + values.update(dict(product_brand_id=False)) elif applied_on == "1_product": - values.update(dict(product_brand_id=None)) + values.update(dict(product_brand_id=False)) elif applied_on == "0_product_variant": - values.update(dict(product_brand_id=None)) + values.update(dict(product_brand_id=False)) return super().write(values) diff --git a/pricelist_brand/readme/CONTRIBUTORS.md b/pricelist_brand/readme/CONTRIBUTORS.md index 81fc965b6..cbee58924 100644 --- a/pricelist_brand/readme/CONTRIBUTORS.md +++ b/pricelist_brand/readme/CONTRIBUTORS.md @@ -1 +1,2 @@ - Quentin Groulard \ +- Alex Garcia \ diff --git a/pricelist_brand/static/description/index.html b/pricelist_brand/static/description/index.html index 2a88bcede..465aec0a2 100644 --- a/pricelist_brand/static/description/index.html +++ b/pricelist_brand/static/description/index.html @@ -425,6 +425,7 @@

Authors

Contributors

diff --git a/pricelist_brand/tests/test_product_pricelist.py b/pricelist_brand/tests/test_product_pricelist.py index b9ba6c952..4626ce49d 100644 --- a/pricelist_brand/tests/test_product_pricelist.py +++ b/pricelist_brand/tests/test_product_pricelist.py @@ -1,7 +1,6 @@ # Copyright 2020 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import _ from odoo.exceptions import ValidationError from odoo.tests.common import TransactionCase from odoo.tools import float_compare @@ -15,11 +14,26 @@ def setUpClass(cls): cls.product_brand = cls.env["product.brand"].create( {"name": "Test Brand", "description": "Test brand description"} ) - cls.product = cls.env.ref("product.product_product_4") - cls.product.write({"product_brand_id": cls.product_brand.id}) - cls.product_2 = cls.env.ref("product.product_product_5") + cls.product_categ = cls.env["product.category"].create( + {"name": "Test Category"} + ) + cls.product = cls.env["product.product"].create( + { + "name": "Test Product 1", + "lst_price": 100.0, + "product_brand_id": cls.product_brand.id, + "categ_id": cls.product_categ.id, + } + ) + cls.product_2 = cls.env["product.product"].create( + { + "name": "Test Product 2", + "lst_price": 200.0, + "categ_id": cls.product_categ.id, + } + ) - cls.list0 = cls.env.ref("product.list0") + cls.list0 = cls.env["product.pricelist"].create({"name": "Public Pricelist"}) cls.pricelist = cls.env["product.pricelist"].create( { "name": "Test Pricelist", @@ -49,7 +63,6 @@ def setUpClass(cls): ], } ) - cls.product_categ = cls.env.ref("product.product_category_2") def test_ensure_pricelist_item_consistency(self): with self.assertRaises(ValidationError): @@ -71,9 +84,10 @@ def test_ensure_pricelist_item_consistency(self): } ) pricelist_item.write({"product_brand_id": self.product_brand.id}) - pricelist_item._compute_name_and_price() + pricelist_item._compute_name() self.assertEqual( - pricelist_item.name, _("Brand: %s") % (self.product_brand.display_name) + pricelist_item.name, + self.env._("Brand: %s", self.product_brand.display_name), ) pricelist_item_2 = self.env["product.pricelist.item"].create( { diff --git a/pricelist_brand/views/product_pricelist.xml b/pricelist_brand/views/product_pricelist.xml index f35812258..e59bae4f1 100644 --- a/pricelist_brand/views/product_pricelist.xml +++ b/pricelist_brand/views/product_pricelist.xml @@ -7,13 +7,12 @@ product.pricelist.item - + From cbff23aade66b919ea56583e6e703e47a2fcb396 Mon Sep 17 00:00:00 2001 From: Thomas Binsfeld Date: Wed, 1 Apr 2026 15:09:34 +0200 Subject: [PATCH 8/8] [MIG] pricelist_brand (backport from 19.0) --- pricelist_brand/README.rst | 21 ++++++------- pricelist_brand/__manifest__.py | 2 +- pricelist_brand/models/product_pricelist.py | 4 +-- pricelist_brand/readme/CONTRIBUTORS.md | 1 + pricelist_brand/static/description/index.html | 31 ++++++++----------- 5 files changed, 26 insertions(+), 33 deletions(-) diff --git a/pricelist_brand/README.rst b/pricelist_brand/README.rst index 053008000..f5b8f63f6 100644 --- a/pricelist_brand/README.rst +++ b/pricelist_brand/README.rst @@ -1,7 +1,3 @@ -.. image:: https://odoo-community.org/readme-banner-image - :target: https://odoo-community.org/get-involved?utm_source=readme - :alt: Odoo Community Association - =============== Pricelist Brand =============== @@ -17,17 +13,17 @@ Pricelist Brand .. |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/license-AGPL--3-blue.png +.. |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%2Fbrand-lightgray.png?logo=github - :target: https://github.com/OCA/brand/tree/19.0/pricelist_brand + :target: https://github.com/OCA/brand/tree/18.0/pricelist_brand :alt: OCA/brand .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/brand-19-0/brand-19-0-pricelist_brand + :target: https://translation.odoo-community.org/projects/brand-18-0/brand-18-0-pricelist_brand :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/brand&target_branch=19.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/brand&target_branch=18.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -61,7 +57,7 @@ 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 `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -76,8 +72,9 @@ Authors Contributors ------------ -- Quentin Groulard -- Alex Garcia +- Quentin Groulard +- Alex Garcia +- Thomas Binsfeld Maintainers ----------- @@ -92,6 +89,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/brand `_ project on GitHub. +This module is part of the `OCA/brand `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/pricelist_brand/__manifest__.py b/pricelist_brand/__manifest__.py index 12b376758..127682368 100644 --- a/pricelist_brand/__manifest__.py +++ b/pricelist_brand/__manifest__.py @@ -4,7 +4,7 @@ { "name": "Pricelist Brand", "summary": """This module allows to apply pricelist items on brand""", - "version": "19.0.1.0.0", + "version": "18.0.1.0.0", "license": "AGPL-3", "author": "ACSONE SA/NV,Odoo Community Association (OCA)", "website": "https://github.com/OCA/brand", diff --git a/pricelist_brand/models/product_pricelist.py b/pricelist_brand/models/product_pricelist.py index c57542b63..c78b80f0c 100644 --- a/pricelist_brand/models/product_pricelist.py +++ b/pricelist_brand/models/product_pricelist.py @@ -3,7 +3,7 @@ from odoo import api, fields, models from odoo.exceptions import ValidationError -from odoo.fields import Domain +from odoo.osv import expression class ProductPricelist(models.Model): @@ -19,7 +19,7 @@ def _get_applicable_rules_domain(self, products, date, **kwargs): "in", products.product_tmpl_id.product_brand_id.ids, ) - res = Domain.AND( + res = expression.AND( [ res, [ diff --git a/pricelist_brand/readme/CONTRIBUTORS.md b/pricelist_brand/readme/CONTRIBUTORS.md index cbee58924..d90c6ac18 100644 --- a/pricelist_brand/readme/CONTRIBUTORS.md +++ b/pricelist_brand/readme/CONTRIBUTORS.md @@ -1,2 +1,3 @@ - Quentin Groulard \ - Alex Garcia \ +- Thomas Binsfeld \ diff --git a/pricelist_brand/static/description/index.html b/pricelist_brand/static/description/index.html index 465aec0a2..b0ac388cf 100644 --- a/pricelist_brand/static/description/index.html +++ b/pricelist_brand/static/description/index.html @@ -3,7 +3,7 @@ -README.rst +Pricelist Brand -
+
+

Pricelist Brand

- - -Odoo Community Association - -
-

Pricelist Brand

-

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

+

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

This module allows to configure pricelist items so that they are applied on products of specific brands.

Table of contents

@@ -391,7 +386,7 @@

Pricelist Brand

-

Usage

+

Usage

To apply pricelist items on branded products:

  1. See ‘product_brand’ module to learn how to configure brands on @@ -406,30 +401,31 @@

    Usage

-

Bug Tracker

+

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.

+feedback.

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

-

Credits

+

Credits

-

Authors

+

Authors

  • ACSONE SA/NV
-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association @@ -437,11 +433,10 @@

Maintainers

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

+

This module is part of the OCA/brand project on GitHub.

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

-