Merge branch 'develop' into show_address_in_online_pos
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index f4876bd..1b88bdc 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -5,7 +5,7 @@
 from erpnext.hooks import regional_overrides
 from frappe.utils import getdate
 
-__version__ = '10.0.14'
+__version__ = '10.0.17'
 
 def get_default_company(user=None):
 	'''Get default company for user'''
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js
index 48062a3..60c974f 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.js
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js
@@ -82,8 +82,8 @@
 			$.each(this.frm.doc.accounts || [], function(i, jvd) {
 				frappe.model.set_default_values(jvd);
 			});
-
-			if(!this.frm.doc.amended_from) this.frm.doc.posting_date = this.frm.posting_date || frappe.datetime.get_today();
+			var posting_date = this.frm.posting_date;
+			if(!this.frm.doc.amended_from) this.frm.set_value('posting_date', posting_date || frappe.datetime.get_today());
 		}
 	},
 
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 3f9bca7..21b71ff 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -96,7 +96,7 @@
 		if not self.credit_to:
 			self.credit_to = get_party_account("Supplier", self.supplier, self.company)
 		if not self.due_date:
-			self.due_date = get_due_date(self.posting_date, "Supplier", self.supplier)
+			self.due_date = get_due_date(self.posting_date, "Supplier", self.supplier, self.company)
 
 		super(PurchaseInvoice, self).set_missing_values(for_validate)
 
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index bf6ad49..266e3e1 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -237,7 +237,7 @@
 		if not self.debit_to:
 			self.debit_to = get_party_account("Customer", self.customer, self.company)
 		if not self.due_date and self.customer:
-			self.due_date = get_due_date(self.posting_date, "Customer", self.customer)
+			self.due_date = get_due_date(self.posting_date, "Customer", self.customer, self.company)
 
 		super(SalesInvoice, self).set_missing_values(for_validate)
 
diff --git a/erpnext/accounts/doctype/subscription/subscription.py b/erpnext/accounts/doctype/subscription/subscription.py
index 1103b70..480abd4 100644
--- a/erpnext/accounts/doctype/subscription/subscription.py
+++ b/erpnext/accounts/doctype/subscription/subscription.py
@@ -232,6 +232,8 @@
 def send_notification(new_rv, subscription_doc, print_format='Standard'):
 	"""Notify concerned persons about recurring document generation"""
 	print_format = print_format
+	subject = subscription_doc.subject or ''
+	message = subscription_doc.message or ''
 
 	if not subscription_doc.subject:
 		subject = _("New {0}: #{1}").format(new_rv.doctype, new_rv.name)
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index c575d59..03a06cc 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -191,8 +191,9 @@
 	for entry in gl_entries:
 		validate_frozen_account(entry["account"], adv_adj)
 		validate_balance_type(entry["account"], adv_adj)
-		validate_expense_against_budget(entry)
+		if not adv_adj:
+			validate_expense_against_budget(entry)
 		
-		if entry.get("against_voucher") and update_outstanding == 'Yes':
+		if entry.get("against_voucher") and update_outstanding == 'Yes' and not adv_adj:
 			update_outstanding_amt(entry["account"], entry.get("party_type"), entry.get("party"), entry.get("against_voucher_type"),
 				entry.get("against_voucher"), on_cancel=True)
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index 7bccfe8..5237a71 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -51,7 +51,7 @@
 	set_other_values(out, party, party_type)
 	set_price_list(out, party, party_type, price_list)
 	out["taxes_and_charges"] = set_taxes(party.name, party_type, posting_date, company, out.customer_group, out.supplier_type)
-	out["payment_terms_template"] = get_pyt_term_template(party.name, party_type)
+	out["payment_terms_template"] = get_pyt_term_template(party.name, party_type, company)
 
 	if not out.get("currency"):
 		out["currency"] = currency
@@ -164,7 +164,7 @@
 	out = {
 		party_type.lower(): party,
 		account_fieldname : account,
-		"due_date": get_due_date(posting_date, party_type, party)
+		"due_date": get_due_date(posting_date, party_type, party, company)
 	}
 	return out
 
@@ -267,12 +267,12 @@
 
 
 @frappe.whitelist()
-def get_due_date(posting_date, party_type, party):
+def get_due_date(posting_date, party_type, party, company=None):
 	"""Get due date from `Payment Terms Template`"""
 	due_date = None
 	if posting_date and party:
 		due_date = posting_date
-		template_name = get_pyt_term_template(party, party_type)
+		template_name = get_pyt_term_template(party, party_type, company)
 		if template_name:
 			due_date = get_due_date_from_template(template_name, posting_date).strftime("%Y-%m-%d")
 		else:
@@ -305,12 +305,11 @@
 
 	return due_date
 
-
-def validate_due_date(posting_date, due_date, party_type, party):
+def validate_due_date(posting_date, due_date, party_type, party, company=None):
 	if getdate(due_date) < getdate(posting_date):
 		frappe.throw(_("Due Date cannot be before Posting Date"))
 	else:
-		default_due_date = get_due_date(posting_date, party_type, party)
+		default_due_date = get_due_date(posting_date, party_type, party, company)
 		if not default_due_date:
 			return
 
@@ -360,14 +359,32 @@
 
 
 @frappe.whitelist()
-def get_pyt_term_template(party_name, party_type):
+def get_pyt_term_template(party_name, party_type, company=None):
+	if party_type not in ("Customer", "Supplier"):
+		return
+
 	template = None
-	if party_type in ('Customer', 'Supplier'):
-		template = frappe.db.get_value(party_type, party_name, fieldname='payment_terms')
+	if party_type == 'Customer':
+		customer = frappe.db.get_value("Customer", party_name,
+			fieldname=['payment_terms', "customer_group"], as_dict=1)
+		template = customer.payment_terms
+
+		if not template and customer.customer_group:
+			template = frappe.db.get_value("Customer Group",
+				customer.customer_group, fieldname='payment_terms')
+	else:
+		supplier = frappe.db.get_value("Supplier", party_name,
+			fieldname=['payment_terms', "supplier_type"], as_dict=1)
+		template = supplier.payment_terms
+
+		if not template and supplier.supplier_type:
+			template = frappe.db.get_value("Supplier Type", supplier.supplier_type, fieldname='payment_terms')
+
+	if not template and company:
+		template = frappe.db.get_value("Company", company, fieldname='payment_terms')
 
 	return template
 
-
 def validate_party_frozen_disabled(party_type, party_name):
 	if party_type and party_name:
 		if party_type in ("Customer", "Supplier"):
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
index fd5241b..ac641c2 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
@@ -29,6 +29,24 @@
 			"options": "Payment Terms Template"
 		},
 		{
+			"fieldname":"territory",
+			"label": __("Territory"),
+			"fieldtype": "Link",
+			"options": "Territory"
+		},
+		{
+			"fieldname":"sales_partner",
+			"label": __("Sales Partner"),
+			"fieldtype": "Link",
+			"options": "Sales Partner"
+		},
+		{
+			"fieldname":"sales_person",
+			"label": __("Sales Person"),
+			"fieldtype": "Link",
+			"options": "Sales Person"
+		},
+		{
 			"fieldtype": "Break",
 		},
 		{
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 0732b7d..14fdbbd 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -282,11 +282,27 @@
 				conditions.append("""party in (select name from tabCustomer
 					where exists(select name from `tabCustomer Group` where lft >= {0} and rgt <= {1}
 						and name=tabCustomer.customer_group))""".format(lft, rgt))
+			
+			if self.filters.get("territory"):
+				lft, rgt = frappe.db.get_value("Territory",
+					self.filters.get("territory"), ["lft", "rgt"])
+
+				conditions.append("""party in (select name from tabCustomer
+					where exists(select name from `tabTerritory` where lft >= {0} and rgt <= {1}
+						and name=tabCustomer.territory))""".format(lft, rgt))
 
 			if self.filters.get("payment_terms_template"):
 				conditions.append("party in (select name from tabCustomer where payment_terms=%s)")
 				values.append(self.filters.get("payment_terms_template"))
 
+			if self.filters.get("sales_partner"):
+				conditions.append("party in (select name from tabCustomer where default_sales_partner=%s)")
+				values.append(self.filters.get("sales_partner"))
+
+			if self.filters.get("sales_person"):
+				conditions.append("""party in (select parent
+					from `tabSales Team` where sales_person=%s and parenttype = 'Customer')""")
+				values.append(self.filters.get("sales_person"))
 		return " and ".join(conditions), values
 
 	def get_gl_entries_for(self, party, party_type, against_voucher_type, against_voucher):
diff --git a/erpnext/buying/doctype/supplier/test_records.json b/erpnext/buying/doctype/supplier/test_records.json
index 7479f55..370ce8d 100644
--- a/erpnext/buying/doctype/supplier/test_records.json
+++ b/erpnext/buying/doctype/supplier/test_records.json
@@ -9,7 +9,6 @@
   "doctype": "Supplier",
   "supplier_name": "_Test Supplier P",
   "supplier_type": "_Test Supplier Type",
-  "credit_days_based_on": "Fixed Days"
  },
  {
   "doctype": "Supplier",
diff --git a/erpnext/config/desktop.py b/erpnext/config/desktop.py
index ffe9996..18bb36b 100644
--- a/erpnext/config/desktop.py
+++ b/erpnext/config/desktop.py
@@ -283,7 +283,7 @@
 			"label": _("Education"),
 			"hidden": 1
 		},
