diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py index d34f420091..64d4c6c082 100644 --- a/erpnext/stock/doctype/serial_no/serial_no.py +++ b/erpnext/stock/doctype/serial_no/serial_no.py @@ -205,6 +205,7 @@ def process_serial_no(sle): def validate_serial_no(sle, item_det): serial_nos = get_serial_nos(sle.serial_no) if sle.serial_no else [] + validate_material_transfer_entry(sle) if item_det.has_serial_no==0: if serial_nos: @@ -224,7 +225,9 @@ def validate_serial_no(sle, item_det): for serial_no in serial_nos: if frappe.db.exists("Serial No", serial_no): - sr = frappe.get_doc("Serial No", serial_no) + sr = frappe.db.get_value("Serial No", serial_no, ["name", "item_code", "batch_no", "sales_order", + "delivery_document_no", "delivery_document_type", "warehouse", + "purchase_document_no", "company"], as_dict=1) if sr.item_code!=sle.item_code: if not allow_serial_nos_with_different_item(serial_no, sle): @@ -305,6 +308,19 @@ def validate_serial_no(sle, item_det): frappe.throw(_("Cannot cancel {0} {1} because Serial No {2} does not belong to the warehouse {3}") .format(sle.voucher_type, sle.voucher_no, serial_no, sle.warehouse)) +def validate_material_transfer_entry(sle_doc): + sle_doc.update({ + "skip_update_serial_no": False, + "skip_serial_no_validaiton": False + }) + + if (sle_doc.voucher_type == "Stock Entry" and sle_doc.is_cancelled == "No" and + frappe.get_cached_value("Stock Entry", sle_doc.voucher_no, "purpose") == "Material Transfer"): + if sle_doc.actual_qty < 0: + sle_doc.skip_update_serial_no = True + else: + sle_doc.skip_serial_no_validaiton = True + def validate_so_serial_no(sr, sales_order,): if not sr.sales_order or sr.sales_order!= sales_order: frappe.throw(_("""Sales Order {0} has reservation for item {1}, you can @@ -312,7 +328,8 @@ def validate_so_serial_no(sr, sales_order,): be delivered""").format(sales_order, sr.item_code, sr.name)) def has_duplicate_serial_no(sn, sle): - if sn.warehouse and sle.voucher_type != 'Stock Reconciliation': + if (sn.warehouse and not sle.skip_serial_no_validaiton + and sle.voucher_type != 'Stock Reconciliation'): return True if sn.company != sle.company: @@ -337,7 +354,7 @@ def allow_serial_nos_with_different_item(sle_serial_no, sle): """ allow_serial_nos = False if sle.voucher_type=="Stock Entry" and cint(sle.actual_qty) > 0: - stock_entry = frappe.get_doc("Stock Entry", sle.voucher_no) + stock_entry = frappe.get_cached_doc("Stock Entry", sle.voucher_no) if stock_entry.purpose in ("Repack", "Manufacture"): for d in stock_entry.get("items"): if d.serial_no and (d.s_warehouse if sle.is_cancelled=="No" else d.t_warehouse): @@ -348,6 +365,7 @@ def allow_serial_nos_with_different_item(sle_serial_no, sle): return allow_serial_nos def update_serial_nos(sle, item_det): + if sle.skip_update_serial_no: return if sle.is_cancelled == "No" and not sle.serial_no and cint(sle.actual_qty) > 0 \ 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) @@ -369,22 +387,16 @@ def auto_make_serial_nos(args): voucher_type = args.get('voucher_type') item_code = args.get('item_code') for serial_no in serial_nos: + is_new = False if frappe.db.exists("Serial No", serial_no): - sr = frappe.get_doc("Serial No", serial_no) - sr.via_stock_ledger = True - sr.item_code = item_code - sr.warehouse = args.get('warehouse') if args.get('actual_qty', 0) > 0 else None - sr.batch_no = args.get('batch_no') - sr.location = args.get('location') - sr.company = args.get('company') - sr.supplier = args.get('supplier') - if sr.sales_order and voucher_type == "Stock Entry" \ - and not args.get('actual_qty', 0) > 0: - sr.sales_order = None - sr.update_serial_no_reference() - sr.save(ignore_permissions=True) + sr = frappe.get_cached_doc("Serial No", serial_no) elif args.get('actual_qty', 0) > 0: - created_numbers.append(make_serial_no(serial_no, args)) + sr = frappe.new_doc("Serial No") + is_new = True + + sr = update_args_for_serial_no(sr, serial_no, args, is_new=is_new) + if is_new: + created_numbers.append(sr.name) form_links = list(map(lambda d: frappe.utils.get_link_to_form('Serial No', d), created_numbers)) @@ -419,20 +431,34 @@ def get_serial_nos(serial_no): return [s.strip() for s in cstr(serial_no).strip().upper().replace(',', '\n').split('\n') if s.strip()] -def make_serial_no(serial_no, args): - sr = frappe.new_doc("Serial No") - sr.serial_no = serial_no - sr.item_code = args.get('item_code') - sr.company = args.get('company') - sr.batch_no = args.get('batch_no') - sr.via_stock_ledger = args.get('via_stock_ledger') or True - sr.warehouse = args.get('warehouse') +def update_args_for_serial_no(serial_no_doc, serial_no, args, is_new=False): + serial_no_doc.update({ + "item_code": args.get("item_code"), + "company": args.get("company"), + "batch_no": args.get("batch_no"), + "via_stock_ledger": args.get("via_stock_ledger") or True, + "supplier": args.get("supplier"), + "location": args.get("location"), + "warehouse": (args.get("warehouse") + if args.get("actual_qty", 0) > 0 else None) + }) - sr.validate_item() - sr.update_serial_no_reference(serial_no) - sr.db_insert() + if is_new: + serial_no_doc.serial_no = serial_no - return sr.name + if (serial_no_doc.sales_order and args.get("voucher_type") == "Stock Entry" + and not args.get("actual_qty", 0) > 0): + serial_no_doc.sales_order = None + + serial_no_doc.validate_item() + serial_no_doc.update_serial_no_reference(serial_no) + + if is_new: + serial_no_doc.db_insert() + else: + serial_no_doc.db_update() + + return serial_no_doc def update_serial_nos_after_submit(controller, parentfield): stock_ledger_entries = frappe.db.sql("""select voucher_detail_no, serial_no, actual_qty, warehouse diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json index c9eba71b0d..c03eb79eec 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json +++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json @@ -240,6 +240,7 @@ "options": "Company", "print_width": "150px", "read_only": 1, + "search_index": 1, "width": "150px" }, { @@ -274,7 +275,7 @@ "icon": "fa fa-list", "idx": 1, "in_create": 1, - "modified": "2019-11-27 12:17:31.522675", + "modified": "2020-02-25 22:53:33.504681", "modified_by": "Administrator", "module": "Stock", "name": "Stock Ledger Entry", diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py index 2c6c95393b..f3381c7609 100644 --- a/erpnext/stock/utils.py +++ b/erpnext/stock/utils.py @@ -136,7 +136,7 @@ def get_bin(item_code, warehouse): bin_obj.flags.ignore_permissions = 1 bin_obj.insert() else: - bin_obj = frappe.get_doc('Bin', bin) + bin_obj = frappe.get_cached_doc('Bin', bin) bin_obj.flags.ignore_permissions = True return bin_obj