diff --git a/product_pricelist_overcharge_by_amount/README.rst b/product_pricelist_overcharge_by_amount/README.rst new file mode 100644 index 000000000000..3fe7496a4cd4 --- /dev/null +++ b/product_pricelist_overcharge_by_amount/README.rst @@ -0,0 +1,114 @@ +===================================== +Amount overcharge in sales pricelists +===================================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:59e13141ec33e51f7acc923989e89fbd639e502e2010c1369aa684ccac6ce261 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/14.0/product_pricelist_overcharge_by_amount + :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-14-0/product-attribute-14-0-product_pricelist_overcharge_by_amount + :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=14.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows you to add overcharge amount to sales pricelist based on the price result. +You will be able to create multiple rules/options (just the first match will be applied). +This is usefull when you need to add extra charge base on the actual value computed by the pricelist. +For example, based on the product cost I would like to add and extra margin percentage by ranges. So +with this module you could create a regular pricelist by cost and add the overcharge rules to acomplish this. + +**Table of contents** + +.. contents:: + :local: + +Installation +============ + +Although this module doesn't depend technically on **Sales Management**, you +must install it for configuring and seeing the effects of it. + +Configuration +============= + +To configure pricelists with the new feature of this module, you need to: + +#. Go to *Sales > Configuration > Settings* and check + "Pricelists" option and "Advanced price rules (discounts, formulas)" + after that. You must have correct permissions and you must install + **Sales Management** app (sale) to see these settings. +#. Create or edit a Sales Pricelist at *Sales > Products > Pricelists*. +#. Add or edit a pricelist item and check "Overcharge" option in + the new Overcharge section. +#. This will display a new section to add rules based on the computed price, + it will be check by sequence order and apply just the first match. + +Usage +===== + +For checking pricelists in action, you can (with `sale` module installed): + +#. Go to *Sales > Orders > Quotations* +#. Create or edit a quotation. +#. Add a line. +#. Select a product with the criteria to match the pricelist with overcharge. +#. See the proper price appears in the line. + +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 `_: + + * Christian Ramos + +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_pricelist_overcharge_by_amount/__init__.py b/product_pricelist_overcharge_by_amount/__init__.py new file mode 100644 index 000000000000..0650744f6bc6 --- /dev/null +++ b/product_pricelist_overcharge_by_amount/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/product_pricelist_overcharge_by_amount/__manifest__.py b/product_pricelist_overcharge_by_amount/__manifest__.py new file mode 100644 index 000000000000..f976820be1cc --- /dev/null +++ b/product_pricelist_overcharge_by_amount/__manifest__.py @@ -0,0 +1,17 @@ +# Copyright 2024 Binhex - Christian Ramos +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ + "name": "Amount overcharge in sales pricelists", + "summary": "Allows to add/substract amount to the final priceslists price", + "version": "14.0.0.1.0", + "category": "Sales", + "website": "https://github.com/OCA/product-attribute", + "author": "Binhex, Odoo Community Association (OCA)", + "license": "AGPL-3", + "depends": ["product"], + "data": [ + "security/ir.model.access.csv", + "views/product_pricelist_item_views.xml", + ], + "installable": True, +} diff --git a/product_pricelist_overcharge_by_amount/i18n/product_pricelist_overcharge_by_amount.pot b/product_pricelist_overcharge_by_amount/i18n/product_pricelist_overcharge_by_amount.pot new file mode 100644 index 000000000000..60adb51cfc55 --- /dev/null +++ b/product_pricelist_overcharge_by_amount/i18n/product_pricelist_overcharge_by_amount.pot @@ -0,0 +1,201 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_pricelist_overcharge_by_amount +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-09-30 10:54+0000\n" +"PO-Revision-Date: 2024-09-30 10:54+0000\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_pricelist_overcharge_by_amount +#: model:ir.model.fields.selection,name:product_pricelist_overcharge_by_amount.selection__product_pricelist_overcharge_item__applied_on__allways +msgid "Allways" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist_overcharge_item__applied_on +msgid "Apply" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist_item__overcharge +msgid "Apply overcharge to the final price" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields.selection,name:product_pricelist_overcharge_by_amount.selection__product_pricelist_overcharge_item__applied_on__between +msgid "Between" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields.selection,name:product_pricelist_overcharge_by_amount.selection__product_pricelist_overcharge_item__applied_on__bigger +msgid "Bigger/Equal than" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist_overcharge_item__create_uid +msgid "Created by" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist_overcharge_item__create_date +msgid "Created on" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist_overcharge_item__currency_id +msgid "Currency" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model_terms:ir.ui.view,arch_db:product_pricelist_overcharge_by_amount.product_pricelist_overcharge_item_tree_view +msgid "Discount" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist__display_name +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist_item__display_name +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist_overcharge_item__display_name +msgid "Display Name" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields.selection,name:product_pricelist_overcharge_by_amount.selection__product_pricelist_overcharge_item__applied_on__equal +msgid "Equal than" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist__id +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist_item__id +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist_overcharge_item__id +msgid "ID" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist____last_update +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist_item____last_update +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist_overcharge_item____last_update +msgid "Last Modified on" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist_overcharge_item__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist_overcharge_item__write_date +msgid "Last Updated on" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist_overcharge_item__max_price +msgid "Max price" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,help:product_pricelist_overcharge_by_amount.field_product_pricelist_overcharge_item__max_price +msgid "Maximun price to apply the overcharge." +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist_overcharge_item__min_price +msgid "Min price" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,help:product_pricelist_overcharge_by_amount.field_product_pricelist_overcharge_item__min_price +msgid "Minimal price to apply the overcharge." +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,help:product_pricelist_overcharge_by_amount.field_product_pricelist_item__overcharge_item_ids +msgid "Only match prices from the selected supplier" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model_terms:ir.ui.view,arch_db:product_pricelist_overcharge_by_amount.product_pricelist_view_inherit +msgid "Overcharge" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist_overcharge_item__overcharge_discount +msgid "Overcharge Discount" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist_item__overcharge_item_ids +#: model_terms:ir.ui.view,arch_db:product_pricelist_overcharge_by_amount.product_pricelist_overcharge_item_form_view +msgid "Overcharge Items" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model_terms:ir.ui.view,arch_db:product_pricelist_overcharge_by_amount.product_pricelist_overcharge_item_tree_view +msgid "Overcharge Rules" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist_overcharge_item__overcharge_surcharge +msgid "Overcharge Surcharge" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,help:product_pricelist_overcharge_by_amount.field_product_pricelist_overcharge_item__applied_on +msgid "Overcharge applicable on selected option" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model,name:product_pricelist_overcharge_by_amount.model_product_pricelist +msgid "Pricelist" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist_overcharge_item__item_id +msgid "Pricelist Item" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model,name:product_pricelist_overcharge_by_amount.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,field_description:product_pricelist_overcharge_by_amount.field_product_pricelist_overcharge_item__sequence +msgid "Sequence" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields.selection,name:product_pricelist_overcharge_by_amount.selection__product_pricelist_overcharge_item__applied_on__smaller +msgid "Smaller/Equal than" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model.fields,help:product_pricelist_overcharge_by_amount.field_product_pricelist_overcharge_item__overcharge_surcharge +msgid "" +"Specify the fixed amount to add or subtract(if negative) to the result " +"amount" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model_terms:ir.ui.view,arch_db:product_pricelist_overcharge_by_amount.product_pricelist_overcharge_item_tree_view +msgid "Surcharge" +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: code:addons/product_pricelist_overcharge_by_amount/models/product_pricelist.py:0 +#, python-format +msgid "The minimum price should be lower than the maximum price." +msgstr "" + +#. module: product_pricelist_overcharge_by_amount +#: model:ir.model,name:product_pricelist_overcharge_by_amount.model_product_pricelist_overcharge_item +msgid "product.pricelist.overcharge.item" +msgstr "" diff --git a/product_pricelist_overcharge_by_amount/models/__init__.py b/product_pricelist_overcharge_by_amount/models/__init__.py new file mode 100644 index 000000000000..efc8f0fa5e6c --- /dev/null +++ b/product_pricelist_overcharge_by_amount/models/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import product_pricelist diff --git a/product_pricelist_overcharge_by_amount/models/product_pricelist.py b/product_pricelist_overcharge_by_amount/models/product_pricelist.py new file mode 100644 index 000000000000..c7667c92c7c7 --- /dev/null +++ b/product_pricelist_overcharge_by_amount/models/product_pricelist.py @@ -0,0 +1,139 @@ +# Copyright 2024 Binhex - Christian Ramos +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError +from odoo.tools import float_compare, float_round + + +class ProductPricelist(models.Model): + _inherit = "product.pricelist" + + def _compute_price_rule(self, products_qty_partner, date=False, uom_id=False): + """Apply overcharge to the price when applicable.""" + rule_obj = self.env["product.pricelist.item"] + result = super()._compute_price_rule(products_qty_partner, date, uom_id) + for product, _qty, _partner in products_qty_partner: + rule = rule_obj.browse(result[product.id][1]) + if rule.overcharge: + for overcharge in rule.overcharge_item_ids: + price = result[product.id][0] + if overcharge.can_be_apply(price): + result[product.id] = ( + overcharge.apply_overcharge(price), + rule.id, + ) + break + return result + + +class ProductPricelistItem(models.Model): + _inherit = "product.pricelist.item" + + overcharge = fields.Boolean( + string="Apply overcharge to the final price", + ) + overcharge_item_ids = fields.One2many( + "product.pricelist.overcharge.item", + "item_id", + "Overcharge Items", + help="Only match prices from the selected supplier", + copy=True, + ) + + +class ProductPricelistOverchargeItem(models.Model): + _name = "product.pricelist.overcharge.item" + + sequence = fields.Integer(string="Sequence", default=1) + item_id = fields.Many2one( + "product.pricelist.item", + "Pricelist Item", + ondelete="cascade", + ) + applied_on = fields.Selection( + [ + ("allways", "Allways"), + ("equal", "Equal than"), + ("smaller", "Smaller/Equal than"), + ("bigger", "Bigger/Equal than"), + ("between", "Between"), + ], + "Apply", + default="allways", + required=True, + help="Overcharge applicable on selected option", + ) + min_price = fields.Float( + "Min price", + digits="Product Price", + help="Minimal price to apply the overcharge.", + ) + max_price = fields.Float( + "Max price", + digits="Product Price", + help="Maximun price to apply the overcharge.", + ) + overcharge_surcharge = fields.Float( + "Overcharge Surcharge", + digits="Product Price", + help="Specify the fixed amount to add or subtract(if negative) to the result amount", + ) + overcharge_discount = fields.Float("Overcharge Discount", default=0, digits=(16, 2)) + currency_id = fields.Many2one( + "res.currency", + "Currency", + readonly=True, + related="item_id.currency_id", + store=True, + ) + + @api.constrains("min_price", "max_price") + def _check_margin(self): + if any( + overc_item.applied_on == "between" + and overc_item.min_price > overc_item.max_price + for overc_item in self + ): + raise ValidationError( + _("The minimum price should be lower than the maximum price.") + ) + return True + + def can_be_apply(self, price): + """Check if the overcharge is applicable""" + self.ensure_one() + if hasattr(self, "%s_can_be_apply" % self.applied_on): + return getattr(self, "%s_can_be_apply" % self.applied_on)(price) + + def allways_can_be_apply(self, price): + self.ensure_one() + return True + + def equal_can_be_apply(self, price): + self.ensure_one() + return float_compare(price, self.min_price, self.currency_id.rounding) == 0 + + def smaller_can_be_apply(self, price): + self.ensure_one() + return float_compare(price, self.max_price, self.currency_id.rounding) <= 0 + + def bigger_can_be_apply(self, price): + self.ensure_one() + return float_compare(price, self.min_price, self.currency_id.rounding) >= 0 + + def between_can_be_apply(self, price): + self.ensure_one() + return ( + float_compare(price, self.max_price, self.currency_id.rounding) <= 0 + and float_compare(price, self.min_price, self.currency_id.rounding) >= 0 + ) + + def apply_overcharge(self, price): + """Apply overcharge""" + self.ensure_one() + price = (price - (price * (self.overcharge_discount / 100))) or 0.0 + if self.item_id.price_round: + price = float_round(price, precision_rounding=self.item_id.price_round) + price += self.overcharge_surcharge + return price diff --git a/product_pricelist_overcharge_by_amount/readme/CONFIGURE.rst b/product_pricelist_overcharge_by_amount/readme/CONFIGURE.rst new file mode 100644 index 000000000000..de18ce5fc1b3 --- /dev/null +++ b/product_pricelist_overcharge_by_amount/readme/CONFIGURE.rst @@ -0,0 +1,11 @@ +To configure pricelists with the new feature of this module, you need to: + +#. Go to *Sales > Configuration > Settings* and check + "Pricelists" option and "Advanced price rules (discounts, formulas)" + after that. You must have correct permissions and you must install + **Sales Management** app (sale) to see these settings. +#. Create or edit a Sales Pricelist at *Sales > Products > Pricelists*. +#. Add or edit a pricelist item and check "Overcharge" option in + the new Overcharge section. +#. This will display a new section to add rules based on the computed price, + it will be check by sequence order and apply just the first match. diff --git a/product_pricelist_overcharge_by_amount/readme/CONTRIBUTORS.rst b/product_pricelist_overcharge_by_amount/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000000..3453d7cc3eac --- /dev/null +++ b/product_pricelist_overcharge_by_amount/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* `Binhex `_: + + * Christian Ramos diff --git a/product_pricelist_overcharge_by_amount/readme/DESCRIPTION.rst b/product_pricelist_overcharge_by_amount/readme/DESCRIPTION.rst new file mode 100644 index 000000000000..6b9e5da13bd1 --- /dev/null +++ b/product_pricelist_overcharge_by_amount/readme/DESCRIPTION.rst @@ -0,0 +1,5 @@ +This module allows you to add overcharge amount to sales pricelist based on the price result. +You will be able to create multiple rules/options (just the first match will be applied). +This is usefull when you need to add extra charge base on the actual value computed by the pricelist. +For example, based on the product cost I would like to add and extra margin percentage by ranges. So +with this module you could create a regular pricelist by cost and add the overcharge rules to acomplish this. diff --git a/product_pricelist_overcharge_by_amount/readme/INSTALL.rst b/product_pricelist_overcharge_by_amount/readme/INSTALL.rst new file mode 100644 index 000000000000..6e98804bdeba --- /dev/null +++ b/product_pricelist_overcharge_by_amount/readme/INSTALL.rst @@ -0,0 +1,2 @@ +Although this module doesn't depend technically on **Sales Management**, you +must install it for configuring and seeing the effects of it. diff --git a/product_pricelist_overcharge_by_amount/readme/USAGE.rst b/product_pricelist_overcharge_by_amount/readme/USAGE.rst new file mode 100644 index 000000000000..db2f77c8c28f --- /dev/null +++ b/product_pricelist_overcharge_by_amount/readme/USAGE.rst @@ -0,0 +1,7 @@ +For checking pricelists in action, you can (with `sale` module installed): + +#. Go to *Sales > Orders > Quotations* +#. Create or edit a quotation. +#. Add a line. +#. Select a product with the criteria to match the pricelist with overcharge. +#. See the proper price appears in the line. diff --git a/product_pricelist_overcharge_by_amount/security/ir.model.access.csv b/product_pricelist_overcharge_by_amount/security/ir.model.access.csv new file mode 100644 index 000000000000..88173175df50 --- /dev/null +++ b/product_pricelist_overcharge_by_amount/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_product_pricelist_overcharge_item_user,product.pricelist.overcharge.item.user,model_product_pricelist_overcharge_item,base.group_user,1,0,0,0 +access_product_pricelist_overcharge_item_manager,product.pricelist.overcharge.item.manager,model_product_pricelist_overcharge_item,base.group_system,1,1,1,1 diff --git a/product_pricelist_overcharge_by_amount/static/description/icon.png b/product_pricelist_overcharge_by_amount/static/description/icon.png new file mode 100644 index 000000000000..3a0328b516c4 Binary files /dev/null and b/product_pricelist_overcharge_by_amount/static/description/icon.png differ diff --git a/product_pricelist_overcharge_by_amount/static/description/index.html b/product_pricelist_overcharge_by_amount/static/description/index.html new file mode 100644 index 000000000000..90eee6c6a9a0 --- /dev/null +++ b/product_pricelist_overcharge_by_amount/static/description/index.html @@ -0,0 +1,464 @@ + + + + + +Amount overcharge in sales pricelists + + + +
+

