Stock Entry: Serial No Mandatory when purpose in Material Transfer, Sales Return, Purchase Return
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 847e09e..aba7a88 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -424,8 +424,7 @@
def get_stock_items(self):
stock_items = []
- item_codes = list(set(item.item_code for item in
- self.get(self.fname)))
+ item_codes = list(set(item.item_code for item in self.get(self.fname)))
if item_codes:
stock_items = [r[0] for r in frappe.db.sql("""select name
from `tabItem` where name in (%s) and is_stock_item='Yes'""" % \
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index d310347..83cec98 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -275,6 +275,16 @@
and voucher_no=%s""", (self.doctype, self.name)):
self.make_gl_entries()
+ def get_serialized_items(self):
+ serialized_items = []
+ item_codes = list(set([d.item_code for d in self.get(self.fname)]))
+ if item_codes:
+ serialized_items = frappe.db.sql_list("""select name from `tabItem`
+ where has_serial_no='Yes' and name in ({})""".format(", ".join(["%s"]*len(item_codes))),
+ tuple(item_codes))
+
+ return serialized_items
+
def update_gl_entries_after(posting_date, posting_time, warehouse_account=None, for_items=None):
def _delete_gl_entries(voucher_type, voucher_no):
frappe.db.sql("""delete from `tabGL Entry`
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 125a293..a7e007a 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -77,6 +77,7 @@
def validate_item(self):
stock_items = self.get_stock_items()
+ serialized_items = self.get_serialized_items()
for item in self.get("mtn_details"):
if item.item_code not in stock_items:
frappe.throw(_("{0} is not a stock Item").format(item.item_code))
@@ -88,6 +89,12 @@
item.conversion_factor = 1
if not item.transfer_qty:
item.transfer_qty = item.qty * item.conversion_factor
+ if (self.purpose in ("Material Transfer", "Sales Return", "Purchase Return")
+ and not item.serial_no
+ and item.item_code in serialized_items):
+ frappe.throw(_("Row #{0}: Please specify Serial No for Item {1}").format(item.idx, item.item_code),
+ frappe.MandatoryError)
+
def validate_warehouse(self, pro_obj):
"""perform various (sometimes conditional) validations on warehouse"""