From 2ed7d8a1fbdedbaa99e0c6d4bd91f28b23610982 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Fri, 14 Apr 2023 15:22:41 +0530 Subject: [PATCH] fix: don't allow `Stock Reconciliation` for items having reserved stock --- .../stock_reconciliation.py | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index 482b103d1e4..484ec71d901 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -47,6 +47,7 @@ class StockReconciliation(StockController): self.validate_putaway_capacity() if self._action == "submit": + self.validate_reserved_stock() self.make_batches("warehouse") def on_submit(self): @@ -60,6 +61,7 @@ class StockReconciliation(StockController): def on_cancel(self): self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry", "Repost Item Valuation") + self.validate_reserved_stock() self.make_sle_on_cancel() self.make_gl_entries_on_cancel() self.repost_future_sle_and_gle() @@ -224,6 +226,46 @@ class StockReconciliation(StockController): except Exception as e: self.validation_messages.append(_("Row #") + " " + ("%d: " % (row.idx)) + cstr(e)) + def validate_reserved_stock(self) -> None: + """Raises an exception if there is any reserved stock for the items in the Stock Reconciliation.""" + + from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import ( + get_sre_reserved_qty_details_for_item_and_warehouse as get_sre_reserved_qty_details, + ) + + item_code_list, warehouse_list = [], [] + for item in self.items: + item_code_list.append(item.item_code) + warehouse_list.append(item.warehouse) + + sre_reserved_qty_details = get_sre_reserved_qty_details(item_code_list, warehouse_list) + + if sre_reserved_qty_details: + data = [] + for (item_code, warehouse), reserved_qty in sre_reserved_qty_details.items(): + data.append([item_code, warehouse, reserved_qty]) + + msg = "" + if len(data) == 1: + msg = _( + "{0} units are reserved for Item {1} in Warehouse {2}, please un-reserve the same to {3} the Stock Reconciliation." + ).format(bold(data[0][2]), bold(data[0][0]), bold(data[0][1]), self._action) + else: + items_html = "" + for d in data: + items_html += "
  • {0} units of Item {1} in Warehouse {2}
  • ".format( + bold(d[2]), bold(d[0]), bold(d[1]) + ) + + msg = _( + "The stock has been reserved for the following Items and Warehouses, un-reserve the same to {0} the Stock Reconciliation:

    {1}" + ).format(self._action, items_html) + + frappe.throw( + msg, + title=_("Stock Reservation"), + ) + def update_stock_ledger(self): """find difference between current and expected entries and create stock ledger entries based on the difference"""