Amount overcharge in sales pricelists

+ + +

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

+

This module allows you to add overcharge amount to sales pricelist based on the price result. +You will be able to create multiple rules/options (just the first match will be applied). +This is usefull when you need to add extra charge base on the actual value computed by the pricelist. +For example, based on the product cost I would like to add and extra margin percentage by ranges. So +with this module you could create a regular pricelist by cost and add the overcharge rules to acomplish this.

+

Table of contents

+ +
+

Installation

+

Although this module doesn’t depend technically on Sales Management, you +must install it for configuring and seeing the effects of it.

+
+
+

Configuration

+

To configure pricelists with the new feature of this module, you need to:

+
    +
  1. Go to Sales > Configuration > Settings and check +“Pricelists” option and “Advanced price rules (discounts, formulas)” +after that. You must have correct permissions and you must install +Sales Management app (sale) to see these settings.
  2. +
  3. Create or edit a Sales Pricelist at Sales > Products > Pricelists.
  4. +
  5. Add or edit a pricelist item and check “Overcharge” option in +the new Overcharge section.
  6. +
  7. This will display a new section to add rules based on the computed price, +it will be check by sequence order and apply just the first match.
  8. +
+
+
+

Usage

+

For checking pricelists in action, you can (with sale module installed):

+
    +
  1. Go to Sales > Orders > Quotations
  2. +
  3. Create or edit a quotation.
  4. +
  5. Add a line.
  6. +
  7. Select a product with the criteria to match the pricelist with overcharge.
  8. +
  9. See the proper price appears in the line.
  10. +
