mirror of
https://github.com/frappe/erpnext.git
synced 2026-09-20 03:47:11 +00:00
fix: stock reservation validation in the stock entry (#47524)
This commit is contained in:
@@ -207,9 +207,9 @@ frappe.ui.form.on("Production Plan", {
|
||||
set_field_options("projected_qty_formula", projected_qty_formula);
|
||||
},
|
||||
|
||||
has_unreserved_stock(frm, table) {
|
||||
has_unreserved_stock(frm, table, qty_field = "required_qty") {
|
||||
let has_unreserved_stock = frm.doc[table].some(
|
||||
(item) => flt(item.qty) > flt(item.stock_reserved_qty)
|
||||
(item) => flt(item[qty_field]) > flt(item.stock_reserved_qty)
|
||||
);
|
||||
|
||||
return has_unreserved_stock;
|
||||
@@ -249,7 +249,7 @@ frappe.ui.form.on("Production Plan", {
|
||||
|
||||
setup_stock_reservation_for_raw_materials(frm) {
|
||||
if (frm.doc.docstatus === 1 && frm.doc.reserve_stock) {
|
||||
if (frm.events.has_unreserved_stock(frm, "mr_items")) {
|
||||
if (frm.events.has_unreserved_stock(frm, "mr_items", "required_bom_qty")) {
|
||||
frm.add_custom_button(
|
||||
__("Reserve for Raw Materials"),
|
||||
() => erpnext.stock_reservation.make_entries(frm, "mr_items"),
|
||||
|
||||
@@ -1619,18 +1619,20 @@ def get_items_for_material_requests(doc, warehouses=None, get_parent_warehouse_d
|
||||
frappe.throw(_("For row {0}: Enter Planned Qty").format(data.get("idx")))
|
||||
|
||||
if bom_no:
|
||||
if data.get("include_exploded_items") and doc.get("skip_available_sub_assembly_item"):
|
||||
item_details = {}
|
||||
if doc.get("sub_assembly_items"):
|
||||
item_details = get_raw_materials_of_sub_assembly_items(
|
||||
so_item_details[doc.get("sales_order")].keys() if so_item_details else [],
|
||||
item_details,
|
||||
company,
|
||||
bom_no,
|
||||
include_non_stock_items,
|
||||
sub_assembly_items,
|
||||
planned_qty=planned_qty,
|
||||
)
|
||||
if (
|
||||
data.get("include_exploded_items")
|
||||
and doc.get("skip_available_sub_assembly_item")
|
||||
and doc.get("sub_assembly_items")
|
||||
):
|
||||
item_details = get_raw_materials_of_sub_assembly_items(
|
||||
so_item_details[doc.get("sales_order")].keys() if so_item_details else [],
|
||||
item_details,
|
||||
company,
|
||||
bom_no,
|
||||
include_non_stock_items,
|
||||
sub_assembly_items,
|
||||
planned_qty=planned_qty,
|
||||
)
|
||||
|
||||
elif data.get("include_exploded_items") and include_subcontracted_items:
|
||||
# fetch exploded items from BOM
|
||||
@@ -2089,7 +2091,7 @@ def get_reserved_qty_for_sub_assembly(item_code, warehouse):
|
||||
def make_stock_reservation_entries(doc, items=None, table_name=None, notify=False):
|
||||
if isinstance(doc, str):
|
||||
doc = parse_json(doc)
|
||||
doc = frappe.get_doc("Work Order", doc.get("name"))
|
||||
doc = frappe.get_doc("Production Plan", doc.get("name"))
|
||||
|
||||
if items and isinstance(items, str):
|
||||
items = parse_json(items)
|
||||
@@ -2113,9 +2115,22 @@ def make_stock_reservation_entries(doc, items=None, table_name=None, notify=Fals
|
||||
|
||||
sre = StockReservation(doc, items=items, kwargs=mapper[child_table_name], notify=notify)
|
||||
if doc.docstatus == 1:
|
||||
sre.make_stock_reservation_entries()
|
||||
frappe.msgprint(_("Stock Reservation Entries Created"), alert=True)
|
||||
sre_created = sre.make_stock_reservation_entries()
|
||||
if sre_created:
|
||||
frappe.msgprint(_("Stock Reservation Entries Created"), alert=True)
|
||||
elif doc.docstatus == 2:
|
||||
sre.cancel_stock_reservation_entries()
|
||||
|
||||
doc.reload()
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def cancel_stock_reservation_entries(doc, sre_list):
|
||||
if isinstance(doc, str):
|
||||
doc = parse_json(doc)
|
||||
doc = frappe.get_doc("Production Plan", doc.get("name"))
|
||||
|
||||
sre = StockReservation(doc)
|
||||
sre.cancel_stock_reservation_entries(sre_list)
|
||||
|
||||
doc.reload()
|
||||
|
||||
@@ -1415,8 +1415,12 @@ class TestProductionPlan(IntegrationTestCase):
|
||||
do_not_submit=1,
|
||||
skip_available_sub_assembly_item=1,
|
||||
warehouse="_Test Warehouse - _TC",
|
||||
sub_assembly_warehouse="_Test Warehouse - _TC",
|
||||
)
|
||||
|
||||
plan.get_sub_assembly_items()
|
||||
plan.save()
|
||||
|
||||
items = get_items_for_material_requests(
|
||||
plan.as_dict(), warehouses=[{"warehouse": "_Test Warehouse - _TC"}]
|
||||
)
|
||||
|
||||
@@ -1426,7 +1426,7 @@ class WorkOrder(Document):
|
||||
return
|
||||
|
||||
item_list = list(items.values())
|
||||
make_stock_reservation_entries(self, item_list, notify=True)
|
||||
make_stock_reservation_entries(self, item_list, is_transfer=False, notify=True)
|
||||
|
||||
def get_list_of_materials_for_reservation(self, stock_entry):
|
||||
items = frappe._dict()
|
||||
@@ -1648,7 +1648,7 @@ class WorkOrder(Document):
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_stock_reservation_entries(doc, items=None, table_name=None, notify=False):
|
||||
def make_stock_reservation_entries(doc, items=None, table_name=None, is_transfer=True, notify=False):
|
||||
if isinstance(doc, str):
|
||||
doc = parse_json(doc)
|
||||
doc = frappe.get_doc("Work Order", doc.get("name"))
|
||||
@@ -1658,14 +1658,15 @@ def make_stock_reservation_entries(doc, items=None, table_name=None, notify=Fals
|
||||
|
||||
sre = StockReservation(doc, items=items, notify=notify)
|
||||
if doc.docstatus == 1:
|
||||
if doc.production_plan:
|
||||
if doc.production_plan and is_transfer:
|
||||
sre.transfer_reservation_entries_to(
|
||||
doc.production_plan, from_doctype="Production Plan", to_doctype="Work Order"
|
||||
)
|
||||
else:
|
||||
sre.make_stock_reservation_entries()
|
||||
sre_created = sre.make_stock_reservation_entries()
|
||||
if sre_created:
|
||||
frappe.msgprint(_("Stock Reservation Entries Created"), alert=True)
|
||||
|
||||
frappe.msgprint(_("Stock Reservation Entries Created"), alert=True)
|
||||
elif doc.docstatus == 2:
|
||||
sre.cancel_stock_reservation_entries()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user