Merge branch 'develop'
diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.js b/accounts/doctype/purchase_invoice/purchase_invoice.js
index 9d75264..fc530dd 100644
--- a/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -36,7 +36,7 @@
 					"from_date": doc.posting_date,
 					"to_date": doc.posting_date,
 				};
-				wn.set_route("general-ledger");
+				wn.set_route("query-report/General Ledger");
 			}, "icon-table");
 		}
 
diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js
index 7784005..55f6dde 100644
--- a/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/accounts/doctype/sales_invoice/sales_invoice.js
@@ -55,7 +55,7 @@
 					"from_date": doc.posting_date,
 					"to_date": doc.posting_date,
 				};
-				wn.set_route("general-ledger");
+				wn.set_route("query-report/General Ledger");
 			}, "icon-table");
 			
 			var percent_paid = cint(flt(doc.grand_total - doc.outstanding_amount) / flt(doc.grand_total) * 100);
diff --git a/accounts/report/general_ledger/general_ledger.py b/accounts/report/general_ledger/general_ledger.py
index fcf8010..bf07e25 100644
--- a/accounts/report/general_ledger/general_ledger.py
+++ b/accounts/report/general_ledger/general_ledger.py
@@ -3,20 +3,24 @@
 
 from __future__ import unicode_literals
 import webnotes
-from webnotes.utils import flt
+from webnotes.utils import flt, add_days
 from webnotes import _
+from accounts.utils import get_balance_on
 
 def execute(filters=None):
 	validate_filters(filters)
 	columns = get_columns()
-	
+	data = []
 	if filters.get("group_by"):
-		data = get_grouped_gle(filters)
+		data += get_grouped_gle(filters)
 	else:
-		data = get_gl_entries(filters)
+		data += get_gl_entries(filters)
 		if data:
 			data.append(get_total_row(data))
 
+	if filters.get("account"):
+		data = [get_opening_balance_row(filters)] + data + [get_closing_balance_row(filters)]
+
 	return columns, data
 	
 def validate_filters(filters):
@@ -27,12 +31,20 @@
 		webnotes.throw(_("Can not filter based on Voucher No, if grouped by Voucher"))
 	
 def get_columns():
