fix: don't allow to deliver/transfer reserved stock
This commit is contained in:
parent
56097807b4
commit
f0acb2049b
@ -179,18 +179,13 @@ def get_stock_reservation_entries_for_voucher(
|
|||||||
|
|
||||||
|
|
||||||
def get_sre_reserved_qty_details_for_item_and_warehouse(
|
def get_sre_reserved_qty_details_for_item_and_warehouse(
|
||||||
item_code: str | list, warehouse: str | list
|
item_code_list: list, warehouse_list: list
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""Returns a dict like {("item_code", "warehouse"): "reserved_qty", ... }."""
|
"""Returns a dict like {("item_code", "warehouse"): "reserved_qty", ... }."""
|
||||||
|
|
||||||
sre_details = {}
|
sre_details = {}
|
||||||
|
|
||||||
if item_code and warehouse:
|
if item_code_list and warehouse_list:
|
||||||
if isinstance(item_code, str):
|
|
||||||
item_code = [item_code]
|
|
||||||
if isinstance(warehouse, str):
|
|
||||||
warehouse = [warehouse]
|
|
||||||
|
|
||||||
sre = frappe.qb.DocType("Stock Reservation Entry")
|
sre = frappe.qb.DocType("Stock Reservation Entry")
|
||||||
sre_data = (
|
sre_data = (
|
||||||
frappe.qb.from_(sre)
|
frappe.qb.from_(sre)
|
||||||
@ -201,8 +196,8 @@ def get_sre_reserved_qty_details_for_item_and_warehouse(
|
|||||||
)
|
)
|
||||||
.where(
|
.where(
|
||||||
(sre.docstatus == 1)
|
(sre.docstatus == 1)
|
||||||
& (sre.item_code.isin(item_code))
|
& (sre.item_code.isin(item_code_list))
|
||||||
& (sre.warehouse.isin(warehouse))
|
& (sre.warehouse.isin(warehouse_list))
|
||||||
& (sre.status.notin(["Delivered", "Cancelled"]))
|
& (sre.status.notin(["Delivered", "Cancelled"]))
|
||||||
)
|
)
|
||||||
.groupby(sre.item_code, sre.warehouse)
|
.groupby(sre.item_code, sre.warehouse)
|
||||||
@ -214,6 +209,27 @@ def get_sre_reserved_qty_details_for_item_and_warehouse(
|
|||||||
return sre_details
|
return sre_details
|
||||||
|
|
||||||
|
|
||||||
|
def get_sre_reserved_qty_for_item_and_warehouse(item_code: str, warehouse: str) -> float:
|
||||||
|
"""Returns `Reserved Qty` for Item and Warehouse combination."""
|
||||||
|
|
||||||
|
reserved_qty = 0.0
|
||||||
|
|
||||||
|
if item_code and warehouse:
|
||||||
|
sre = frappe.qb.DocType("Stock Reservation Entry")
|
||||||
|
return (
|
||||||
|
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(as_list=True)[0][0] or 0.0
|
||||||
|
|
||||||
|
return reserved_qty
|
||||||
|
|
||||||
|
|
||||||
def get_sre_reserved_qty_details_for_voucher(
|
def get_sre_reserved_qty_details_for_voucher(
|
||||||
voucher_type: str, voucher_no: str, voucher_detail_no: str = None
|
voucher_type: str, voucher_no: str, voucher_detail_no: str = None
|
||||||
) -> dict:
|
) -> dict:
|
||||||
|
|||||||
@ -13,6 +13,9 @@ from frappe.utils import cint, cstr, flt, get_link_to_form, getdate, now, nowdat
|
|||||||
|
|
||||||
import erpnext
|
import erpnext
|
||||||
from erpnext.stock.doctype.bin.bin import update_qty as update_bin_qty
|
from erpnext.stock.doctype.bin.bin import update_qty as update_bin_qty
|
||||||
|
from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import (
|
||||||
|
get_sre_reserved_qty_for_item_and_warehouse as get_reserved_stock,
|
||||||
|
)
|
||||||
from erpnext.stock.utils import (
|
from erpnext.stock.utils import (
|
||||||
get_incoming_outgoing_rate_for_cancel,
|
get_incoming_outgoing_rate_for_cancel,
|
||||||
get_or_make_bin,
|
get_or_make_bin,
|
||||||
@ -380,6 +383,7 @@ class update_entries_after(object):
|
|||||||
self.new_items_found = False
|
self.new_items_found = False
|
||||||
self.distinct_item_warehouses = args.get("distinct_item_warehouses", frappe._dict())
|
self.distinct_item_warehouses = args.get("distinct_item_warehouses", frappe._dict())
|
||||||
self.affected_transactions: Set[Tuple[str, str]] = set()
|
self.affected_transactions: Set[Tuple[str, str]] = set()
|
||||||
|
self.reserved_stock = get_reserved_stock(self.args.item_code, self.args.warehouse)
|
||||||
|
|
||||||
self.data = frappe._dict()
|
self.data = frappe._dict()
|
||||||
self.initialize_previous_data(self.args)
|
self.initialize_previous_data(self.args)
|
||||||
@ -610,7 +614,7 @@ class update_entries_after(object):
|
|||||||
validate negative stock for entries current datetime onwards
|
validate negative stock for entries current datetime onwards
|
||||||
will not consider cancelled entries
|
will not consider cancelled entries
|
||||||
"""
|
"""
|
||||||
diff = self.wh_data.qty_after_transaction + flt(sle.actual_qty)
|
diff = self.wh_data.qty_after_transaction + flt(sle.actual_qty) - flt(self.reserved_stock)
|
||||||
diff = flt(diff, self.flt_precision) # respect system precision
|
diff = flt(diff, self.flt_precision) # respect system precision
|
||||||
|
|
||||||
if diff < 0 and abs(diff) > 0.0001:
|
if diff < 0 and abs(diff) > 0.0001:
|
||||||
@ -1006,6 +1010,7 @@ class update_entries_after(object):
|
|||||||
msg_list = []
|
msg_list = []
|
||||||
for warehouse, exceptions in self.exceptions.items():
|
for warehouse, exceptions in self.exceptions.items():
|
||||||
deficiency = min(e["diff"] for e in exceptions)
|
deficiency = min(e["diff"] for e in exceptions)
|
||||||
|
msg_prefix = _("As {} units are reserved, ").format(frappe.bold(self.reserved_stock))
|
||||||
|
|
||||||
if (
|
if (
|
||||||
exceptions[0]["voucher_type"],
|
exceptions[0]["voucher_type"],
|
||||||
@ -1013,7 +1018,7 @@ class update_entries_after(object):
|
|||||||
) in frappe.local.flags.currently_saving:
|
) in frappe.local.flags.currently_saving:
|
||||||
|
|
||||||
msg = _("{0} units of {1} needed in {2} to complete this transaction.").format(
|
msg = _("{0} units of {1} needed in {2} to complete this transaction.").format(
|
||||||
abs(deficiency),
|
frappe.bold(abs(deficiency)),
|
||||||
frappe.get_desk_link("Item", exceptions[0]["item_code"]),
|
frappe.get_desk_link("Item", exceptions[0]["item_code"]),
|
||||||
frappe.get_desk_link("Warehouse", warehouse),
|
frappe.get_desk_link("Warehouse", warehouse),
|
||||||
)
|
)
|
||||||
@ -1021,7 +1026,7 @@ class update_entries_after(object):
|
|||||||
msg = _(
|
msg = _(
|
||||||
"{0} units of {1} needed in {2} on {3} {4} for {5} to complete this transaction."
|
"{0} units of {1} needed in {2} on {3} {4} for {5} to complete this transaction."
|
||||||
).format(
|
).format(
|
||||||
abs(deficiency),
|
frappe.bold(abs(deficiency)),
|
||||||
frappe.get_desk_link("Item", exceptions[0]["item_code"]),
|
frappe.get_desk_link("Item", exceptions[0]["item_code"]),
|
||||||
frappe.get_desk_link("Warehouse", warehouse),
|
frappe.get_desk_link("Warehouse", warehouse),
|
||||||
exceptions[0]["posting_date"],
|
exceptions[0]["posting_date"],
|
||||||
@ -1030,6 +1035,9 @@ class update_entries_after(object):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if msg:
|
if msg:
|
||||||
|
if self.reserved_stock:
|
||||||
|
msg = msg_prefix + msg
|
||||||
|
|
||||||
msg_list.append(msg)
|
msg_list.append(msg)
|
||||||
|
|
||||||
if msg_list:
|
if msg_list:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user