From fd83b5251302a83eba332d35198f60d9aec2a6a2 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 18 Dec 2024 20:53:56 +0530 Subject: [PATCH] fix: do not reset picked items (cherry picked from commit 34a80bfcd30b4f03be5886a286b2c8056a9931e1) --- erpnext/stock/doctype/pick_list/pick_list.py | 39 +++++++++++---- .../stock/doctype/pick_list/test_pick_list.py | 48 +++++++++++++++++-- 2 files changed, 73 insertions(+), 14 deletions(-) diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py index b48d479560d2..4550d71677ae 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.py +++ b/erpnext/stock/doctype/pick_list/pick_list.py @@ -74,9 +74,8 @@ def onload(self) -> None: def validate(self): self.validate_for_qty() - if self.pick_manually and self.get("locations"): - self.validate_stock_qty() - self.check_serial_no_status() + self.validate_stock_qty() + self.check_serial_no_status() def before_save(self): self.update_status() @@ -90,14 +89,24 @@ def validate_stock_qty(self): from erpnext.stock.doctype.batch.batch import get_batch_qty for row in self.get("locations"): - if row.batch_no and not row.qty: + if not row.picked_qty: + continue + + if row.batch_no and row.picked_qty: batch_qty = get_batch_qty(row.batch_no, row.warehouse, row.item_code) - if row.qty > batch_qty: + if row.picked_qty > batch_qty: frappe.throw( _( - "At Row #{0}: The picked quantity {1} for the item {2} is greater than available stock {3} for the batch {4} in the warehouse {5}." - ).format(row.idx, row.item_code, batch_qty, row.batch_no, bold(row.warehouse)), + "At Row #{0}: The picked quantity {1} for the item {2} is greater than available stock {3} for the batch {4} in the warehouse {5}. Please restock the item." + ).format( + row.idx, + row.picked_qty, + row.item_code, + batch_qty, + row.batch_no, + bold(row.warehouse), + ), title=_("Insufficient Stock"), ) @@ -109,11 +118,11 @@ def validate_stock_qty(self): "actual_qty", ) - if row.qty > flt(bin_qty): + if row.picked_qty > flt(bin_qty): frappe.throw( _( "At Row #{0}: The picked quantity {1} for the item {2} is greater than available stock {3} in the warehouse {4}." - ).format(row.idx, row.qty, bold(row.item_code), bin_qty, bold(row.warehouse)), + ).format(row.idx, row.picked_qty, bold(row.item_code), bin_qty, bold(row.warehouse)), title=_("Insufficient Stock"), ) @@ -429,7 +438,14 @@ def set_item_locations(self, save=False): locations_replica = self.get("locations") # reset - self.delete_key("locations") + reset_rows = [] + for row in self.get("locations"): + if not row.picked_qty: + reset_rows.append(row) + + for row in reset_rows: + self.remove(row) + updated_locations = frappe._dict() for item_doc in items: item_code = item_doc.item_code @@ -499,6 +515,9 @@ def aggregate_item_qty(self): # aggregate qty for same item item_map = OrderedDict() for item in locations: + if item.picked_qty: + continue + if not item.item_code: frappe.throw(f"Row #{item.idx}: Item Code is Mandatory") if not cint( diff --git a/erpnext/stock/doctype/pick_list/test_pick_list.py b/erpnext/stock/doctype/pick_list/test_pick_list.py index ef74ec9d6274..624b169b5ae5 100644 --- a/erpnext/stock/doctype/pick_list/test_pick_list.py +++ b/erpnext/stock/doctype/pick_list/test_pick_list.py @@ -870,7 +870,7 @@ def test_pick_list_validation(self): so = make_sales_order(item_code=item, qty=4, rate=100) pl = create_pick_list(so.name) - self.assertFalse(hasattr(pl, "locations")) + self.assertFalse(pl.locations) def test_pick_list_validation_for_serial_no(self): warehouse = "_Test Warehouse - _TC" @@ -901,7 +901,7 @@ def test_pick_list_validation_for_serial_no(self): so = make_sales_order(item_code=item, qty=4, rate=100) pl = create_pick_list(so.name) - self.assertFalse(hasattr(pl, "locations")) + self.assertFalse(pl.locations) def test_pick_list_validation_for_batch_no(self): warehouse = "_Test Warehouse - _TC" @@ -937,7 +937,7 @@ def test_pick_list_validation_for_batch_no(self): so = make_sales_order(item_code=item, qty=4, rate=100) pl = create_pick_list(so.name) - self.assertFalse(hasattr(pl, "locations")) + self.assertFalse(pl.locations) def test_pick_list_validation_for_batch_no_and_serial_item(self): warehouse = "_Test Warehouse - _TC" @@ -977,7 +977,7 @@ def test_pick_list_validation_for_batch_no_and_serial_item(self): so = make_sales_order(item_code=item, qty=4, rate=100) pl = create_pick_list(so.name) - self.assertFalse(hasattr(pl, "locations")) + self.assertFalse(pl.locations) def test_pick_list_validation_for_multiple_batches_and_sales_order(self): warehouse = "_Test Warehouse - _TC" @@ -1172,6 +1172,7 @@ def test_validate_picked_qty_with_manual_option(self): for row in pl.locations: row.qty = row.qty + 10 + row.picked_qty = row.qty self.assertRaises(frappe.ValidationError, pl.save) @@ -1266,3 +1267,42 @@ def test_ignore_pricing_rule_in_pick_list(self): delivery_note = create_delivery_note(pl.name) self.assertEqual(len(delivery_note.items), 1) + + def test_pick_list_not_reset_batch(self): + warehouse = "_Test Warehouse - _TC" + item = make_item( + "Test Do Not Reset Picked Item", + properties={ + "is_stock_item": 1, + "has_batch_no": 1, + "create_new_batch": 1, + "batch_number_series": "BTH-PICKLT-.######", + }, + ).name + + se = make_stock_entry(item=item, to_warehouse=warehouse, qty=10) + batch1 = get_batch_from_bundle(se.items[0].serial_and_batch_bundle) + se = make_stock_entry(item=item, to_warehouse=warehouse, qty=10) + batch2 = get_batch_from_bundle(se.items[0].serial_and_batch_bundle) + + so = make_sales_order(item_code=item, qty=10, rate=100) + + pl = create_pick_list(so.name) + pl.save() + + for loc in pl.locations: + self.assertEqual(loc.batch_no, batch1) + loc.batch_no = batch2 + loc.picked_qty = 0.0 + + pl.save() + + for loc in pl.locations: + self.assertEqual(loc.batch_no, batch1) + loc.batch_no = batch2 + loc.picked_qty = 10.0 + + pl.save() + + for loc in pl.locations: + self.assertEqual(loc.batch_no, batch2)