diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index b6a979dbc61..9b14616373b 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -1785,7 +1785,9 @@ def create_pick_list(source_name, target_doc=None): doc.purpose = "Delivery" - doc.set_item_locations() + # Only auto-assign serial numbers if not picking manually + if not doc.pick_manually: + doc.set_item_locations() return doc diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js index c72fa864960..252a5d2872f 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.js +++ b/erpnext/stock/doctype/pick_list/pick_list.js @@ -81,6 +81,26 @@ frappe.ui.form.on("Pick List", { }; }); }, + pick_manually: (frm) => { + // Clear auto-assigned serial numbers and related fields when switching to manual picking + if (frm.doc.pick_manually && frm.doc.locations) { + let has_changes = false; + frm.doc.locations.forEach((row) => { + if (row.serial_no || row.batch_no || row.serial_and_batch_bundle) { + row.serial_no = ""; + row.batch_no = ""; + row.serial_and_batch_bundle = ""; + row.picked_qty = 0; + has_changes = true; + } + }); + + if (has_changes) { + frappe.show_alert(__("Cleared auto-assigned serial numbers and batch numbers for manual picking"), 3); + frm.refresh_field("locations"); + } + } + }, set_item_locations: (frm, save) => { if (!(frm.doc.locations && frm.doc.locations.length)) { frappe.msgprint(__("Add items in the Item Locations table")); @@ -273,7 +293,7 @@ frappe.ui.form.on("Pick List", { max_qty_field: "qty", dont_allow_new_row: true, prompt_qty: frm.doc.prompt_qty, - serial_no_field: "not_supported", // doesn't make sense for picklist without a separate field. + serial_no_field: "serial_no", }; const barcode_scanner = new erpnext.utils.BarcodeScanner(opts); barcode_scanner.process_scan(); diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py index f554f4bd140..24fecce135a 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.py +++ b/erpnext/stock/doctype/pick_list/pick_list.py @@ -572,10 +572,16 @@ class PickList(TransactionBase): if not item.item_code: frappe.throw(f"Row #{item.idx}: Item Code is Mandatory") - if not cint( - frappe.get_cached_value("Item", item.item_code, "is_stock_item") - ) and not frappe.db.exists("Product Bundle", {"new_item_code": item.item_code, "disabled": 0}): - continue + + # Check if item is stock item or product bundle + is_stock_item = cint(frappe.get_cached_value("Item", item.item_code, "is_stock_item")) + is_product_bundle = frappe.db.exists("Product Bundle", {"new_item_code": item.item_code, "disabled": 0}) + + # Include non-stock items for delivery purposes, but skip them for warehouse assignment + if not is_stock_item and not is_product_bundle: + # For non-stock items, set warehouse to None and continue processing + item.warehouse = None + item_code = item.item_code reference = item.sales_order_item or item.material_request_item key = (item_code, item.uom, item.warehouse, item.batch_no, reference)