-        {
+		{
 			"module_name": "Healthcare",
 			"color": "#FF888B",
 			"icon": "fa fa-heartbeat",
@@ -292,29 +292,14 @@
 			"hidden": 1
 		},
         {
-			"module_name": "Lab Test",
-			"color": "#7578f6",
-			"icon": "octicon octicon-beaker",
-			"doctype": "Lab Test",
-			"type": "list",
-			"link": "List/Lab Test",
-			"label": _("Lab Test")
-        },
-        {
-			"module_name": "Consultation",
-			"color": "#2ecc71",
-			"icon": "fa fa-stethoscope",
-			"doctype": "Consultation",
-			"type": "link",
-			"label": _("Consultationt")
-        },
-        {
 			"module_name": "Patient",
 			"color": "#6BE273",
 			"icon": "fa fa-user",
 			"doctype": "Patient",
 			"type": "link",
-			"label": _("Patient")
+			"link": "List/Patient",
+			"label": _("Patient"),
+			"hidden": 1
         },
         {
 			"module_name": "Patient Appointment",
@@ -322,7 +307,29 @@
 			"icon": "fa fa-calendar-plus-o",
 			"doctype": "Patient Appointment",
 			"type": "link",
-			"label": _("Patient Appointment")
+			"link": "List/Patient Appointment",
+			"label": _("Patient Appointment"),
+			"hidden": 1
+        },
+        {
+			"module_name": "Consultation",
+			"color": "#2ecc71",
+			"icon": "fa fa-stethoscope",
+			"doctype": "Consultation",
+			"type": "link",
+			"link": "List/Consultation",
+			"label": _("Consultation"),
+			"hidden": 1
+        },
+        {
+			"module_name": "Lab Test",
+			"color": "#7578f6",
+			"icon": "octicon octicon-beaker",
+			"doctype": "Lab Test",
+			"type": "list",
+			"link": "List/Lab Test",
+			"label": _("Lab Test"),
+			"hidden": 1
         },
 		{
 			"module_name": "Hub",
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index c7b5206..b3672cb 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -135,9 +135,9 @@
 			if not self.due_date:
 				frappe.throw(_("Due Date is mandatory"))
 
-			validate_due_date(self.posting_date, self.due_date, "Customer", self.customer)
+			validate_due_date(self.posting_date, self.due_date, "Customer", self.customer, self.company)
 		elif self.doctype == "Purchase Invoice":
-			validate_due_date(self.posting_date, self.due_date, "Supplier", self.supplier)
+			validate_due_date(self.posting_date, self.due_date, "Supplier", self.supplier, self.company)
 
 	def set_price_list_currency(self, buying_or_selling):
 		if self.meta.get_field("posting_date"):
diff --git "a/erpnext/docs/user/manual/en/regional/france/fichier_des_\303\251critures_comptables.md" b/erpnext/docs/user/manual/en/regional/france/fichier_des_ecritures_comptables.md
similarity index 100%
rename from "erpnext/docs/user/manual/en/regional/france/fichier_des_\303\251critures_comptables.md"
rename to erpnext/docs/user/manual/en/regional/france/fichier_des_ecritures_comptables.md
diff --git a/erpnext/docs/user/manual/en/regional/france/index.txt b/erpnext/docs/user/manual/en/regional/france/index.txt
new file mode 100644
index 0000000..2edf323
--- /dev/null
+++ b/erpnext/docs/user/manual/en/regional/france/index.txt
@@ -0,0 +1 @@
+fichier_des_ecritures_comptables
diff --git a/erpnext/education/api.py b/erpnext/education/api.py
index ea4da69..99fb36e 100644
--- a/erpnext/education/api.py
+++ b/erpnext/education/api.py
@@ -269,7 +269,10 @@
 	:param Percentage: Score Percentage Percentage
 	"""
 	grading_scale_intervals = {}
-	for d in frappe.get_all("Grading Scale Interval", fields=["grade_code", "threshold"], filters={"parent": grading_scale}):
+	if not hasattr(frappe.local, 'grading_scale'):
+		grading_scale = frappe.get_all("Grading Scale Interval", fields=["grade_code", "threshold"], filters={"parent": grading_scale})
+		frappe.local.grading_scale = grading_scale
+	for d in frappe.local.grading_scale:
 		grading_scale_intervals.update({d.threshold:d.grade_code})
 	intervals = sorted(grading_scale_intervals.keys(), key=float, reverse=True)
 	for interval in intervals:
diff --git a/erpnext/education/doctype/assessment_criteria/assessment_criteria.py b/erpnext/education/doctype/assessment_criteria/assessment_criteria.py
index e666a74..eadc0de 100644
--- a/erpnext/education/doctype/assessment_criteria/assessment_criteria.py
+++ b/erpnext/education/doctype/assessment_criteria/assessment_criteria.py
@@ -6,5 +6,9 @@
 import frappe
 from frappe.model.document import Document
 
+STD_CRITERIA = ["total", "total score", "total grade", "maximum score", "score", "grade"]
+
 class AssessmentCriteria(Document):
-	pass
+	def validate(self):
+		if self.assessment_criteria.lower() in STD_CRITERIA:
+			frappe.throw("Can't create standard criteria. Please rename the criteria")
\ No newline at end of file
diff --git a/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.html b/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.html
index 60300b0..e46a5e7 100644
--- a/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.html
+++ b/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.html
@@ -6,9 +6,15 @@
 {% } %}
 <h4 class="text-center">{%= __("Assessment Report") %}</h4>
 <hr>
+<h5 class="text-center">{%= __("Academic Year: ") %} {%= filters.academic_year %} </h5>
+{% if (filters.academic_term){ %}
+<h5 class="text-center">{%= __("Academic Term: ") %} {%= filters.academic_term %} </h5>
+{% } %}
 <h5 class="text-center">{%= __("Course Code: ") %} {%= filters.course %}</h5>
 <h5 class="text-center">{%= __("Assessment Group: ") %} {%= filters.assessment_group %}</h5>
-<h5 class="text-center">{%= __("Assessment Plan: ") %} {%= data_to_be_printed[0]["assessment_plan"] %} </h5>
+{% if (filters.student_group){ %}
+<h5 class="text-center">{%= __("Student Group: ") %} {%= filters.student_group %} </h5>
+{% } %}
 <hr>
 
 <table class="table table-bordered">
diff --git a/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.js b/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.js
index 42b19eb..8c42d48 100644
--- a/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.js
+++ b/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.js
@@ -4,18 +4,17 @@
 frappe.query_reports["Course wise Assessment Report"] = {
 	"filters": [
 		{
-			"fieldname":"assessment_group",
-			"label": __("Assessment Group"),
+			"fieldname":"academic_year",
+			"label": __("Academic Year"),
 			"fieldtype": "Link",
-			"options": "Assessment Group",
-			"reqd": 1,
-			"get_query": function() {
-				return{
-					filters: {
-						'is_group': 0
-					}
-				};
-			}
+			"options": "Academic Year",
+			"reqd": 1
+		},
+		{
+			"fieldname":"academic_term",
+			"label": __("Academic Term"),
+			"fieldtype": "Link",
+			"options": "Academic Term"
 		},
 		{
 			"fieldname":"course",
@@ -29,6 +28,13 @@
 			"label": __("Student Group"),
 			"fieldtype": "Link",
 			"options": "Student Group"
+		},
+		{
+			"fieldname":"assessment_group",
+			"label": __("Assessment Group"),
+			"fieldtype": "Link",
+			"options": "Assessment Group",
+			"reqd": 1
 		}
 	]
 };
diff --git a/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.py b/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.py
index ff17238..a50ad7b 100644
--- a/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.py
+++ b/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.py
@@ -5,129 +5,189 @@
 import frappe
 from frappe import _
 from frappe.utils import flt
-from collections import defaultdict
+from collections import defaultdict, OrderedDict
 from erpnext.education.api import get_grade
 
 
 def execute(filters=None):
-	data = []
-
+	data, chart, grades = [], [], []
 	args = frappe._dict()
+	grade_wise_analysis = defaultdict(dict)
+
+	args["academic_year"] = filters.get("academic_year")
+	args["course"] = filters.get("course")
 	args["assessment_group"] = filters.get("assessment_group")
+
+	args["academic_term"] = filters.get("academic_term")
+	args["student_group"] = filters.get("student_group")
+
 	if args["assessment_group"] == "All Assessment Groups":
 		frappe.throw(_("Please select the assessment group other than 'All Assessment Groups'"))
 
-	args["course"] = filters.get("course")
-	args["student_group"] = filters.get("student_group")
+	returned_values = get_formatted_result(args, get_assessment_criteria=True)
+	student_dict = returned_values["student_details"]
+	result_dict = returned_values["assessment_result"]
+	assessment_criteria_dict = returned_values["assessment_criteria"]
+
+	for student in result_dict:
+		student_row = {}
+		student_row["student"] = student
+		student_row["student_name"] = student_dict[student]
+		for criteria in assessment_criteria_dict:
+			scrub_criteria = frappe.scrub(criteria)
+			if criteria in result_dict[student][args.course][args.assessment_group]:
+				student_row[scrub_criteria] = result_dict[student][args.course][args.assessment_group][criteria]["grade"]
+				student_row[scrub_criteria + "_score"] = result_dict[student][args.course][args.assessment_group][criteria]["score"]
+
+				# create the list of possible grades
+				if student_row[scrub_criteria] not in grades:
+					grades.append(student_row[scrub_criteria])
+				
+				# create the dict of for gradewise analysis
+				if student_row[scrub_criteria] not in grade_wise_analysis[criteria]:
+					grade_wise_analysis[criteria][student_row[scrub_criteria]] = 1
+				else:
+					grade_wise_analysis[criteria][student_row[scrub_criteria]] += 1
+			else:
+				student_row[frappe.scrub(criteria)] = ""
+				student_row[frappe.scrub(criteria)+ "_score"] = ""
+		data.append(student_row)
+
+	assessment_criteria_list = [d for d in assessment_criteria_dict]
+	columns = get_column(assessment_criteria_dict)
+	chart = get_chart_data(grades, assessment_criteria_list, grade_wise_analysis)
+
+	return columns, data, None, chart
 
 
-	# find all assessment plan and related details linked with the given filters
-	def get_assessment_details():
-		if args["student_group"]:
-			cond = "and ap.student_group=%(student_group)s"
+def get_formatted_result(args, get_assessment_criteria=False, get_course=False):
+	cond, cond1, cond2, cond3, cond4 = " ", " ", " ", " ", " "
+	args_list = [args.academic_year]
+
+	if args.course:
+		cond = " and ar.course=%s"
+		args_list.append(args.course)
+
+	if args.academic_term:
+		cond1 = " and ar.academic_term=%s"
+		args_list.append(args.academic_term)
+
+	if args.student_group:
+		cond2 = " and ar.student_group=%s"
+		args_list.append(args.student_group)
+
+	create_total_dict = False
+	group_type = frappe.get_value("Assessment Group", args.assessment_group, "is_group")
+	if group_type:
+		from frappe.desk.treeview import get_children
+		assessment_groups = [d.get("value") for d in get_children("Assessment Group",
+			args.assessment_group) if d.get("value") and not d.get("expandable")]
+		cond3 = " and ar.assessment_group in (%s)"%(', '.join(['%s']*len(assessment_groups)))
+	else:
+		assessment_groups = [args.assessment_group]
+		cond3 = " and ar.assessment_group=%s"
+	args_list += assessment_groups
+
+	if args.students:
+		cond4 = " and ar.student in (%s)"%(', '.join(['%s']*len(args.students)))
+		args_list += args.students
+
+	assessment_result = frappe.db.sql('''
+		SELECT
+			ar.student, ar.student_name, ar.academic_year, ar.academic_term, ar.program, ar.course,
+			ar.assessment_plan, ar.grading_scale, ar.assessment_group, ar.student_group,
+			ard.assessment_criteria, ard.maximum_score, ard.grade, ard.score
+		FROM
+			`tabAssessment Result` ar, `tabAssessment Result Detail` ard
+		WHERE
+			ar.name=ard.parent and ar.docstatus=1 and ar.academic_year=%s {0} {1} {2} {3} {4}
+		ORDER BY
+			ard.assessment_criteria'''.format(cond, cond1, cond2, cond3, cond4),
+		tuple(args_list), as_dict=1)
+
+	# create the nested dictionary structure as given below:
+	# <variable_name>.<student_name>.<course>.<assessment_group>.<assessment_criteria>.<grade/score/max_score>
+	# "Total Score" -> assessment criteria used for totaling and args.assessment_group -> for totaling all the assesments
+
+	student_details = {}
+	formatted_assessment_result = defaultdict(dict)
+	assessment_criteria_dict = OrderedDict()
+	course_dict = OrderedDict()
+	total_maximum_score = None
+	if not (len(assessment_groups) == 1 and assessment_groups[0] == args.assessment_group):
+		create_total_dict = True
+
+	# add the score for a given score and recalculate the grades
+	def add_score_and_recalculate_grade(result, assessment_group, assessment_criteria):
+		formatted_assessment_result[result.student][result.course][assessment_group]\
+			[assessment_criteria]["maximum_score"] += result.maximum_score
+		formatted_assessment_result[result.student][result.course][assessment_group]\
+			[assessment_criteria]["score"] += result.score
+		tmp_grade = get_grade(result.grading_scale, ((formatted_assessment_result[result.student][result.course]
+			[assessment_group][assessment_criteria]["score"])/(formatted_assessment_result[result.student]
+			[result.course][assessment_group][assessment_criteria]["maximum_score"]))*100)
+		formatted_assessment_result[result.student][result.course][assessment_group]\
+			[assessment_criteria]["grade"] = tmp_grade
+
+	# create the assessment criteria "Total Score" with the sum of all the scores of the assessment criteria in a given assessment group
+	def add_total_score(result, assessment_group):
+		if "Total Score" not in formatted_assessment_result[result.student][result.course][assessment_group]:
+			formatted_assessment_result[result.student][result.course][assessment_group]["Total Score"] = frappe._dict({
+				"assessment_criteria": "Total Score", "maximum_score": result.maximum_score, "score": result.score, "grade": result.grade})
 		else:
-			cond = ''
+			add_score_and_recalculate_grade(result, assessment_group, "Total Score")
 
-		assessment_plan = frappe.db.sql('''
-			select
-				ap.name, ap.student_group, ap.grading_scale, apc.assessment_criteria, apc.maximum_score as max_score
-			from
-				`tabAssessment Plan` ap, `tabAssessment Plan Criteria` apc
-			where
-				ap.assessment_group=%(assessment_group)s and ap.course=%(course)s and
-				ap.name=apc.parent and ap.docstatus=1 {0}
-			order by
-				apc.assessment_criteria'''.format(cond), (args), as_dict=1)
+	for result in assessment_result:
+		if result.student not in student_details:
+			student_details[result.student] = result.student_name
 
-		assessment_plan_list = list(set([d["name"] for d in assessment_plan]))
-		if not assessment_plan_list:
-			frappe.throw(_("No assessment plan linked with this assessment group"))
+		assessment_criteria_details = frappe._dict({"assessment_criteria": result.assessment_criteria,
+			"maximum_score": result.maximum_score, "score": result.score, "grade": result.grade})
 
-		assessment_criteria_list = list(set([(d["assessment_criteria"],d["max_score"]) for d in assessment_plan]))
-		student_group_list = list(set([d["student_group"] for d in assessment_plan]))
-		total_maximum_score = flt(sum([flt(d[1]) for d in assessment_criteria_list]))
-		grading_scale = assessment_plan[0]["grading_scale"]
+		if not formatted_assessment_result[result.student]:
+			formatted_assessment_result[result.student] = defaultdict(dict)
+		if not formatted_assessment_result[result.student][result.course]:
+			formatted_assessment_result[result.student][result.course] = defaultdict(dict)
 
-		return assessment_plan_list, assessment_criteria_list, total_maximum_score, grading_scale, student_group_list
+		if not create_total_dict:
+			formatted_assessment_result[result.student][result.course][result.assessment_group]\
+				[result.assessment_criteria] = assessment_criteria_details
+			add_total_score(result, result.assessment_group)
+
+		# create the total of all the assessment groups criteria-wise
+		elif create_total_dict:
+			if not formatted_assessment_result[result.student][result.course][args.assessment_group]:
+				formatted_assessment_result[result.student][result.course][args.assessment_group] = defaultdict(dict)
+				formatted_assessment_result[result.student][result.course][args.assessment_group]\
+					[result.assessment_criteria] = assessment_criteria_details
+			elif result.assessment_criteria not in formatted_assessment_result[result.student][result.course][args.assessment_group]:
+				formatted_assessment_result[result.student][result.course][args.assessment_group]\
+					[result.assessment_criteria] = assessment_criteria_details
+			elif result.assessment_criteria in formatted_assessment_result[result.student][result.course][args.assessment_group]:
+				add_score_and_recalculate_grade(result, args.assessment_group, result.assessment_criteria)
+
+			add_total_score(result, args.assessment_group)
+
+		total_maximum_score = formatted_assessment_result[result.student][result.course][args.assessment_group]\
+			["Total Score"]["maximum_score"]
+		if get_assessment_criteria:
+			assessment_criteria_dict[result.assessment_criteria] = formatted_assessment_result[result.student][result.course]\
+				[args.assessment_group][result.assessment_criteria]["maximum_score"]
+		if get_course:
+			course_dict[result.course] = total_maximum_score
+
+	if get_assessment_criteria and total_maximum_score:
+		assessment_criteria_dict["Total Score"] = total_maximum_score
+
+	return {
+		"student_details": student_details,
+		"assessment_result": formatted_assessment_result,
+		"assessment_criteria": assessment_criteria_dict,
+		"course_dict": course_dict
+	}
 
 
-	# get all the result and make a dict map student as the key and value as dict of result
-	def get_result_map():
-		result_dict = defaultdict(dict)
-		kounter = defaultdict(dict)
-		assessment_result = frappe.db.sql('''select ar.student, ard.assessment_criteria, ard.grade, ard.score
-			from `tabAssessment Result` ar, `tabAssessment Result Detail` ard
-			where ar.assessment_plan in (%s) and ar.name=ard.parent and ar.docstatus=1
-			order by ard.assessment_criteria''' %', '.join(['%s']*len(assessment_plan_list)),
-			tuple(assessment_plan_list), as_dict=1)
-
-		for result in assessment_result:
-			if "total_score" in result_dict[result.student]:
-				total_score = result_dict[result.student]["total_score"] + result.score
-			else:
-				total_score = result.score
-			total = get_grade(grading_scale, (total_score/total_maximum_score)*100)
-
-			if result.grade in kounter[result.assessment_criteria]:
-				kounter[result.assessment_criteria][result.grade] += 1
-			else:
-				kounter[result.assessment_criteria].update({result.grade: 1})
-
-			if "Total" not in kounter:
-				kounter["Total"] = {}
-
-			if "total" in result_dict[result.student]:
-				prev_grade = result_dict[result.student]["total"]
-				prev_grade_count = kounter["Total"].get(prev_grade) - 1
-				kounter["Total"].update({prev_grade: prev_grade_count})
-			latest_grade_count = kounter["Total"].get(total)+1 if kounter["Total"].get(total) else 1
-			kounter["Total"].update({total: latest_grade_count})
-
-			result_dict[result.student].update({
-					frappe.scrub(result.assessment_criteria): result.grade,
-					frappe.scrub(result.assessment_criteria)+"_score": result.score,
-					"total_score": total_score,
-					"total": total
-				})
-
-		return result_dict, kounter
-
-	# make data from the result dict
-	def get_data():
-		student_list = frappe.db.sql('''select sgs.student, sgs.student_name
-			from `tabStudent Group` sg, `tabStudent Group Student` sgs
-			where sg.name = sgs.parent and sg.name in (%s)
-			order by sgs.group_roll_number asc''' %', '.join(['%s']*len(student_group_list)),
-			tuple(student_group_list), as_dict=1)
-
-		for student in student_list:
-			student.update(result_dict[student.student])
-		return student_list
-
-
-	# get chart data
-	def get_chart():
-		grading_scale = frappe.db.get_value("Assessment Plan", list(assessment_plan_list)[0], "grading_scale")
-		grades = frappe.db.sql_list('''select grade_code from `tabGrading Scale Interval` where parent=%s''',
-			(grading_scale))
-		criteria_list = [d[0] for d in assessment_criteria_list] + ["Total"]
-		return get_chart_data(grades, criteria_list, kounter)
-
-
-	assessment_plan_list, assessment_criteria_list, total_maximum_score, grading_scale,\
-		student_group_list = get_assessment_details()
-	result_dict, kounter = get_result_map()
-	data = get_data()
-
-	columns = get_column(assessment_criteria_list, total_maximum_score)
-	chart = get_chart()
-	data_to_be_printed = [{
-		"assessment_plan": ", ".join(assessment_plan_list)
-	}]
-
-	return columns, data, None, chart, data_to_be_printed
-
-def get_column(assessment_criteria, total_maximum_score):
+def get_column(assessment_criteria):
 	columns = [{
 		"fieldname": "student",
 		"label": _("Student ID"),
@@ -143,40 +203,28 @@
 	}]
 	for d in assessment_criteria:
 		columns.append({
-			"fieldname": frappe.scrub(d[0]),
-			"label": d[0],
+			"fieldname": frappe.scrub(d),
+			"label": d,
 			"fieldtype": "Data",
 			"width": 110
 		})
 		columns.append({
-			"fieldname": frappe.scrub(d[0]) +"_score",
-			"label": "Score(" + str(int(d[1])) + ")",
+			"fieldname": frappe.scrub(d) +"_score",
+			"label": "Score(" + str(int(assessment_criteria[d])) + ")",
 			"fieldtype": "Float",
 			"width": 100
 		})
 
-	columns += [{
-		"fieldname": "total",
-		"label": "Total",
-		"fieldtype": "Data",
-		"width": 100
-	},
-	{
-		"fieldname": "total_score",
-		"label": "Total Score("+ str(int(total_maximum_score)) + ")",
-		"fieldtype": "Float",
-		"width": 110
-	}]
-
 	return columns
 
-def get_chart_data(grades, assessment_criteria_list, kounter):
+
+def get_chart_data(grades, criteria_list, kounter):
 	grades = sorted(grades)
 	datasets = []
 
 	for grade in grades:
 		tmp = frappe._dict({"values":[], "title": grade})
-		for criteria in assessment_criteria_list:
+		for criteria in criteria_list:
 			if grade in kounter[criteria]:
 				tmp["values"].append(kounter[criteria][grade])
 			else:
@@ -185,7 +233,7 @@
 
 	return {
 		"data": {
-			"labels": assessment_criteria_list,
+			"labels": criteria_list,
 			"datasets": datasets
 		},
 		"type": 'bar',
diff --git a/erpnext/education/report/final_assessment_grades/__init__.py b/erpnext/education/report/final_assessment_grades/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/education/report/final_assessment_grades/__init__.py
diff --git a/erpnext/education/report/final_assessment_grades/final_assessment_grades.js b/erpnext/education/report/final_assessment_grades/final_assessment_grades.js
new file mode 100644
index 0000000..ba0a42f
--- /dev/null
+++ b/erpnext/education/report/final_assessment_grades/final_assessment_grades.js
@@ -0,0 +1,38 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["Final Assessment Grades"] = {
+	"filters": [
+		{
+			"fieldname":"academic_year",
+			"label": __("Academic Year"),
+			"fieldtype": "Link",
+			"options": "Academic Year",
+			"reqd": 1
+		},
+		{
+			"fieldname":"student_group",
+			"label": __("Student Group"),
+			"fieldtype": "Link",
+			"options": "Student Group",
+			"reqd": 1,
+			"get_query": function() {
+				return{
+					filters: {
+						"group_based_on": "Batch",
+						"academic_year": frappe.query_report_filters_by_name.academic_year.value
+					}
+				};
+			}
+		},
+		{
+			"fieldname":"assessment_group",
+			"label": __("Assessment Group"),
+			"fieldtype": "Link",
+			"options": "Assessment Group",
+			"reqd": 1
+		}
+
+	]
+}
diff --git a/erpnext/education/report/final_assessment_grades/final_assessment_grades.json b/erpnext/education/report/final_assessment_grades/final_assessment_grades.json
new file mode 100644
index 0000000..1efbb6e
--- /dev/null
+++ b/erpnext/education/report/final_assessment_grades/final_assessment_grades.json
@@ -0,0 +1,20 @@
+{
+ "add_total_row": 0, 
+ "apply_user_permissions": 1, 
+ "creation": "2018-01-22 17:04:43.412054", 
+ "disabled": 0, 
+ "docstatus": 0, 
+ "doctype": "Report", 
+ "idx": 0, 
+ "is_standard": "Yes", 
+ "letter_head": "Shishuvan Secondary School", 
+ "modified": "2018-01-22 17:04:43.412054", 
+ "modified_by": "Administrator", 
+ "module": "Education", 
+ "name": "Final Assessment Grades", 
+ "owner": "Administrator", 
+ "ref_doctype": "Assessment Result", 
+ "report_name": "Final Assessment Grades", 
+ "report_type": "Script Report", 
+ "roles": []
+}
\ No newline at end of file
diff --git a/erpnext/education/report/final_assessment_grades/final_assessment_grades.py b/erpnext/education/report/final_assessment_grades/final_assessment_grades.py
new file mode 100644
index 0000000..efc9aff
--- /dev/null
+++ b/erpnext/education/report/final_assessment_grades/final_assessment_grades.py
@@ -0,0 +1,85 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from collections import defaultdict
+
+from erpnext.education.report.course_wise_assessment_report.course_wise_assessment_report import get_formatted_result
+from erpnext.education.report.course_wise_assessment_report.course_wise_assessment_report import get_chart_data
+
+
+def execute(filters=None):
+	columns, data, grades = [], [], []
+	args = frappe._dict()
+	course_wise_analysis = defaultdict(dict)
+
+	args["academic_year"] = filters.get("academic_year")
+	assessment_group = args["assessment_group"] = filters.get("assessment_group")
+
+	student_group = filters.get("student_group")
+	args.students = frappe.db.sql_list("select student from `tabStudent Group Student` where parent=%s", (student_group))
+
+	values = get_formatted_result(args, get_course=True)
+	student_details = values.get("student_details")
+	assessment_result = values.get("assessment_result")
+	course_dict = values.get("course_dict")
+
+	for student in args.students:
+		student_row = {}
+		student_row["student"] = student
+		student_row["student_name"] = student_details[student]
+		for course in course_dict:
+			scrub_course = frappe.scrub(course)
+			if assessment_group in assessment_result[student][course]:
+				student_row["grade_" + scrub_course] = assessment_result[student][course][assessment_group]["Total Score"]["grade"]
+				student_row["score_" + scrub_course] = assessment_result[student][course][assessment_group]["Total Score"]["score"]
+
+				# create the list of possible grades
+				if student_row["grade_" + scrub_course] not in grades:
+					grades.append(student_row["grade_" + scrub_course])
+
+				# create the dict of for gradewise analysis
+				if student_row["grade_" + scrub_course] not in course_wise_analysis[course]:
+					course_wise_analysis[course][student_row["grade_" + scrub_course]] = 1
+				else:
+					course_wise_analysis[course][student_row["grade_" + scrub_course]] += 1
+
+		data.append(student_row)
+
+	course_list = [d for d in course_dict]
+	columns = get_column(course_dict)
+	chart = get_chart_data(grades, course_list, course_wise_analysis)
+	return columns, data, None, chart
+
+
+def get_column(course_dict):
+	columns = [{
+		"fieldname": "student",
+		"label": _("Student ID"),
+		"fieldtype": "Link",
+		"options": "Student",
+		"width": 90
+	},
+	{
+		"fieldname": "student_name",
+		"label": _("Student Name"),
+		"fieldtype": "Data",
+		"width": 160
+	}]
+	for course in course_dict:
+		columns.append({
+			"fieldname": "grade_" + frappe.scrub(course),
+			"label": course,
+			"fieldtype": "Data",
+			"width": 110
+		})
+		columns.append({
+			"fieldname": "score_" + frappe.scrub(course),
+			"label": "Score(" + str(course_dict[course]) + ")",
+			"fieldtype": "Float",
+			"width": 100
+		})
+
+	return columns
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 846ca26..d300285 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -183,7 +183,6 @@
 execute:frappe.db.sql("""delete from `tabProject Task`""")
 erpnext.patches.v5_0.update_item_desc_in_invoice
 erpnext.patches.v5_1.fix_against_account
-erpnext.patches.v5_1.fix_credit_days_based_on
 execute:frappe.rename_doc("DocType", "Salary Manager", "Process Payroll", force=True)
 erpnext.patches.v5_1.rename_roles
 erpnext.patches.v5_1.default_bom
@@ -489,4 +488,6 @@
 erpnext.patches.v10_0.fichier_des_ecritures_comptables_for_france
 erpnext.patches.v10_0.update_assessment_plan
 erpnext.patches.v10_0.update_assessment_result
-erpnext.patches.v10_0.workflow_leave_application #2018-01-24
\ No newline at end of file
+erpnext.patches.v10_0.added_extra_gst_custom_field
+erpnext.patches.v10_0.workflow_leave_application #2018-01-24
+erpnext.patches.v10_0.set_default_payment_terms_based_on_company
diff --git a/erpnext/patches/v10_0/added_extra_gst_custom_field.py b/erpnext/patches/v10_0/added_extra_gst_custom_field.py
new file mode 100644
index 0000000..a1512ed
--- /dev/null
+++ b/erpnext/patches/v10_0/added_extra_gst_custom_field.py
@@ -0,0 +1,9 @@
+import frappe
+from erpnext.regional.india.setup  import make_custom_fields
+
+def execute():
+	company = frappe.get_all('Company', filters = {'country': 'India'})
+	if not company:
+		return
+
+	make_custom_fields()
\ No newline at end of file
diff --git a/erpnext/patches/v10_0/set_default_payment_terms_based_on_company.py b/erpnext/patches/v10_0/set_default_payment_terms_based_on_company.py
new file mode 100644
index 0000000..a90e096
--- /dev/null
+++ b/erpnext/patches/v10_0/set_default_payment_terms_based_on_company.py
@@ -0,0 +1,37 @@
+from __future__ import unicode_literals
+import frappe
+from erpnext.patches.v8_10.change_default_customer_credit_days import make_payment_term, make_template
+
+def execute():
+	for dt in ("Company", "Customer Group"):
+		frappe.reload_doc("setup", "doctype", frappe.scrub(dt))
+
+		credit_records = frappe.db.sql("""
+			SELECT DISTINCT `credit_days`, `credit_days_based_on`, `name`
+			from `tab{0}`
+			where
+				((credit_days_based_on='Fixed Days' or credit_days_based_on is null) and credit_days is not null)
+				or credit_days_based_on='Last Day of the Next Month'
+		""".format(dt), as_dict=1)
+
+		for d in credit_records:
+			template = create_payment_terms_template(d)
+
+			frappe.db.sql("""
+				update `tab{0}`
+				set `payment_terms` = %s
+				where name = %s
+			""".format(dt), (template.name, d.name))
+
+def create_payment_terms_template(data):
+	if data.credit_days_based_on == "Fixed Days":
+		pyt_template_name = 'Default Payment Term - N{0}'.format(data.credit_days)
+	else:
+		pyt_template_name = 'Default Payment Term - EO2M'
+
+	if not frappe.db.exists("Payment Terms Template", pyt_template_name):
+		payment_term = make_payment_term(data.credit_days, data.credit_days_based_on)
+		template = make_template(payment_term)
+	else:
+		template = frappe.get_doc("Payment Terms Template", pyt_template_name)
+	return template
\ No newline at end of file
diff --git a/erpnext/patches/v10_0/workflow_leave_application.py b/erpnext/patches/v10_0/workflow_leave_application.py
index f2b74a3..8a68f89 100644
--- a/erpnext/patches/v10_0/workflow_leave_application.py
+++ b/erpnext/patches/v10_0/workflow_leave_application.py
@@ -9,4 +9,5 @@
 	frappe.reload_doc("hr", "doctype", "leave_application")
 	frappe.reload_doc("workflow", "doctype", "workflow")
 	leave_application_workflow()
-	frappe.db.sql("""update `tabLeave Application` set workflow_state = status""")
+	if frappe.db.has_column("Leave Application", "status"):
+		frappe.db.sql("""update `tabLeave Application` set workflow_state = status""")
diff --git a/erpnext/patches/v5_1/fix_credit_days_based_on.py b/erpnext/patches/v5_1/fix_credit_days_based_on.py
deleted file mode 100644
index 6df19f2..0000000
--- a/erpnext/patches/v5_1/fix_credit_days_based_on.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from __future__ import unicode_literals
-
-import frappe
-
-def execute():
-	for dt in ("Customer", "Customer Group", "Company"):
-		frappe.reload_doctype(dt, force=True)
-		frappe.db.sql("""update `tab{0}` set credit_days_based_on='Fixed Days'
-			where ifnull(credit_days, 0) > 0""".format(dt))
diff --git a/erpnext/patches/v8_10/change_default_customer_credit_days.py b/erpnext/patches/v8_10/change_default_customer_credit_days.py
index 640c8aa..eddafb5 100644
--- a/erpnext/patches/v8_10/change_default_customer_credit_days.py
+++ b/erpnext/patches/v8_10/change_default_customer_credit_days.py
@@ -17,7 +17,8 @@
 			SELECT DISTINCT `credit_days`, `credit_days_based_on`, `name`
 			from `tab{0}`
 			where
-				(credit_days_based_on='Fixed Days' and credit_days is not null)
+				((credit_days_based_on='Fixed Days' or credit_days_based_on is null)
+					and credit_days is not null)
 				or credit_days_based_on='Last Day of the Next Month'
 		""".format(doctype))
 
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index f155e09..e44c3fb 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -523,7 +523,8 @@
 					},
 					callback: function(r, rt) {
 						if(r.message) {
-							me.frm.set_value("due_date", r.message);
+							me.frm.doc.due_date = r.message;
+							refresh_field("due_date");
 							frappe.ui.form.trigger(me.frm.doc.doctype, "currency");
 							me.recalculate_terms();
 						}
@@ -538,7 +539,7 @@
 	due_date: function() {
 		// due_date is to be changed, payment terms template and/or payment schedule must
 		// be removed as due_date is automatically changed based on payment terms
-		if (this.frm.doc.due_date) {
+		if (this.frm.doc.due_date && !this.frm.updating_party_details && !this.frm.doc.is_pos) {
 			if (this.frm.doc.payment_terms_template ||
 				(this.frm.doc.payment_schedule && this.frm.doc.payment_schedule.length)) {
 				var message1 = "";
@@ -555,11 +556,9 @@
 					if (message1.length !== 0) message2 = " and " + message2;
 					final_message = final_message + message2;
 				}
-
 				frappe.msgprint(final_message);
 			}
-
-	    }
+		}
 	},
 
 	recalculate_terms: function() {
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 7143bd3..e9d91ab 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -103,7 +103,20 @@
 			depends_on='eval:in_list(["SEZ", "Export", "Deemed Export"], doc.invoice_type)',
 			options='\nWith Payment of Tax\nWithout Payment of Tax'),
 		dict(fieldname='ecommerce_gstin', label='E-commerce GSTIN',
-			fieldtype='Data', insert_after='export_type', print_hide=1)
+			fieldtype='Data', insert_after='export_type', print_hide=1),
+		dict(fieldname='reason_for_issuing_document', label='Reason For Issuing document',
+			fieldtype='Select', insert_after='ecommerce_gstin', print_hide=1,
+			depends_on='eval:doc.is_return==1',
+			options='\n01-Sales Return\n02-Post Sale Discount\n03-Deficiency in services\n04-Correction in Invoice\n05-Change in POS\n06-Finalization of Provisional assessment\n07-Others'),
+		dict(fieldname='port_code', label='Port Code',
+			fieldtype='Data', insert_after='reason_for_issuing_document', print_hide=1,
+			depends_on="eval:doc.invoice_type=='Export' "),
+		dict(fieldname='shipping_bill_number', label=' Shipping Bill Number',
+			fieldtype='Data', insert_after='port_code', print_hide=1,
+			depends_on="eval:doc.invoice_type=='Export' "),
+		dict(fieldname='shipping_bill_date', label='Shipping Bill Date',
+			fieldtype='Date', insert_after='shipping_bill_number', print_hide=1,
+			depends_on="eval:doc.invoice_type=='Export' "),
 	]
 
 	purchase_invoice_gst_fields = [
diff --git a/erpnext/regional/report/gstr_1/gstr_1.js b/erpnext/regional/report/gstr_1/gstr_1.js
index 9437786..3a63527 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.js
+++ b/erpnext/regional/report/gstr_1/gstr_1.js
@@ -31,7 +31,7 @@
 			"label": __("Type of Business"),
 			"fieldtype": "Select",
 			"reqd": 1,
-			"options": ["B2B", "B2C Large", "B2C Small"],
+			"options": ["B2B", "B2C Large", "B2C Small","CDNR", "EXPORT"],
 			"default": "B2B"
 		}
 	]
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
index 65b1b89..b6df878 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.py
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -4,6 +4,7 @@
 from __future__ import unicode_literals
 import frappe, json
 from frappe import _
