Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: do not consider rejected warehouses in pick list (backport #39539) (backport #39804) #39811

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions erpnext/selling/doctype/sales_order/test_sales_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
from erpnext.selling.doctype.sales_order.sales_order import (
WarehouseRequired,
create_pick_list,
make_delivery_note,
make_material_request,
make_raw_material_request,
Expand Down Expand Up @@ -1973,6 +1974,83 @@ def test_expired_rate_for_packed_item(self):
self.assertEqual(so.items[0].rate, scenario.get("expected_rate"))
self.assertEqual(so.packed_items[0].rate, scenario.get("expected_rate"))

def test_pick_list_without_rejected_materials(self):
serial_and_batch_item = make_item(
"_Test Serial and Batch Item for Rejected Materials",
properties={
"has_serial_no": 1,
"has_batch_no": 1,
"create_new_batch": 1,
"batch_number_series": "BAT-TSBIFRM-.#####",
"serial_no_series": "SN-TSBIFRM-.#####",
},
).name

serial_item = make_item(
"_Test Serial Item for Rejected Materials",
properties={
"has_serial_no": 1,
"serial_no_series": "SN-TSIFRM-.#####",
},
).name

batch_item = make_item(
"_Test Batch Item for Rejected Materials",
properties={
"has_batch_no": 1,
"create_new_batch": 1,
"batch_number_series": "BAT-TBIFRM-.#####",
},
).name

normal_item = make_item("_Test Normal Item for Rejected Materials").name

warehouse = "_Test Warehouse - _TC"
rejected_warehouse = "_Test Dummy Rejected Warehouse - _TC"

if not frappe.db.exists("Warehouse", rejected_warehouse):
frappe.get_doc(
{
"doctype": "Warehouse",
"warehouse_name": rejected_warehouse,
"company": "_Test Company",
"warehouse_group": "_Test Warehouse Group",
"is_rejected_warehouse": 1,
}
).insert()

se = make_stock_entry(item_code=normal_item, qty=1, to_warehouse=warehouse, do_not_submit=True)
for item in [serial_and_batch_item, serial_item, batch_item]:
se.append("items", {"item_code": item, "qty": 1, "t_warehouse": warehouse})

se.save()
se.submit()

se = make_stock_entry(
item_code=normal_item, qty=1, to_warehouse=rejected_warehouse, do_not_submit=True
)
for item in [serial_and_batch_item, serial_item, batch_item]:
se.append("items", {"item_code": item, "qty": 1, "t_warehouse": rejected_warehouse})

se.save()
se.submit()

so = make_sales_order(item_code=normal_item, qty=2, do_not_submit=True)

for item in [serial_and_batch_item, serial_item, batch_item]:
so.append("items", {"item_code": item, "qty": 2, "warehouse": warehouse})

so.save()
so.submit()

pick_list = create_pick_list(so.name)

pick_list.save()
for row in pick_list.locations:
self.assertEqual(row.qty, 1.0)
self.assertFalse(row.warehouse == rejected_warehouse)
self.assertTrue(row.warehouse == warehouse)


def automatically_fetch_payment_terms(enable=1):
accounts_settings = frappe.get_doc("Accounts Settings")
Expand Down
12 changes: 10 additions & 2 deletions erpnext/stock/doctype/pick_list/pick_list.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"for_qty",
"column_break_4",
"parent_warehouse",
"consider_rejected_warehouses",
"get_item_locations",
"section_break_6",
"scan_barcode",
Expand Down Expand Up @@ -184,11 +185,18 @@
"report_hide": 1,
"reqd": 1,
"search_index": 1
},
{
"default": "0",
"description": "Enable it if users want to consider rejected materials to dispatch.",
"fieldname": "consider_rejected_warehouses",
"fieldtype": "Check",
"label": "Consider Rejected Warehouses"
}
],
"is_submittable": 1,
"links": [],
"modified": "2024-02-01 16:17:44.877426",
"modified": "2024-02-02 16:17:44.877426",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List",
Expand Down Expand Up @@ -260,4 +268,4 @@
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}
74 changes: 68 additions & 6 deletions erpnext/stock/doctype/pick_list/pick_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ def set_item_locations(self, save=False):
self.item_count_map.get(item_code),
self.company,
picked_item_details=picked_items_details.get(item_code),
consider_rejected_warehouses=self.consider_rejected_warehouses,
),
)

