From 62b1a29898238c92bf31d741b71d7aa4d0512dda Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Tue, 30 Jan 2024 11:25:20 +0530 Subject: [PATCH 1/5] fix: do not consider rejected warehouses in pick list (#39539) * fix: do not picked rejected materials * test: test case for pick list without rejected materials (cherry picked from commit f6725e43425043eaba7dcdd3cf3768a857a39ee6) # Conflicts: # erpnext/selling/doctype/sales_order/test_sales_order.py # erpnext/stock/doctype/pick_list/pick_list.json # erpnext/stock/doctype/pick_list/pick_list.py --- .../doctype/sales_order/test_sales_order.py | 80 ++++++++++ .../stock/doctype/pick_list/pick_list.json | 12 ++ erpnext/stock/doctype/pick_list/pick_list.py | 139 +++++++++++++++++- .../stock/doctype/warehouse/warehouse.json | 10 +- 4 files changed, 236 insertions(+), 5 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 5ae48ee56170..f446020a4fe0 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -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, @@ -1996,6 +1997,7 @@ 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")) +<<<<<<< HEAD def test_sales_order_advance_payment_status(self): from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request @@ -2022,6 +2024,84 @@ def test_sales_order_advance_payment_status(self): self.assertEqual( frappe.db.get_value(so.doctype, so.name, "advance_payment_status"), "Not Requested" ) +======= + 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) +>>>>>>> f6725e4342 (fix: do not consider rejected warehouses in pick list (#39539)) def automatically_fetch_payment_terms(enable=1): diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json index bd84aadef74b..4f09497f3706 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.json +++ b/erpnext/stock/doctype/pick_list/pick_list.json @@ -16,6 +16,7 @@ "for_qty", "column_break_4", "parent_warehouse", + "consider_rejected_warehouses", "get_item_locations", "section_break_6", "scan_barcode", @@ -184,11 +185,22 @@ "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": [], +<<<<<<< HEAD "modified": "2024-02-01 16:17:44.877426", +======= + "modified": "2024-01-24 17:05:20.317180", +>>>>>>> f6725e4342 (fix: do not consider rejected warehouses in pick list (#39539)) "modified_by": "Administrator", "module": "Stock", "name": "Pick List", diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py index e2edb20510cf..b9f97960bfa2 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.py +++ b/erpnext/stock/doctype/pick_list/pick_list.py @@ -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, ), ) @@ -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 = ( @@ -725,18 +727,37 @@ def get_available_item_locations( required_qty, company, total_picked_qty, +<<<<<<< HEAD +======= + consider_rejected_warehouses=consider_rejected_warehouses, +>>>>>>> f6725e4342 (fix: do not consider rejected warehouses in pick list (#39539)) ) 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) @@ -769,12 +790,97 @@ def get_available_item_locations( return locations +<<<<<<< HEAD +======= +def get_available_item_locations_for_serialized_item( + item_code, + from_warehouses, + required_qty, + company, + total_picked_qty=0, + consider_rejected_warehouses=False, +): + sn = frappe.qb.DocType("Serial No") + query = ( + frappe.qb.from_(sn) + .select(sn.name, sn.warehouse) + .where((sn.item_code == item_code) & (sn.company == company)) + .orderby(sn.purchase_date) + .limit(ceil(required_qty + total_picked_qty)) + ) + + if from_warehouses: + query = query.where(sn.warehouse.isin(from_warehouses)) + 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() + for serial_no, warehouse in serial_nos: + warehouse_serial_nos_map.setdefault(warehouse, []).append(serial_no) + + locations = [] + for warehouse, serial_nos in warehouse_serial_nos_map.items(): + locations.append({"qty": len(serial_nos), "warehouse": warehouse, "serial_no": serial_nos}) + + return locations + + +def get_available_item_locations_for_batched_item( + item_code, + from_warehouses, + required_qty, + company, + total_picked_qty=0, + consider_rejected_warehouses=False, +): + sle = frappe.qb.DocType("Stock Ledger Entry") + batch = frappe.qb.DocType("Batch") + + query = ( + frappe.qb.from_(sle) + .from_(batch) + .select(sle.warehouse, sle.batch_no, Sum(sle.actual_qty).as_("qty")) + .where( + (sle.batch_no == batch.name) + & (sle.item_code == item_code) + & (sle.company == company) + & (batch.disabled == 0) + & (sle.is_cancelled == 0) + & (IfNull(batch.expiry_date, "2200-01-01") > today()) + ) + .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(ceil(required_qty + total_picked_qty)) + ) + + if from_warehouses: + query = query.where(sle.warehouse.isin(from_warehouses)) + + if not consider_rejected_warehouses: + if rejected_warehouses := get_rejected_warehouses(): + query = query.where(sle.warehouse.notin(rejected_warehouses)) + + return query.run(as_dict=True) + + +>>>>>>> f6725e4342 (fix: do not consider rejected warehouses in pick list (#39539)) def get_available_item_locations_for_serial_and_batched_item( item_code, from_warehouses, required_qty, company, total_picked_qty=0, +<<<<<<< HEAD +======= + consider_rejected_warehouses=False, +>>>>>>> f6725e4342 (fix: do not consider rejected warehouses in pick list (#39539)) ): # Get batch nos by FIFO locations = get_available_item_locations_for_batched_item( @@ -782,6 +888,10 @@ def get_available_item_locations_for_serial_and_batched_item( from_warehouses, required_qty, company, +<<<<<<< HEAD +======= + consider_rejected_warehouses=consider_rejected_warehouses, +>>>>>>> f6725e4342 (fix: do not consider rejected warehouses in pick list (#39539)) ) if locations: @@ -898,7 +1008,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 = ( @@ -915,6 +1030,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 @@ -1236,3 +1355,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 diff --git a/erpnext/stock/doctype/warehouse/warehouse.json b/erpnext/stock/doctype/warehouse/warehouse.json index 43b2ad2a69b0..7b0cade3ca46 100644 --- a/erpnext/stock/doctype/warehouse/warehouse.json +++ b/erpnext/stock/doctype/warehouse/warehouse.json @@ -13,6 +13,7 @@ "column_break_3", "is_group", "parent_warehouse", + "is_rejected_warehouse", "column_break_4", "account", "company", @@ -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", From f506c6bd4f4008fa83ff506f7518fe874336afeb Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Thu, 8 Feb 2024 11:13:29 +0530 Subject: [PATCH 2/5] chore: fix conflicts --- erpnext/stock/doctype/pick_list/pick_list.py | 101 ++----------------- 1 file changed, 9 insertions(+), 92 deletions(-) diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py index b9f97960bfa2..22ad7947bc93 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.py +++ b/erpnext/stock/doctype/pick_list/pick_list.py @@ -727,10 +727,7 @@ def get_available_item_locations( required_qty, company, total_picked_qty, -<<<<<<< HEAD -======= consider_rejected_warehouses=consider_rejected_warehouses, ->>>>>>> f6725e4342 (fix: do not consider rejected warehouses in pick list (#39539)) ) elif has_serial_no: locations = get_available_item_locations_for_serialized_item( @@ -790,97 +787,13 @@ def get_available_item_locations( return locations -<<<<<<< HEAD -======= -def get_available_item_locations_for_serialized_item( - item_code, - from_warehouses, - required_qty, - company, - total_picked_qty=0, - consider_rejected_warehouses=False, -): - sn = frappe.qb.DocType("Serial No") - query = ( - frappe.qb.from_(sn) - .select(sn.name, sn.warehouse) - .where((sn.item_code == item_code) & (sn.company == company)) - .orderby(sn.purchase_date) - .limit(ceil(required_qty + total_picked_qty)) - ) - - if from_warehouses: - query = query.where(sn.warehouse.isin(from_warehouses)) - 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() - for serial_no, warehouse in serial_nos: - warehouse_serial_nos_map.setdefault(warehouse, []).append(serial_no) - - locations = [] - for warehouse, serial_nos in warehouse_serial_nos_map.items(): - locations.append({"qty": len(serial_nos), "warehouse": warehouse, "serial_no": serial_nos}) - - return locations - - -def get_available_item_locations_for_batched_item( - item_code, - from_warehouses, - required_qty, - company, - total_picked_qty=0, - consider_rejected_warehouses=False, -): - sle = frappe.qb.DocType("Stock Ledger Entry") - batch = frappe.qb.DocType("Batch") - - query = ( - frappe.qb.from_(sle) - .from_(batch) - .select(sle.warehouse, sle.batch_no, Sum(sle.actual_qty).as_("qty")) - .where( - (sle.batch_no == batch.name) - & (sle.item_code == item_code) - & (sle.company == company) - & (batch.disabled == 0) - & (sle.is_cancelled == 0) - & (IfNull(batch.expiry_date, "2200-01-01") > today()) - ) - .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(ceil(required_qty + total_picked_qty)) - ) - - if from_warehouses: - query = query.where(sle.warehouse.isin(from_warehouses)) - - if not consider_rejected_warehouses: - if rejected_warehouses := get_rejected_warehouses(): - query = query.where(sle.warehouse.notin(rejected_warehouses)) - - return query.run(as_dict=True) - - ->>>>>>> f6725e4342 (fix: do not consider rejected warehouses in pick list (#39539)) def get_available_item_locations_for_serial_and_batched_item( item_code, from_warehouses, required_qty, company, total_picked_qty=0, -<<<<<<< HEAD -======= consider_rejected_warehouses=False, ->>>>>>> f6725e4342 (fix: do not consider rejected warehouses in pick list (#39539)) ): # Get batch nos by FIFO locations = get_available_item_locations_for_batched_item( @@ -888,10 +801,7 @@ def get_available_item_locations_for_serial_and_batched_item( from_warehouses, required_qty, company, -<<<<<<< HEAD -======= consider_rejected_warehouses=consider_rejected_warehouses, ->>>>>>> f6725e4342 (fix: do not consider rejected warehouses in pick list (#39539)) ) if locations: @@ -921,7 +831,7 @@ 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) @@ -938,6 +848,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() @@ -970,7 +884,7 @@ 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( @@ -986,6 +900,9 @@ def get_available_item_locations_for_batched_item( warehouse_wise_batches = frappe._dict() for d in data: + if consider_rejected_warehouses and d.warehouse in consider_rejected_warehouses: + continue + if d.warehouse not in warehouse_wise_batches: warehouse_wise_batches.setdefault(d.warehouse, defaultdict(float)) From bbd4d4397302f73992be3edfabc5d67293227f80 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Thu, 8 Feb 2024 11:15:23 +0530 Subject: [PATCH 3/5] chore: fix conflicts --- erpnext/selling/doctype/sales_order/test_sales_order.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index f446020a4fe0..b5189b8f06f5 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -1997,7 +1997,6 @@ 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")) -<<<<<<< HEAD def test_sales_order_advance_payment_status(self): from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request @@ -2024,7 +2023,7 @@ def test_sales_order_advance_payment_status(self): self.assertEqual( frappe.db.get_value(so.doctype, so.name, "advance_payment_status"), "Not Requested" ) -======= + def test_pick_list_without_rejected_materials(self): serial_and_batch_item = make_item( "_Test Serial and Batch Item for Rejected Materials", @@ -2101,7 +2100,6 @@ def test_pick_list_without_rejected_materials(self): self.assertEqual(row.qty, 1.0) self.assertFalse(row.warehouse == rejected_warehouse) self.assertTrue(row.warehouse == warehouse) ->>>>>>> f6725e4342 (fix: do not consider rejected warehouses in pick list (#39539)) def automatically_fetch_payment_terms(enable=1): From 14627e7ad5c025370d24b76fa48c95a24276cfe0 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Thu, 8 Feb 2024 11:16:23 +0530 Subject: [PATCH 4/5] chore: fix conflicts --- erpnext/stock/doctype/pick_list/pick_list.json | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json index 4f09497f3706..0c474342a973 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.json +++ b/erpnext/stock/doctype/pick_list/pick_list.json @@ -196,11 +196,7 @@ ], "is_submittable": 1, "links": [], -<<<<<<< HEAD - "modified": "2024-02-01 16:17:44.877426", -======= - "modified": "2024-01-24 17:05:20.317180", ->>>>>>> f6725e4342 (fix: do not consider rejected warehouses in pick list (#39539)) + "modified": "2024-02-02 16:17:44.877426", "modified_by": "Administrator", "module": "Stock", "name": "Pick List", @@ -272,4 +268,4 @@ "sort_order": "DESC", "states": [], "track_changes": 1 -} \ No newline at end of file +} From ffb6da99cef3917c2ef24bd11bd4aad0dcbdae99 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 8 Feb 2024 13:06:06 +0530 Subject: [PATCH 5/5] chore: fixed test case --- erpnext/stock/doctype/pick_list/pick_list.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py index 22ad7947bc93..98ed569af1eb 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.py +++ b/erpnext/stock/doctype/pick_list/pick_list.py @@ -831,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, consider_rejected_warehouses=False, + 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) @@ -884,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, consider_rejected_warehouses=False, + item_code, + from_warehouses, + required_qty, + company, + total_picked_qty=0, + consider_rejected_warehouses=False, ): locations = [] data = get_auto_batch_nos( @@ -899,8 +909,12 @@ def get_available_item_locations_for_batched_item( ) warehouse_wise_batches = frappe._dict() + rejected_warehouses = get_rejected_warehouses() + for d in data: - if consider_rejected_warehouses and d.warehouse in consider_rejected_warehouses: + if ( + not consider_rejected_warehouses and rejected_warehouses and d.warehouse in rejected_warehouses + ): continue if d.warehouse not in warehouse_wise_batches: