Merge remote-tracking branch 'frappe/develop' into wip-4.1
diff --git a/erpnext/accounts/doctype/account/account.json b/erpnext/accounts/doctype/account/account.json
index 4c24199..f909ef6 100644
--- a/erpnext/accounts/doctype/account/account.json
+++ b/erpnext/accounts/doctype/account/account.json
@@ -288,6 +288,7 @@
   },
   {
    "amend": 0,
+   "apply_user_permissions": 0,
    "create": 1,
    "delete": 1,
    "email": 1,
diff --git a/erpnext/accounts/doctype/chart_of_accounts/import_charts.py b/erpnext/accounts/doctype/chart_of_accounts/import_charts.py
index 9e60551..7a47f6e 100644
--- a/erpnext/accounts/doctype/chart_of_accounts/import_charts.py
+++ b/erpnext/accounts/doctype/chart_of_accounts/import_charts.py
@@ -5,6 +5,7 @@
 import frappe, os, json
 
 def import_charts():
+	print "Importing Chart of Accounts"
 	frappe.db.sql("""delete from `tabChart of Accounts`""")
 	charts_dir = os.path.join(os.path.dirname(__file__), "charts")
 	for fname in os.listdir(charts_dir):
@@ -19,8 +20,8 @@
 						"source_file": fname,
 						"country": country
 					}).insert()
-					print doc.name.encode("utf-8")
-				else:
-					print "No chart for: " + chart.get("name").encode("utf-8")
-				
-	frappe.db.commit()
\ No newline at end of file
+					#print doc.name.encode("utf-8")
+				#else:
+					#print "No chart for: " + chart.get("name").encode("utf-8")
+
+	frappe.db.commit()
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.html b/erpnext/accounts/report/general_ledger/general_ledger.html
new file mode 100644
index 0000000..dda1e61
--- /dev/null
+++ b/erpnext/accounts/report/general_ledger/general_ledger.html
@@ -0,0 +1,38 @@
+<h2 class="text-center">{%= __("Statement of Account") %}</h2>
+<h4 class="text-center">{%= filters.account || "General Ledger" %}</h3>
+<hr>
+<table class="table table-bordered">
+	<thead>
+		<tr>
+			<th style="width: 10%">{%= __("Date") %}</th>
+			<th style="width: 15%">{%= __("Ref") %}</th>
+			<th style="width: 45%">{%= __("Party") %}</th>
+			<th style="width: 15%">{%= __("Debit") %}</th>
+			<th style="width: 15%">{%= __("Credit") %}</th>
+		</tr>
+	</thead>
+	<tbody>
+		{% for(var i=0, l=data.length; i<l; i++) { %}
+			<tr>
+			{% if(data[i].posting_date) { %}
+				<td>{%= dateutil.str_to_user(data[i].posting_date) %}</td>
+				<td>{%= data[i].voucher_no %}</td>
+				<td>{%= data[i].account %}
+					<br>{%= __("Against") %}: {%= data[i].account %}
+					<br>{%= __("Remarks") %}: {%= data[i].remarks %}</td>
+				<td style="text-align: right">{%= fmt_money(data[i].debit) %}</td>
+				<td style="text-align: right">{%= fmt_money(data[i].credit) %}</td>
+			{% } else { %}
+				<td></td>
+				<td></td>
+				<td><b>{%= data[i].account || "&nbsp;" %}</b></td>
+				<td style="text-align: right">
+					{%= data[i].account && fmt_money(data[i].debit) %}</td>
+				<td style="text-align: right">
+					{%= data[i].account && fmt_money(data[i].credit) %}</td>
+			{% } %}
+			</tr>
+		{% } %}
+	</tbody>
+</table>
+<p class="text-right text-muted">Printed On {%= dateutil.get_datetime_as_string() %}</p>
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 8b147b0..1dde638 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -19,11 +19,11 @@
 dump_report_map = "erpnext.startup.report_data_map.data_map"
 update_website_context = "erpnext.startup.webutils.update_website_context"
 
-mail_footer = "erpnext.startup.mail_footer"
-
 on_session_creation = "erpnext.startup.event_handlers.on_session_creation"
 before_tests = "erpnext.setup.utils.before_tests"
 
+website_generators = ["Item Group", "Item", "Sales Partner"]
+
 standard_queries = "Customer:erpnext.selling.doctype.customer.customer.get_customer_list"
 
 permission_query_conditions = {
@@ -74,3 +74,4 @@
 		"erpnext.setup.doctype.backup_manager.backup_manager.take_backups_weekly"
 	]
 }
+
diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py
index 63bf3b4..94cd3ec 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -7,6 +7,10 @@
 from frappe.utils.nestedset import NestedSet
 from frappe.website.website_generator import WebsiteGenerator
 from frappe.website.render import clear_cache
+from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow
+
+condition_field = "show_in_website"
+template = "templates/generators/item_group.html"
 
 class ItemGroup(NestedSet, WebsiteGenerator):
 	nsm_parent_field = 'parent_item_group'
@@ -39,6 +43,53 @@
 		if frappe.db.exists("Item", self.name):
 			frappe.throw(frappe._("An item exists with same name ({0}), please change the item group name or rename the item").format(self.name))
 
+	def get_context(self, context):
+		context.update({
+			"items": get_product_list_for_group(product_group = self.name, limit=100),
+			"parent_groups": get_parent_item_groups(self.name),
+			"title": self.name
+		})
+
+		if self.slideshow:
+			context.update(get_slideshow(self))
+
+		return context
+
+def get_product_list_for_group(product_group=None, start=0, limit=10):
+	child_groups = ", ".join(['"' + i[0] + '"' for i in get_child_groups(product_group)])
+
+	# base query
+	query = """select t1.name, t1.item_name, t1.page_name, t1.website_image, t1.item_group,
+			t1.web_long_description as website_description, t2.name as route
+		from `tabItem` t1, `tabWebsite Route` t2
+		where t1.show_in_website = 1 and (item_group in (%s)
+			or t1.name in (select parent from `tabWebsite Item Group` where item_group in (%s)))
+			and t1.name = t2.docname and t2.ref_doctype='Item' """ % (child_groups, child_groups)
+
+	query += """order by t1.weightage desc, t1.modified desc limit %s, %s""" % (start, limit)
+
+	data = frappe.db.sql(query, {"product_group": product_group}, as_dict=1)
+
+	return [get_item_for_list_in_html(r) for r in data]
+
+def get_child_groups(item_group_name):
+	item_group = frappe.get_doc("Item Group", item_group_name)
+	return frappe.db.sql("""select name
+		from `tabItem Group` where lft>=%(lft)s and rgt<=%(rgt)s
+			and show_in_website = 1""", {"lft": item_group.lft, "rgt": item_group.rgt})
+
+def get_item_for_list_in_html(context):
+	return frappe.get_template("templates/includes/product_in_grid.html").render(context)
+
+def get_group_item_count(item_group):
+	child_groups = ", ".join(['"' + i[0] + '"' for i in get_child_groups(item_group)])
+	return frappe.db.sql("""select count(*) from `tabItem`
+		where docstatus = 0 and show_in_website = 1
+		and (item_group in (%s)
+			or name in (select parent from `tabWebsite Item Group`
+				where item_group in (%s))) """ % (child_groups, child_groups))[0][0]
+
+
 def get_parent_item_groups(item_group_name):
 	item_group = frappe.get_doc("Item Group", item_group_name)
 	return frappe.db.sql("""select name, page_name from `tabItem Group`
diff --git a/erpnext/setup/doctype/sales_partner/sales_partner.py b/erpnext/setup/doctype/sales_partner/sales_partner.py
index b90b65e..6969519 100644
--- a/erpnext/setup/doctype/sales_partner/sales_partner.py
+++ b/erpnext/setup/doctype/sales_partner/sales_partner.py
@@ -3,9 +3,12 @@
 
 from __future__ import unicode_literals
 import frappe
-from frappe.utils import cint, cstr, filter_strip_join
+from frappe.utils import cstr, filter_strip_join
 from frappe.website.website_generator import WebsiteGenerator
 
+condition_field = "show_in_website"
+template = "templates/generators/sales_partner.html"
+
 class SalesPartner(WebsiteGenerator):
 	def autoname(self):
 		self.name = self.partner_name
@@ -25,3 +28,21 @@
 
 	def get_page_title(self):
 		return self.partner_name
+
+	def get_context(self, context):
+		address = frappe.db.get_value("Address",
+			{"sales_partner": self.name, "is_primary_address": 1},
+			"*", as_dict=True)
+		if address:
+			city_state = ", ".join(filter(None, [address.city, address.state]))
+			address_rows = [address.address_line1, address.address_line2,
+				city_state, address.pincode, address.country]
+
+			context.update({
+				"email": address.email_id,
+				"partner_address": filter_strip_join(address_rows, "\n<br>"),
+				"phone": filter_strip_join(cstr(address.phone).split(","), "\n<br>")
+			})
+
+		return context
+
diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py
index ba1dfb7..344a89e 100644
--- a/erpnext/setup/install.py
+++ b/erpnext/setup/install.py
@@ -7,6 +7,9 @@
 
 from frappe import _
 
+default_mail_footer = """<div style="padding: 7px; text-align: right; color: #888"><small>Sent via
+	<a style="color: #888" href="http://erpnext.org">ERPNext</a></div>"""
+
 def after_install():
 	frappe.get_doc({'doctype': "Role", "role_name": "Analytics"}).insert()
 	set_single_defaults()
@@ -79,3 +82,6 @@
 				pass
 
 	frappe.db.set_default("date_format", "dd-mm-yyyy")
+
+	frappe.db.set_value("Outgoing Email Settings", "Outgoing Email Settings", "footer",
+		default_mail_footer)
diff --git a/erpnext/startup/__init__.py b/erpnext/startup/__init__.py
index e20ece3..576ab05 100644
--- a/erpnext/startup/__init__.py
+++ b/erpnext/startup/__init__.py
@@ -27,10 +27,6 @@
 	"Territory": "territory"
 }
 
-# add startup propertes
-mail_footer = """<div style="padding: 7px; text-align: right; color: #888"><small>Sent via 
-	<a style="color: #888" href="http://erpnext.org">ERPNext</a></div>"""
-	
 def get_monthly_bulk_mail_limit():
 	import frappe
 	# if global settings, then 500 or unlimited
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index f43b531..f68f0e9 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -6,11 +6,15 @@
 from frappe import msgprint, _
 from frappe.utils import cstr, flt, getdate, now_datetime, formatdate
 from frappe.website.website_generator import WebsiteGenerator
-from erpnext.setup.doctype.item_group.item_group import invalidate_cache_for
+from erpnext.setup.doctype.item_group.item_group import invalidate_cache_for, get_parent_item_groups
 from frappe.website.render import clear_cache
+from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow
 
 class WarehouseNotSet(frappe.ValidationError): pass
 
+condition_field = "show_in_website"
+template = "templates/generators/item.html"
+
 class Item(WebsiteGenerator):
 	def onload(self):
 		super(Item, self).onload()
@@ -55,6 +59,14 @@
 		self.validate_name_with_item_group()
 		self.update_item_price()
 
+	def get_context(self, context):
+		context["parent_groups"] = get_parent_item_groups(self.item_group) + \
+			[{"name": self.name}]
+		if self.slideshow:
+			context.update(get_slideshow(self))
+
+		return context
+
 	def check_warehouse_is_set_for_stock_item(self):
 		if self.is_stock_item=="Yes" and not self.default_warehouse:
 			frappe.msgprint(_("Default Warehouse is mandatory for stock Item."),
diff --git a/erpnext/templates/generators/item.py b/erpnext/templates/generators/item.py
deleted file mode 100644
index 1ad070e..0000000
--- a/erpnext/templates/generators/item.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-
-import frappe
-from erpnext.setup.doctype.item_group.item_group import get_parent_item_groups
-from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow
-
-doctype = "Item"
-condition_field = "show_in_website"
-
-def get_context(context):
-	item_context = context.doc.as_dict()
-	item_context["parent_groups"] = get_parent_item_groups(context.doc.item_group) + \
-		[{"name":context.doc.name}]
-	if context.doc.slideshow:
-		item_context.update(get_slideshow(context.doc))
-
-	return item_context
diff --git a/erpnext/templates/generators/item_group.py b/erpnext/templates/generators/item_group.py
deleted file mode 100644
index 8e09dbc..0000000
--- a/erpnext/templates/generators/item_group.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-
-import frappe
-from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow
-from erpnext.setup.doctype.item_group.item_group import get_parent_item_groups
-
-doctype = "Item Group"
-condition_field = "show_in_website"
-
-def get_context(context):
-	item_group_context = context.doc.as_dict()
-	item_group_context.update({
-		"items": get_product_list_for_group(product_group = context.docname, limit=100),
-		"parent_groups": get_parent_item_groups(context.docname),
-		"title": context.docname
-	})
-
-	if context.doc.slideshow:
-		item_group_context.update(get_slideshow(context.doc))
-
-	return item_group_context
-
-def get_product_list_for_group(product_group=None, start=0, limit=10):
-	child_groups = ", ".join(['"' + i[0] + '"' for i in get_child_groups(product_group)])
-
-	# base query
-	query = """select t1.name, t1.item_name, t1.page_name, t1.website_image, t1.item_group,
-			t1.web_long_description as website_description, t2.name as route
-		from `tabItem` t1, `tabWebsite Route` t2
-		where t1.show_in_website = 1 and (item_group in (%s)
-			or t1.name in (select parent from `tabWebsite Item Group` where item_group in (%s)))
-			and t1.name = t2.docname and t2.ref_doctype='Item' """ % (child_groups, child_groups)
-
-	query += """order by t1.weightage desc, t1.modified desc limit %s, %s""" % (start, limit)
-
-	data = frappe.db.sql(query, {"product_group": product_group}, as_dict=1)
-
-	return [get_item_for_list_in_html(r) for r in data]
-
-def get_child_groups(item_group_name):
-	item_group = frappe.get_doc("Item Group", item_group_name)
-	return frappe.db.sql("""select name
-		from `tabItem Group` where lft>=%(lft)s and rgt<=%(rgt)s
-			and show_in_website = 1""", {"lft": item_group.lft, "rgt": item_group.rgt})
-
-def get_item_for_list_in_html(context):
-	return frappe.get_template("templates/includes/product_in_grid.html").render(context)
-
-def get_group_item_count(item_group):
-	child_groups = ", ".join(['"' + i[0] + '"' for i in get_child_groups(item_group)])
-	return frappe.db.sql("""select count(*) from `tabItem`
-		where docstatus = 0 and show_in_website = 1
-		and (item_group in (%s)
-			or name in (select parent from `tabWebsite Item Group`
-				where item_group in (%s))) """ % (child_groups, child_groups))[0][0]
-
diff --git a/erpnext/templates/generators/partner.py b/erpnext/templates/generators/partner.py
deleted file mode 100644
index 2079309..0000000
--- a/erpnext/templates/generators/partner.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.utils import filter_strip_join
-
-doctype = "Sales Partner"
-condition_field = "show_in_website"
-
-def get_context(context):
-	partner_context = context.doc.as_dict()
-	
-	address = frappe.db.get_value("Address", 
-		{"sales_partner": context.doc.name, "is_primary_address": 1}, 
-		"*", as_dict=True)
-	if address:
-		city_state = ", ".join(filter(None, [address.city, address.state]))
-		address_rows = [address.address_line1, address.address_line2,
-			city_state, address.pincode, address.country]
-			
-		partner_context.update({
-			"email": address.email_id,
-			"partner_address": filter_strip_join(address_rows, "\n<br>"),
-			"phone": filter_strip_join(cstr(address.phone).split(","), "\n<br>")
-		})
-	
-	return partner_context
diff --git a/erpnext/templates/includes/footer_powered.html b/erpnext/templates/includes/footer_powered.html
index 0abf2e4..9661181 100644
--- a/erpnext/templates/includes/footer_powered.html
+++ b/erpnext/templates/includes/footer_powered.html
@@ -1 +1 @@
-<a href="http://erpnext.org" style="color: #aaa;">ERPNext Powered</a>
\ No newline at end of file
+<a href="http://erpnext.com" style="color: #aaa; font-size: 11px;">ERPNext Powered</a>
diff --git a/erpnext/templates/pages/product_search.py b/erpnext/templates/pages/product_search.py
index 8b454ce..8464b25 100644
--- a/erpnext/templates/pages/product_search.py
+++ b/erpnext/templates/pages/product_search.py
@@ -4,7 +4,7 @@
 from __future__ import unicode_literals
 import frappe
 from frappe.utils import cstr
-from erpnext.templates.generators.item_group import get_item_for_list_in_html
+from erpnext.setup.doctype.item_group.item_group import get_item_for_list_in_html
 
 no_cache = 1
 no_sitemap = 1