diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 63d2e80888c..76c57ae873d 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -807,43 +807,45 @@ class StockEntry(StockController): 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 0faa600cbc7..d61c8f575cb 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", @@ -530,6 +531,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", @@ -537,8 +545,8 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2025-10-17 18:32:35.829395", - "modified_by": "hello@aerele.in", + "modified": "2025-11-11 11:35:39.864923", + "modified_by": "Administrator", "module": "Stock", "name": "Stock Settings", "owner": "Administrator", @@ -563,4 +571,4 @@ "sort_order": "ASC", "states": [], "track_changes": 1 -} \ No newline at end of file +} diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.py b/erpnext/stock/doctype/stock_settings/stock_settings.py index c05b100b3fc..268d1570b08 100644 --- a/erpnext/stock/doctype/stock_settings/stock_settings.py +++ b/erpnext/stock/doctype/stock_settings/stock_settings.py @@ -67,6 +67,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