From 461385654a268a092c8c56f30852cfd4a9ccd0df Mon Sep 17 00:00:00 2001 From: utpat-odoo Date: Tue, 2 Dec 2025 22:28:08 +0530 Subject: [PATCH] [ADD] purchase_discount: add global discount functionality in purchase order Purpose: When you have a big RFQ (with a lot of lines) and you receive a Quote from the vendor with a global discount (% or amount), it's very time consuming to apply it to all lines. Technical changes: Add discount_type, discount_in_value and computed discount_in_percentage fields on purchase.order. Add constraints for validate discount percentage. Add discount button in purchase order view form. Add action_discount to open a popup and apply_discount to apply the global discount on all order lines. Discount can be entered either as a percentage or as a fixed amount. task-5366796 --- purchase_discount/__init__.py | 1 + purchase_discount/__manifest__.py | 15 ++++++ purchase_discount/models/__init__.py | 1 + purchase_discount/models/purchase_order.py | 53 +++++++++++++++++++ .../views/purchase_order_views.xml | 46 ++++++++++++++++ 5 files changed, 116 insertions(+) create mode 100644 purchase_discount/__init__.py create mode 100644 purchase_discount/__manifest__.py create mode 100644 purchase_discount/models/__init__.py create mode 100644 purchase_discount/models/purchase_order.py create mode 100644 purchase_discount/views/purchase_order_views.xml diff --git a/purchase_discount/__init__.py b/purchase_discount/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/purchase_discount/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/purchase_discount/__manifest__.py b/purchase_discount/__manifest__.py new file mode 100644 index 00000000000..27b2e7da02e --- /dev/null +++ b/purchase_discount/__manifest__.py @@ -0,0 +1,15 @@ +{ + 'author': 'Odoo S.A.', + 'name': 'Purchase Discount', + "description": """ + This module introduces a global discount feature for Purchase Orders, + allowing users to apply either value-based or percentage-based discounts. + """, + 'depends': ['purchase'], + 'license': 'LGPL-3', + 'data': [ + 'views/purchase_order_views.xml' + ], + 'application': True, + 'installable': True +} diff --git a/purchase_discount/models/__init__.py b/purchase_discount/models/__init__.py new file mode 100644 index 00000000000..9f03530643d --- /dev/null +++ b/purchase_discount/models/__init__.py @@ -0,0 +1 @@ +from . import purchase_order diff --git a/purchase_discount/models/purchase_order.py b/purchase_discount/models/purchase_order.py new file mode 100644 index 00000000000..88eea5f59c8 --- /dev/null +++ b/purchase_discount/models/purchase_order.py @@ -0,0 +1,53 @@ +from odoo import models, fields, api +from odoo.exceptions import ValidationError +from odoo.tools import _ + + +class PurchaseOrder(models.Model): + _inherit = "purchase.order" + + discount_type = fields.Selection( + selection=[ + ("value", "$"), + ("percentage", "%"), + ], + default="percentage", + ) + discount_in_value = fields.Float(string="Discount") + discount_in_percentage = fields.Float(compute="_compute_discount_percentage", store=True, readonly=True) + + @api.depends("discount_type", "discount_in_value") + def _compute_discount_percentage(self): + for record in self: + if record.discount_type == "value" and record.amount_total > 0: + record.discount_in_percentage = (record.discount_in_value * 100) / (record.amount_total) + elif record.discount_type == "percentage": + record.discount_in_percentage = record.discount_in_value + else: + record.discount_in_percentage = 0.0 + + @api.constrains("discount_in_value", "discount_type", "amount_total") + def _check_discount_price(self): + for record in self: + if record.discount_type == "percentage": + if record.discount_in_value < 0 or record.discount_in_value > 100: + raise ValidationError("discount value is not valid please check again") + if record.discount_type == "value": + if record.discount_in_value < 0 or record.discount_in_value > record.amount_total: + raise ValidationError("discount value is not valid please check again") + + def apply_discount(self): + self.order_line.discount = self.discount_in_percentage + + def action_discount(self): + return { + "type": "ir.actions.act_window", + "name": _("Discount"), + "res_model": "purchase.order", + "view_mode": "form", + "view_id": self.env.ref( + "purchase_discount.view_purchase_order_discount_form" + ).id, + "res_id": self.id, + "target": "new", + } diff --git a/purchase_discount/views/purchase_order_views.xml b/purchase_discount/views/purchase_order_views.xml new file mode 100644 index 00000000000..da5830053da --- /dev/null +++ b/purchase_discount/views/purchase_order_views.xml @@ -0,0 +1,46 @@ + + + + purchase.order.discount.form + purchase.order + 17 + +
+ +
+ +
+ +
+
+ +
+ + (%) + +
+
+
+
+
+
+
+ + + purchase.order.view.form.inherit + purchase.order + + + +
+
+
+
+
+