+
+
+

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:
      +
    • Christian Ramos
    • +
    +
  • +
+
+
+

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_pricelist_overcharge_by_amount/tests/__init__.py b/product_pricelist_overcharge_by_amount/tests/__init__.py new file mode 100644 index 000000000000..c66d07b019e8 --- /dev/null +++ b/product_pricelist_overcharge_by_amount/tests/__init__.py @@ -0,0 +1 @@ +from . import test_product_pricelist_overcharge diff --git a/product_pricelist_overcharge_by_amount/tests/test_product_pricelist_overcharge.py b/product_pricelist_overcharge_by_amount/tests/test_product_pricelist_overcharge.py new file mode 100644 index 000000000000..fa6a74578f58 --- /dev/null +++ b/product_pricelist_overcharge_by_amount/tests/test_product_pricelist_overcharge.py @@ -0,0 +1,169 @@ +# Copyright 2024 Binhex - Christian Ramos +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from odoo.exceptions import ValidationError +from odoo.tests import SavepointCase, tagged + + +@tagged("post_install", "-at_install") +class TestPricelistOvercharge(SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.product = cls.env["product.product"].create( + {"name": "Product Test", "standard_price": 15, "list_price": 35} + ) + cls.pricelist = cls.env["product.pricelist"].create( + { + "name": "Overcharge Pricelist", + "item_ids": [ + ( + 0, + 0, + { + "compute_price": "fixed", + "price_round": 0.01, + "fixed_price": 30, + "price_discount": 0, + "overcharge": True, + "overcharge_item_ids": [ + ( + 0, + 0, + { + "applied_on": "equal", + "min_price": 30, + "overcharge_discount": -10, + "overcharge_surcharge": 10, + }, + ), + ( + 0, + 0, + { + "applied_on": "smaller", + "max_price": 70, + "overcharge_discount": -20, + "overcharge_surcharge": 20, + }, + ), + ( + 0, + 0, + { + "applied_on": "bigger", + "min_price": 80, + "overcharge_discount": -30, + "overcharge_surcharge": 30, + }, + ), + ( + 0, + 0, + { + "applied_on": "between", + "min_price": 100, + "max_price": 120, + "overcharge_discount": -40, + "overcharge_surcharge": 40, + }, + ), + ( + 0, + 0, + { + "applied_on": "allways", + "overcharge_discount": -50, + "overcharge_surcharge": 50, + }, + ), + ], + }, + ), + ], + } + ) + + def test_pricelist_overcharge(self): + # equal + self.assertAlmostEqual( + self.pricelist.get_product_price(self.product, 1, False), + 43, + ) + self.pricelist.item_ids[0].write( + { + "fixed_price": 60, + } + ) + # smaller + self.assertAlmostEqual( + self.pricelist.get_product_price(self.product, 1, False), + 92.0, + ) + self.pricelist.item_ids[0].write( + { + "fixed_price": 90, + } + ) + # bigger + self.assertAlmostEqual( + self.pricelist.get_product_price(self.product, 1, False), + 147.0, + ) + self.pricelist.item_ids[0].write( + { + "fixed_price": 110, + } + ) + # between + self.assertAlmostEqual( + self.pricelist.get_product_price(self.product, 1, False), + 173.0, + ) + self.pricelist.item_ids[0].write( + { + "fixed_price": 75, + } + ) + # allways + self.assertAlmostEqual( + self.pricelist.get_product_price(self.product, 1, False), + 162.5, + ) + + def test_pricelist_overcharge_constraint(self): + with self.assertRaises(ValidationError) as ve: + self.env["product.pricelist"].create( + { + "name": "Overcharge Pricelist", + "item_ids": [ + ( + 0, + 0, + { + "compute_price": "fixed", + "fixed_price": 30, + "price_discount": 0, + "overcharge": True, + "overcharge_item_ids": [ + ( + 0, + 0, + { + "applied_on": "between", + "min_price": 100, + "max_price": 70, + "overcharge_discount": -40, + "overcharge_surcharge": 40, + }, + ), + ], + }, + ), + ], + } + ) + self.assertIn( + "The minimum price should be lower than the maximum price.", + ve.exception.args[0], + ) diff --git a/product_pricelist_overcharge_by_amount/views/product_pricelist_item_views.xml b/product_pricelist_overcharge_by_amount/views/product_pricelist_item_views.xml new file mode 100644 index 000000000000..f12039ba2560 --- /dev/null +++ b/product_pricelist_overcharge_by_amount/views/product_pricelist_item_views.xml @@ -0,0 +1,101 @@ + + + + + product.pricelist.overcharge.item.tree + product.pricelist.overcharge.item + 10 + + + + + + + + + + + + product.pricelist.overcharge.item.form + product.pricelist.overcharge.item + 10 + +
+ + + + + + + + + + +
+
+
+ + + product.pricelist.item.form + product.pricelist.item + + + + + + + + + + + + + product.pricelist.item.tree + product.pricelist.item + + + + + + + + + + product.pricelist.form + product.pricelist + + + + + + + + + +
+
diff --git a/setup/product_pricelist_overcharge_by_amount/odoo/addons/product_pricelist_overcharge_by_amount b/setup/product_pricelist_overcharge_by_amount/odoo/addons/product_pricelist_overcharge_by_amount new file mode 120000 index 000000000000..33bcd8430219 --- /dev/null +++ b/setup/product_pricelist_overcharge_by_amount/odoo/addons/product_pricelist_overcharge_by_amount @@ -0,0 +1 @@ +../../../../product_pricelist_overcharge_by_amount \ No newline at end of file diff --git a/setup/product_pricelist_overcharge_by_amount/setup.py b/setup/product_pricelist_overcharge_by_amount/setup.py new file mode 100644 index 000000000000..28c57bb64031 --- /dev/null +++ b/setup/product_pricelist_overcharge_by_amount/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)