Expand Down Expand Up @@ -710,6 +711,7 @@ def get_available_item_locations(
company,
ignore_validation=False,
picked_item_details=None,
consider_rejected_warehouses=False,
):
locations = []
total_picked_qty = (
Expand All @@ -725,18 +727,34 @@ def get_available_item_locations(
required_qty,
company,
total_picked_qty,
consider_rejected_warehouses=consider_rejected_warehouses,
)
elif has_serial_no:
locations = get_available_item_locations_for_serialized_item(
item_code, from_warehouses, required_qty, company, total_picked_qty
item_code,
from_warehouses,
required_qty,
company,
total_picked_qty,
consider_rejected_warehouses=consider_rejected_warehouses,
)
elif has_batch_no:
locations = get_available_item_locations_for_batched_item(
item_code, from_warehouses, required_qty, company, total_picked_qty
item_code,
from_warehouses,
required_qty,
company,
total_picked_qty,
consider_rejected_warehouses=consider_rejected_warehouses,
)
else:
locations = get_available_item_locations_for_other_item(
item_code, from_warehouses, required_qty, company, total_picked_qty
item_code,
from_warehouses,
required_qty,
company,
total_picked_qty,
consider_rejected_warehouses=consider_rejected_warehouses,
)

total_qty_available = sum(location.get("qty") for location in locations)
Expand Down Expand Up @@ -775,13 +793,15 @@ def get_available_item_locations_for_serial_and_batched_item(
required_qty,
company,
total_picked_qty=0,
consider_rejected_warehouses=False,
):
# Get batch nos by FIFO
locations = get_available_item_locations_for_batched_item(
item_code,
from_warehouses,
required_qty,
company,
consider_rejected_warehouses=consider_rejected_warehouses,
)

if locations:
Expand Down Expand Up @@ -811,7 +831,12 @@ def get_available_item_locations_for_serial_and_batched_item(


def get_available_item_locations_for_serialized_item(
item_code, from_warehouses, required_qty, company, total_picked_qty=0
item_code,
from_warehouses,
required_qty,
company,
total_picked_qty=0,
consider_rejected_warehouses=False,
):
picked_serial_nos = get_picked_serial_nos(item_code, from_warehouses)

Expand All @@ -828,6 +853,10 @@ def get_available_item_locations_for_serialized_item(
else:
query = query.where(Coalesce(sn.warehouse, "") != "")

if not consider_rejected_warehouses:
if rejected_warehouses := get_rejected_warehouses():
query = query.where(sn.warehouse.notin(rejected_warehouses))

serial_nos = query.run(as_list=True)

warehouse_serial_nos_map = frappe._dict()
Expand Down Expand Up @@ -860,7 +889,12 @@ def get_available_item_locations_for_serialized_item(


def get_available_item_locations_for_batched_item(
item_code, from_warehouses, required_qty, company, total_picked_qty=0
item_code,
from_warehouses,
required_qty,
company,
total_picked_qty=0,
consider_rejected_warehouses=False,
):
locations = []
data = get_auto_batch_nos(
Expand All @@ -875,7 +909,14 @@ def get_available_item_locations_for_batched_item(
)

warehouse_wise_batches = frappe._dict()
rejected_warehouses = get_rejected_warehouses()

for d in data:
if (
not consider_rejected_warehouses and rejected_warehouses and d.warehouse in rejected_warehouses
):
continue

if d.warehouse not in warehouse_wise_batches:
warehouse_wise_batches.setdefault(d.warehouse, defaultdict(float))

Expand All @@ -898,7 +939,12 @@ def get_available_item_locations_for_batched_item(


def get_available_item_locations_for_other_item(
item_code, from_warehouses, required_qty, company, total_picked_qty=0
item_code,
from_warehouses,
required_qty,
company,
total_picked_qty=0,
consider_rejected_warehouses=False,
):
bin = frappe.qb.DocType("Bin")
query = (
Expand All @@ -915,6 +961,10 @@ def get_available_item_locations_for_other_item(
wh = frappe.qb.DocType("Warehouse")
query = query.from_(wh).where((bin.warehouse == wh.name) & (wh.company == company))

if not consider_rejected_warehouses:
if rejected_warehouses := get_rejected_warehouses():
query = query.where(bin.warehouse.notin(rejected_warehouses))

item_locations = query.run(as_dict=True)

return item_locations
Expand Down Expand Up @@ -1236,3 +1286,15 @@ def update_common_item_properties(item, location):
item.serial_no = location.serial_no
item.batch_no = location.batch_no
item.material_request_item = location.material_request_item


def get_rejected_warehouses():
if not hasattr(frappe.local, "rejected_warehouses"):
frappe.local.rejected_warehouses = []

if not frappe.local.rejected_warehouses:
frappe.local.rejected_warehouses = frappe.get_all(
"Warehouse", filters={"is_rejected_warehouse": 1}, pluck="name"
)

return frappe.local.rejected_warehouses
10 changes: 9 additions & 1 deletion erpnext/stock/doctype/warehouse/warehouse.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"column_break_3",
"is_group",
"parent_warehouse",
"is_rejected_warehouse",
"column_break_4",
"account",
"company",
Expand Down Expand Up @@ -249,13 +250,20 @@
{
"fieldname": "column_break_qajx",
"fieldtype": "Column Break"
},
{
"default": "0",
"description": "If yes, then this warehouse will be used to store rejected materials",
"fieldname": "is_rejected_warehouse",
"fieldtype": "Check",
"label": "Is Rejected Warehouse"
}
],
"icon": "fa fa-building",
"idx": 1,
"is_tree": 1,
"links": [],
"modified": "2023-05-29 13:10:43.333160",
"modified": "2024-01-24 16:27:28.299520",
"modified_by": "Administrator",
"module": "Stock",
"name": "Warehouse",
Expand Down
Loading