From 9af557f9d7446da9afef41ab57fa11630ae310fe Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Mon, 30 Dec 2019 13:26:47 +0530 Subject: [PATCH] fix: incorrect batch fetched for the serialized items (#20119) * fix: incorrect batch fetched for the serialized items * Update stock_controller.py Co-authored-by: Nabin Hait --- erpnext/controllers/stock_controller.py | 12 ++++++++ erpnext/stock/doctype/batch/batch.py | 30 ++++++++++++++----- .../stock/doctype/stock_entry/stock_entry.py | 1 + 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 542073ebd76..f4a13d583f5 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -20,6 +20,7 @@ class StockController(AccountsController): def validate(self): super(StockController, self).validate() self.validate_inspection() + self.validate_serialized_batch() def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False): if self.docstatus == 2: @@ -42,6 +43,17 @@ class StockController(AccountsController): gl_entries = self.get_asset_gl_entry(gl_entries) make_gl_entries(gl_entries, from_repost=from_repost) + def validate_serialized_batch(self): + from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos + for d in self.get("items"): + if hasattr(d, 'serial_no') and hasattr(d, 'batch_no') and d.serial_no and d.batch_no: + serial_nos = get_serial_nos(d.serial_no) + for serial_no_data in frappe.get_all("Serial No", + filters={"name": ("in", serial_nos)}, fields=["batch_no", "name"]): + if serial_no_data.batch_no != d.batch_no: + frappe.throw(_("Row #{0}: Serial No {1} does not belong to Batch {2}") + .format(d.idx, serial_no_data.name, d.batch_no)) + def get_gl_entries(self, warehouse_account=None, default_expense_account=None, default_cost_center=None): diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py index 0524eee2d53..8ae978eaf05 100644 --- a/erpnext/stock/doctype/batch/batch.py +++ b/erpnext/stock/doctype/batch/batch.py @@ -226,16 +226,14 @@ def set_batch_nos(doc, warehouse_field, throw=False): warehouse = d.get(warehouse_field, None) if has_batch_no and warehouse and qty > 0: if not d.batch_no: - d.batch_no = get_batch_no(d.item_code, warehouse, qty, throw) + d.batch_no = get_batch_no(d.item_code, warehouse, qty, throw, d.serial_no) else: batch_qty = get_batch_qty(batch_no=d.batch_no, warehouse=warehouse) if flt(batch_qty, d.precision("qty")) < flt(qty, d.precision("qty")): frappe.throw(_("Row #{0}: The batch {1} has only {2} qty. Please select another batch which has {3} qty available or split the row into multiple rows, to deliver/issue from multiple batches").format(d.idx, d.batch_no, batch_qty, qty)) - - @frappe.whitelist() -def get_batch_no(item_code, warehouse, qty=1, throw=False): +def get_batch_no(item_code, warehouse, qty=1, throw=False, serial_no=None): """ Get batch number using First Expiring First Out method. :param item_code: `item_code` of Item Document @@ -245,7 +243,7 @@ def get_batch_no(item_code, warehouse, qty=1, throw=False): """ batch_no = None - batches = get_batches(item_code, warehouse, qty, throw) + batches = get_batches(item_code, warehouse, qty, throw, serial_no) for batch in batches: if cint(qty) <= cint(batch.qty): @@ -260,7 +258,23 @@ def get_batch_no(item_code, warehouse, qty=1, throw=False): return batch_no -def get_batches(item_code, warehouse, qty=1, throw=False): +def get_batches(item_code, warehouse, qty=1, throw=False, serial_no=None): + from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos + cond = '' + if serial_no: + batch = frappe.get_all("Serial No", + fields = ["distinct batch_no"], + filters= { + "item_code": item_code, + "warehouse": warehouse, + "name": ("in", get_serial_nos(serial_no)) + } + ) + + if batch and len(batch) > 1: + return [] + + cond = " and `tabBatch`.name = %s" %(frappe.db.escape(batch[0].batch_no)) return frappe.db.sql(""" select batch_id, sum(`tabStock Ledger Entry`.actual_qty) as qty @@ -268,7 +282,7 @@ def get_batches(item_code, warehouse, qty=1, throw=False): join `tabStock Ledger Entry` ignore index (item_code, warehouse) on (`tabBatch`.batch_id = `tabStock Ledger Entry`.batch_no ) where `tabStock Ledger Entry`.item_code = %s and `tabStock Ledger Entry`.warehouse = %s - and (`tabBatch`.expiry_date >= CURDATE() or `tabBatch`.expiry_date IS NULL) + and (`tabBatch`.expiry_date >= CURDATE() or `tabBatch`.expiry_date IS NULL) {0} group by batch_id order by `tabBatch`.expiry_date ASC, `tabBatch`.creation ASC - """, (item_code, warehouse), as_dict=True) \ No newline at end of file + """.format(cond), (item_code, warehouse), as_dict=True) \ No newline at end of file diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 400d1f435ac..01d54deadf3 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -75,6 +75,7 @@ class StockEntry(StockController): set_batch_nos(self, 's_warehouse') self.set_incoming_rate() + self.validate_serialized_batch() self.set_actual_qty() self.calculate_rate_and_amount(update_finished_item_rate=False)