mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-06 05:39:12 +00:00
feat: add checkbox to reserve qty on sales return
This commit is contained in:
@@ -20,6 +20,7 @@
|
|||||||
"editable_price_list_rate",
|
"editable_price_list_rate",
|
||||||
"validate_selling_price",
|
"validate_selling_price",
|
||||||
"editable_bundle_item_rates",
|
"editable_bundle_item_rates",
|
||||||
|
"dont_reserve_sales_order_qty_on_sales_return",
|
||||||
"sales_transactions_settings_section",
|
"sales_transactions_settings_section",
|
||||||
"so_required",
|
"so_required",
|
||||||
"dn_required",
|
"dn_required",
|
||||||
@@ -172,6 +173,12 @@
|
|||||||
"fieldname": "enable_discount_accounting",
|
"fieldname": "enable_discount_accounting",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Enable Discount Accounting for Selling"
|
"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",
|
"icon": "fa fa-cog",
|
||||||
@@ -179,7 +186,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-05-31 19:39:48.398738",
|
"modified": "2022-06-17 12:30:57.221570",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Selling",
|
"module": "Selling",
|
||||||
"name": "Selling Settings",
|
"name": "Selling Settings",
|
||||||
|
|||||||
@@ -1064,11 +1064,23 @@ class TestDeliveryNote(FrappeTestCase):
|
|||||||
|
|
||||||
self.assertEqual(dn.items[0].rate, rate)
|
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.controllers.sales_and_purchase_return import make_return_doc
|
||||||
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note
|
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note
|
||||||
from erpnext.stock.stock_balance import get_reserved_qty
|
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
|
item = make_item().name
|
||||||
warehouse = "_Test Warehouse - _TC"
|
warehouse = "_Test Warehouse - _TC"
|
||||||
qty_to_reserve = 5
|
qty_to_reserve = 5
|
||||||
@@ -1093,8 +1105,8 @@ class TestDeliveryNote(FrappeTestCase):
|
|||||||
returned = frappe.get_doc("Delivery Note", dn_return.name)
|
returned = frappe.get_doc("Delivery Note", dn_return.name)
|
||||||
returned.update_prevdoc_status()
|
returned.update_prevdoc_status()
|
||||||
|
|
||||||
# Test that item qty is not reserved on sales return.
|
# 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)
|
self.assertEqual(get_reserved_qty(item, warehouse), 0 if dont_reserve_qty else qty_to_reserve)
|
||||||
|
|
||||||
|
|
||||||
def create_delivery_note(**args):
|
def create_delivery_note(**args):
|
||||||
|
|||||||
@@ -98,10 +98,6 @@ def get_balance_qty_from_sle(item_code, warehouse):
|
|||||||
|
|
||||||
|
|
||||||
def get_reserved_qty(item_code, warehouse):
|
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:
|
def append_open_so_query(q: QueryBuilder, child_table: Table) -> QueryBuilder:
|
||||||
return (
|
return (
|
||||||
q.inner_join(SalesOrder)
|
q.inner_join(SalesOrder)
|
||||||
@@ -110,19 +106,29 @@ def get_reserved_qty(item_code, warehouse):
|
|||||||
.where(SalesOrder.status != "Closed")
|
.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 = (
|
tab = (
|
||||||
frappe.qb.from_(SalesOrderItem)
|
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.item_code == item_code)
|
||||||
.where(SalesOrderItem.warehouse == warehouse)
|
.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)
|
tab = append_open_so_query(tab, SalesOrderItem)
|
||||||
|
|
||||||
dnpi = (
|
dnpi = (
|
||||||
@@ -131,28 +137,23 @@ def get_reserved_qty(item_code, warehouse):
|
|||||||
.where(PackedItem.item_code == item_code)
|
.where(PackedItem.item_code == item_code)
|
||||||
.where(PackedItem.warehouse == warehouse)
|
.where(PackedItem.warehouse == warehouse)
|
||||||
)
|
)
|
||||||
dnpi = append_open_so_query(dnpi, PackedItem)
|
append_open_so_query(dnpi, PackedItem)
|
||||||
|
|
||||||
qty_queries = {}
|
dnpi_parent = frappe.qb.from_(dnpi).select(dnpi.qty.as_("dnpi_qty"))
|
||||||
for key, so_item_field in [
|
for key, so_item_field, cond in [
|
||||||
("so_item_qty", "qty"),
|
("so_item_qty", "qty", 1),
|
||||||
("so_item_delivered_qty", "delivered_qty"),
|
("so_item_delivered_qty", "delivered_qty", 1),
|
||||||
("so_item_returned_qty", "returned_qty"),
|
("so_item_returned_qty", "returned_qty", dont_reserve_qty_on_sales_return),
|
||||||
]:
|
]:
|
||||||
qty_queries.update(
|
if cond:
|
||||||
{
|
dnpi_parent = dnpi_parent.select(
|
||||||
key: (
|
(
|
||||||
frappe.qb.from_(SalesOrderItem)
|
frappe.qb.from_(SalesOrderItem)
|
||||||
.select(SalesOrderItem[so_item_field])
|
.select(SalesOrderItem[so_item_field])
|
||||||
.where(SalesOrderItem.name == dnpi.parent_detail_docname)
|
.where(SalesOrderItem.name == dnpi.parent_detail_docname)
|
||||||
.where(SalesOrderItem.delivered_by_supplier == 0)
|
.where(SalesOrderItem.delivered_by_supplier == 0)
|
||||||
)
|
).as_(key)
|
||||||
}
|
)
|
||||||
)
|
|
||||||
|
|
||||||
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))
|
|
||||||
dnpi_parent = dnpi_parent.select(dnpi.parent, dnpi.name)
|
dnpi_parent = dnpi_parent.select(dnpi.parent, dnpi.name)
|
||||||
|
|
||||||
dnpi_parent = dnpi_parent + tab
|
dnpi_parent = dnpi_parent + tab
|
||||||
@@ -166,7 +167,7 @@ def get_reserved_qty(item_code, warehouse):
|
|||||||
(
|
(
|
||||||
dnpi_parent.so_item_qty
|
dnpi_parent.so_item_qty
|
||||||
- dnpi_parent.so_item_delivered_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
|
/ dnpi_parent.so_item_qty
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user