mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-12 17:51:20 +00:00
Merge pull request #48204 from rohitwaghchaure/fixed-stock-reservation-status
fix: stock reservation status
This commit is contained in:
@@ -884,6 +884,9 @@ class ProductionPlan(Document):
|
|||||||
|
|
||||||
wo = frappe.new_doc("Work Order")
|
wo = frappe.new_doc("Work Order")
|
||||||
wo.update(item)
|
wo.update(item)
|
||||||
|
if not wo.source_warehouse:
|
||||||
|
wo.source_warehouse = item.get("fg_warehouse")
|
||||||
|
|
||||||
wo.reserve_stock = self.reserve_stock
|
wo.reserve_stock = self.reserve_stock
|
||||||
wo.planned_start_date = item.get("planned_start_date") or item.get("schedule_date")
|
wo.planned_start_date = item.get("planned_start_date") or item.get("schedule_date")
|
||||||
|
|
||||||
@@ -891,7 +894,7 @@ class ProductionPlan(Document):
|
|||||||
wo.fg_warehouse = item.get("warehouse")
|
wo.fg_warehouse = item.get("warehouse")
|
||||||
|
|
||||||
wo.set_work_order_operations()
|
wo.set_work_order_operations()
|
||||||
wo.set_required_items()
|
wo.set_required_items(reset_source_warehouse=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
wo.flags.ignore_mandatory = True
|
wo.flags.ignore_mandatory = True
|
||||||
|
|||||||
@@ -1213,7 +1213,7 @@ class WorkOrder(Document):
|
|||||||
if self.wip_warehouse:
|
if self.wip_warehouse:
|
||||||
d.available_qty_at_wip_warehouse = get_latest_stock_qty(d.item_code, self.wip_warehouse)
|
d.available_qty_at_wip_warehouse = get_latest_stock_qty(d.item_code, self.wip_warehouse)
|
||||||
|
|
||||||
def set_required_items(self, reset_only_qty=False):
|
def set_required_items(self, reset_only_qty=False, reset_source_warehouse=False):
|
||||||
"""set required_items for production to keep track of reserved qty"""
|
"""set required_items for production to keep track of reserved qty"""
|
||||||
if not reset_only_qty:
|
if not reset_only_qty:
|
||||||
self.required_items = []
|
self.required_items = []
|
||||||
@@ -1247,7 +1247,9 @@ class WorkOrder(Document):
|
|||||||
"description": item.description,
|
"description": item.description,
|
||||||
"allow_alternative_item": item.allow_alternative_item,
|
"allow_alternative_item": item.allow_alternative_item,
|
||||||
"required_qty": item.qty,
|
"required_qty": item.qty,
|
||||||
"source_warehouse": item.source_warehouse or item.default_warehouse,
|
"source_warehouse": (item.source_warehouse or item.default_warehouse)
|
||||||
|
if not reset_source_warehouse
|
||||||
|
else self.source_warehouse,
|
||||||
"include_item_in_manufacturing": item.include_item_in_manufacturing,
|
"include_item_in_manufacturing": item.include_item_in_manufacturing,
|
||||||
"operation_row_id": item.operation_row_id,
|
"operation_row_id": item.operation_row_id,
|
||||||
},
|
},
|
||||||
@@ -1295,22 +1297,37 @@ class WorkOrder(Document):
|
|||||||
self.update_qty_in_stock_reservation(row, transferred_qty, row_wise_serial_batch)
|
self.update_qty_in_stock_reservation(row, transferred_qty, row_wise_serial_batch)
|
||||||
|
|
||||||
def update_qty_in_stock_reservation(self, row, transferred_qty, row_wise_serial_batch):
|
def update_qty_in_stock_reservation(self, row, transferred_qty, row_wise_serial_batch):
|
||||||
if name := frappe.db.get_value(
|
if names := frappe.get_all(
|
||||||
"Stock Reservation Entry",
|
"Stock Reservation Entry",
|
||||||
{
|
filters={
|
||||||
"voucher_no": self.name,
|
"voucher_no": self.name,
|
||||||
"item_code": row.item_code,
|
"item_code": row.item_code,
|
||||||
"voucher_detail_no": row.name,
|
"voucher_detail_no": row.name,
|
||||||
"warehouse": row.source_warehouse,
|
"warehouse": row.source_warehouse,
|
||||||
},
|
},
|
||||||
"name",
|
pluck="name",
|
||||||
):
|
):
|
||||||
doc = frappe.get_doc("Stock Reservation Entry", name)
|
for name in names:
|
||||||
doc.db_set("transferred_qty", flt(transferred_qty), update_modified=False)
|
doc = frappe.get_doc("Stock Reservation Entry", name)
|
||||||
if (doc.has_batch_no or doc.has_serial_no) and doc.reservation_based_on == "Serial and Batch":
|
qty_to_update = 0.0
|
||||||
doc.consume_serial_batch_for_material_transfer(row_wise_serial_batch)
|
if transferred_qty <= 0:
|
||||||
doc.update_status()
|
continue
|
||||||
doc.update_reserved_stock_in_bin()
|
|
||||||
|
if transferred_qty > flt(doc.reserved_qty - doc.consumed_qty):
|
||||||
|
qty_to_update = doc.reserved_qty - doc.transferred_qty
|
||||||
|
transferred_qty -= qty_to_update
|
||||||
|
else:
|
||||||
|
qty_to_update = transferred_qty
|
||||||
|
transferred_qty = 0.0
|
||||||
|
|
||||||
|
if qty_to_update <= 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
doc.db_set("transferred_qty", flt(qty_to_update), update_modified=False)
|
||||||
|
if (doc.has_batch_no or doc.has_serial_no) and doc.reservation_based_on == "Serial and Batch":
|
||||||
|
doc.consume_serial_batch_for_material_transfer(row_wise_serial_batch)
|
||||||
|
doc.update_status()
|
||||||
|
doc.update_reserved_stock_in_bin()
|
||||||
|
|
||||||
def update_returned_qty(self):
|
def update_returned_qty(self):
|
||||||
ste = frappe.qb.DocType("Stock Entry")
|
ste = frappe.qb.DocType("Stock Entry")
|
||||||
@@ -2167,8 +2184,8 @@ def create_job_card(work_order, row, enable_capacity_planning=False, auto_create
|
|||||||
"hour_rate": row.get("hour_rate"),
|
"hour_rate": row.get("hour_rate"),
|
||||||
"serial_no": row.get("serial_no"),
|
"serial_no": row.get("serial_no"),
|
||||||
"time_required": row.get("time_in_mins"),
|
"time_required": row.get("time_in_mins"),
|
||||||
"source_warehouse": row.get("source_warehouse"),
|
"source_warehouse": row.get("source_warehouse") or work_order.get("source_warehouse"),
|
||||||
"target_warehouse": row.get("fg_warehouse"),
|
"target_warehouse": row.get("fg_warehouse") or work_order.get("fg_warehouse"),
|
||||||
"wip_warehouse": work_order.wip_warehouse or row.get("wip_warehouse")
|
"wip_warehouse": work_order.wip_warehouse or row.get("wip_warehouse")
|
||||||
if not work_order.skip_transfer or work_order.from_wip_warehouse
|
if not work_order.skip_transfer or work_order.from_wip_warehouse
|
||||||
else work_order.source_warehouse or row.get("source_warehouse"),
|
else work_order.source_warehouse or row.get("source_warehouse"),
|
||||||
|
|||||||
@@ -953,7 +953,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2025-05-31 18:51:32.651562",
|
"modified": "2025-05-31 19:51:32.651562",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Delivery Note Item",
|
"name": "Delivery Note Item",
|
||||||
|
|||||||
@@ -1923,9 +1923,10 @@ def get_reserved_serial_nos(kwargs) -> list:
|
|||||||
if not reserved_entries:
|
if not reserved_entries:
|
||||||
return ignore_serial_nos, consider_serial_nos
|
return ignore_serial_nos, consider_serial_nos
|
||||||
|
|
||||||
reserved_voucher_details = get_reserved_voucher_details(kwargs)
|
if kwargs.get("sabb_voucher_type") == "Delivery Note" and kwargs.get("against_sales_order"):
|
||||||
if not reserved_voucher_details:
|
reserved_voucher_details = [kwargs.get("against_sales_order")]
|
||||||
return ignore_serial_nos, consider_serial_nos
|
else:
|
||||||
|
reserved_voucher_details = get_reserved_voucher_details(kwargs)
|
||||||
|
|
||||||
serial_nos = []
|
serial_nos = []
|
||||||
for entry in reserved_entries:
|
for entry in reserved_entries:
|
||||||
|
|||||||
@@ -1156,7 +1156,7 @@ class StockReservation:
|
|||||||
sre.voucher_no = item.get("voucher_no") or self.doc.name
|
sre.voucher_no = item.get("voucher_no") or self.doc.name
|
||||||
sre.voucher_detail_no = item.get(child_doctype) or item.name or item.get("voucher_detail_no")
|
sre.voucher_detail_no = item.get(child_doctype) or item.name or item.get("voucher_detail_no")
|
||||||
sre.available_qty = self.available_qty_to_reserve
|
sre.available_qty = self.available_qty_to_reserve
|
||||||
sre.voucher_qty = qty
|
sre.voucher_qty = self.qty_to_be_reserved
|
||||||
sre.reserved_qty = self.qty_to_be_reserved
|
sre.reserved_qty = self.qty_to_be_reserved
|
||||||
sre.company = self.doc.company
|
sre.company = self.doc.company
|
||||||
sre.stock_uom = item_details.stock_uom
|
sre.stock_uom = item_details.stock_uom
|
||||||
|
|||||||
@@ -365,17 +365,9 @@ class TestStockReservationEntry(IntegrationTestCase):
|
|||||||
dn2 = make_delivery_note(so.name)
|
dn2 = make_delivery_note(so.name)
|
||||||
|
|
||||||
for item in dn2.items:
|
for item in dn2.items:
|
||||||
item.qty = 80
|
item.qty = 70
|
||||||
|
|
||||||
dn2.save()
|
dn2.save()
|
||||||
for row in dn2.items:
|
|
||||||
if row.item_code in item_wise_serial_nos:
|
|
||||||
consumed_serial_no = ", ".join(item_wise_serial_nos[row.item_code])
|
|
||||||
picked_serial_no = get_serial_nos(row.serial_no)
|
|
||||||
|
|
||||||
serial_nos = list(set(picked_serial_no) - set(consumed_serial_no))
|
|
||||||
row.serial_no = "\n".join(serial_nos)
|
|
||||||
|
|
||||||
dn2.submit()
|
dn2.submit()
|
||||||
|
|
||||||
for item in so.items:
|
for item in so.items:
|
||||||
|
|||||||
@@ -208,6 +208,9 @@ def update_stock(ctx, out, doc=None):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if ctx.get("doctype") == "Delivery Note":
|
||||||
|
kwargs["against_sales_order"] = ctx.get("against_sales_order")
|
||||||
|
|
||||||
if ctx.get("ignore_serial_nos"):
|
if ctx.get("ignore_serial_nos"):
|
||||||
kwargs["ignore_serial_nos"] = ctx.get("ignore_serial_nos")
|
kwargs["ignore_serial_nos"] = ctx.get("ignore_serial_nos")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user