fix: consider existing pick list

This commit is contained in:
s-aga-r 2023-01-23 13:51:07 +05:30
parent 9ae3a54ce9
commit b642718f08

View File

@ -181,7 +181,11 @@ class PickList(Document):
self.item_location_map.setdefault(
item_code,
get_available_item_locations(
item_code, from_warehouses, self.item_count_map.get(item_code), self.company
item_code,
from_warehouses,
self.item_count_map.get(item_code),
self.company,
picked_item_details=picked_items_details.get(item_code),
),
)
@ -473,31 +477,38 @@ def get_items_with_location_and_quantity(item_doc, item_location_map, docstatus)
def get_available_item_locations(
item_code, from_warehouses, required_qty, company, ignore_validation=False
item_code,
from_warehouses,
required_qty,
company,
ignore_validation=False,
picked_item_details=None,
):
locations = []
total_picked_qty = (
sum([v.get("picked_qty") for k, v in picked_item_details.items()]) if picked_item_details else 0
)
has_serial_no = frappe.get_cached_value("Item", item_code, "has_serial_no")
has_batch_no = frappe.get_cached_value("Item", item_code, "has_batch_no")
if has_batch_no and has_serial_no:
locations = get_available_item_locations_for_serial_and_batched_item(
item_code, from_warehouses, required_qty, company
item_code, from_warehouses, required_qty, company, total_picked_qty
)
elif has_serial_no:
locations = get_available_item_locations_for_serialized_item(
item_code, from_warehouses, required_qty, company
item_code, from_warehouses, required_qty, company, total_picked_qty
)
elif has_batch_no:
locations = get_available_item_locations_for_batched_item(
item_code, from_warehouses, required_qty, company
item_code, from_warehouses, required_qty, company, total_picked_qty
)
else:
locations = get_available_item_locations_for_other_item(
item_code, from_warehouses, required_qty, company
item_code, from_warehouses, required_qty, company, total_picked_qty
)
total_qty_available = sum(location.get("qty") for location in locations)
remaining_qty = required_qty - total_qty_available
if remaining_qty > 0 and not ignore_validation:
@ -508,11 +519,44 @@ def get_available_item_locations(
title=_("Insufficient Stock"),
)
if picked_item_details:
for location in list(locations):
key = (
(location["warehouse"], location["batch_no"])
if location.get("batch_no")
else location["warehouse"]
)
if key in picked_item_details:
picked_detail = picked_item_details[key]
if picked_detail.get("serial_no") and location.get("serial_no"):
location["serial_no"] = list(
set(location["serial_no"]).difference(set(picked_detail["serial_no"]))
)
location["qty"] = len(location["serial_no"])
else:
location["qty"] -= picked_detail.get("picked_qty")
if location["qty"] < 1:
locations.remove(location)
total_qty_available = sum(location.get("qty") for location in locations)
remaining_qty = required_qty - total_qty_available
if remaining_qty > 0 and not ignore_validation:
frappe.msgprint(
_("{0} units of Item {1} is picked in another Pick List.").format(
remaining_qty, frappe.get_desk_link("Item", item_code)
),
title=_("Already Picked"),
)
return locations
def get_available_item_locations_for_serialized_item(
item_code, from_warehouses, required_qty, company
item_code, from_warehouses, required_qty, company, total_picked_qty=0
):
sn = frappe.qb.DocType("Serial No")
query = (
@ -520,7 +564,7 @@ def get_available_item_locations_for_serialized_item(
.select(sn.name, sn.warehouse)
.where((sn.item_code == item_code) & (sn.company == company))
.orderby(sn.purchase_date)
.limit(cint(required_qty))
.limit(cint(required_qty + total_picked_qty))
)
if from_warehouses:
@ -542,7 +586,7 @@ def get_available_item_locations_for_serialized_item(
def get_available_item_locations_for_batched_item(
item_code, from_warehouses, required_qty, company
item_code, from_warehouses, required_qty, company, total_picked_qty=0
):
sle = frappe.qb.DocType("Stock Ledger Entry")
batch = frappe.qb.DocType("Batch")
@ -562,6 +606,7 @@ def get_available_item_locations_for_batched_item(
.groupby(sle.warehouse, sle.batch_no, sle.item_code)
.having(Sum(sle.actual_qty) > 0)
.orderby(IfNull(batch.expiry_date, "2200-01-01"), batch.creation, sle.batch_no, sle.warehouse)
.limit(cint(required_qty + total_picked_qty))
)
if from_warehouses:
@ -571,7 +616,7 @@ def get_available_item_locations_for_batched_item(
def get_available_item_locations_for_serial_and_batched_item(
item_code, from_warehouses, required_qty, company
item_code, from_warehouses, required_qty, company, total_picked_qty=0
):
# Get batch nos by FIFO
locations = get_available_item_locations_for_batched_item(
@ -594,23 +639,26 @@ def get_available_item_locations_for_serial_and_batched_item(
(conditions) & (sn.batch_no == location.batch_no) & (sn.warehouse == location.warehouse)
)
.orderby(sn.purchase_date)
.limit(cint(location.qty))
.limit(cint(location.qty + total_picked_qty))
).run(as_dict=True)
serial_nos = [sn.name for sn in serial_nos]
location.serial_no = serial_nos
location.qty = len(serial_nos)
return locations
def get_available_item_locations_for_other_item(item_code, from_warehouses, required_qty, company):
def get_available_item_locations_for_other_item(
item_code, from_warehouses, required_qty, company, total_picked_qty=0
):
bin = frappe.qb.DocType("Bin")
query = (
frappe.qb.from_(bin)
.select(bin.warehouse, bin.actual_qty.as_("qty"))
.where((bin.item_code == item_code) & (bin.actual_qty > 0))
.orderby(bin.creation)
.limit(cint(required_qty))
.limit(cint(required_qty + total_picked_qty))
)
if from_warehouses: