diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 932f8a4844e..5906eb36c56 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -875,43 +875,45 @@ class StockEntry(StockController, SubcontractingInwardController): and target to ensure a meaningful transfer is occurring. Raises: - frappe.ValidationError: If warehouses are same and no inventory dimensions differ + frappe.ValidationError: If warehouses are same and no inventory dimensions differ """ - from erpnext.stock.doctype.inventory_dimension.inventory_dimension import get_inventory_dimensions - inventory_dimensions = get_inventory_dimensions() - if self.purpose == "Material Transfer": - for item in self.items: - if cstr(item.s_warehouse) == cstr(item.t_warehouse): - if not inventory_dimensions: - frappe.throw( - _( - "Row #{0}: Source and Target Warehouse cannot be the same for Material Transfer" - ).format(item.idx), - title=_("Invalid Source and Target Warehouse"), - ) - else: - difference_found = False - for dimension in inventory_dimensions: - fieldname = ( - dimension.source_fieldname - if dimension.source_fieldname.startswith("to_") - else f"to_{dimension.source_fieldname}" - ) - if ( - item.get(dimension.source_fieldname) - and item.get(fieldname) - and item.get(dimension.source_fieldname) != item.get(fieldname) - ): - difference_found = True - break - if not difference_found: + if frappe.get_single_value("Stock Settings", "validate_material_transfer_warehouses"): + from erpnext.stock.doctype.inventory_dimension.inventory_dimension import get_inventory_dimensions + + inventory_dimensions = get_inventory_dimensions() + if self.purpose == "Material Transfer": + for item in self.items: + if cstr(item.s_warehouse) == cstr(item.t_warehouse): + if not inventory_dimensions: frappe.throw( _( - "Row #{0}: Source, Target Warehouse and Inventory Dimensions cannot be the exact same for Material Transfer" + "Row #{0}: Source and Target Warehouse cannot be the same for Material Transfer" ).format(item.idx), title=_("Invalid Source and Target Warehouse"), ) + else: + difference_found = False + for dimension in inventory_dimensions: + fieldname = ( + dimension.source_fieldname + if dimension.source_fieldname.startswith("to_") + else f"to_{dimension.source_fieldname}" + ) + if ( + item.get(dimension.source_fieldname) + and item.get(fieldname) + and item.get(dimension.source_fieldname) != item.get(fieldname) + ): + difference_found = True + break + if not difference_found: + frappe.throw( + _( + "Row #{0}: Source, Target Warehouse and Inventory Dimensions cannot be the exact same for Material Transfer" + ).format(item.idx), + title=_("Invalid Source and Target Warehouse"), + ) def get_matched_items(self, item_code): for row in self.items: diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.json b/erpnext/stock/doctype/stock_settings/stock_settings.json index 78210c87447..bd6aa7f2786 100644 --- a/erpnext/stock/doctype/stock_settings/stock_settings.json +++ b/erpnext/stock/doctype/stock_settings/stock_settings.json @@ -36,6 +36,7 @@ "show_barcode_field", "clean_description_html", "allow_internal_transfer_at_arms_length_price", + "validate_material_transfer_warehouses", "serial_and_batch_item_settings_tab", "section_break_7", "allow_existing_serial_no", @@ -538,6 +539,13 @@ "label": "Update Price List Based On", "mandatory_depends_on": "eval: doc.auto_insert_price_list_rate_if_missing", "options": "Rate\nPrice List Rate" + }, + { + "default": "0", + "description": "If enabled, the source and target warehouse in the Material Transfer Stock Entry must be different else an error will be thrown. If inventory dimensions are present, same source and target warehouse can be allowed but atleast any one of the inventory dimension fields must be different.", + "fieldname": "validate_material_transfer_warehouses", + "fieldtype": "Check", + "label": "Validate Material Transfer Warehouses" } ], "icon": "icon-cog", @@ -545,7 +553,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2025-10-23 13:16:10.527190", + "modified": "2025-11-11 11:35:39.864923", "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 2dcb9cd7c1e..a112cd089e2 100644 --- a/erpnext/stock/doctype/stock_settings/stock_settings.py +++ b/erpnext/stock/doctype/stock_settings/stock_settings.py @@ -68,6 +68,7 @@ class StockSettings(Document): update_price_list_based_on: DF.Literal["Rate", "Price List Rate"] use_naming_series: DF.Check use_serial_batch_fields: DF.Check + validate_material_transfer_warehouses: DF.Check valuation_method: DF.Literal["FIFO", "Moving Average", "LIFO"] # end: auto-generated types