+from datetime import date
 
 def execute(filters=None):
 	return Gstr1Report(filters).run()
@@ -12,7 +13,7 @@
 	def __init__(self, filters=None):
 		self.filters = frappe._dict(filters or {})
 		self.customer_type = "Company" if self.filters.get("type_of_business") ==  "B2B" else "Individual"
-		
+
 	def run(self):
 		self.get_columns()
 		self.get_data()
@@ -35,13 +36,15 @@
 			for rate, items in items_based_on_rate.items():
 				row = []
 				for fieldname in invoice_fields:
-					if fieldname == "invoice_value":
+					if self.filters.get("type_of_business") ==  "CDNR" and fieldname == "invoice_value":
+						row.append(abs(invoice_details.base_rounded_total) or abs(invoice_details.base_grand_total))
+					elif fieldname == "invoice_value":
 						row.append(invoice_details.base_rounded_total or invoice_details.base_grand_total)
 					else:
 						row.append(invoice_details.get(fieldname))
 
 				row += [rate,
-					sum([net_amount for item_code, net_amount in self.invoice_items.get(inv).items()
+					sum([abs(net_amount) for item_code, net_amount in self.invoice_items.get(inv).items()
 						if item_code in items]),
 					self.invoice_cess.get(inv)
 				]
@@ -49,6 +52,10 @@
 				if self.filters.get("type_of_business") ==  "B2C Small":
 					row.append("E" if invoice_details.ecommerce_gstin else "OE")
 
+				if self.filters.get("type_of_business") ==  "CDNR":
+					row.append("Y" if invoice_details.posting_date <= date(2017, 7, 1) else "N")
+					row.append("C" if invoice_details.return_against else "R")
+
 				self.data.append(row)
 
 	def get_invoice_data(self):
@@ -66,7 +73,15 @@
 				place_of_supply,
 				ecommerce_gstin,
 				reverse_charge,
-				invoice_type
+				invoice_type,
+				return_against,
+				is_return,
+				invoice_type,
+				export_type,
+				port_code,
+				shipping_bill_number,
+				shipping_bill_date,
+				reason_for_issuing_document
 			from `tabSales Invoice`
 			where docstatus = 1 %s
 			order by posting_date desc
@@ -85,18 +100,27 @@
 					conditions += opts[1]
 
 		customers = frappe.get_all("Customer", filters={"customer_type": self.customer_type})
-		conditions += " and customer in ('{0}')".format("', '".join([frappe.db.escape(c.name)
-			for c in customers]))
+
+		if self.filters.get("type_of_business") ==  "B2B":
+			conditions += " and invoice_type != 'Export' and is_return != 1 and customer in ('{0}')".\
+				format("', '".join([frappe.db.escape(c.name) for c in customers]))
 
 		if self.filters.get("type_of_business") ==  "B2C Large":
 			conditions += """ and SUBSTR(place_of_supply, 1, 2) != SUBSTR(company_gstin, 1, 2)
-				and grand_total > 250000"""
+				and grand_total > 250000 and is_return != 1 and customer in ('{0}')""".\
+					format("', '".join([frappe.db.escape(c.name) for c in customers]))
+
 		elif self.filters.get("type_of_business") ==  "B2C Small":
 			conditions += """ and (
 				SUBSTR(place_of_supply, 1, 2) = SUBSTR(company_gstin, 1, 2)
-				or grand_total <= 250000
-			)"""
+					or grand_total <= 250000 ) and is_return != 1 and customer in ('{0}')""".\
+						format("', '".join([frappe.db.escape(c.name) for c in customers]))
 
+		elif self.filters.get("type_of_business") ==  "CDNR":
+			conditions += """ and is_return = 1 """
+
+		elif self.filters.get("type_of_business") ==  "EXPORT":
+			conditions += """ and is_return !=1 and invoice_type = 'Export' """
 		return conditions
 
 	def get_invoice_items(self):
@@ -118,7 +142,7 @@
 			where
 				parenttype = 'Sales Invoice' and docstatus = 1
 				and parent in (%s)
-				and tax_amount_after_discount_amount > 0
+
 			order by account_head
 		""" % (', '.join(['%s']*len(self.invoices.keys()))), tuple(self.invoices.keys()))
 
@@ -152,7 +176,6 @@
 								.setdefault(tax_rate, [])
 							if item_code not in rate_based_dict:
 								rate_based_dict.append(item_code)
-
 					except ValueError:
 						continue
 		if unidentified_gst_accounts:
@@ -185,12 +208,6 @@
 				"label": "Taxable Value",
 				"fieldtype": "Currency",
 				"width": 100
-			},
-			{
-				"fieldname": "cess_amount",
-				"label": "Cess Amount",
-				"fieldtype": "Currency",
-				"width": 100
 			}
 		]
 		self.other_columns = []
@@ -200,33 +217,39 @@
 				{
 					"fieldname": "customer_gstin",
 					"label": "GSTIN/UIN of Recipient",
-					"fieldtype": "Data"
+					"fieldtype": "Data",
+					"width": 150
 				},
 				{
 					"fieldname": "customer_name",
 					"label": "Receiver Name",
-					"fieldtype": "Data"
+					"fieldtype": "Data",
+					"width":100
 				},
 				{
 					"fieldname": "invoice_number",
 					"label": "Invoice Number",
 					"fieldtype": "Link",
-					"options": "Sales Invoice"
+					"options": "Sales Invoice",
+					"width":100
 				},
 				{
 					"fieldname": "posting_date",
 					"label": "Invoice date",
-					"fieldtype": "Date"
+					"fieldtype": "Date",
+					"width":80
 				},
 				{
 					"fieldname": "invoice_value",
 					"label": "Invoice Value",
-					"fieldtype": "Currency"
+					"fieldtype": "Currency",
+					"width":100
 				},
 				{
 					"fieldname": "place_of_supply",
 					"label": "Place of Supply",
-					"fieldtype": "Data"
+					"fieldtype": "Data",
+					"width":100
 				},
 				{
 					"fieldname": "reverse_charge",
@@ -241,9 +264,19 @@
 				{
 					"fieldname": "ecommerce_gstin",
 					"label": "E-Commerce GSTIN",
-					"fieldtype": "Data"
+					"fieldtype": "Data",
+					"width":120
 				}
 			]
+			self.other_columns = [
+					{
+						"fieldname": "cess_amount",
+						"label": "Cess Amount",
+						"fieldtype": "Currency",
+						"width": 100
+					}
+				]
+
 		elif self.filters.get("type_of_business") ==  "B2C Large":
 			self.invoice_columns = [
 				{
@@ -278,6 +311,93 @@
 					"width": 130
 				}
 			]
+			self.other_columns = [
+					{
+						"fieldname": "cess_amount",
+						"label": "Cess Amount",
+						"fieldtype": "Currency",
+						"width": 100
+					}
+				]
+		elif self.filters.get("type_of_business") ==  "CDNR":
+			self.invoice_columns = [
+				{
+					"fieldname": "customer_gstin",
+					"label": "GSTIN/UIN of Recipient",
+					"fieldtype": "Data",
+					"width": 150
+				},
+				{
+					"fieldname": "customer_name",
+					"label": "Receiver Name",
+					"fieldtype": "Data",
+					"width": 120
+				},
+				{
+					"fieldname": "return_against",
+					"label": "Invoice/Advance Receipt Number",
+					"fieldtype": "Link",
+					"options": "Sales Invoice",
+					"width": 120
+				},
+				{
+					"fieldname": "posting_date",
+					"label": "Invoice/Advance Receipt date",
+					"fieldtype": "Date",
+					"width": 120
+				},
+				{
+					"fieldname": "invoice_number",
+					"label": "Invoice/Advance Receipt Number",
+					"fieldtype": "Link",
+					"options": "Sales Invoice",
+					"width":120
+				},
+				{
+					"fieldname": "posting_date",
+					"label": "Invoice/Advance Receipt date",
+					"fieldtype": "Date",
+					"width": 120
+				},
+				{
+					"fieldname": "reason_for_issuing_document",
+					"label": "Reason For Issuing document",
+					"fieldtype": "Data",
+					"width": 140
+				},
+				{
+					"fieldname": "place_of_supply",
+					"label": "Place of Supply",
+					"fieldtype": "Data",
+					"width": 120
+				},
+				{
+					"fieldname": "invoice_value",
+					"label": "Invoice Value",
+					"fieldtype": "Currency",
+					"width": 120
+				}
+			]
+			self.other_columns = [
+				{
+						"fieldname": "cess_amount",
+						"label": "Cess Amount",
+						"fieldtype": "Currency",
+						"width": 100
+				},
+				{
+					"fieldname": "pre_gst",
+					"label": "PRE GST",
+					"fieldtype": "Data",
+					"width": 80
+				},
+				{
+					"fieldname": "document_type",
+					"label": "Document Type",
+					"fieldtype": "Data",
+					"width": 80
+				}
+			]
 		elif self.filters.get("type_of_business") ==  "B2C Small":
 			self.invoice_columns = [
 				{
@@ -295,10 +415,62 @@
 			]
 			self.other_columns = [
 				{
+						"fieldname": "cess_amount",
+						"label": "Cess Amount",
+						"fieldtype": "Currency",
+						"width": 100
+				},
+				{
 					"fieldname": "type",
 					"label": "Type",
 					"fieldtype": "Data",
 					"width": 50
 				}
 			]
-		self.columns = self.invoice_columns + self.tax_columns + self.other_columns
\ No newline at end of file
+		elif self.filters.get("type_of_business") ==  "EXPORT":
+			self.invoice_columns = [
+				{
+					"fieldname": "export_type",
+					"label": "Export Type",
+					"fieldtype": "Data",
+					"width":120
+				},
+				{
+					"fieldname": "invoice_number",
+					"label": "Invoice Number",
+					"fieldtype": "Link",
+					"options": "Sales Invoice",
+					"width":120
+				},
+				{
+					"fieldname": "posting_date",
+					"label": "Invoice date",
+					"fieldtype": "Date",
+					"width": 120
+				},
+				{
+					"fieldname": "invoice_value",
+					"label": "Invoice Value",
+					"fieldtype": "Currency",
+					"width": 120
+				},
+				{
+					"fieldname": "port_code",
+					"label": "Port Code",
+					"fieldtype": "Data",
+					"width": 120
+				},
+				{
+					"fieldname": "shipping_bill_number",
+					"label": "Shipping Bill Number",
+					"fieldtype": "Data",
+					"width": 120
+				},
+				{
+					"fieldname": "shipping_bill_date",
+					"label": "Shipping Bill Date",
+					"fieldtype": "Date",
+					"width": 120
+				}
+			]
+		self.columns = self.invoice_columns + self.tax_columns + self.other_columns
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 1c3354c..5bacf28 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -567,10 +567,12 @@
 		target.base_amount = target.amount * flt(source_parent.conversion_rate)
 		target.qty = target.amount / flt(source.rate) if (source.rate and source.billed_amt) else source.qty
 
-		item = frappe.db.get_value("Item", target.item_code, ["item_group", "selling_cost_center"], as_dict=1)
-		target.cost_center = frappe.db.get_value("Project", source_parent.project, "cost_center") \
-			or item.selling_cost_center \
-			or frappe.db.get_value("Item Group", item.item_group, "default_cost_center")
+		if source_parent.project:
+			target.cost_center = frappe.db.get_value("Project", source_parent.project, "cost_center")
+		if not target.cost_center and target.item_code:
+			item = frappe.db.get_value("Item", target.item_code, ["item_group", "selling_cost_center"], as_dict=1)
+			target.cost_center = item.selling_cost_center \
+				or frappe.db.get_value("Item Group", item.item_group, "default_cost_center")
 
 	doclist = get_mapped_doc("Sales Order", source_name, {
 		"Sales Order": {
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index 3d174b7..5ca2618 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -340,7 +340,8 @@
 
 	conversion_factor: function(doc, cdt, cdn, dont_fetch_price_list_rate) {
 	    this._super(doc, cdt, cdn, dont_fetch_price_list_rate);
-		if(frappe.meta.get_docfield(cdt, "stock_qty", cdn)) {
+		if(frappe.meta.get_docfield(cdt, "stock_qty", cdn) &&
+			in_list(['Delivery Note', 'Sales Invoice'], doc.doctype)) {
 			this.set_batch_number(cdt, cdn);
 		}
 	},
diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json
index 9824c70..d444417 100644
--- a/erpnext/setup/doctype/company/company.json
+++ b/erpnext/setup/doctype/company/company.json
@@ -1186,6 +1186,35 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
+   "fieldname": "column_break_26", 
+   "fieldtype": "Column 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, 
+   "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, 
    "depends_on": "eval:!doc.__islocal", 
    "fieldname": "credit_limit", 
    "fieldtype": "Currency", 
@@ -1219,8 +1248,9 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
-   "fieldname": "column_break_26", 
-   "fieldtype": "Column Break", 
+   "depends_on": "", 
+   "fieldname": "payment_terms", 
+   "fieldtype": "Link", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
    "ignore_xss_filter": 0, 
@@ -1228,8 +1258,10 @@
    "in_global_search": 0, 
    "in_list_view": 0, 
    "in_standard_filter": 0, 
+   "label": "Default Payment Terms Template", 
    "length": 0, 
    "no_copy": 0, 
+   "options": "Payment Terms Template", 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
@@ -1248,69 +1280,6 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
-   "fieldname": "credit_days_based_on", 
-   "fieldtype": "Select", 
-   "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": "Credit Days Based On", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "\nFixed Days\nLast Day of the Next Month", 
-   "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, 
-   "depends_on": "eval:(!doc.__islocal && doc.credit_days_based_on=='Fixed Days')", 
-   "fieldname": "credit_days", 
-   "fieldtype": "Int", 
-   "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": "Credit Days", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "credit_days", 
-   "oldfieldtype": "Int", 
-   "permlevel": 0, 
-   "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, 
    "depends_on": "eval:!doc.__islocal", 
    "fieldname": "auto_accounting_for_stock_settings", 
    "fieldtype": "Section Break", 
@@ -2052,7 +2021,7 @@
  "istable": 0, 
  "max_attachments": 0, 
  "menu_index": 0, 
- "modified": "2017-12-07 18:40:24.646920", 
+ "modified": "2018-01-29 12:40:24.646920", 
  "modified_by": "Administrator", 
  "module": "Setup", 
  "name": "Company", 
diff --git a/erpnext/setup/doctype/customer_group/customer_group.json b/erpnext/setup/doctype/customer_group/customer_group.json
index 316f11b..062a49a 100644
--- a/erpnext/setup/doctype/customer_group/customer_group.json
+++ b/erpnext/setup/doctype/customer_group/customer_group.json
@@ -162,12 +162,14 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
-   "fieldname": "credit_days_based_on", 
-   "fieldtype": "Select", 
+   "depends_on": "", 
+   "fieldname": "payment_terms", 
+   "fieldtype": "Link", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
    "ignore_xss_filter": 0, 
@@ -175,10 +177,10 @@
    "in_global_search": 0, 
    "in_list_view": 0, 
    "in_standard_filter": 0, 
-   "label": "Credit Days Based On", 
+   "label": "Default Payment Terms Template", 
    "length": 0, 
    "no_copy": 0, 
-   "options": "\nFixed Days\nLast Day of the Next Month", 
+   "options": "Payment Terms Template", 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
@@ -196,35 +198,6 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
-   "depends_on": "eval:doc.credit_days_based_on=='Fixed Days'", 
-   "fieldname": "credit_days", 
-   "fieldtype": "Int", 
-   "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": "Credit Days", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 1, 
-   "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_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
    "fieldname": "credit_limit", 
    "fieldtype": "Currency", 
    "hidden": 0, 
@@ -411,7 +384,7 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2017-02-20 13:25:31.549874", 
+ "modified": "2018-01-29 13:25:31.549874", 
  "modified_by": "Administrator", 
  "module": "Setup", 
  "name": "Customer Group", 
diff --git a/erpnext/setup/utils.py b/erpnext/setup/utils.py
index 5fcc3a2..8d9bba3 100644
--- a/erpnext/setup/utils.py
+++ b/erpnext/setup/utils.py
@@ -128,7 +128,7 @@
 		doc.update(r)
 		try:
 			doc.insert(ignore_permissions=True)
-		except frappe.DuplicateEntryError, e:
+		except frappe.DuplicateEntryError as e:
 			# pass DuplicateEntryError and continue
 			if e.args and e.args[0]==doc.doctype and e.args[1]==doc.name:
 				# make sure DuplicateEntryError is for the exact same doc and not a related doc
diff --git a/erpnext/stock/dashboard/item_dashboard.js b/erpnext/stock/dashboard/item_dashboard.js
index 23820d3..2748436 100644
--- a/erpnext/stock/dashboard/item_dashboard.js
+++ b/erpnext/stock/dashboard/item_dashboard.js
@@ -75,7 +75,7 @@
 			this.content.find('.more').addClass('hidden');
 		}
 
-        // If not any stock in any warehouses provide a message to end user
+		// If not any stock in any warehouses provide a message to end user
 		if (context.data.length > 0) {
 			$(frappe.render_template('item_dashboard_list', context)).appendTo(this.result);
 		} else {
@@ -86,6 +86,7 @@
 	get_item_dashboard_data: function(data, max_count, show_item) {
 		if(!max_count) max_count = 0;
 		if(!data) data = [];
+
 		data.forEach(function(d) {
 			d.actual_or_pending = d.projected_qty + d.reserved_qty + d.reserved_qty_for_production;
 			d.pending_qty = 0;
@@ -97,9 +98,16 @@
 			max_count = Math.max(d.actual_or_pending, d.actual_qty,
 				d.total_reserved, max_count);
 		});
+
+		var can_write = 0;
+		if(frappe.boot.user.can_write.indexOf("Stock Entry")>=0){
+			can_write = 1;
+		}
+
 		return {
 			data: data,
 			max_count: max_count,
+			can_write:can_write,
 			show_item: show_item || false
 		}
 	}
@@ -187,4 +195,4 @@
 				frappe.set_route('Form', doc.doctype, doc.name);
 			})
 		});
-}
+}
\ No newline at end of file
diff --git a/erpnext/stock/dashboard/item_dashboard_list.html b/erpnext/stock/dashboard/item_dashboard_list.html
index 63f2480..e0b3431 100644
--- a/erpnext/stock/dashboard/item_dashboard_list.html
+++ b/erpnext/stock/dashboard/item_dashboard_list.html
@@ -39,6 +39,7 @@
 					</span>
 				</span>
 			</div>
+			{% if can_write %}
 			<div class="col-sm-2 text-right" style="margin-top: 8px;">
 				{% if d.actual_qty %}
 				<button class="btn btn-default btn-xs btn-move"
@@ -52,6 +53,7 @@
 					data-item="{{ d.item_code }}"
 					data-rate="{{ d.valuation_rate }}">{{ __("Add") }}</a>
 			</div>
+			{% endif %}
 		</div>
 	</div>
 {% endfor %}
diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py
index 42e2cef..bcbc35e 100644
--- a/erpnext/stock/doctype/batch/batch.py
+++ b/erpnext/stock/doctype/batch/batch.py
@@ -5,24 +5,31 @@
 import frappe
 from frappe import _
 from frappe.model.document import Document
-from frappe.model.naming import make_autoname
+from frappe.model.naming import make_autoname, revert_series_if_last
 from frappe.utils import flt, cint
 
 
-class UnableToSelectBatchError(frappe.ValidationError): pass
+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 + '.#####')
+	"""
+	Get a name generated for a Batch from the Batch's naming series.
+	:return: The string that was generated.
+	"""
+	naming_series_prefix = _get_batch_prefix()
+	key = _make_naming_series_key(naming_series_prefix)
+	name = make_autoname(key)
 
 	return name
 
 
 def get_name_from_hash():
+	"""
+	Get a name for a Batch by generating a unique hash.
+	:return: The hash that was generated.
+	"""
 	temp = None
 	while not temp:
 		temp = frappe.generate_hash()[:7].upper()
@@ -32,13 +39,66 @@
 	return temp
 
 
+def batch_uses_naming_series():
+	"""
+	Verify if the Batch is to be named using a naming series
+	:return: bool
+	"""
+	use_naming_series = cint(frappe.db.get_single_value('Stock Settings', 'use_naming_series'))
+	return bool(use_naming_series)
+
+
+def _get_batch_prefix():
+	"""
+	Get the naming series prefix set in Stock Settings.
+
+	It does not do any sanity checks so make sure to use it after checking if the Batch
+	is set to use naming series.
+	:return: The naming series.
+	"""
+	naming_series_prefix = frappe.db.get_single_value('Stock Settings', 'naming_series_prefix')
+	if not naming_series_prefix:
+		naming_series_prefix = 'BATCH-'
+
+	return naming_series_prefix
+
+
+def _make_naming_series_key(prefix):
+	"""
+	Make naming series key for a Batch.
+
+	Naming series key is in the format [prefix].[#####]
+	:param prefix: Naming series prefix gotten from Stock Settings
+	:return: The derived key. If no prefix is given, an empty string is returned
+	"""
+	if not unicode(prefix):
+		return ''
+	else:
+		return prefix.upper() + '.#####'
+
+
+def get_batch_naming_series():
+	"""
+	Get naming series key for a Batch.
+
+	Naming series key is in the format [prefix].[#####]
+	:return: The naming series or empty string if not available
+	"""
+	series = ''
+	if batch_uses_naming_series():
+		prefix = _get_batch_prefix()
+		key = _make_naming_series_key(prefix)
+		series = key
+
+	return series
+
+
 class Batch(Document):
 	def autoname(self):
 		"""Generate random ID for batch if not specified"""
 		if not self.batch_id:
 			if frappe.db.get_value('Item', self.item, 'create_new_batch'):
-				use_naming_series = frappe.db.get_single_value('Stock Settings', 'use_naming_series')
-				if use_naming_series:
+				if batch_uses_naming_series():
 					self.batch_id = get_name_from_naming_series()
 				else:
 					self.batch_id = get_name_from_hash()
@@ -50,13 +110,17 @@
 	def onload(self):
 		self.image = frappe.db.get_value('Item', self.item, 'image')
 
+	def after_delete(self):
+		revert_series_if_last(get_batch_naming_series(), self.name)
+
 	def validate(self):
 		self.item_has_batch_enabled()
 
 	def item_has_batch_enabled(self):
-		if frappe.db.get_value("Item",self.item,"has_batch_no") == 0:
+		if frappe.db.get_value("Item", self.item, "has_batch_no") == 0:
 			frappe.throw(_("The selected item cannot have Batch"))
 
+
 @frappe.whitelist()
 def get_batch_qty(batch_no=None, warehouse=None, item_code=None):
 	"""Returns batch actual qty if warehouse is passed,
@@ -89,16 +153,18 @@
 
 	return out
 
+
 @frappe.whitelist()
 def get_batches_by_oldest(item_code, 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 = 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])
 	return batches_dates
 
+
 @frappe.whitelist()
-def split_batch(batch_no, item_code, warehouse, qty, new_batch_id = None):
+def split_batch(batch_no, item_code, warehouse, qty, new_batch_id=None):
 	"""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(
@@ -106,16 +172,16 @@
 		purpose='Repack',
 		items=[
 			dict(
-				item_code = item_code,
-				qty = float(qty or 0),
-				s_warehouse = warehouse,
-				batch_no = batch_no
+				item_code=item_code,
+				qty=float(qty or 0),
+				s_warehouse=warehouse,
+				batch_no=batch_no
 			),
 			dict(
-				item_code = item_code,
-				qty = float(qty or 0),
-				t_warehouse = warehouse,
-				batch_no = batch.name
+				item_code=item_code,
+				qty=float(qty or 0),
+				t_warehouse=warehouse,
+				batch_no=batch.name
 			),
 		]
 	))
@@ -124,7 +190,8 @@
 
 	return batch.name
 
-def set_batch_nos(doc, warehouse_field, throw = False):
+
+def set_batch_nos(doc, warehouse_field, throw=False):
 	"""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
@@ -135,8 +202,9 @@
 				d.batch_no = get_batch_no(d.item_code, warehouse, qty, throw)
 			else:
 				batch_qty = get_batch_qty(batch_no=d.batch_no, warehouse=warehouse)
-				if flt(batch_qty) < flt(qty):
-					frappe.throw(_("Row #{0}: The batch {1} has only {2} qty. Please select another batch which has {3} qty available or split the row into multiple rows, to deliver/issue from multiple batches").format(d.idx, d.batch_no, batch_qty, d.qty))
+				if flt(batch_qty, d.precision("qty")) < flt(qty, d.precision("qty")):
+					frappe.throw(_("Row #{0}: The batch {1} has only {2} qty. Please select another batch which has {3} qty available or split the row into multiple rows, to deliver/issue from multiple batches").format(d.idx, d.batch_no, batch_qty, d.stock_qty))
+
 
 @frappe.whitelist()
 def get_batch_no(item_code, warehouse, qty=1, throw=False):
diff --git a/erpnext/stock/doctype/batch/batch_list.js b/erpnext/stock/doctype/batch/batch_list.js
index 2138fa1..7ee81aa 100644
--- a/erpnext/stock/doctype/batch/batch_list.js
+++ b/erpnext/stock/doctype/batch/batch_list.js
@@ -1,7 +1,7 @@
 frappe.listview_settings['Batch'] = {
 	add_fields: ["item", "expiry_date"],
 	get_indicator: function(doc) {
-		if(doc.expiry_date && frappe.datetime.get_diff(doc.expiry_date) <= 0) {
+		if(doc.expiry_date && frappe.datetime.get_diff(doc.expiry_date, frappe.datetime.nowdate()) <= 0) {
 			return [__("Expired"), "red", "expiry_date,>=,Today"]
 		} else if(doc.expiry_date) {
 			return [__("Not Expired"), "green", "expiry_date,<,Today"]
diff --git a/erpnext/stock/doctype/batch/test_batch.py b/erpnext/stock/doctype/batch/test_batch.py
index a327b2d..9538781 100644
--- a/erpnext/stock/doctype/batch/test_batch.py
+++ b/erpnext/stock/doctype/batch/test_batch.py
@@ -7,6 +7,8 @@
 import unittest
 
 from erpnext.stock.doctype.batch.batch import get_batch_qty, UnableToSelectBatchError, get_batch_no
+from frappe.utils import cint
+
 
 class TestBatch(unittest.TestCase):
 
@@ -21,7 +23,7 @@
 	def make_batch_item(cls, item_name):
 		from erpnext.stock.doctype.item.test_item import make_item
 		if not frappe.db.exists(item_name):
-			make_item(item_name, dict(has_batch_no = 1, create_new_batch = 1))
+			return make_item(item_name, dict(has_batch_no = 1, create_new_batch = 1))
 
 	def test_purchase_receipt(self, batch_qty = 100):
 		'''Test automated batch creation from Purchase Receipt'''
@@ -192,3 +194,37 @@
 			]
 		)).insert()
 		stock_entry.submit()
+
+	def test_batch_name_with_naming_series(self):
+		stock_settings = frappe.get_single('Stock Settings')
+		use_naming_series = cint(stock_settings.use_naming_series)
+
+		if not use_naming_series:
+			frappe.set_value('Stock Settings', 'Stock Settings', 'use_naming_series', 1)
+
+		batch = self.make_new_batch('_Test Stock Item For Batch Test1')
+		batch_name = batch.name
+
+		self.assertTrue(batch_name.startswith('BATCH-'))
+
+		batch.delete()
+		batch = self.make_new_batch('_Test Stock Item For Batch Test2')
+
+		self.assertEqual(batch_name, batch.name)
+
+		# reset Stock Settings
+		if not use_naming_series:
+			frappe.set_value('Stock Settings', 'Stock Settings', 'use_naming_series', 0)
+
+	def make_new_batch(self, item_name, batch_id=None, do_not_insert=0):
+		batch = frappe.new_doc('Batch')
+		item = self.make_batch_item(item_name)
+		batch.item = item.name
+
+		if batch_id:
+			batch.batch_id = batch_id
+
+		if not do_not_insert:
+			batch.insert()
+
+		return batch
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index dd8d998..80afd49 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -293,7 +293,7 @@
 
 			# get basic rate
 			if not d.bom_no:
-				if not flt(d.basic_rate) or d.s_warehouse or force:
+				if (not flt(d.basic_rate) and not d.allow_zero_valuation_rate) or d.s_warehouse or force:
 					basic_rate = flt(get_incoming_rate(args), self.precision("basic_rate", d))
 					if basic_rate > 0:
 						d.basic_rate = basic_rate
@@ -304,7 +304,8 @@
 
 			# get scrap items basic rate
 			if d.bom_no:
-				if not flt(d.basic_rate) and getattr(self, "pro_doc", frappe._dict()).scrap_warehouse == d.t_warehouse:
+				if not flt(d.basic_rate) and not d.allow_zero_valuation_rate and \
+					getattr(self, "pro_doc", frappe._dict()).scrap_warehouse == d.t_warehouse:
 					basic_rate = flt(get_incoming_rate(args), self.precision("basic_rate", d))
 					if basic_rate > 0:
 						d.basic_rate = basic_rate
diff --git a/erpnext/utilities/user_progress_utils.py b/erpnext/utilities/user_progress_utils.py
index 18d38c0..58a03e3 100644
--- a/erpnext/utilities/user_progress_utils.py
+++ b/erpnext/utilities/user_progress_utils.py
@@ -40,12 +40,12 @@
 @frappe.whitelist()
 def create_letterhead(args_data):
 	args = json.loads(args_data)
-	letterhead = args.get("letterhead").encode('utf-8')
+	letterhead = args.get("letterhead")
 	if letterhead:
 		try:
 			frappe.get_doc({
 					"doctype":"Letter Head",
-					"content":"""<div><img src="{0}" style='max-width: 100%%;'><br></div>""".format(letterhead),
+					"content":"""<div><img src="{0}" style='max-width: 100%%;'><br></div>""".format(letterhead.encode('utf-8')),
 					"letter_head_name": _("Standard"),
 					"is_default": 1
 			}).insert()