diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index c4394c066e0..ac5ec434b76 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -948,6 +948,8 @@ class TestPurchaseOrder(FrappeTestCase): # self.assertEqual(po.payment_terms_template, pi.payment_terms_template) compare_payment_schedules(self, po, pi) + @change_settings("Selling Settings", {"maintain_same_sales_rate": 1}) + @change_settings("Buying Settings", {"maintain_same_rate": 1}) def test_internal_transfer_flow(self): from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center from erpnext.accounts.doctype.sales_invoice.sales_invoice import ( @@ -959,9 +961,6 @@ class TestPurchaseOrder(FrappeTestCase): ) from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_purchase_receipt - frappe.db.set_single_value("Selling Settings", "maintain_same_sales_rate", 1) - frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 1) - prepare_data_for_internal_transfer() supplier = "_Test Internal Supplier 2" diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index 05011a6b9d9..34ff799a83c 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -312,13 +312,12 @@ class StatusUpdater(Document): qty_or_amount, ) - role_allowed_to_over_deliver_receive = frappe.db.get_single_value( - "Stock Settings", "role_allowed_to_over_deliver_receive" - ) - role_allowed_to_over_bill = frappe.db.get_single_value( - "Accounts Settings", "role_allowed_to_over_bill" - ) - role = role_allowed_to_over_deliver_receive if qty_or_amount == "qty" else role_allowed_to_over_bill + role = None + if qty_or_amount == "qty": + if args.get("overflow_type") in ("delivery", "receipt"): + role = frappe.get_single_value("Stock Settings", "role_allowed_to_over_deliver_receive") + else: + role = frappe.get_single_value("Accounts Settings", "role_allowed_to_over_bill") overflow_percent = ( (item[args["target_field"]] - item[args["target_ref_field"]]) / item[args["target_ref_field"]] diff --git a/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py b/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py index a6eb18f47bc..b28d5a1b41b 100644 --- a/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py +++ b/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py @@ -1,7 +1,7 @@ # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt import frappe -from frappe.tests.utils import FrappeTestCase +from frappe.tests.utils import FrappeTestCase, change_settings from frappe.utils import add_months, today from erpnext import get_company_currency @@ -91,6 +91,32 @@ class TestBlanketOrder(FrappeTestCase): frappe.db.set_single_value("Buying Settings", "blanket_order_allowance", 10) po.submit() + @change_settings("Selling Settings", {"blanket_order_allowance": 0}) + @change_settings("Buying Settings", {"blanket_order_allowance": 0}) + @change_settings( + "Stock Settings", + {"over_delivery_receipt_allowance": 10, "role_allowed_to_over_deliver_receive": "Stock Manager"}, + ) + def test_stock_over_delivery_role_does_not_bypass_blanket_order_allowance(self): + test_user = frappe.get_doc("User", "test@example.com") + test_user.add_roles("Accounts User", "Stock Manager") + + frappe.clear_cache() + for blanket_order_type, doctype, date_field in ( + ("Selling", "Sales Order", "delivery_date"), + ("Purchasing", "Purchase Order", "schedule_date"), + ): + bo = make_blanket_order(blanket_order_type=blanket_order_type, quantity=100) + frappe.flags.args.doctype = doctype + order = make_order(bo.name) + order.currency = get_company_currency(order.company) + setattr(order, date_field, today()) + order.items[0].qty = 110 + + with self.set_user("test@example.com"): + order.flags.ignore_permissions = True + self.assertRaises(frappe.ValidationError, order.submit) + def test_party_item_code(self): item_doc = make_item("_Test Item 1 for Blanket Order") item_code = item_doc.name diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.json b/erpnext/stock/doctype/stock_settings/stock_settings.json index 58ea8083087..488eefeefc7 100644 --- a/erpnext/stock/doctype/stock_settings/stock_settings.json +++ b/erpnext/stock/doctype/stock_settings/stock_settings.json @@ -131,7 +131,8 @@ "description": "The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.", "fieldname": "over_delivery_receipt_allowance", "fieldtype": "Float", - "label": "Over Delivery/Receipt Allowance (%)" + "label": "Over Delivery/Receipt Allowance (%)", + "non_negative": 1 }, { "default": "Stop", @@ -282,7 +283,8 @@ "description": "The percentage you are allowed to transfer more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed transfer 110 units.", "fieldname": "mr_qty_allowance", "fieldtype": "Float", - "label": "Over Transfer Allowance" + "label": "Over Transfer Allowance", + "non_negative": 1 }, { "default": "0", @@ -446,7 +448,8 @@ "description": "The percentage you are allowed to pick more items in the pick list than the ordered quantity.", "fieldname": "over_picking_allowance", "fieldtype": "Percent", - "label": "Over Picking Allowance" + "label": "Over Picking Allowance", + "non_negative": 1 }, { "default": "1", @@ -528,7 +531,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2026-03-27 22:39:16.812184", + "modified": "2026-08-01 23:35:02.896836", "modified_by": "Administrator", "module": "Stock", "name": "Stock Settings", diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.py b/erpnext/stock/doctype/stock_settings/stock_settings.py index f573c35925b..2924e8c70f9 100644 --- a/erpnext/stock/doctype/stock_settings/stock_settings.py +++ b/erpnext/stock/doctype/stock_settings/stock_settings.py @@ -101,6 +101,7 @@ class StockSettings(Document): ) self.validate_warehouses() + self.validate_over_delivery_receipt_allowance() self.cant_change_valuation_method() self.validate_clean_description_html() self.validate_pending_reposts() @@ -110,6 +111,10 @@ class StockSettings(Document): self.change_precision_for_purchase() self.validate_do_not_use_batchwise_valuation() + def validate_over_delivery_receipt_allowance(self): + if not self.over_delivery_receipt_allowance: + self.role_allowed_to_over_deliver_receive = None + def validate_do_not_use_batchwise_valuation(self): doc_before_save = self.get_doc_before_save() if not doc_before_save: