Merge branch 'master' of github.com:webnotes/erpnext
diff --git a/accounts/doctype/journal_voucher/journal_voucher.py b/accounts/doctype/journal_voucher/journal_voucher.py
index 36a5bf9..c750fc3 100644
--- a/accounts/doctype/journal_voucher/journal_voucher.py
+++ b/accounts/doctype/journal_voucher/journal_voucher.py
@@ -43,6 +43,9 @@
 		self.is_approving_authority = -1
 
 	def autoname(self):
+		if not self.doc.naming_series:
+			webnotes.msgprint("""Naming Series is mandatory""", raise_exception=1)
+			
 		self.doc.name = make_autoname(self.doc.naming_series+'.#####')
 
 	def get_outstanding(self, args):
diff --git a/stock/doctype/bin/bin.py b/stock/doctype/bin/bin.py
index 8d21a5c..2f78f9c 100644
--- a/stock/doctype/bin/bin.py
+++ b/stock/doctype/bin/bin.py
@@ -116,15 +116,17 @@
 		"""
 		diff = cqty + s['actual_qty']
 		if  diff < 0 and (abs(diff) > 0.0001) and s['is_cancelled'] == 'No':
-			msgprint("""
-				Negative stock error: 
-				Cannot complete this transaction because stock will 
-				become negative (%s) for Item <b>%s</b> in Warehouse 
-				<b>%s</b> on <b>%s %s</b> in Transaction %s %s""" % \
-				(str(diff), self.doc.item_code, self.doc.warehouse, \
-					s['posting_date'], s['posting_time'], s['voucher_type'], s['voucher_no']), \
-					raise_exception=1)
-
+			self.exc_list.append({
+				"diff": diff,
+				"posting_date": s["posting_date"],
+				"posting_time": s["posting_time"],
+				"voucher_type": s["voucher_type"],
+				"voucher_no": s["voucher_no"]
+			})
+			return True
+		else:
+			return False
+			
 	def get_serialized_inventory_values(self, val_rate, in_rate, opening_qty, \
 			actual_qty, is_cancelled, serial_nos):
 		"""
@@ -226,7 +228,7 @@
 			stock_val = sum([flt(d[0])*flt(d[1]) for d in self.fcfs_bal])
 		return stock_val
 
-	def update_entries_after(self, posting_date, posting_time):
+	def update_entries_after(self, posting_date, posting_time, verbose=1):
 		"""
 			update valution rate and qty after transaction 
 			from the current time-bucket onwards
@@ -267,11 +269,14 @@
 				(self.doc.item_code, self.doc.warehouse, \
 					prev_sle.get('posting_date','1900-01-01'), \
 					prev_sle.get('posting_time', '12:00')), as_dict = 1)
-					
+		
+		self.exc_list = []
 		for sle in sll:
 			# block if stock level goes negative on any date
 			if val_method != 'Moving Average' or flt(allow_negative_stock) == 0:
-				self.validate_negative_stock(cqty, sle)
+				if self.validate_negative_stock(cqty, sle):
+					cqty += sle['actual_qty']
+					continue
 
 			stock_val, in_rate = 0, sle['incoming_rate'] # IN
 			serial_nos = sle["serial_no"] and ("'"+"', '".join(cstr(sle["serial_no"]).split('\n')) \
@@ -289,6 +294,22 @@
 				incoming_rate = %s where name=%s""", \
 				(cqty, flt(val_rate), cstr(self.fcfs_bal), stock_val, in_rate, sle['name']))
 		
+		if self.exc_list:
+			deficiency = min(e["diff"] for e in self.exc_list)
+			msg = """Negative stock error: 
+				Cannot complete this transaction because stock will start
+				becoming negative (%s) for Item <b>%s</b> in Warehouse 
+				<b>%s</b> on <b>%s %s</b> in Transaction %s %s.
+				Total Quantity Deficiency: <b>%s</b>""" % \
+				(self.exc_list[0]["diff"], self.doc.item_code, self.doc.warehouse,
+				self.exc_list[0]["posting_date"], self.exc_list[0]["posting_time"],
+				self.exc_list[0]["voucher_type"], self.exc_list[0]["voucher_no"],
+				abs(deficiency))
+			if verbose:
+				msgprint(msg, raise_exception=1)
+			else:
+				raise webnotes.ValidationError, msg
+		
 		# update the bin
 		if sll or not prev_sle:
 			sql("""update `tabBin` set valuation_rate=%s, actual_qty=%s, stock_value = %s,
diff --git a/stock/doctype/stock_reconciliation/stock_reconciliation.py b/stock/doctype/stock_reconciliation/stock_reconciliation.py
index 7ae5170..9a806f6 100644
--- a/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -16,7 +16,7 @@
 
 from __future__ import unicode_literals
 import webnotes
-from webnotes.utils import cstr, flt, get_defaults, nowdate
+from webnotes.utils import cstr, flt, get_defaults, nowdate, formatdate
 from webnotes import msgprint, errprint
 from webnotes.model.code import get_obj
 sql = webnotes.conn.sql
@@ -229,8 +229,31 @@
 			and voucher_type = 'Stock Reconciliation'""", self.doc.name)
 		
 		from webnotes.model.code import get_obj
+		errors = []
 		for d in item_warehouse:
 			bin = webnotes.conn.sql("select name from `tabBin` where item_code = %s and \
 				warehouse = %s", (d[0], d[1]))
-			get_obj('Bin', bin[0][0]).update_entries_after(self.doc.reconciliation_date, \
-				self.doc.reconciliation_time)
\ No newline at end of file
+			try:
+				get_obj('Bin',
+					bin[0][0]).update_entries_after(self.doc.reconciliation_date,
+					self.doc.reconciliation_time, verbose=0)
+			except webnotes.ValidationError, e:
+				errors.append([d[0], d[1], e])
+		
+		if errors:
+			import re
+			error_msg = [["Item Code", "Warehouse", "Qty"]]
+			qty_regex = re.compile(": <b>(.*)</b>")
+			for e in errors:
+				qty = qty_regex.findall(unicode(e[2]))
+				qty = qty and abs(flt(qty[0])) or None
+				
+				error_msg.append([e[0], e[1], flt(qty)])
+			
+			webnotes.msgprint("""Your stock is going into negative value \
+				in a future transaction.
+				To cancel, you need to create a stock entry with the \
+				following values on %s %s""" % \
+				(formatdate(self.doc.reconciliation_date), self.doc.reconciliation_time))
+			webnotes.msgprint(error_msg, as_table=1, raise_exception=1)
+			
\ No newline at end of file