Autoname for Batch DocType #12302 (#12461)

* add new fields:
check: use naming series
data: series prefix

* refactor autoname:
use new function - get_name_from_hash

* add new function - get_name_from_naming_series

* refactor autoname to generate name from naming series

* PEP 8 compliance
diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py
index 760643c..42e2cef 100644
--- a/erpnext/stock/doctype/batch/batch.py
+++ b/erpnext/stock/doctype/batch/batch.py
@@ -5,23 +5,43 @@
 import frappe
 from frappe import _
 from frappe.model.document import Document
+from frappe.model.naming import make_autoname
 from frappe.utils import flt, cint
 
 
 class UnableToSelectBatchError(frappe.ValidationError): pass
 
+
+def get_name_from_naming_series():
+	naming_series_prefix = frappe.db.get_single_value('Stock Settings', 'naming_series_prefix')
+	if not naming_series_prefix:
+		naming_series_prefix = 'BATCH-'
+
+	name = make_autoname(naming_series_prefix + '.#####')
+
+	return name
+
+
+def get_name_from_hash():
+	temp = None
+	while not temp:
+		temp = frappe.generate_hash()[:7].upper()
+		if frappe.db.exists('Batch', temp):
+			temp = None
+
+	return temp
+
+
 class Batch(Document):
 	def autoname(self):
-		'''Generate random ID for batch if not specified'''
+		"""Generate random ID for batch if not specified"""
 		if not self.batch_id:
 			if frappe.db.get_value('Item', self.item, 'create_new_batch'):
-				temp = None
-				while not temp:
-					temp = frappe.generate_hash()[:7].upper()
-					if frappe.db.exists('Batch', temp):
-						temp = None
-
-				self.batch_id = temp
+				use_naming_series = frappe.db.get_single_value('Stock Settings', 'use_naming_series')
+				if use_naming_series:
+					self.batch_id = get_name_from_naming_series()
+				else:
+					self.batch_id = get_name_from_hash()
 			else:
 				frappe.throw(_('Batch ID is mandatory'), frappe.MandatoryError)
 
@@ -39,14 +59,14 @@
 
 @frappe.whitelist()
 def get_batch_qty(batch_no=None, warehouse=None, item_code=None):
-	'''Returns batch actual qty if warehouse is passed,
+	"""Returns batch actual qty if warehouse is passed,
 		or returns dict of qty by warehouse if warehouse is None
 
 	The user must pass either batch_no or batch_no + warehouse or item_code + warehouse
 
 	:param batch_no: Optional - give qty for this batch no
 	:param warehouse: Optional - give qty for this warehouse
-	:param item_code: Optional - give qty for this item'''
+	:param item_code: Optional - give qty for this item"""
 	frappe.has_permission('Batch', throw=True)
 	out = 0
 	if batch_no and warehouse:
@@ -71,7 +91,7 @@
 
 @frappe.whitelist()
 def get_batches_by_oldest(item_code, warehouse):
-	'''Returns the oldest batch and qty for the given item_code and warehouse'''
+	"""Returns the oldest batch and qty for the given item_code and warehouse"""
 	batches = get_batch_qty(item_code = item_code, warehouse = warehouse)
 	batches_dates = [[batch, frappe.get_value('Batch', batch.batch_no, 'expiry_date')] for batch in batches]
 	batches_dates.sort(key=lambda tup: tup[1])
@@ -79,7 +99,7 @@
 
 @frappe.whitelist()
 def split_batch(batch_no, item_code, warehouse, qty, new_batch_id = None):
-	'''Split the batch into a new batch'''
+	"""Split the batch into a new batch"""
 	batch = frappe.get_doc(dict(doctype='Batch', item=item_code, batch_id=new_batch_id)).insert()
 	stock_entry = frappe.get_doc(dict(
 		doctype='Stock Entry',
@@ -105,7 +125,7 @@
 	return batch.name
 
 def set_batch_nos(doc, warehouse_field, throw = False):
-	'''Automatically select `batch_no` for outgoing items in item table'''
+	"""Automatically select `batch_no` for outgoing items in item table"""
 	for d in doc.items:
 		qty = d.get('stock_qty') or d.get('transfer_qty') or d.get('qty') or 0
 		has_batch_no = frappe.db.get_value('Item', d.item_code, 'has_batch_no')
diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.json b/erpnext/stock/doctype/stock_settings/stock_settings.json
index 761f807..48f89ec 100644
--- a/erpnext/stock/doctype/stock_settings/stock_settings.json
+++ b/erpnext/stock/doctype/stock_settings/stock_settings.json
@@ -3,6 +3,7 @@
  "allow_guest_to_view": 0, 
  "allow_import": 0, 
  "allow_rename": 0, 
+ "autoname": "", 
  "beta": 0, 
  "creation": "2013-06-24 16:37:54", 
  "custom": 0, 
@@ -666,6 +667,99 @@
    "search_index": 0, 
    "set_only_once": 0, 
    "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "batch_id_sb", 
+   "fieldtype": "Section Break", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Batch Identification", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "default": "0", 
+   "fieldname": "use_naming_series", 
+   "fieldtype": "Check", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Use Naming Series", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "default": "BATCH-", 
+   "depends_on": "eval:doc.use_naming_series==1", 
+   "fieldname": "naming_series_prefix", 
+   "fieldtype": "Data", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Naming Series Prefix", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
   }
  ], 
  "has_web_view": 0, 
@@ -679,7 +773,7 @@
  "issingle": 1, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2017-11-17 01:35:49.562613", 
+ "modified": "2018-01-12 09:38:58.200950", 
  "modified_by": "Administrator", 
  "module": "Stock", 
  "name": "Stock Settings",