chore: used frappe.db.bulk_insert to create serial nos and serial bunndle
diff --git a/erpnext/public/js/utils/serial_no_batch_selector.js b/erpnext/public/js/utils/serial_no_batch_selector.js
index 1c98037..90967d9 100644
--- a/erpnext/public/js/utils/serial_no_batch_selector.js
+++ b/erpnext/public/js/utils/serial_no_batch_selector.js
@@ -771,7 +771,7 @@
}
frappe.call({
- method: 'erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.add_serial_batch_no_ledgers',
+ method: 'erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.add_serial_batch_ledgers',
args: {
ledgers: ledgers,
child_row: this.item
@@ -786,7 +786,7 @@
render_data() {
if (!this.frm.is_new() && this.item.serial_and_batch_bundle) {
frappe.call({
- method: 'erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.get_serial_batch_no_ledgers',
+ method: 'erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.get_serial_batch_ledgers',
args: {
item_code: this.item.item_code,
name: this.item.serial_and_batch_bundle,
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
index 97e7d72..900fb75 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
@@ -991,6 +991,7 @@
"fieldname": "serial_and_batch_bundle",
"fieldtype": "Link",
"label": "Serial and Batch Bundle",
+ "no_copy": 1,
"options": "Serial and Batch Bundle"
},
{
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 ae25aad..554c032 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
@@ -48,7 +48,7 @@
@frappe.whitelist()
-def get_serial_batch_no_ledgers(item_code, voucher_no, name=None):
+def get_serial_batch_ledgers(item_code, voucher_no, name=None):
return frappe.get_all(
"Serial and Batch Bundle",
fields=[
@@ -68,7 +68,7 @@
@frappe.whitelist()
-def add_serial_batch_no_ledgers(ledgers, child_row) -> object:
+def add_serial_batch_ledgers(ledgers, child_row) -> object:
if isinstance(child_row, str):
child_row = frappe._dict(frappe.parse_json(child_row))
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index 9338dc5..98beda0 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -16,6 +16,7 @@
flt,
get_link_to_form,
getdate,
+ now,
nowdate,
safe_json_loads,
)
@@ -189,7 +190,6 @@
def get_last_sle(self, serial_no=None):
entries = {}
sle_dict = self.get_stock_ledger_entries(serial_no)
- print("sle_dict", sle_dict)
if sle_dict:
if sle_dict.get("incoming", []):
entries["purchase_sle"] = sle_dict["incoming"][0]
@@ -538,13 +538,151 @@
and item_det.has_serial_no == 1
and item_det.serial_no_series
):
- serial_nos = get_auto_serial_nos(item_det.serial_no_series, sle.actual_qty)
- sle.db_set("serial_no", serial_nos)
- validate_serial_no(sle, item_det)
- if sle.serial_and_batch_bundle:
+ bundle = make_serial_bundle(sle, item_det)
+ if bundle:
+ sle.db_set("serial_and_batch_bundle", bundle.name)
+ child_doctype = sle.voucher_type + " Item"
+ if sle.voucher_type == "Stock Entry":
+ child_doctype = "Stock Entry Detail"
+ elif sle.voucher_type == "Stock Reconciliation":
+ child_doctype = "Stock Reconciliation Item"
+
+ frappe.db.set_value(
+ child_doctype, sle.voucher_detail_no, "serial_and_batch_bundle", bundle.name
+ )
+
+ elif sle.serial_and_batch_bundle:
auto_make_serial_nos(sle)
+def make_serial_bundle(sle, item_details):
+ sr_nos = auto_create_serial_nos(sle, item_details)
+
+ if sr_nos:
+ sn_doc = frappe.new_doc("Serial and Batch Bundle")
+ sn_doc.item_code = item_details.name
+ sn_doc.item_name = item_details.item_name
+ sn_doc.item_group = item_details.item_group
+ sn_doc.has_serial_no = item_details.has_serial_no
+ sn_doc.has_batch_no = item_details.has_batch_no
+ sn_doc.voucher_type = sle.voucher_type
+ sn_doc.voucher_no = sle.voucher_no
+ sn_doc.flags.ignore_mandatory = True
+ sn_doc.qty = sle.actual_qty
+ sn_doc.insert()
+
+ batch_no = ""
+ if item_details.has_batch_no:
+ batch_no = create_batch_for_serial_no(sle)
+
+ ledgers = []
+ fields = [
+ "name",
+ "serial_no",
+ "batch_no",
+ "warehouse",
+ "qty",
+ "parent",
+ "parenttype",
+ "parentfield",
+ ]
+
+ for serial_no in sr_nos:
+ ledgers.append(
+ (
+ frappe.generate_hash("", 10),
+ serial_no,
+ batch_no,
+ sle.warehouse,
+ 1,
+ sn_doc.name,
+ sn_doc.doctype,
+ "ledgers",
+ )
+ )
+
+ frappe.db.bulk_insert(
+ "Serial and Batch Ledger",
+ fields=fields,
+ values=set(ledgers),
+ ignore_duplicates=True,
+ )
+
+ sn_doc.load_from_db()
+ return sn_doc.submit()
+
+
+def create_batch_for_serial_no(sle):
+ from erpnext.stock.doctype.batch.batch import make_batch
+
+ return make_batch(
+ frappe._dict(
+ {
+ "item": sle.item_code,
+ "reference_doctype": sle.voucher_type,
+ "reference_name": sle.voucher_no,
+ }
+ )
+ )
+
+
+def auto_create_serial_nos(sle, item_details) -> List[str]:
+ sr_nos = []
+ serial_nos_details = []
+ for i in range(cint(sle.actual_qty)):
+ serial_no = make_autoname(item_details.serial_no_series, "Serial No")
+ sr_nos.append(serial_no)
+ serial_nos_details.append(
+ (
+ serial_no,
+ serial_no,
+ now(),
+ now(),
+ frappe.session.user,
+ frappe.session.user,
+ sle.voucher_type,
+ sle.voucher_no,
+ sle.warehouse,
+ sle.company,
+ sle.posting_date,
+ sle.posting_time,
+ sle.incoming_rate,
+ sle.item_code,
+ item_details.item_name,
+ item_details.description,
+ )
+ )
+
+ if serial_nos_details:
+ fields = [
+ "name",
+ "serial_no",
+ "creation",
+ "modified",
+ "owner",
+ "modified_by",
+ "purchase_document_type",
+ "purchase_document_no",
+ "warehouse",
+ "company",
+ "purchase_date",
+ "purchase_time",
+ "purchase_rate",
+ "item_code",
+ "item_name",
+ "description",
+ ]
+
+ frappe.db.bulk_insert(
+ "Serial No",
+ fields=fields,
+ values=set(serial_nos_details),
+ ignore_duplicates=True,
+ )
+
+ return sr_nos
+
+
def get_auto_serial_nos(serial_no_series, qty):
serial_nos = []
for i in range(cint(qty)):
@@ -609,7 +747,8 @@
def get_item_details(item_code):
return frappe.db.sql(
"""select name, has_batch_no, docstatus,
- is_stock_item, has_serial_no, serial_no_series
+ is_stock_item, has_serial_no, serial_no_series, description, item_name,
+ item_group, stock_uom
from tabItem where name=%s""",
item_code,
as_dict=True,
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
index 916b14a..1bcea69 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
@@ -40,7 +40,6 @@
from erpnext.stock.utils import validate_disabled_warehouse, validate_warehouse_company
self.validate_mandatory()
- self.validate_serial_batch_no_bundle()
self.validate_batch()
validate_disabled_warehouse(self.warehouse)
validate_warehouse_company(self.warehouse, self.company)
@@ -58,6 +57,8 @@
process_serial_no(self)
+ self.validate_serial_batch_no_bundle()
+
def calculate_batch_qty(self):
if self.batch_no:
batch_qty = (