fix: SRE `Available Qty to Reserve` for Group Warehouse
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 6e2fb2e..507deae 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -784,6 +784,10 @@
gl_entries.append(self.get_gl_dict(gl_entry, item=item))
def make_sr_entries(self):
+ from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import (
+ get_available_qty_to_reserve,
+ )
+
if not self.get("reserve_stock"):
return
@@ -1021,33 +1025,6 @@
return or_conditions
-@frappe.whitelist()
-def get_available_qty_to_reserve(item_code, warehouse):
- from frappe.query_builder.functions import Sum
-
- from erpnext.stock.utils import get_stock_balance
-
- available_qty = get_stock_balance(item_code, warehouse)
-
- if available_qty:
- sre = frappe.qb.DocType("Stock Reservation Entry")
- reserved_qty = (
- frappe.qb.from_(sre)
- .select(Sum(sre.reserved_qty - sre.delivered_qty))
- .where(
- (sre.docstatus == 1)
- & (sre.item_code == item_code)
- & (sre.warehouse == warehouse)
- & (sre.status.notin(["Delivered", "Cancelled"]))
- )
- ).run()[0][0] or 0.0
-
- if reserved_qty:
- return available_qty - reserved_qty
-
- return available_qty
-
-
def create_repost_item_valuation_entry(args):
args = frappe._dict(args)
repost_entry = frappe.new_doc("Repost Item Valuation")
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 5accaf6..403477b 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -634,9 +634,12 @@
for item in source.get("items"):
if item.name in sre_dict:
- qty_to_deliver = (
- sre_dict[item.name]["reserved_qty"] - sre_dict[item.name]["delivered_qty"]
- ) / item.conversion_factor
+ reserved_qty, delivered_qty, warehouse = (
+ sre_dict[item.name]["reserved_qty"],
+ sre_dict[item.name]["delivered_qty"],
+ sre_dict[item.name]["warehouse"],
+ )
+ qty_to_deliver = (reserved_qty - delivered_qty) / item.conversion_factor
row = frappe.new_doc("Delivery Note Item")
row.against_sales_order = source.name
@@ -650,6 +653,9 @@
row.uom = item.uom
row.conversion_factor = item.conversion_factor
+ if not frappe.get_cached_value("Warehouse", warehouse, "is_group"):
+ row.warehouse = warehouse
+
target.append("items", row)
target.run_method("set_missing_values")
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 efe9979..c470493 100644
--- a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py
+++ b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py
@@ -85,6 +85,38 @@
)
+@frappe.whitelist()
+def get_available_qty_to_reserve(item_code, warehouse):
+ from frappe.query_builder.functions import Sum
+
+ from erpnext.stock.get_item_details import get_bin_details
+
+ available_qty = get_bin_details(item_code, warehouse, include_child_warehouses=True).get(
+ "actual_qty"
+ )
+
+ if available_qty:
+ from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
+
+ warehouses = get_child_warehouses(warehouse)
+ sre = frappe.qb.DocType("Stock Reservation Entry")
+ reserved_qty = (
+ frappe.qb.from_(sre)
+ .select(Sum(sre.reserved_qty - sre.delivered_qty))
+ .where(
+ (sre.docstatus == 1)
+ & (sre.item_code == item_code)
+ & (sre.warehouse.isin(warehouses))
+ & (sre.status.notin(["Delivered", "Cancelled"]))
+ )
+ ).run()[0][0] or 0.0
+
+ if reserved_qty:
+ return available_qty - reserved_qty
+
+ return available_qty
+
+
def get_stock_reservation_entries_for_voucher(
voucher_type: str, voucher_no: str, voucher_detail_no: str = None, fields: list[str] = None
) -> list[dict]: