diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index 15d06e1fe51601a0146a5718f38e39c9e012565a..46fb02f65c24f703913b6681259603addfdd5826 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -1013,7 +1013,7 @@ class SellingController(StockController): "voucher_no": item.get(so_field), "voucher_detail_no": item.so_detail, "warehouse": item.warehouse, - "status": ["in", ["Partially Delivered", "Delivered"]], + "status": ["in", ["Partially Delivered", "Delivered", "Partially Used", "Closed"]], }, order_by="creation", ) diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index 18b89080cbaa13408ea0194338fcb75f5644d256..353b86f052e5e4437a6b600166f3b7afd7357b2c 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -1342,7 +1342,7 @@ class WorkOrder(Document): for name in names: doc = frappe.get_doc("Stock Reservation Entry", name) qty_to_update = 0.0 - if transferred_qty <= 0: + if transferred_qty < 0: continue if transferred_qty > flt(doc.reserved_qty - doc.consumed_qty): @@ -1352,12 +1352,16 @@ class WorkOrder(Document): qty_to_update = transferred_qty transferred_qty = 0.0 - if qty_to_update <= 0: + if qty_to_update < 0: continue doc.db_set("transferred_qty", flt(qty_to_update), update_modified=False) if (doc.has_batch_no or doc.has_serial_no) and doc.reservation_based_on == "Serial and Batch": doc.consume_serial_batch_for_material_transfer(row_wise_serial_batch) + + if doc.transferred_qty >= doc.reserved_qty: + doc.db_set("status", "Closed", update_modified=False) + doc.update_status() doc.update_reserved_stock_in_bin() @@ -2405,7 +2409,7 @@ def get_row_wise_serial_batch(work_order, purpose=None): row_wise_serial_batch = {} for entry in serial_batch_entries: - key = (entry.item_code, entry.warehouse, entry.voucher_detail_no) + key = (entry.item_code, entry.warehouse) if key not in row_wise_serial_batch: row_wise_serial_batch[key] = frappe._dict( { diff --git a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json index e6fef3e0c87577c4f842b131c18f6860ef682819..c3e99c5addde1ec791727fe15ebbea4416f64e4b 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json +++ b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json @@ -172,7 +172,7 @@ "fieldtype": "Select", "label": "Status", "no_copy": 1, - "options": "Draft\nPartially Reserved\nReserved\nPartially Delivered\nDelivered\nCancelled\nClosed", + "options": "Draft\nPartially Reserved\nReserved\nPartially Delivered\nPartially Used\nDelivered\nCancelled\nClosed", "read_only": 1 }, { @@ -344,7 +344,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2025-06-24 00:24:40.394164", + "modified": "2025-08-25 19:48:33.170835", "modified_by": "Administrator", "module": "Stock", "name": "Stock Reservation Entry", diff --git a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py index 02bfbfbc0667e8086f74f8c174d54a37c567b83b..b49ad53f5f2fb52f8947a496a0ec97978c935b2d 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py +++ b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py @@ -47,6 +47,7 @@ class StockReservationEntry(Document): "Partially Reserved", "Reserved", "Partially Delivered", + "Partially Used", "Delivered", "Cancelled", "Closed", @@ -498,7 +499,12 @@ class StockReservationEntry(Document): if self.docstatus == 2: status = "Cancelled" elif self.docstatus == 1: - if self.reserved_qty == (self.delivered_qty or self.transferred_qty or self.consumed_qty): + if self.transferred_qty: + status = "Closed" + if self.transferred_qty < self.reserved_qty: + status = "Partially Used" + + elif self.reserved_qty == (self.delivered_qty or self.consumed_qty): status = "Delivered" elif self.delivered_qty and self.delivered_qty < self.reserved_qty: status = "Partially Delivered" @@ -610,54 +616,19 @@ class StockReservationEntry(Document): def consume_serial_batch_for_material_transfer(self, row_wise_serial_batch): for entry in self.sb_entries: - if entry.reference_for_reservation: - entry.delete() - - qty_to_consume = self.reserved_qty - for (item_code, warehouse, reference_for_reservation), data in row_wise_serial_batch.items(): - if item_code != self.item_code or warehouse != self.warehouse: - continue - - remove_serial_nos = [] - for serial_no in data.serial_nos: - if qty_to_consume <= 0: - break + entry.delivered_qty = 0 - new_row = self.append( - "sb_entries", - { - "serial_no": serial_no, - "qty": -1, - "warehouse": self.warehouse, - "reference_for_reservation": reference_for_reservation, - }, - ) - - new_row.insert() - qty_to_consume -= 1 - remove_serial_nos.append(serial_no) - - for sn in remove_serial_nos: - data.serial_nos.remove(sn) + for entry in self.sb_entries: + for row in row_wise_serial_batch: + data = row_wise_serial_batch[row] - for batch_no, batch_qty in data.batch_nos.items(): - if qty_to_consume <= 0: - break + if entry.serial_no in data.serial_nos: + entry.delivered_qty = 1 - qty = batch_qty if batch_qty <= qty_to_consume else (qty_to_consume) - new_row = self.append( - "sb_entries", - { - "batch_no": batch_no, - "qty": qty * -1, - "warehouse": self.warehouse, - "reference_for_reservation": reference_for_reservation, - }, - ) + elif entry.batch_no in data.batch_nos: + entry.delivered_qty = data.batch_nos[entry.batch_no] - new_row.insert() - qty_to_consume -= qty - data.batch_nos[batch_no] -= qty + entry.db_update() def validate_stock_reservation_settings(voucher: object) -> None: