Skip to content

Commit

Permalink
fix: decrease Delivered Qty in SRE on DN cancel
Browse files Browse the repository at this point in the history
  • Loading branch information
s-aga-r committed Aug 26, 2023
1 parent 460a7b6 commit 8377e42
Showing 1 changed file with 114 additions and 53 deletions.
167 changes: 114 additions & 53 deletions erpnext/stock/doctype/delivery_note/delivery_note.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,8 @@ def on_cancel(self):
self.update_prevdoc_status()
self.update_billing_status()

self.update_stock_reservation_entries()

# Updating stock ledger should always be called after updating prevdoc status,
# because updating reserved qty in bin depends upon updated delivered qty in SO
self.update_stock_ledger()
Expand All @@ -297,64 +299,123 @@ def on_cancel(self):
def update_stock_reservation_entries(self) -> None:
"""Updates Delivered Qty in Stock Reservation Entries."""

# Don't update Delivered Qty on Return or Cancellation.
if self.is_return or self._action == "cancel":
# Don't update Delivered Qty on Return.
if self.is_return:
return

for item in self.get("items"):
# Skip if `Sales Order` or `Sales Order Item` reference is not set.
if not item.against_sales_order or not item.so_detail:
continue

sre_list = frappe.db.get_all(
"Stock Reservation Entry",
{
"docstatus": 1,
"voucher_type": "Sales Order",
"voucher_no": item.against_sales_order,
"voucher_detail_no": item.so_detail,
"warehouse": item.warehouse,
"status": ["not in", ["Delivered", "Cancelled"]],
},
order_by="creation",
)
if self._action == "submit":
for item in self.get("items"):
# Skip if `Sales Order` or `Sales Order Item` reference is not set.
if not item.against_sales_order or not item.so_detail:
continue

# Skip if no Stock Reservation Entries.
if not sre_list:
continue
sre_list = frappe.db.get_all(
"Stock Reservation Entry",
{
"docstatus": 1,
"voucher_type": "Sales Order",
"voucher_no": item.against_sales_order,
"voucher_detail_no": item.so_detail,
"warehouse": item.warehouse,
"status": ["not in", ["Delivered", "Cancelled"]],
},
order_by="creation",
)

available_qty_to_deliver = item.stock_qty
for sre in sre_list:
if available_qty_to_deliver <= 0:
break
# Skip if no Stock Reservation Entries.
if not sre_list:
continue

qty_to_deliver = item.stock_qty
for sre in sre_list:
if qty_to_deliver <= 0:
break

sre_doc = frappe.get_doc("Stock Reservation Entry", sre)

# `Delivered Qty` should be less than or equal to `Reserved Qty`.
qty_can_be_deliver = min((sre_doc.reserved_qty - sre_doc.delivered_qty), qty_to_deliver)

sre_doc.delivered_qty += qty_can_be_deliver
sre_doc.db_update()

if sre_doc.reservation_based_on == "Serial and Batch":
sbb = frappe.get_doc("Serial and Batch Bundle", item.serial_and_batch_bundle)
if sre_doc.has_serial_no:
delivered_serial_nos = [d.serial_no for d in sbb.entries]
for entry in sre_doc.sb_entries:
if entry.serial_no in delivered_serial_nos:
entry.delivered_qty = 1 # Qty will always be 0 or 1 for Serial No.
entry.db_update()
else:
delivered_batch_qty = {d.batch_no: -1 * d.qty for d in sbb.entries}
for entry in sre_doc.sb_entries:
if entry.batch_no in delivered_batch_qty:
entry.delivered_qty += min(
(entry.qty - entry.delivered_qty), delivered_batch_qty[entry.batch_no]
)
entry.db_update()

# Update Stock Reservation Entry `Status` based on `Delivered Qty`.
sre_doc.update_status()

qty_to_deliver -= qty_can_be_deliver

if self._action == "cancel":
for item in self.get("items"):
# Skip if `Sales Order` or `Sales Order Item` reference is not set.
if not item.against_sales_order or not item.so_detail:
continue

sre_list = frappe.db.get_all(
"Stock Reservation Entry",
{
"docstatus": 1,
"voucher_type": "Sales Order",
"voucher_no": item.against_sales_order,
"voucher_detail_no": item.so_detail,
"warehouse": item.warehouse,
"status": ["in", ["Partially Delivered", "Delivered"]],
},
order_by="creation",
)

sre_doc = frappe.get_doc("Stock Reservation Entry", sre)

# `Delivered Qty` should be less than or equal to `Reserved Qty`.
qty_to_be_deliver = min(sre_doc.reserved_qty - sre_doc.delivered_qty, available_qty_to_deliver)

sre_doc.delivered_qty += qty_to_be_deliver
sre_doc.db_update()

if sre_doc.reservation_based_on == "Serial and Batch":
sbb = frappe.get_doc("Serial and Batch Bundle", item.serial_and_batch_bundle)
if sre_doc.has_serial_no:
delivered_serial_nos = [d.serial_no for d in sbb.entries]
for entry in sre_doc.sb_entries:
if entry.serial_no in delivered_serial_nos:
entry.delivered_qty = 1 # Qty will always be 1 for Serial No.
entry.db_update()
else:
delivered_batch_qty = {d.batch_no: -1 * d.qty for d in sbb.entries}
for entry in sre_doc.sb_entries:
if entry.batch_no in delivered_batch_qty:
entry.delivered_qty += min(entry.qty, delivered_batch_qty[entry.batch_no])
entry.db_update()

# Update Stock Reservation Entry `Status` based on `Delivered Qty`.
sre_doc.update_status()

available_qty_to_deliver -= qty_to_be_deliver
# Skip if no Stock Reservation Entries.
if not sre_list:
continue

qty_to_undelivered = item.stock_qty
for sre in sre_list:
if qty_to_undelivered <= 0:
break

sre_doc = frappe.get_doc("Stock Reservation Entry", sre)

# `Qty to Undelivered` should be less than or equal to `Delivered Qty`.
qty_can_be_undelivered = min(sre_doc.delivered_qty, qty_to_undelivered)

sre_doc.delivered_qty -= qty_can_be_undelivered
sre_doc.db_update()

if sre_doc.reservation_based_on == "Serial and Batch":
sbb = frappe.get_doc("Serial and Batch Bundle", item.serial_and_batch_bundle)
if sre_doc.has_serial_no:
serial_nos_to_undelivered = [d.serial_no for d in sbb.entries]
for entry in sre_doc.sb_entries:
if entry.serial_no in serial_nos_to_undelivered:
entry.delivered_qty = 0 # Qty will always be 0 or 1 for Serial No.
entry.db_update()
else:
batch_qty_to_undelivered = {d.batch_no: -1 * d.qty for d in sbb.entries}
for entry in sre_doc.sb_entries:
if entry.batch_no in batch_qty_to_undelivered:
entry.delivered_qty -= min(entry.delivered_qty, batch_qty_to_undelivered[entry.batch_no])
entry.db_update()

# Update Stock Reservation Entry `Status` based on `Delivered Qty`.
sre_doc.update_status()

qty_to_undelivered -= qty_can_be_undelivered

def validate_against_stock_reservation_entries(self):
"""Validates if Stock Reservation Entries are available for the Sales Order Item reference."""
Expand Down

0 comments on commit 8377e42

Please sign in to comment.