feat: add checkbox to reserve qty on sales return
diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json
index 2abb169..7e2d1c7 100644
--- a/erpnext/selling/doctype/selling_settings/selling_settings.json
+++ b/erpnext/selling/doctype/selling_settings/selling_settings.json
@@ -20,6 +20,7 @@
"editable_price_list_rate",
"validate_selling_price",
"editable_bundle_item_rates",
+ "dont_reserve_sales_order_qty_on_sales_return",
"sales_transactions_settings_section",
"so_required",
"dn_required",
@@ -172,6 +173,12 @@
"fieldname": "enable_discount_accounting",
"fieldtype": "Check",
"label": "Enable Discount Accounting for Selling"
+ },
+ {
+ "default": "0",
+ "fieldname": "dont_reserve_sales_order_qty_on_sales_return",
+ "fieldtype": "Check",
+ "label": "Don't Reserve Sales Order Qty on Sales Return"
}
],
"icon": "fa fa-cog",
@@ -179,7 +186,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2022-05-31 19:39:48.398738",
+ "modified": "2022-06-17 12:30:57.221570",
"modified_by": "Administrator",
"module": "Selling",
"name": "Selling Settings",
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index ce90eec..8dd2d11 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -1064,11 +1064,23 @@
self.assertEqual(dn.items[0].rate, rate)
- def test_reserved_qty(self):
+ def test_reserve_qty_on_sales_return(self):
+ frappe.db.set_single_value("Selling Settings", "dont_reserve_sales_order_qty_on_sales_return", 0)
+ self.reserved_qty_check()
+
+ def test_dont_reserve_qty_on_sales_return(self):
+ frappe.db.set_single_value("Selling Settings", "dont_reserve_sales_order_qty_on_sales_return", 1)
+ self.reserved_qty_check()
+
+ def reserved_qty_check(self):
from erpnext.controllers.sales_and_purchase_return import make_return_doc
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note
from erpnext.stock.stock_balance import get_reserved_qty
+ dont_reserve_qty = frappe.db.get_single_value(
+ "Selling Settings", "dont_reserve_sales_order_qty_on_sales_return"
+ )
+
item = make_item().name
warehouse = "_Test Warehouse - _TC"
qty_to_reserve = 5
@@ -1093,8 +1105,8 @@
returned = frappe.get_doc("Delivery Note", dn_return.name)
returned.update_prevdoc_status()
- # Test that item qty is not reserved on sales return.
- self.assertEqual(get_reserved_qty(item, warehouse), 0)
+ # Test that item qty is not reserved on sales return, if selling setting don't reserve qty is checked.
+ self.assertEqual(get_reserved_qty(item, warehouse), 0 if dont_reserve_qty else qty_to_reserve)
def create_delivery_note(**args):
diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py
index 2f5bac9..fbb5bf8 100644
--- a/erpnext/stock/stock_balance.py
+++ b/erpnext/stock/stock_balance.py
@@ -98,10 +98,6 @@
def get_reserved_qty(item_code, warehouse):
- SalesOrder = DocType("Sales Order")
- SalesOrderItem = DocType("Sales Order Item")
- PackedItem = DocType("Packed Item")
-
def append_open_so_query(q: QueryBuilder, child_table: Table) -> QueryBuilder:
return (
q.inner_join(SalesOrder)
@@ -110,19 +106,29 @@
.where(SalesOrder.status != "Closed")
)
+ SalesOrder = DocType("Sales Order")
+ SalesOrderItem = DocType("Sales Order Item")
+ PackedItem = DocType("Packed Item")
+
+ dont_reserve_qty_on_sales_return = frappe.db.get_single_value(
+ "Selling Settings", "dont_reserve_sales_order_qty_on_sales_return"
+ )
+
tab = (
frappe.qb.from_(SalesOrderItem)
- .select(
- SalesOrderItem.stock_qty.as_("dnpi_qty"),
- SalesOrderItem.qty.as_("so_item_qty"),
- SalesOrderItem.delivered_qty.as_("so_item_delivered_qty"),
- SalesOrderItem.returned_qty.as_("so_item_returned_qty"),
- SalesOrderItem.parent,
- SalesOrderItem.name,
- )
.where(SalesOrderItem.item_code == item_code)
.where(SalesOrderItem.warehouse == warehouse)
)
+ for field, cond in [
+ (SalesOrderItem.stock_qty.as_("dnpi_qty"), 1),
+ (SalesOrderItem.qty.as_("so_item_qty"), 1),
+ (SalesOrderItem.delivered_qty.as_("so_item_delivered_qty"), 1),
+ (SalesOrderItem.returned_qty.as_("so_item_returned_qty"), dont_reserve_qty_on_sales_return),
+ (SalesOrderItem.parent, 1),
+ (SalesOrderItem.name, 1),
+ ]:
+ if cond:
+ tab = tab.select(field)
tab = append_open_so_query(tab, SalesOrderItem)
dnpi = (
@@ -131,28 +137,23 @@
.where(PackedItem.item_code == item_code)
.where(PackedItem.warehouse == warehouse)
)
- dnpi = append_open_so_query(dnpi, PackedItem)
+ append_open_so_query(dnpi, PackedItem)
- qty_queries = {}
- for key, so_item_field in [
- ("so_item_qty", "qty"),
- ("so_item_delivered_qty", "delivered_qty"),
- ("so_item_returned_qty", "returned_qty"),
+ dnpi_parent = frappe.qb.from_(dnpi).select(dnpi.qty.as_("dnpi_qty"))
+ for key, so_item_field, cond in [
+ ("so_item_qty", "qty", 1),
+ ("so_item_delivered_qty", "delivered_qty", 1),
+ ("so_item_returned_qty", "returned_qty", dont_reserve_qty_on_sales_return),
]:
- qty_queries.update(
- {
- key: (
+ if cond:
+ dnpi_parent = dnpi_parent.select(
+ (
frappe.qb.from_(SalesOrderItem)
.select(SalesOrderItem[so_item_field])
.where(SalesOrderItem.name == dnpi.parent_detail_docname)
.where(SalesOrderItem.delivered_by_supplier == 0)
- )
- }
- )
-
- dnpi_parent = frappe.qb.from_(dnpi).select(dnpi.qty.as_("dnpi_qty"))
- for key, query in qty_queries.items():
- dnpi_parent = dnpi_parent.select(query.as_(key))
+ ).as_(key)
+ )
dnpi_parent = dnpi_parent.select(dnpi.parent, dnpi.name)
dnpi_parent = dnpi_parent + tab
@@ -166,7 +167,7 @@
(
dnpi_parent.so_item_qty
- dnpi_parent.so_item_delivered_qty
- - dnpi_parent.so_item_returned_qty
+ - (dnpi_parent.so_item_returned_qty if dont_reserve_qty_on_sales_return else 0)
)
/ dnpi_parent.so_item_qty
)