-	return ["Posting Date:Date:100", "Account:Link/Account:200", "Debit:Currency:100", 
-		"Credit:Currency:100", "Voucher Type::120", "Voucher No::160", 
+	return ["Posting Date:Date:100", "Account:Link/Account:200", "Debit:Float:100", 
+		"Credit:Float:100", "Voucher Type::120", "Voucher No::160", "Link::20", 
 		"Cost Center:Link/Cost Center:100", "Remarks::200"]
 		
+def get_opening_balance_row(filters):
+	opening_balance = get_balance_on(filters["account"], add_days(filters["from_date"], -1))
+	return ["", "Opening Balance", opening_balance, 0.0, "", "", ""]
+	
+def get_closing_balance_row(filters):
+	closing_balance = get_balance_on(filters["account"], filters["to_date"])
+	return ["", "Closing Balance", closing_balance, 0.0, "", "", ""]
+		
 def get_gl_entries(filters):
-	return webnotes.conn.sql("""select 
+	gl_entries = webnotes.conn.sql("""select 
 			posting_date, account, debit, credit, voucher_type, voucher_no, cost_center, remarks 
 		from `tabGL Entry`
 		where company=%(company)s 
@@ -40,6 +52,13 @@
 			{conditions}
 		order by posting_date, account"""\
 		.format(conditions=get_conditions(filters)), filters, as_list=1)
+		
+	for d in gl_entries:
+		icon = """<a href="%s"><i class="icon icon-share" style="cursor: pointer;"></i></a>""" \
+			% ("/".join(["#Form", d[4], d[5]]),)
+		d.insert(6, icon)
+		
+	return gl_entries
 			
 def get_conditions(filters):
 	conditions = []
diff --git a/config.json b/config.json
index 07b0a13..f1f433e 100644
--- a/config.json
+++ b/config.json
@@ -1,6 +1,6 @@
 {
  "app_name": "ERPNext", 
- "app_version": "3.3.3", 
+ "app_version": "3.3.4", 
  "base_template": "app/portal/templates/base.html", 
  "modules": {
   "Accounts": {
diff --git a/patches/july_2013/p07_repost_billed_amt_in_sales_cycle.py b/patches/july_2013/p07_repost_billed_amt_in_sales_cycle.py
index 6419315..95004c0 100644
--- a/patches/july_2013/p07_repost_billed_amt_in_sales_cycle.py
+++ b/patches/july_2013/p07_repost_billed_amt_in_sales_cycle.py
@@ -5,7 +5,8 @@
 
 def execute():
 	import webnotes
+	webnotes.reload_doc('stock', 'doctype', 'packed_item')
 	for si in webnotes.conn.sql("""select name from `tabSales Invoice` where docstatus = 1"""):
 		webnotes.get_obj("Sales Invoice", si[0], 
 			with_children=1).update_qty(change_modified=False)
-		webnotes.conn.commit()
\ No newline at end of file
+		webnotes.conn.commit()
diff --git a/setup/doctype/email_digest/email_digest.py b/setup/doctype/email_digest/email_digest.py
index 082b92f..f01c8a8 100644
--- a/setup/doctype/email_digest/email_digest.py
+++ b/setup/doctype/email_digest/email_digest.py
@@ -9,6 +9,7 @@
 from webnotes.utils.dateutils import datetime_in_user_format
 from datetime import timedelta
 from dateutil.relativedelta import relativedelta
+from webnotes.utils.email_lib import sendmail
 
 content_sequence = [
 	["Income / Expenses", ["income_year_to_date", "bank_balance",
@@ -80,15 +81,15 @@
 			for user_id in recipients:
 				msg_for_this_receipient = self.get_msg_html(self.get_user_specific_content(user_id) + \
 					common_msg)
-				from webnotes.utils.email_lib import sendmail
-				sendmail(recipients=user_id, 
-					subject="[ERPNext] [{frequency} Digest] {name}".format(
-						frequency=self.doc.frequency, name=self.doc.name), 
-					msg=msg_for_this_receipient)
+				if msg_for_this_receipient:
+					sendmail(recipients=user_id, 
+						subject="[ERPNext] [{frequency} Digest] {name}".format(
+							frequency=self.doc.frequency, name=self.doc.name), 
+						msg=msg_for_this_receipient)
 			
 	def get_digest_msg(self):
 		return self.get_msg_html(self.get_user_specific_content(webnotes.session.user) + \
-			self.get_common_content())
+			self.get_common_content(), send_only_if_updates=False)
 	
 	def get_common_content(self):
 		out = []
@@ -119,14 +120,19 @@
 		
 		return out
 				
-	def get_msg_html(self, out):
+	def get_msg_html(self, out, send_only_if_updates=True):
 		with_value = [o[1] for o in out if o[0]]
 		
 		if with_value:
+			has_updates = True
 			with_value = "\n".join(with_value)
 		else:
+			has_updates = False
 			with_value = "<p>There were no updates in the items selected for this digest.</p><hr>"
 		
+		if not has_updates and send_only_if_updates:
+			return
+			
 		# seperate out no value items
 		no_value = [o[1] for o in out if not o[0]]
 		if no_value:
diff --git a/stock/report/stock_ledger/stock_ledger.py b/stock/report/stock_ledger/stock_ledger.py
index ea1a60f..034884b 100644
--- a/stock/report/stock_ledger/stock_ledger.py
+++ b/stock/report/stock_ledger/stock_ledger.py
@@ -13,10 +13,14 @@
 	data = []
 	for sle in sl_entries:
 		item_detail = item_details[sle.item_code]
+		voucher_link_icon = """<a href="%s"><i class="icon icon-share" 
+			style="cursor: pointer;"></i></a>""" \
+			% ("/".join(["#Form", sle.voucher_type, sle.voucher_no]),)
+			
 		data.append([sle.date, sle.item_code, item_detail.item_name, item_detail.item_group, 
 			item_detail.brand, item_detail.description, sle.warehouse, item_detail.stock_uom, 
 			sle.actual_qty, sle.qty_after_transaction, sle.stock_value, sle.voucher_type, 
-			sle.voucher_no, sle.batch_no, sle.serial_no, sle.company])
+			sle.voucher_no, voucher_link_icon, sle.batch_no, sle.serial_no, sle.company])
 	
 	return columns, data
 	
@@ -25,7 +29,7 @@
 		"Item Group:Link/Item Group:100", "Brand:Link/Brand:100",
 		"Description::200", "Warehouse:Link/Warehouse:100",
 		"Stock UOM:Link/UOM:100", "Qty:Float:50", "Balance Qty:Float:80", 
-		"Balance Value:Currency:100", "Voucher Type::100", "Voucher #::100",
+		"Balance Value:Currency:100", "Voucher Type::100", "Voucher #::100", "Link::30", 
 		"Batch:Link/Batch:100", "Serial #:Link/Serial No:100", "Company:Link/Company:100"]
 	
 def get_stock_ledger_entries(filters):
diff --git a/stock/report/stock_projected_qty/stock_projected_qty.py b/stock/report/stock_projected_qty/stock_projected_qty.py
index d116d03..0572f79 100644
--- a/stock/report/stock_projected_qty/stock_projected_qty.py
+++ b/stock/report/stock_projected_qty/stock_projected_qty.py
@@ -20,7 +20,7 @@
 		where item_code = item.name and warehouse = wh.name
 		order by item.name, wh.name"""\
 		.format(item_conditions=get_item_conditions(filters),
-			warehouse_conditions=get_warehouse_conditions(filters)), filters, debug=1)
+			warehouse_conditions=get_warehouse_conditions(filters)), filters)
 	
 	return columns, data