fix: incorrect batch picked in the pick list (backport #45761) (#46315)

fix: incorrect batch picked in the pick list

(cherry picked from commit e1b7688a17)

Co-authored-by: Rohit Waghchaure <rohitw1991@gmail.com>
This commit is contained in:
mergify[bot]
2025-03-05 14:48:01 +05:30
committed by GitHub
parent c85fd36960
commit 5a3073c4c1
2 changed files with 70 additions and 3 deletions

View File

@@ -2,6 +2,13 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Pick List", { frappe.ui.form.on("Pick List", {
after_save(frm) {
setTimeout(() => {
// Added to fix the issue of locations table not getting updated after save
frm.reload_doc();
}, 500);
},
setup: (frm) => { setup: (frm) => {
frm.ignore_doctypes_on_cancel_all = ["Serial and Batch Bundle"]; frm.ignore_doctypes_on_cancel_all = ["Serial and Batch Bundle"];

View File

@@ -73,6 +73,7 @@ class PickList(Document):
self.set_onload("has_reserved_stock", True) self.set_onload("has_reserved_stock", True)
def validate(self): def validate(self):
self.validate_expired_batches()
self.validate_for_qty() self.validate_for_qty()
self.validate_stock_qty() self.validate_stock_qty()
self.check_serial_no_status() self.check_serial_no_status()
@@ -205,6 +206,33 @@ class PickList(Document):
self.update_reference_qty() self.update_reference_qty()
self.update_sales_order_picking_status() self.update_sales_order_picking_status()
def validate_expired_batches(self):
batches = []
for row in self.get("locations"):
if row.get("batch_no") and row.get("picked_qty"):
batches.append(row.batch_no)
if batches:
batch = frappe.qb.DocType("Batch")
query = (
frappe.qb.from_(batch)
.select(batch.name)
.where(
(batch.name.isin(batches))
& (batch.expiry_date <= frappe.utils.nowdate())
& (batch.expiry_date.isnotnull())
)
)
expired_batches = query.run(as_dict=True)
if expired_batches:
msg = "<ul>" + "".join(f"<li>{batch.name}</li>" for batch in expired_batches) + "</ul>"
frappe.throw(
_("The following batches are expired, please restock them: <br> {0}").format(msg),
title=_("Expired Batches"),
)
def make_bundle_using_old_serial_batch_fields(self): def make_bundle_using_old_serial_batch_fields(self):
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
@@ -447,6 +475,7 @@ class PickList(Document):
self.remove(row) self.remove(row)
updated_locations = frappe._dict() updated_locations = frappe._dict()
len_idx = len(self.get("locations")) or 0
for item_doc in items: for item_doc in items:
item_code = item_doc.item_code item_code = item_doc.item_code
@@ -489,6 +518,8 @@ class PickList(Document):
if location.picked_qty > location.stock_qty: if location.picked_qty > location.stock_qty:
location.picked_qty = location.stock_qty location.picked_qty = location.stock_qty
len_idx += 1
location.idx = len_idx
self.append("locations", location) self.append("locations", location)
# If table is empty on update after submit, set stock_qty, picked_qty to 0 so that indicator is red # If table is empty on update after submit, set stock_qty, picked_qty to 0 so that indicator is red
@@ -497,7 +528,11 @@ class PickList(Document):
for location in locations_replica: for location in locations_replica:
location.stock_qty = 0 location.stock_qty = 0
location.picked_qty = 0 location.picked_qty = 0
len_idx += 1
location.idx = len_idx
self.append("locations", location) self.append("locations", location)
frappe.msgprint( frappe.msgprint(
_( _(
"Please Restock Items and Update the Pick List to continue. To discontinue, cancel the Pick List." "Please Restock Items and Update the Pick List to continue. To discontinue, cancel the Pick List."
@@ -638,8 +673,31 @@ class PickList(Document):
if serial_no: if serial_no:
picked_items[item_data.item_code][key]["serial_no"].extend(serial_no) picked_items[item_data.item_code][key]["serial_no"].extend(serial_no)
self.update_picked_item_from_current_pick_list(picked_items)
return picked_items return picked_items
def update_picked_item_from_current_pick_list(self, picked_items):
for row in self.locations:
if flt(row.picked_qty) > 0:
key = (row.warehouse, row.batch_no) if row.batch_no else row.warehouse
serial_no = [x for x in row.serial_no.split("\n") if x] if row.serial_no else None
if row.item_code not in picked_items:
picked_items[row.item_code] = {}
if key not in picked_items[row.item_code]:
picked_items[row.item_code][key] = frappe._dict(
{
"picked_qty": 0,
"serial_no": [],
"batch_no": row.batch_no or "",
"warehouse": row.warehouse,
}
)
picked_items[row.item_code][key]["picked_qty"] += flt(row.stock_qty) or flt(row.picked_qty)
if serial_no:
picked_items[row.item_code][key]["serial_no"].extend(serial_no)
def _get_pick_list_items(self, items): def _get_pick_list_items(self, items):
pi = frappe.qb.DocType("Pick List") pi = frappe.qb.DocType("Pick List")
pi_item = frappe.qb.DocType("Pick List Item") pi_item = frappe.qb.DocType("Pick List Item")
@@ -653,9 +711,11 @@ class PickList(Document):
pi_item.batch_no, pi_item.batch_no,
pi_item.serial_and_batch_bundle, pi_item.serial_and_batch_bundle,
pi_item.serial_no, pi_item.serial_no,
(Case().when(pi_item.picked_qty > 0, pi_item.picked_qty).else_(pi_item.stock_qty)).as_( (
"picked_qty" Case()
), .when((pi_item.picked_qty > 0) & (pi_item.docstatus == 1), pi_item.picked_qty)
.else_(pi_item.stock_qty)
).as_("picked_qty"),
) )
.where( .where(
(pi_item.item_code.isin([x.item_code for x in items])) (pi_item.item_code.isin([x.item_code for x in items]))