diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py index db64d06962..d8cbcc141b 100644 --- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py +++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py @@ -387,7 +387,7 @@ def split_invoices(invoices): ] for pos_invoice in pos_return_docs: for item in pos_invoice.items: - if not item.serial_no: + if not item.serial_no and not item.serial_and_batch_bundle: continue return_against_is_added = any( diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/test_pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/test_pos_invoice_merge_log.py index 9e696f18b6..6af8a0015b 100644 --- a/erpnext/accounts/doctype/pos_invoice_merge_log/test_pos_invoice_merge_log.py +++ b/erpnext/accounts/doctype/pos_invoice_merge_log/test_pos_invoice_merge_log.py @@ -13,6 +13,9 @@ from erpnext.accounts.doctype.pos_invoice.test_pos_invoice import create_pos_inv from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import ( consolidate_pos_invoices, ) +from erpnext.stock.doctype.serial_and_batch_bundle.test_serial_and_batch_bundle import ( + get_serial_nos_from_bundle, +) from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry @@ -410,13 +413,13 @@ class TestPOSInvoiceMergeLog(unittest.TestCase): try: se = make_serialized_item() - serial_no = get_serial_nos(se.get("items")[0].serial_no)[0] + serial_no = get_serial_nos_from_bundle(se.get("items")[0].serial_and_batch_bundle)[0] init_user_and_profile() pos_inv = create_pos_invoice( item_code="_Test Serialized Item With Series", - serial_no=serial_no, + serial_no=[serial_no], qty=1, rate=100, do_not_submit=1, @@ -430,7 +433,7 @@ class TestPOSInvoiceMergeLog(unittest.TestCase): pos_inv2 = create_pos_invoice( item_code="_Test Serialized Item With Series", - serial_no=serial_no, + serial_no=[serial_no], qty=1, rate=100, do_not_submit=1, diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 9fa7a86cb3..51e0d91615 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2981,7 +2981,7 @@ class TestSalesInvoice(unittest.TestCase): # Sales Invoice with Payment Schedule si_with_payment_schedule = create_sales_invoice(do_not_submit=True) - si_with_payment_schedule.extend( + si_with_payment_schedule.set( "payment_schedule", [ { diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py index 34e3b131c5..11cee28a57 100644 --- a/erpnext/controllers/sales_and_purchase_return.py +++ b/erpnext/controllers/sales_and_purchase_return.py @@ -663,19 +663,31 @@ def get_filters( return filters -def get_returned_serial_nos(child_doc, parent_doc, serial_no_field=None): +def get_returned_serial_nos( + child_doc, parent_doc, serial_no_field=None, ignore_voucher_detail_no=None +): + from erpnext.stock.doctype.serial_no.serial_no import ( + get_serial_nos as get_serial_nos_from_serial_no, + ) from erpnext.stock.serial_batch_bundle import get_serial_nos if not serial_no_field: serial_no_field = "serial_and_batch_bundle" + old_field = "serial_no" + if serial_no_field == "rejected_serial_and_batch_bundle": + old_field = "rejected_serial_no" + return_ref_field = frappe.scrub(child_doc.doctype) if child_doc.doctype == "Delivery Note Item": return_ref_field = "dn_detail" serial_nos = [] - fields = [f"`{'tab' + child_doc.doctype}`.`{serial_no_field}`"] + fields = [ + f"`{'tab' + child_doc.doctype}`.`{serial_no_field}`", + f"`{'tab' + child_doc.doctype}`.`{old_field}`", + ] filters = [ [parent_doc.doctype, "return_against", "=", parent_doc.name], @@ -684,9 +696,15 @@ def get_returned_serial_nos(child_doc, parent_doc, serial_no_field=None): [parent_doc.doctype, "docstatus", "=", 1], ] + # Required for POS Invoice + if ignore_voucher_detail_no: + filters.append([child_doc.doctype, "name", "!=", ignore_voucher_detail_no]) + ids = [] for row in frappe.get_all(parent_doc.doctype, fields=fields, filters=filters): ids.append(row.get("serial_and_batch_bundle")) + if row.get(old_field): + serial_nos.extend(get_serial_nos_from_serial_no(row.get(old_field))) serial_nos.extend(get_serial_nos(ids)) diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py index ff2d70501c..15a72a862e 100644 --- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py @@ -931,7 +931,7 @@ class TestDeliveryNote(FrappeTestCase): "is_stock_item": 1, "has_batch_no": 1, "create_new_batch": 1, - "batch_number_series": "TESTBATCH.#####", + "batch_number_series": "TESTBATCHIUU.#####", }, ) make_product_bundle(parent=batched_bundle.name, items=[batched_item.name]) @@ -942,7 +942,7 @@ class TestDeliveryNote(FrappeTestCase): dn = create_delivery_note(item_code=batched_bundle.name, qty=1) dn.load_from_db() - batch_no = get_batch_from_bundle(dn.items[0].serial_and_batch_bundle) + batch_no = get_batch_from_bundle(dn.packed_items[0].serial_and_batch_bundle) self.assertTrue(batch_no) def test_payment_terms_are_fetched_when_creating_sales_invoice(self): diff --git a/erpnext/stock/doctype/putaway_rule/putaway_rule.py b/erpnext/stock/doctype/putaway_rule/putaway_rule.py index 623fbde2b0..0a04210e0b 100644 --- a/erpnext/stock/doctype/putaway_rule/putaway_rule.py +++ b/erpnext/stock/doctype/putaway_rule/putaway_rule.py @@ -11,7 +11,6 @@ from frappe import _ from frappe.model.document import Document from frappe.utils import cint, cstr, floor, flt, nowdate -from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos from erpnext.stock.utils import get_stock_balance @@ -99,7 +98,6 @@ def apply_putaway_rule(doctype, items, company, sync=None, purpose=None): item = frappe._dict(item) source_warehouse = item.get("s_warehouse") - serial_nos = get_serial_nos(item.get("serial_no")) item.conversion_factor = flt(item.conversion_factor) or 1.0 pending_qty, item_code = flt(item.qty), item.item_code pending_stock_qty = flt(item.transfer_qty) if doctype == "Stock Entry" else flt(item.stock_qty) @@ -145,9 +143,7 @@ def apply_putaway_rule(doctype, items, company, sync=None, purpose=None): if not qty_to_allocate: break - updated_table = add_row( - item, qty_to_allocate, rule.warehouse, updated_table, rule.name, serial_nos=serial_nos - ) + updated_table = add_row(item, qty_to_allocate, rule.warehouse, updated_table, rule.name) pending_stock_qty -= stock_qty_to_allocate pending_qty -= qty_to_allocate @@ -245,7 +241,7 @@ def get_ordered_putaway_rules(item_code, company, source_warehouse=None): return False, vacant_rules -def add_row(item, to_allocate, warehouse, updated_table, rule=None, serial_nos=None): +def add_row(item, to_allocate, warehouse, updated_table, rule=None): new_updated_table_row = copy.deepcopy(item) new_updated_table_row.idx = 1 if not updated_table else cint(updated_table[-1].idx) + 1 new_updated_table_row.name = None @@ -264,8 +260,8 @@ def add_row(item, to_allocate, warehouse, updated_table, rule=None, serial_nos=N if rule: new_updated_table_row.putaway_rule = rule - if serial_nos: - new_updated_table_row.serial_no = get_serial_nos_to_allocate(serial_nos, to_allocate) + + new_updated_table_row.serial_and_batch_bundle = "" updated_table.append(new_updated_table_row) return updated_table @@ -297,12 +293,3 @@ def show_unassigned_items_message(items_not_accomodated): ) frappe.msgprint(msg, title=_("Insufficient Capacity"), is_minimizable=True, wide=True) - - -def get_serial_nos_to_allocate(serial_nos, to_allocate): - if serial_nos: - allocated_serial_nos = serial_nos[0 : cint(to_allocate)] - serial_nos[:] = serial_nos[cint(to_allocate) :] # pop out allocated serial nos and modify list - return "\n".join(allocated_serial_nos) if allocated_serial_nos else "" - else: - return "" diff --git a/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py index ab0ca106a8..f5bad51714 100644 --- a/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py +++ b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py @@ -7,6 +7,11 @@ from frappe.tests.utils import FrappeTestCase from erpnext.stock.doctype.batch.test_batch import make_new_batch from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt +from erpnext.stock.doctype.serial_and_batch_bundle.test_serial_and_batch_bundle import ( + get_batch_from_bundle, + get_serial_nos_from_bundle, + make_serial_batch_bundle, +) from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse from erpnext.stock.get_item_details import get_conversion_factor @@ -382,42 +387,49 @@ class TestPutawayRule(FrappeTestCase): make_new_batch(batch_id="BOTTL-BATCH-1", item_code="Water Bottle") pr = make_purchase_receipt(item_code="Water Bottle", qty=5, do_not_submit=1) - pr.items[0].batch_no = "BOTTL-BATCH-1" pr.save() pr.submit() + pr.load_from_db() - serial_nos = frappe.get_list( - "Serial No", filters={"purchase_document_no": pr.name, "status": "Active"} - ) - serial_nos = [d.name for d in serial_nos] + batch_no = get_batch_from_bundle(pr.items[0].serial_and_batch_bundle) + serial_nos = get_serial_nos_from_bundle(pr.items[0].serial_and_batch_bundle) stock_entry = make_stock_entry( item_code="Water Bottle", source="_Test Warehouse - _TC", qty=5, + serial_no=serial_nos, target="Finished Goods - _TC", purpose="Material Transfer", apply_putaway_rule=1, do_not_save=1, ) - stock_entry.items[0].batch_no = "BOTTL-BATCH-1" - stock_entry.items[0].serial_no = "\n".join(serial_nos) stock_entry.save() + stock_entry.load_from_db() self.assertEqual(stock_entry.items[0].t_warehouse, self.warehouse_1) self.assertEqual(stock_entry.items[0].qty, 3) self.assertEqual(stock_entry.items[0].putaway_rule, rule_1.name) - self.assertEqual(stock_entry.items[0].serial_no, "\n".join(serial_nos[:3])) - self.assertEqual(stock_entry.items[0].batch_no, "BOTTL-BATCH-1") + self.assertEqual( + get_serial_nos_from_bundle(stock_entry.items[0].serial_and_batch_bundle), serial_nos[0:3] + ) + self.assertEqual(get_batch_from_bundle(stock_entry.items[0].serial_and_batch_bundle), batch_no) self.assertEqual(stock_entry.items[1].t_warehouse, self.warehouse_2) self.assertEqual(stock_entry.items[1].qty, 2) self.assertEqual(stock_entry.items[1].putaway_rule, rule_2.name) - self.assertEqual(stock_entry.items[1].serial_no, "\n".join(serial_nos[3:])) - self.assertEqual(stock_entry.items[1].batch_no, "BOTTL-BATCH-1") + self.assertEqual( + get_serial_nos_from_bundle(stock_entry.items[1].serial_and_batch_bundle), serial_nos[3:5] + ) + self.assertEqual(get_batch_from_bundle(stock_entry.items[1].serial_and_batch_bundle), batch_no) self.assertUnchangedItemsOnResave(stock_entry) + for row in stock_entry.items: + if row.serial_and_batch_bundle: + frappe.delete_doc("Serial and Batch Bundle", row.serial_and_batch_bundle) + + stock_entry.load_from_db() stock_entry.delete() pr.cancel() rule_1.delete() diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py index cfb03f0389..9f26b40aa7 100644 --- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py +++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py @@ -6,7 +6,7 @@ from collections import defaultdict from typing import Dict, List import frappe -from frappe import _, bold +from frappe import _, _dict, bold from frappe.model.document import Document from frappe.query_builder.functions import CombineDatetime, Sum from frappe.utils import add_days, cint, flt, get_link_to_form, nowtime, today @@ -82,16 +82,20 @@ class SerialandBatchBundle(Document): return serial_nos = [d.serial_no for d in self.entries if d.serial_no] - available_serial_nos = get_available_serial_nos( - frappe._dict( - { - "item_code": self.item_code, - "posting_date": self.posting_date, - "posting_time": self.posting_time, - } - ) + kwargs = frappe._dict( + { + "item_code": self.item_code, + "posting_date": self.posting_date, + "posting_time": self.posting_time, + "serial_nos": serial_nos, + } ) + if self.returned_against and self.docstatus == 1: + kwargs["ignore_voucher_detail_no"] = self.voucher_detail_no + + available_serial_nos = get_available_serial_nos(kwargs) + for data in available_serial_nos: if data.serial_no in serial_nos: self.throw_error_message( @@ -776,6 +780,10 @@ def get_available_serial_nos(kwargs): ignore_serial_nos = get_reserved_serial_nos_for_pos(kwargs) + # To ignore serial nos in the same record for the draft state + if kwargs.get("ignore_serial_nos"): + ignore_serial_nos.extend(kwargs.get("ignore_serial_nos")) + if kwargs.get("posting_date"): if kwargs.get("posting_time") is None: kwargs.posting_time = nowtime() @@ -801,7 +809,7 @@ def get_serial_nos_based_on_posting_date(kwargs, ignore_serial_nos): for d in data: if d.serial_and_batch_bundle: - sns = get_serial_nos_from_bundle(d.serial_and_batch_bundle) + sns = get_serial_nos_from_bundle(d.serial_and_batch_bundle, kwargs.get("serial_nos", [])) if d.actual_qty > 0: serial_nos.update(sns) else: @@ -823,12 +831,19 @@ def get_serial_nos_based_on_posting_date(kwargs, ignore_serial_nos): def get_reserved_serial_nos_for_pos(kwargs): + from erpnext.controllers.sales_and_purchase_return import get_returned_serial_nos from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos ignore_serial_nos = [] pos_invoices = frappe.get_all( "POS Invoice", - fields=["`tabPOS Invoice Item`.serial_no", "`tabPOS Invoice Item`.serial_and_batch_bundle"], + fields=[ + "`tabPOS Invoice Item`.serial_no", + "`tabPOS Invoice`.is_return", + "`tabPOS Invoice Item`.name as child_docname", + "`tabPOS Invoice`.name as parent_docname", + "`tabPOS Invoice Item`.serial_and_batch_bundle", + ], filters=[ ["POS Invoice", "consolidated_invoice", "is", "not set"], ["POS Invoice", "docstatus", "=", 1], @@ -850,11 +865,35 @@ def get_reserved_serial_nos_for_pos(kwargs): ignore_serial_nos.append(d.serial_no) # Will be deprecated in v16 + returned_serial_nos = [] for pos_invoice in pos_invoices: if pos_invoice.serial_no: ignore_serial_nos.extend(get_serial_nos(pos_invoice.serial_no)) - return ignore_serial_nos + if pos_invoice.is_return: + continue + + child_doc = _dict( + { + "doctype": "POS Invoice Item", + "name": pos_invoice.child_docname, + } + ) + + parent_doc = _dict( + { + "doctype": "POS Invoice", + "name": pos_invoice.parent_docname, + } + ) + + returned_serial_nos.extend( + get_returned_serial_nos( + child_doc, parent_doc, ignore_voucher_detail_no=kwargs.get("ignore_voucher_detail_no") + ) + ) + + return list(set(ignore_serial_nos) - set(returned_serial_nos)) def get_auto_batch_nos(kwargs): diff --git a/erpnext/stock/doctype/serial_no/test_serial_no.py b/erpnext/stock/doctype/serial_no/test_serial_no.py index 68623fba11..4a0abb6dd0 100644 --- a/erpnext/stock/doctype/serial_no/test_serial_no.py +++ b/erpnext/stock/doctype/serial_no/test_serial_no.py @@ -11,6 +11,11 @@ from frappe.tests.utils import FrappeTestCase from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt +from erpnext.stock.doctype.serial_and_batch_bundle.test_serial_and_batch_bundle import ( + get_batch_from_bundle, + get_serial_nos_from_bundle, + make_serial_batch_bundle, +) from erpnext.stock.doctype.serial_no.serial_no import * from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry @@ -209,23 +214,6 @@ class TestSerialNo(FrappeTestCase): self.assertEqual(sn_doc.warehouse, "_Test Warehouse - _TC") self.assertEqual(sn_doc.purchase_document_no, se.name) - def test_auto_creation_of_serial_no(self): - """ - Test if auto created Serial No excludes existing serial numbers - """ - item_code = make_item( - "_Test Auto Serial Item ", {"has_serial_no": 1, "serial_no_series": "XYZ.###"} - ).item_code - - # Reserve XYZ005 - pr_1 = make_purchase_receipt(item_code=item_code, qty=1, serial_no="XYZ005") - # XYZ005 is already used and will throw an error if used again - pr_2 = make_purchase_receipt(item_code=item_code, qty=10) - - self.assertEqual(get_serial_nos(pr_1.get("items")[0].serial_no)[0], "XYZ005") - for serial_no in get_serial_nos(pr_2.get("items")[0].serial_no): - self.assertNotEqual(serial_no, "XYZ005") - def test_serial_no_sanitation(self): "Test if Serial No input is sanitised before entering the DB." item_code = "_Test Serialized Item" @@ -288,12 +276,12 @@ class TestSerialNo(FrappeTestCase): in1.reload() in2.reload() - batch1 = in1.items[0].batch_no - batch2 = in2.items[0].batch_no + batch1 = get_batch_from_bundle(in1.items[0].serial_and_batch_bundle) + batch2 = get_batch_from_bundle(in2.items[0].serial_and_batch_bundle) batch_wise_serials = { - batch1: get_serial_nos(in1.items[0].serial_no), - batch2: get_serial_nos(in2.items[0].serial_no), + batch1: get_serial_nos_from_bundle(in1.items[0].serial_and_batch_bundle), + batch2: get_serial_nos_from_bundle(in2.items[0].serial_and_batch_bundle), } # Test FIFO diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index e686e58c1d..2f49822e69 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -142,7 +142,6 @@ class StockEntry(StockController): self.validate_job_card_item() self.set_purpose_for_stock_entry() self.clean_serial_nos() - self.validate_duplicate_serial_no() if not self.from_bom: self.fg_completed_qty = 0.0 @@ -878,52 +877,63 @@ class StockEntry(StockController): if self.stock_entry_type and not self.purpose: self.purpose = frappe.get_cached_value("Stock Entry Type", self.stock_entry_type, "purpose") - def validate_duplicate_serial_no(self): - warehouse_wise_serial_nos = {} - - # In case of repack the source and target serial nos could be same - for warehouse in ["s_warehouse", "t_warehouse"]: - serial_nos = [] - for row in self.items: - if not (row.serial_no and row.get(warehouse)): - continue - - for sn in get_serial_nos(row.serial_no): - if sn in serial_nos: - frappe.throw( - _("The serial no {0} has added multiple times in the stock entry {1}").format( - frappe.bold(sn), self.name - ) - ) - - serial_nos.append(sn) - def make_serial_and_batch_bundle_for_outward(self): + if self.docstatus == 1: + return + serial_or_batch_items = get_serial_or_batch_items(self.items) if not serial_or_batch_items: return + already_picked_serial_nos = [] + for row in self.items: if not row.s_warehouse: continue - if row.serial_and_batch_bundle or row.item_code not in serial_or_batch_items: + if row.item_code not in serial_or_batch_items: continue - bundle_doc = SerialBatchCreation( - { - "item_code": row.item_code, - "warehouse": row.s_warehouse, - "posting_date": self.posting_date, - "posting_time": self.posting_time, - "voucher_type": self.doctype, - "voucher_detail_no": row.name, - "qty": row.qty * -1, - "type_of_transaction": "Outward", - "company": self.company, - "do_not_submit": True, - } - ).make_serial_and_batch_bundle() + bundle_doc = None + if row.serial_and_batch_bundle and abs(row.qty) != abs( + frappe.get_cached_value("Serial and Batch Bundle", row.serial_and_batch_bundle, "total_qty") + ): + bundle_doc = SerialBatchCreation( + { + "item_code": row.item_code, + "warehouse": row.s_warehouse, + "serial_and_batch_bundle": row.serial_and_batch_bundle, + "type_of_transaction": "Outward", + "ignore_serial_nos": already_picked_serial_nos, + "qty": row.qty * -1, + } + ).update_serial_and_batch_entries() + elif not row.serial_and_batch_bundle: + bundle_doc = SerialBatchCreation( + { + "item_code": row.item_code, + "warehouse": row.s_warehouse, + "posting_date": self.posting_date, + "posting_time": self.posting_time, + "voucher_type": self.doctype, + "voucher_detail_no": row.name, + "qty": row.qty * -1, + "ignore_serial_nos": already_picked_serial_nos, + "type_of_transaction": "Outward", + "company": self.company, + "do_not_submit": True, + } + ).make_serial_and_batch_bundle() + + if not bundle_doc: + continue + + if self.docstatus == 0: + for entry in bundle_doc.entries: + if not entry.serial_no: + continue + + already_picked_serial_nos.append(entry.serial_no) row.serial_and_batch_bundle = bundle_doc.name diff --git a/erpnext/stock/serial_batch_bundle.py b/erpnext/stock/serial_batch_bundle.py index 06fe0f1ec2..33dd9607f4 100644 --- a/erpnext/stock/serial_batch_bundle.py +++ b/erpnext/stock/serial_batch_bundle.py @@ -255,11 +255,14 @@ class SerialBatchBundle: frappe.db.set_value("Batch", batch_no, "batch_qty", batches_qty.get(batch_no, 0)) -def get_serial_nos(serial_and_batch_bundle): +def get_serial_nos(serial_and_batch_bundle, serial_nos=None): filters = {"parent": serial_and_batch_bundle} if isinstance(serial_and_batch_bundle, list): filters = {"parent": ("in", serial_and_batch_bundle)} + if serial_nos: + filters["serial_no"] = ("in", serial_nos) + entries = frappe.get_all("Serial and Batch Entry", fields=["serial_no"], filters=filters) return [d.serial_no for d in entries] @@ -694,6 +697,18 @@ class SerialBatchCreation: return doc + def update_serial_and_batch_entries(self): + doc = frappe.get_doc("Serial and Batch Bundle", self.serial_and_batch_bundle) + doc.type_of_transaction = self.type_of_transaction + doc.set("entries", []) + self.set_auto_serial_batch_entries_for_outward() + self.set_serial_batch_entries(doc) + if not doc.get("entries"): + return frappe._dict({}) + + doc.save() + return doc + def set_auto_serial_batch_entries_for_outward(self): from erpnext.stock.doctype.batch.batch import get_available_batches from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos_for_outward @@ -707,6 +722,9 @@ class SerialBatchCreation: } ) + if self.get("ignore_serial_nos"): + kwargs["ignore_serial_nos"] = self.ignore_serial_nos + if self.has_serial_no and not self.get("serial_nos"): self.serial_nos = get_serial_nos_for_outward(kwargs) elif not self.has_serial_no and self.has_batch_no and not self.get("batches"):