my solution for your kind reference
how about keep the original small text Serial No and batch field in the xxx Item (Purchase Invoice Item) row, user can copy from excel multi serial no per row, or same item code and different batch in multi rows, in the backend python code to handle auto create serial no and batch master as needed, also create the serial batch bundle, this way the user can almost work the same way as before.
here is my customized sample code to handle batch no in multi row
items_has_batch_no = frappe.get_all("Item",
filters = {
"name": ("in", [r.item_code for r in doc.items if not r.serial_and_batch_bundle]),
"has_batch_no": 1},
pluck="name")
item_code_batch_map = {}
for row in doc.items:
if row.item_code in items_has_batch_no and row.custom_new_batch_no:
item_code_batch_map.setdefault((row.item_code, row.warehouse), []).append(
(row.qty, row.custom_new_batch_no, row.custom_supplier_batch_no))
item_code_sabb_map = {}
if item_code_batch_map:
for (item_code, warehouse), batches in item_code_batch_map.items():
sabb = frappe.new_doc("Serial and Batch Bundle")
sabb.update({
"item_code": item_code,
"warehouse": warehouse,
"type_of_transaction": "Inward",
"has_batch_no": 1,
"voucher_type": "Purchase Receipt"
})
existing_batches = frappe.get_all("Batch",
filters={"name": ("in", [b[1] for b in batches])},
pluck ="name" )
for (qty, batch_no, custom_supplier_batch_no) in batches:
if not batch_no in existing_batches:
batch_doc = frappe.new_doc("Batch")
batch_doc.update({
"item": item_code,
"batch_id": batch_no,
#"batch_qty": qty,
"custom_supplier_batch_no": custom_supplier_batch_no
})
batch_doc.save()
sabb.append(
"entries",
{
"qty": qty,
"batch_no": batch_no
},
)
sabb.save()
item_code_sabb_map[item_code] = sabb.name
#按物料号合并
qty_map = {} #中间变量记录物料号与数量,库存数量,客户po对照表
row_names = [] #列表变量,记录料号出现第一次的行编号,用来删除其它重复行
if len(doc.items) > len({r.item_code for r in doc.items}): #只有包括重复料号时,才执行这段代码
for row in doc.items:
item_code = row.item_code
qty_dict = qty_map.get(item_code)
if not qty_dict: #判断物料是否第一次出现
qty_map[item_code] = {}
for field in ['qty','stock_qty','received_stock_qty','received_qty']:
qty_map[item_code][field] = row.get(field)
row_names.append(row.name)
else:
for field in ['qty','stock_qty','received_stock_qty','received_qty']: #接下来的重复物料行,累加数量,合并字符串
qty_map[item_code][field] = qty_map[item_code][field] + row.get(field)
#doc.items = [r for r in doc.items if r.name in row_names] #仅保留首次出现的行,即删除重复行,这一句脚本环境运行不了!
items = []
for r in doc.items:
if r.name in row_names:
items.append(r)
doc.items = items
for row in doc.items: #修改数量,库存数量,客户po字段
item_code = row.item_code
row.serial_and_batch_bundle = item_code_sabb_map.get(row.item_code)
row.custom_new_batch_no = ''
row.custom_supplier_batch_no = ''
for field in ['qty','stock_qty','received_stock_qty','received_qty']:
row.update({field:qty_map[item_code][field]})
#根据采购订单号获取采购订单明细ID
po_item_list = frappe.get_all("Purchase Order Item",
filters = {"parent": ("in", [r.purchase_order for r in doc.items if r.purchase_order and not r.purchase_order_item])},
fields = ['parent as po','item_code','name', 'rate'])
if po_item_list:
item_code_po_item_map = {(r.po, r.item_code):(r.name, r.rate) for r in po_item_list}
for row in doc.items:
po_info =item_code_po_item_map.get((row.purchase_order,row.item_code))
if po_info:
row.purchase_order_item = po_info[0]
row.rate = po_info[1]