From 45395027d3b5c51ac3ccdbebb1f0d23d5ffd2ec1 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 19 Oct 2023 19:57:50 +0530 Subject: [PATCH] fix: incorrect serial and batch get reserved --- .../doctype/sales_order/sales_order.py | 15 +++++++++-- erpnext/stock/doctype/pick_list/pick_list.py | 27 ++++++++++++------- .../purchase_receipt/purchase_receipt.py | 10 +++++-- .../stock_reservation_entry.py | 19 +++++++------ 4 files changed, 47 insertions(+), 24 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index d38216242e..94f9d6e37c 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -3,6 +3,7 @@ import json +from typing import Literal import frappe import frappe.utils @@ -534,14 +535,24 @@ class SalesOrder(SellingController): return False @frappe.whitelist() - def create_stock_reservation_entries(self, items_details=None, notify=True) -> None: + def create_stock_reservation_entries( + self, + items_details: list[dict] = None, + from_voucher_type: Literal["Pick List", "Purchase Receipt"] = None, + notify=True, + ) -> None: """Creates Stock Reservation Entries for Sales Order Items.""" from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import ( create_stock_reservation_entries_for_so_items as create_stock_reservation_entries, ) - create_stock_reservation_entries(sales_order=self, items_details=items_details, notify=notify) + create_stock_reservation_entries( + sales_order=self, + items_details=items_details, + from_voucher_type=from_voucher_type, + notify=notify, + ) @frappe.whitelist() def cancel_stock_reservation_entries(self, sre_list=None, notify=True) -> None: diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py index 3503556f3e..ed20209577 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.py +++ b/erpnext/stock/doctype/pick_list/pick_list.py @@ -229,20 +229,27 @@ class PickList(Document): def create_stock_reservation_entries(self, notify=True) -> None: """Creates Stock Reservation Entries for Sales Order Items against Pick List.""" - from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import ( - create_stock_reservation_entries_for_so_items, - ) - - so_details = {} + so_items_details_map = {} for location in self.locations: if location.warehouse and location.sales_order and location.sales_order_item: - so_details.setdefault(location.sales_order, []).append(location) + item_details = { + "name": location.sales_order_item, + "item_code": location.item_code, + "warehouse": location.warehouse, + "qty_to_reserve": (flt(location.picked_qty) - flt(location.stock_reserved_qty)), + "from_voucher_no": location.parent, + "from_voucher_detail_no": location.name, + "serial_and_batch_bundle": location.serial_and_batch_bundle, + } + so_items_details_map.setdefault(location.sales_order, []).append(item_details) - if so_details: - for so, locations in so_details.items(): + if so_items_details_map: + for so, items_details in so_items_details_map.items(): so_doc = frappe.get_doc("Sales Order", so) - create_stock_reservation_entries_for_so_items( - sales_order=so_doc, items_details=locations, from_voucher_type="Pick List", notify=notify + so_doc.create_stock_reservation_entries( + items_details=items_details, + from_voucher_type="Pick List", + notify=notify, ) @frappe.whitelist() diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index fc88dd8d5f..42d6b02dee 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -846,14 +846,20 @@ class PurchaseReceipt(BuyingController): "item_code": item.item_code, "warehouse": item.warehouse, "qty_to_reserve": item.stock_qty, - "serial_and_batch_bundle": item.get("serial_and_batch_bundle"), + "from_voucher_no": item.parent, + "from_voucher_detail_no": item.name, + "serial_and_batch_bundle": item.serial_and_batch_bundle, } so_items_details_map.setdefault(item.sales_order, []).append(item_details) if so_items_details_map: for so, items_details in so_items_details_map.items(): so_doc = frappe.get_doc("Sales Order", so) - so_doc.create_stock_reservation_entries(items_details) + so_doc.create_stock_reservation_entries( + items_details=items_details, + from_voucher_type="Purchase Receipt", + notify=True, + ) def update_billed_amount_based_on_po(po_details, update_modified=True): diff --git a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py index 9097e621e6..e589628c62 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py +++ b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py @@ -794,22 +794,21 @@ def create_stock_reservation_entries_for_so_items( items = [] if items_details: - item_field = "sales_order_item" if from_voucher_type == "Pick List" else "name" - for item in items_details: - so_item = frappe.get_doc("Sales Order Item", item.get(item_field)) + so_item = frappe.get_doc("Sales Order Item", item.get("name")) so_item.warehouse = item.get("warehouse") so_item.qty_to_reserve = ( - item.get("picked_qty") - item.get("stock_reserved_qty", 0) - if from_voucher_type == "Pick List" - else (flt(item.get("qty_to_reserve")) * flt(so_item.conversion_factor, 1)) + flt(item.get("qty_to_reserve")) + if from_voucher_type in ["Pick List", "Purchase Receipt"] + else ( + flt(item.get("qty_to_reserve")) + * (flt(item.get("conversion_factor")) or flt(so_item.conversion_factor) or 1) + ) ) + so_item.from_voucher_no = item.get("from_voucher_no") + so_item.from_voucher_detail_no = item.get("from_voucher_detail_no") so_item.serial_and_batch_bundle = item.get("serial_and_batch_bundle") - if from_voucher_type == "Pick List": - so_item.from_voucher_no = item.get("parent") - so_item.from_voucher_detail_no = item.get("name") - items.append(so_item) sre_count = 0