Merge branch 'develop' into payment-terms
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.json b/erpnext/accounts/doctype/gl_entry/gl_entry.json
index 76e66d0..e27eaab 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.json
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.json
@@ -80,6 +80,36 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
+   "fieldname": "due_date", 
+   "fieldtype": "Date", 
+   "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": "Due Date", 
+   "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, 
    "fieldname": "account", 
    "fieldtype": "Link", 
    "hidden": 0, 
@@ -718,7 +748,7 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2017-08-03 12:40:09.611951", 
+ "modified": "2017-08-10 18:06:44.904081", 
  "modified_by": "Administrator", 
  "module": "Accounts", 
  "name": "GL Entry", 
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js
index 9047a4e..4ce6886 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.js
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js
@@ -185,8 +185,39 @@
 		})
 	},
 
+	due_date_options_cache: {},
+
 	reference_name: function(doc, cdt, cdn) {
 		var d = frappe.get_doc(cdt, cdn);
+		var me = this;
+
+		const get_invoice_due_dates = invoice_name => {
+			const options = this.due_date_options_cache[invoice_name];
+			const input = $(cur_frm.fields_dict["accounts"].wrapper).find("select[data-fieldname=reference_due_date]");
+
+			if (options) {
+				input.empty();
+				input.add_options(options);
+				frappe.model.set_value(cdt, cdn, "reference_due_date", options[0]);
+			}
+			else {
+				frappe.call({
+					method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_invoice_due_dates",
+					args: {name: invoice_name},
+					callback: function(r) {
+						const options = [];
+						$.each(r.message, function(key, value) {
+							options.push(value.due_date);
+						});
+						input.empty();
+						input.add_options(options);
+						frappe.model.set_value(cdt, cdn, "reference_due_date", options[0]);
+						me.due_date_options_cache[d.reference_name] = options;
+					}
+				});
+			}
+		}
+
 		if(d.reference_name) {
 			if (d.reference_type==="Purchase Invoice" && !flt(d.debit)) {
 				this.get_outstanding('Purchase Invoice', d.reference_name, doc.company, d);
@@ -197,6 +228,9 @@
 			if (d.reference_type==="Journal Entry" && !flt(d.credit) && !flt(d.debit)) {
 				this.get_outstanding('Journal Entry', d.reference_name, doc.company, d);
 			}
+			if( in_list(["Sales Invoice", "Purchase Invoice"]), d.reference_type) {
+				get_invoice_due_dates(d.reference_name);
+			}
 		}
 	},
 
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 375d85d..f7e4023 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -436,7 +436,8 @@
 						"against_voucher": d.reference_name,
 						"remarks": self.remark,
 						"cost_center": d.cost_center,
-						"project": d.project
+						"project": d.project,
+						"due_date": d.reference_due_date
 					})
 				)
 
@@ -889,3 +890,14 @@
 		exchange_rate = bank_balance_in_company_currency / bank_balance_in_account_currency
 
 	return exchange_rate
+
+
+@frappe.whitelist()
+def get_invoice_due_dates(name):
+	result = frappe.get_list(
+		doctype='GL Entry', group_by='name, due_date',
+		filters={'voucher_no': name, "ifnull(due_date, '')": ('!=', '')},
+		fields=['due_date'], distinct=True
+	)
+
+	return result
diff --git a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
index 54af579..48d5ed2 100644
--- a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
+++ b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
@@ -1,5 +1,6 @@
 {
  "allow_copy": 0, 
+ "allow_guest_to_view": 0, 
  "allow_import": 0, 
  "allow_rename": 0, 
  "autoname": "hash", 
@@ -13,6 +14,7 @@
  "engine": "InnoDB", 
  "fields": [
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 1, 
    "collapsible": 0, 
@@ -46,6 +48,7 @@
    "width": "250px"
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -75,6 +78,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -106,6 +110,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -141,6 +146,7 @@
    "width": "180px"
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -168,6 +174,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -197,6 +204,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -226,6 +234,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -256,6 +265,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -287,6 +297,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -317,6 +328,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -345,6 +357,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -374,6 +387,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -402,6 +416,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 1, 
    "collapsible": 0, 
@@ -432,6 +447,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 1, 
    "collapsible": 0, 
@@ -464,6 +480,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -491,6 +508,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 1, 
    "collapsible": 0, 
@@ -521,6 +539,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 1, 
    "collapsible": 0, 
@@ -553,6 +572,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -581,6 +601,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -611,6 +632,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -641,6 +663,39 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "depends_on": "eval:doc.reference_type&&!in_list(doc.reference_type, ['Expense Claim', 'Asset', 'Employee Loan'])", 
+   "fieldname": "reference_due_date", 
+   "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": "Reference Due Date", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "", 
+   "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, 
@@ -671,6 +726,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -698,6 +754,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -729,6 +786,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -759,17 +817,17 @@
    "unique": 0
   }
  ], 
+ "has_web_view": 0, 
  "hide_heading": 0, 
  "hide_toolbar": 0, 
  "idx": 1, 
  "image_view": 0, 
  "in_create": 0, 
- "in_dialog": 0, 
  "is_submittable": 0, 
  "issingle": 0, 
  "istable": 1, 
  "max_attachments": 0, 
- "modified": "2017-03-02 05:02:10.102039", 
+ "modified": "2017-08-30 08:44:54.295493", 
  "modified_by": "Administrator", 
  "module": "Accounts", 
  "name": "Journal Entry Account", 
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 908e58e..7ae9bde 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -404,7 +404,8 @@
 				gle = party_gl_dict.copy()
 				gle.update({
 					"against_voucher_type": d.reference_doctype,
-					"against_voucher": d.reference_name
+					"against_voucher": d.reference_name,
+					"due_date": d.due_date
 				})
 
 				allocated_amount_in_company_currency = flt(flt(d.allocated_amount) * flt(d.exchange_rate),
@@ -736,18 +737,53 @@
 	pe.allocate_payment_amount = 1
 	pe.letter_head = doc.get("letter_head")
 
-	pe.append("references", {
-		"reference_doctype": dt,
-		"reference_name": dn,
-		"due_date": doc.get("due_date"),
-		"total_amount": grand_total,
-		"outstanding_amount": outstanding_amount,
-		"allocated_amount": outstanding_amount
-	})
+	if doc.get("payment_schedule"):
+		for d in doc.get("payment_schedule"):
+			invoice_amount = d.payment_amount * doc.conversion_rate \
+				if party_account_currency == doc.company_currency else d.payment_amount
+			paid_amount = get_paid_amount(dt, dn, party_type, pe.party, party_account, d.due_date)
+			outstanding_amount = invoice_amount - paid_amount
+			pe.append("references", {
+				"reference_doctype": dt,
+				"reference_name": dn,
+				"due_date": d.due_date,
+				"total_amount": invoice_amount,
+				"outstanding_amount": outstanding_amount,
+				"allocated_amount": outstanding_amount
+			})
+	else:
+		pe.append("references", {
+			"reference_doctype": dt,
+			"reference_name": dn,
+			"due_date": doc.get("due_date"),
+			"total_amount": grand_total,
+			"outstanding_amount": outstanding_amount,
+			"allocated_amount": outstanding_amount
+		})
 
 	pe.setup_party_account_field()
 	pe.set_missing_values()
 	if party_account and bank:
 		pe.set_exchange_rate()
 		pe.set_amounts()
-	return pe
\ No newline at end of file
+	return pe
+
+def get_paid_amount(dt, dn, party_type, party, account, due_date):
+	if party_type=="Customer":
+		dr_or_cr = "credit_in_account_currency - debit_in_account_currency"
+	else:
+		dr_or_cr = "debit_in_account_currency - credit_in_account_currency"
+
+	paid_amount = frappe.db.sql("""
+		select ifnull(sum({dr_or_cr}), 0) as paid_amount
+		from `tabGL Entry`
+		where against_voucher_type = %s
+			and against_voucher = %s
+			and party_type = %s
+			and party = %s
+			and account = %s
+			and due_date = %s
+			and {dr_or_cr} > 0
+	""".format(dr_or_cr=dr_or_cr), (dt, dn, party_type, party, account, due_date))
+
+	return paid_amount[0][0] if paid_amount else 0
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/payment_schedule/__init__.py b/erpnext/accounts/doctype/payment_schedule/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_schedule/__init__.py
diff --git a/erpnext/accounts/doctype/payment_schedule/payment_schedule.json b/erpnext/accounts/doctype/payment_schedule/payment_schedule.json
new file mode 100644
index 0000000..45a81b0
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_schedule/payment_schedule.json
@@ -0,0 +1,197 @@
+{
+ "allow_copy": 0, 
+ "allow_guest_to_view": 0, 
+ "allow_import": 0, 
+ "allow_rename": 0, 
+ "autoname": "", 
+ "beta": 0, 
+ "creation": "2017-08-10 15:38:00.080575", 
+ "custom": 0, 
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "", 
+ "editable_grid": 1, 
+ "engine": "InnoDB", 
+ "fields": [
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 2, 
+   "fieldname": "payment_term", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Payment Term", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Payment Term", 
+   "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": 2, 
+   "fieldname": "description", 
+   "fieldtype": "Small Text", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Description", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "payment_term.description", 
+   "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": 2, 
+   "fieldname": "due_date", 
+   "fieldtype": "Date", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Due Date", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "payment_term.due_date", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 2, 
+   "fieldname": "invoice_portion", 
+   "fieldtype": "Percent", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Invoice Portion", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "payment_term.invoice_portion", 
+   "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": 2, 
+   "fieldname": "payment_amount", 
+   "fieldtype": "Currency", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Payment Amount", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "currency", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }
+ ], 
+ "has_web_view": 0, 
+ "hide_heading": 0, 
+ "hide_toolbar": 0, 
+ "idx": 0, 
+ "image_view": 0, 
+ "in_create": 0, 
+ "is_submittable": 0, 
+ "issingle": 0, 
+ "istable": 1, 
+ "max_attachments": 0, 
+ "modified": "2017-08-10 18:09:42.122027", 
+ "modified_by": "Administrator", 
+ "module": "Accounts", 
+ "name": "Payment Schedule", 
+ "name_case": "", 
+ "owner": "Administrator", 
+ "permissions": [], 
+ "quick_entry": 1, 
+ "read_only": 0, 
+ "read_only_onload": 0, 
+ "show_name_in_global_search": 0, 
+ "sort_field": "modified", 
+ "sort_order": "DESC", 
+ "track_changes": 1, 
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/payment_schedule/payment_schedule.py b/erpnext/accounts/doctype/payment_schedule/payment_schedule.py
new file mode 100644
index 0000000..4174017
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_schedule/payment_schedule.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from frappe.model.document import Document
+
+
+class PaymentSchedule(Document):
+	pass
diff --git a/erpnext/accounts/doctype/payment_term/__init__.py b/erpnext/accounts/doctype/payment_term/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_term/__init__.py
diff --git a/erpnext/accounts/doctype/payment_term/payment_term.js b/erpnext/accounts/doctype/payment_term/payment_term.js
new file mode 100644
index 0000000..054c2d1
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_term/payment_term.js
@@ -0,0 +1,2 @@
+// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
diff --git a/erpnext/accounts/doctype/payment_term/payment_term.json b/erpnext/accounts/doctype/payment_term/payment_term.json
new file mode 100644
index 0000000..702319b
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_term/payment_term.json
@@ -0,0 +1,344 @@
+{
+ "allow_copy": 0, 
+ "allow_guest_to_view": 0, 
+ "allow_import": 0, 
+ "allow_rename": 0, 
+ "autoname": "field:payment_term_name", 
+ "beta": 0, 
+ "creation": "2017-08-10 15:24:54.876365", 
+ "custom": 0, 
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "", 
+ "editable_grid": 1, 
+ "engine": "InnoDB", 
+ "fields": [
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 1, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "payment_term_name", 
+   "fieldtype": "Data", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Payment Term Name", 
+   "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": 1, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "invoice_portion", 
+   "fieldtype": "Float", 
+   "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": "Invoice Portion", 
+   "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, 
+   "fieldname": "column_break_3", 
+   "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": 1, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "due_date_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": "Due Date Based On", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Day(s) after invoice date\nDay(s) after the end of the invoice month\nMonth(s) after the end of the invoice 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": 1, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "depends_on": "eval:in_list(['Day(s) after invoice date', 'Day(s) after the end of the invoice month'], doc.due_date_based_on)", 
+   "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": 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.due_date_based_on=='Month(s) after the end of the invoice month'", 
+   "fieldname": "credit_months", 
+   "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 Months", 
+   "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, 
+   "fieldname": "section_break_6", 
+   "fieldtype": "Section Break", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "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": 1, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "description", 
+   "fieldtype": "Small Text", 
+   "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": "Description", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }
+ ], 
+ "has_web_view": 0, 
+ "hide_heading": 0, 
+ "hide_toolbar": 0, 
+ "idx": 0, 
+ "image_view": 0, 
+ "in_create": 0, 
+ "is_submittable": 0, 
+ "issingle": 0, 
+ "istable": 0, 
+ "max_attachments": 0, 
+ "modified": "2017-08-10 16:26:03.581501", 
+ "modified_by": "Administrator", 
+ "module": "Accounts", 
+ "name": "Payment Term", 
+ "name_case": "", 
+ "owner": "Administrator", 
+ "permissions": [
+  {
+   "amend": 0, 
+   "apply_user_permissions": 0, 
+   "cancel": 0, 
+   "create": 1, 
+   "delete": 1, 
+   "email": 1, 
+   "export": 1, 
+   "if_owner": 0, 
+   "import": 0, 
+   "permlevel": 0, 
+   "print": 1, 
+   "read": 1, 
+   "report": 1, 
+   "role": "System Manager", 
+   "set_user_permissions": 0, 
+   "share": 1, 
+   "submit": 0, 
+   "write": 1
+  }, 
+  {
+   "amend": 0, 
+   "apply_user_permissions": 0, 
+   "cancel": 0, 
+   "create": 1, 
+   "delete": 1, 
+   "email": 1, 
+   "export": 1, 
+   "if_owner": 0, 
+   "import": 0, 
+   "permlevel": 0, 
+   "print": 1, 
+   "read": 1, 
+   "report": 1, 
+   "role": "Accounts Manager", 
+   "set_user_permissions": 0, 
+   "share": 1, 
+   "submit": 0, 
+   "write": 1
+  }, 
+  {
+   "amend": 0, 
+   "apply_user_permissions": 0, 
+   "cancel": 0, 
+   "create": 1, 
+   "delete": 1, 
+   "email": 1, 
+   "export": 1, 
+   "if_owner": 0, 
+   "import": 0, 
+   "permlevel": 0, 
+   "print": 1, 
+   "read": 1, 
+   "report": 1, 
+   "role": "Accounts User", 
+   "set_user_permissions": 0, 
+   "share": 1, 
+   "submit": 0, 
+   "write": 1
+  }
+ ], 
+ "quick_entry": 1, 
+ "read_only": 0, 
+ "read_only_onload": 0, 
+ "show_name_in_global_search": 0, 
+ "sort_field": "modified", 
+ "sort_order": "DESC", 
+ "track_changes": 1, 
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/payment_term/payment_term.py b/erpnext/accounts/doctype/payment_term/payment_term.py
new file mode 100644
index 0000000..5d4df05
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_term/payment_term.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from frappe.model.document import Document
+
+
+class PaymentTerm(Document):
+	pass
diff --git a/erpnext/accounts/doctype/payment_term/test_payment_term.js b/erpnext/accounts/doctype/payment_term/test_payment_term.js
new file mode 100644
index 0000000..b26e42a
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_term/test_payment_term.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Payment Term", function (assert) {
+	let done = assert.async();
+
+	// number of asserts
+	assert.expect(1);
+
+	frappe.run_serially([
+		// insert a new Payment Term
+		() => frappe.tests.make('Payment Term', [
+			// values to be set
+			{key: 'value'}
+		]),
+		() => {
+			assert.equal(cur_frm.doc.key, 'value');
+		},
+		() => done()
+	]);
+
+});
diff --git a/erpnext/accounts/doctype/payment_term/test_payment_term.py b/erpnext/accounts/doctype/payment_term/test_payment_term.py
new file mode 100644
index 0000000..d9baa59
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_term/test_payment_term.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+import unittest
+
+
+class TestPaymentTerm(unittest.TestCase):
+	pass
diff --git a/erpnext/accounts/doctype/payment_term/test_records.json b/erpnext/accounts/doctype/payment_term/test_records.json
new file mode 100644
index 0000000..ef6e069
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_term/test_records.json
@@ -0,0 +1,34 @@
+[
+  {
+    "doctype":"Payment Term",
+    "due_date_based_on":"Day(s) after invoice date",
+    "payment_term_name":"_Test N30",
+    "description":"_Test Net 30 Days",
+    "invoice_portion":50,
+    "credit_days":30
+  },
+  {
+    "doctype":"Payment Term",
+    "due_date_based_on":"Day(s) after invoice date",
+    "payment_term_name":"_Test COD",
+    "description":"_Test Cash on Delivery",
+    "invoice_portion":50,
+    "credit_days":0
+  },
+  {
+    "doctype":"Payment Term",
+    "due_date_based_on":"Month(s) after the end of the invoice month",
+    "payment_term_name":"_Test EONM",
+    "description":"_Test End of Next Month",
+    "invoice_portion":100,
+    "credit_months":1
+  },
+  {
+    "doctype":"Payment Term",
+    "due_date_based_on":"Day(s) after invoice date",
+    "payment_term_name":"_Test N30 1",
+    "description":"_Test Net 30 Days",
+    "invoice_portion":100,
+    "credit_days":30
+  }
+]
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/payment_terms_template/__init__.py b/erpnext/accounts/doctype/payment_terms_template/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_terms_template/__init__.py
diff --git a/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.js b/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.js
new file mode 100644
index 0000000..558297f
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.js
@@ -0,0 +1,12 @@
+// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Payment Terms Template', {
+	setup: function(frm) {
+		frm.add_fetch("payment_term", "description", "description");
+		frm.add_fetch("payment_term", "invoice_portion", "invoice_portion");
+		frm.add_fetch("payment_term", "due_date_based_on", "due_date_based_on");
+		frm.add_fetch("payment_term", "credit_days", "credit_days");
+		frm.add_fetch("payment_term", "credit_months", "credit_months");
+	}
+});
diff --git a/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.json b/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.json
new file mode 100644
index 0000000..0959658
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.json
@@ -0,0 +1,164 @@
+{
+ "allow_copy": 0, 
+ "allow_guest_to_view": 0, 
+ "allow_import": 0, 
+ "allow_rename": 0, 
+ "autoname": "field:template_name", 
+ "beta": 0, 
+ "creation": "2017-08-10 15:34:28.058054", 
+ "custom": 0, 
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "", 
+ "editable_grid": 1, 
+ "engine": "InnoDB", 
+ "fields": [
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "template_name", 
+   "fieldtype": "Data", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Template Name", 
+   "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, 
+   "fieldname": "terms", 
+   "fieldtype": "Table", 
+   "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": "Payment Terms", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Payment Terms Template Detail", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }
+ ], 
+ "has_web_view": 0, 
+ "hide_heading": 0, 
+ "hide_toolbar": 0, 
+ "idx": 0, 
+ "image_view": 0, 
+ "in_create": 0, 
+ "is_submittable": 0, 
+ "issingle": 0, 
+ "istable": 0, 
+ "max_attachments": 0, 
+ "modified": "2017-08-10 15:46:33.877884", 
+ "modified_by": "Administrator", 
+ "module": "Accounts", 
+ "name": "Payment Terms Template", 
+ "name_case": "", 
+ "owner": "Administrator", 
+ "permissions": [
+  {
+   "amend": 0, 
+   "apply_user_permissions": 0, 
+   "cancel": 0, 
+   "create": 1, 
+   "delete": 1, 
+   "email": 1, 
+   "export": 1, 
+   "if_owner": 0, 
+   "import": 0, 
+   "permlevel": 0, 
+   "print": 1, 
+   "read": 1, 
+   "report": 1, 
+   "role": "System Manager", 
+   "set_user_permissions": 0, 
+   "share": 1, 
+   "submit": 0, 
+   "write": 1
+  }, 
+  {
+   "amend": 0, 
+   "apply_user_permissions": 0, 
+   "cancel": 0, 
+   "create": 1, 
+   "delete": 1, 
+   "email": 1, 
+   "export": 1, 
+   "if_owner": 0, 
+   "import": 0, 
+   "permlevel": 0, 
+   "print": 1, 
+   "read": 1, 
+   "report": 1, 
+   "role": "Accounts User", 
+   "set_user_permissions": 0, 
+   "share": 1, 
+   "submit": 0, 
+   "write": 1
+  }, 
+  {
+   "amend": 0, 
+   "apply_user_permissions": 0, 
+   "cancel": 0, 
+   "create": 1, 
+   "delete": 1, 
+   "email": 1, 
+   "export": 1, 
+   "if_owner": 0, 
+   "import": 0, 
+   "permlevel": 0, 
+   "print": 1, 
+   "read": 1, 
+   "report": 1, 
+   "role": "Accounts Manager", 
+   "set_user_permissions": 0, 
+   "share": 1, 
+   "submit": 0, 
+   "write": 1
+  }
+ ], 
+ "quick_entry": 0, 
+ "read_only": 0, 
+ "read_only_onload": 0, 
+ "show_name_in_global_search": 0, 
+ "sort_field": "modified", 
+ "sort_order": "DESC", 
+ "track_changes": 1, 
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.py b/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.py
new file mode 100644
index 0000000..d2344d6
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from frappe.model.document import Document
+
+
+class PaymentTermsTemplate(Document):
+	pass
diff --git a/erpnext/accounts/doctype/payment_terms_template/test_payment_terms_template.js b/erpnext/accounts/doctype/payment_terms_template/test_payment_terms_template.js
new file mode 100644
index 0000000..494a0ed
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_terms_template/test_payment_terms_template.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Payment Terms Template", function (assert) {
+	let done = assert.async();
+
+	// number of asserts
+	assert.expect(1);
+
+	frappe.run_serially([
+		// insert a new Payment Terms Template
+		() => frappe.tests.make('Payment Terms Template', [
+			// values to be set
+			{key: 'value'}
+		]),
+		() => {
+			assert.equal(cur_frm.doc.key, 'value');
+		},
+		() => done()
+	]);
+
+});
diff --git a/erpnext/accounts/doctype/payment_terms_template/test_payment_terms_template.py b/erpnext/accounts/doctype/payment_terms_template/test_payment_terms_template.py
new file mode 100644
index 0000000..ec37066
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_terms_template/test_payment_terms_template.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+import unittest
+
+
+class TestPaymentTermsTemplate(unittest.TestCase):
+	pass
diff --git a/erpnext/accounts/doctype/payment_terms_template/test_records.json b/erpnext/accounts/doctype/payment_terms_template/test_records.json
new file mode 100644
index 0000000..fea0b35
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_terms_template/test_records.json
@@ -0,0 +1,60 @@
+[
+  {
+    "doctype":"Payment Terms Template",
+    "terms":[
+          {
+            "doctype":"Payment Terms Template Detail",
+            "due_date_based_on":"Day(s) after invoice date",
+            "idx":1,
+            "description":"Cash on Delivery",
+            "invoice_portion":50,
+            "credit_days":0,
+            "credit_months":0,
+            "payment_term":"_Test COD"
+        },
+        {
+            "doctype":"Payment Terms Template Detail",
+            "due_date_based_on":"Day(s) after invoice date",
+            "idx":2,
+            "description":"Net 30 Days ",
+            "invoice_portion":50,
+            "credit_days":30,
+            "credit_months":0,
+            "payment_term":"_Test N30"
+        }
+    ],
+    "template_name":"_Test Payment Term Template"
+  },
+  {
+    "doctype":"Payment Terms Template",
+    "terms":[
+          {
+            "doctype":"Payment Terms Template Detail",
+            "due_date_based_on":"Month(s) after the end of the invoice month",
+            "idx":1,
+            "description":"_Test End of Next Months",
+            "invoice_portion":100,
+            "credit_days":0,
+            "credit_months":1,
+            "payment_term":"_Test EONM"
+        }
+    ],
+    "template_name":"_Test Payment Term Template 1"
+  },
+  {
+    "doctype":"Payment Terms Template",
+    "terms":[
+          {
+            "doctype":"Payment Terms Template Detail",
+            "due_date_based_on":"Day(s) after invoice date",
+            "idx":1,
+            "description":"_Test Net Within 30 days",
+            "invoice_portion":100,
+            "credit_days":30,
+            "credit_months":0,
+            "payment_term":"_Test N30 1"
+        }
+    ],
+    "template_name":"_Test Payment Term Template 3"
+  }
+]
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/payment_terms_template_detail/__init__.py b/erpnext/accounts/doctype/payment_terms_template_detail/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_terms_template_detail/__init__.py
diff --git a/erpnext/accounts/doctype/payment_terms_template_detail/payment_terms_template_detail.json b/erpnext/accounts/doctype/payment_terms_template_detail/payment_terms_template_detail.json
new file mode 100644
index 0000000..88babd5
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_terms_template_detail/payment_terms_template_detail.json
@@ -0,0 +1,229 @@
+{
+ "allow_copy": 0, 
+ "allow_guest_to_view": 0, 
+ "allow_import": 0, 
+ "allow_rename": 0, 
+ "autoname": "PTTD.#####", 
+ "beta": 0, 
+ "creation": "2017-08-10 15:34:09.409562", 
+ "custom": 0, 
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "", 
+ "editable_grid": 1, 
+ "engine": "InnoDB", 
+ "fields": [
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 2, 
+   "fieldname": "payment_term", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Payment Term", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Payment Term", 
+   "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": 2, 
+   "fieldname": "description", 
+   "fieldtype": "Small Text", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Description", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "", 
+   "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": 2, 
+   "fieldname": "invoice_portion", 
+   "fieldtype": "Percent", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Invoice Portion", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "", 
+   "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": 2, 
+   "fieldname": "due_date_based_on", 
+   "fieldtype": "Select", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Due Date Based On", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Day(s) after invoice date\nDay(s) after the end of the invoice month\nMonth(s) after the end of the invoice 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": 2, 
+   "depends_on": "eval:in_list(['Day(s) after invoice date', 'Day(s) after the end of the invoice month'], doc.due_date_based_on)", 
+   "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": 1, 
+   "in_standard_filter": 0, 
+   "label": "Credit Days", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "", 
+   "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.due_date_based_on=='Month(s) after the end of the invoice month'", 
+   "fieldname": "credit_months", 
+   "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 Months", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }
+ ], 
+ "has_web_view": 0, 
+ "hide_heading": 0, 
+ "hide_toolbar": 0, 
+ "idx": 0, 
+ "image_view": 0, 
+ "in_create": 0, 
+ "is_submittable": 0, 
+ "issingle": 0, 
+ "istable": 1, 
+ "max_attachments": 0, 
+ "modified": "2017-08-10 16:27:31.401380", 
+ "modified_by": "Administrator", 
+ "module": "Accounts", 
+ "name": "Payment Terms Template Detail", 
+ "name_case": "", 
+ "owner": "Administrator", 
+ "permissions": [], 
+ "quick_entry": 1, 
+ "read_only": 0, 
+ "read_only_onload": 0, 
+ "show_name_in_global_search": 0, 
+ "sort_field": "modified", 
+ "sort_order": "DESC", 
+ "track_changes": 1, 
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/payment_terms_template_detail/payment_terms_template_detail.py b/erpnext/accounts/doctype/payment_terms_template_detail/payment_terms_template_detail.py
new file mode 100644
index 0000000..54c0fda
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_terms_template_detail/payment_terms_template_detail.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from frappe.model.document import Document
+
+
+class PaymentTermsTemplateDetail(Document):
+	pass
diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
index 82a3d65..9ec69c3 100644
--- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
@@ -252,6 +252,7 @@
 		self.assertEquals(so.items[0].rate, 100)
 
 	def test_pricing_rule_with_margin_and_discount(self):
+		frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
 		make_pricing_rule(selling=1, margin_type="Percentage", margin_rate_or_amount=10)
 		si = create_sales_invoice(do_not_save=True)
 		si.items[0].price_list_rate = 1000
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index b9a7dae..e81dea2 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -377,5 +377,5 @@
 			erpnext.buying.get_default_bom(frm);
 		}
 		frm.toggle_reqd("supplier_warehouse", frm.doc.is_subcontracted==="Yes");
-	},
+	}
 })
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index 748c24d..066809e 100755
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -2731,6 +2731,98 @@
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 1, 
+   "columns": 0, 
+   "fieldname": "payment_schedule_section", 
+   "fieldtype": "Section Break", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Payment Terms Schedule", 
+   "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, 
+   "fieldname": "payment_terms_template", 
+   "fieldtype": "Link", 
+   "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": "Payment Terms Template", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Payment Terms Template", 
+   "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, 
+   "fieldname": "payment_schedule", 
+   "fieldtype": "Table", 
+   "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": "Payment Schedule", 
+   "length": 0, 
+   "no_copy": 1, 
+   "options": "Payment Schedule", 
+   "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": 1, 
    "collapsible_depends_on": "terms", 
    "columns": 0, 
    "fieldname": "terms_section_break", 
@@ -3858,7 +3950,7 @@
  "istable": 0, 
  "max_attachments": 0, 
  "menu_index": 0, 
- "modified": "2017-08-31 11:22:47.074420", 
+ "modified": "2017-08-31 11:22:47.074420",
  "modified_by": "Administrator", 
  "module": "Accounts", 
  "name": "Purchase Invoice", 
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index be388aa..180ad89 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -92,7 +92,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.company)
+			self.due_date = get_due_date(self.posting_date, "Supplier", self.supplier)
 
 		super(PurchaseInvoice, self).set_missing_values(for_validate)
 
@@ -357,7 +357,27 @@
 		return gl_entries
 
 	def make_supplier_gl_entry(self, gl_entries):
-		if self.grand_total:
+		if self.get("payment_schedule"):
+			for d in self.get("payment_schedule"):
+				payment_amount_in_company_currency = flt(d.payment_amount * self.conversion_rate,
+					d.precision("payment_amount"))
+
+				gl_entries.append(
+					self.get_gl_dict({
+						"account": self.credit_to,
+						"party_type": "Supplier",
+						"party": self.supplier,
+						"due_date": d.due_date,
+						"against": self.against_expense_account,
+						"credit": payment_amount_in_company_currency,
+						"credit_in_account_currency": payment_amount_in_company_currency \
+							if self.party_account_currency==self.company_currency else d.payment_amount,
+						"against_voucher": self.return_against if cint(self.is_return) else self.name,
+						"against_voucher_type": self.doctype
+					}, self.party_account_currency)
+				)
+
+		elif self.grand_total:
 			# Didnot use base_grand_total to book rounding loss gle
 			grand_total_in_company_currency = flt(self.grand_total * self.conversion_rate,
 				self.precision("grand_total"))
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index 639620f..59e64aa 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -6,15 +6,16 @@
 import unittest
 import frappe, erpnext
 import frappe.model
-from frappe.utils import cint, flt, today, nowdate
+from frappe.utils import cint, flt, today, nowdate, getdate, add_days
 import frappe.defaults
 from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory, \
 	test_records as pr_test_records
+from erpnext.controllers.accounts_controller import get_payment_terms
 from erpnext.exceptions import InvalidCurrency
 from erpnext.stock.doctype.stock_entry.test_stock_entry import get_qty_after_transaction
 from erpnext.accounts.doctype.account.test_account import get_inventory_account
 
-test_dependencies = ["Item", "Cost Center"]
+test_dependencies = ["Item", "Cost Center", "Payment Term", "Payment Terms Template"]
 test_ignore = ["Serial No"]
 
 class TestPurchaseInvoice(unittest.TestCase):
@@ -61,6 +62,12 @@
 
 		set_perpetual_inventory(0, pi.company)
 
+	def test_terms_added_after_save(self):
+		pi = frappe.copy_doc(test_records[1])
+		pi.insert()
+		self.assertTrue(pi.payment_schedule)
+		self.assertEqual(pi.payment_schedule[0].due_date, pi.due_date)
+
 	def test_payment_entry_unlink_against_purchase_invoice(self):
 		from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
 		unlink_payment_on_cancel_of_invoice(0)
@@ -256,6 +263,55 @@
 		self.assertFalse(frappe.db.sql("""select name from `tabJournal Entry Account`
 			where reference_type='Purchase Invoice' and reference_name=%s""", pi.name))
 
+	def test_invoice_with_advance_and_multi_payment_terms(self):
+		from erpnext.accounts.doctype.journal_entry.test_journal_entry \
+			import test_records as jv_test_records
+
+		jv = frappe.copy_doc(jv_test_records[1])
+		jv.insert()
+		jv.submit()
+
+		pi = frappe.copy_doc(test_records[0])
+
+		pi.append("advances", {
+			"reference_type": "Journal Entry",
+			"reference_name": jv.name,
+			"reference_row": jv.get("accounts")[0].name,
+			"advance_amount": 400,
+			"allocated_amount": 300,
+			"remarks": jv.remark
+		})
+		pi.insert()
+
+		pi.update(
+			{"payment_schedule": get_payment_terms("_Test Payment Term Template", pi.posting_date, pi.grand_total)}
+		)
+
+		pi.save()
+		pi.submit()
+		self.assertEqual(pi.payment_schedule[0].payment_amount, 756.15)
+		self.assertEqual(pi.payment_schedule[0].due_date, pi.posting_date)
+		self.assertEqual(pi.payment_schedule[1].payment_amount, 756.15)
+		self.assertEqual(pi.payment_schedule[1].due_date, add_days(pi.posting_date, 30))
+
+		pi.load_from_db()
+
+		self.assertTrue(
+			frappe.db.sql(
+				"select name from `tabJournal Entry Account` where reference_type='Purchase Invoice' and "
+				"reference_name=%s and debit_in_account_currency=300", pi.name)
+		)
+
+		self.assertEqual(pi.outstanding_amount, 1212.30)
+
+		pi.cancel()
+
+		self.assertFalse(
+			frappe.db.sql(
+				"select name from `tabJournal Entry Account` where reference_type='Purchase Invoice' and "
+				"reference_name=%s", pi.name)
+		)
+
 	def test_total_purchase_cost_for_project(self):
 		existing_purchase_cost = frappe.db.sql("""select sum(base_net_amount)
 			from `tabPurchase Invoice Item` where project = '_Test Project' and docstatus=1""")
@@ -547,6 +603,38 @@
 		#check outstanding after advance cancellation
 		self.assertEqual(flt(pi.outstanding_amount), flt(pi.grand_total + pi.total_advance))
 
+	def test_gl_entry_based_on_payment_schedule(self):
+		pi = make_purchase_invoice(do_not_save=True, supplier="_Test Supplier P")
+		pi.append("payment_schedule", {
+			"due_date": add_days(nowdate(), 15),
+			"payment_amount": 100
+		})
+		pi.append("payment_schedule", {
+			"due_date": add_days(nowdate(), 45),
+			"payment_amount": 150
+		})
+
+		pi.save()
+		pi.submit()
+
+		gl_entries = frappe.db.sql("""select account, debit, credit, due_date
+			from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
+			order by account asc, debit asc""", pi.name, as_dict=1)
+		self.assertTrue(gl_entries)
+
+		expected_gl_entries = sorted([
+			[pi.credit_to, 0.0, 100.0, add_days(nowdate(), 15)],
+			[pi.credit_to, 0.0, 150.0, add_days(nowdate(), 45)],
+			["_Test Account Cost for Goods Sold - _TC", 250.0, 0.0, None]
+		])
+
+		for i, gle in enumerate(sorted(gl_entries, key=lambda gle: gle.account)):
+			self.assertEquals(expected_gl_entries[i][0], gle.account)
+			self.assertEquals(expected_gl_entries[i][1], gle.debit)
+			self.assertEquals(expected_gl_entries[i][2], gle.credit)
+			self.assertEquals(getdate(expected_gl_entries[i][3]), getdate(gle.due_date))
+
+
 def unlink_payment_on_cancel_of_invoice(enable=1):
 	accounts_settings = frappe.get_doc("Accounts Settings")
 	accounts_settings.unlink_payment_on_cancellation_of_invoice = enable
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 11d1825..c7258a4 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -568,3 +568,4 @@
 
 	refresh_field('total_billing_amount')
 }
+
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index 2bb0044..f1ba18c 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -2689,6 +2689,101 @@
    "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
+   "collapsible": 1, 
+   "collapsible_depends_on": "eval:(!doc.is_pos && !doc.is_return)", 
+   "columns": 0, 
+   "fieldname": "payment_schedule_section", 
+   "fieldtype": "Section Break", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Payment Schedule", 
+   "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.is_pos && !doc.is_return)", 
+   "fieldname": "payment_terms_template", 
+   "fieldtype": "Link", 
+   "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": "Payment Terms Template", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Payment Terms Template", 
+   "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.is_pos && !doc.is_return)", 
+   "fieldname": "payment_schedule", 
+   "fieldtype": "Table", 
+   "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": "Payment Schedule", 
+   "length": 0, 
+   "no_copy": 1, 
+   "options": "Payment Schedule", 
+   "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, 
    "collapsible_depends_on": "", 
    "columns": 0, 
@@ -2939,6 +3034,7 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
+   "depends_on": "is_pos", 
    "fieldname": "base_change_amount", 
    "fieldtype": "Currency", 
    "hidden": 0, 
@@ -2999,6 +3095,7 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
+   "depends_on": "is_pos", 
    "fieldname": "change_amount", 
    "fieldtype": "Currency", 
    "hidden": 0, 
@@ -3030,6 +3127,7 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
+   "depends_on": "is_pos", 
    "fieldname": "account_for_change_amount", 
    "fieldtype": "Link", 
    "hidden": 0, 
@@ -4748,8 +4846,8 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "menu_index": 0, 
- "modified": "2017-08-31 11:23:08.675028", 
+ "menu_index": 0,
+ "modified": "2017-08-31 11:23:08.675028",
  "modified_by": "Administrator", 
  "module": "Accounts", 
  "name": "Sales Invoice", 
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 065fb94..3f8a1fb 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -241,7 +241,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.company)
+			self.due_date = get_due_date(self.posting_date, "Customer", self.customer)
 
 		super(SalesInvoice, self).set_missing_values(for_validate)
 
@@ -629,7 +629,27 @@
 		return gl_entries
 
 	def make_customer_gl_entry(self, gl_entries):
-		if self.grand_total:
+		if self.get("payment_schedule"):
+			for d in self.get("payment_schedule"):
+				payment_amount_in_company_currency = flt(d.payment_amount * self.conversion_rate,
+					d.precision("payment_amount"))
+
+				gl_entries.append(
+					self.get_gl_dict({
+						"account": self.debit_to,
+						"party_type": "Customer",
+						"party": self.customer,
+						"due_date": d.due_date,
+						"against": self.against_income_account,
+						"debit": payment_amount_in_company_currency,
+						"debit_in_account_currency": payment_amount_in_company_currency \
+							if self.party_account_currency==self.company_currency else d.payment_amount,
+						"against_voucher": self.return_against if cint(self.is_return) else self.name,
+						"against_voucher_type": self.doctype
+					}, self.party_account_currency)
+				)
+
+		elif self.grand_total:
 			# Didnot use base_grand_total to book rounding loss gle
 			grand_total_in_company_currency = flt(self.grand_total * self.conversion_rate,
 				self.precision("grand_total"))
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.js
index 35b2558..f7a4488 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.js
@@ -40,4 +40,3 @@
 		() => done()
 	]);
 });
-
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index db29563..44cc8d7 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -4,7 +4,7 @@
 
 import frappe
 import unittest, copy
-from frappe.utils import nowdate, add_days, flt
+from frappe.utils import nowdate, add_days, flt, getdate
 from frappe.model.dynamic_links import get_dynamic_link_map
 from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, get_qty_after_transaction
 from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import unlink_payment_on_cancel_of_invoice
@@ -58,6 +58,13 @@
 
 		self.assertRaises(frappe.CannotChangeConstantError, si.save)
 
+	def test_add_terms_after_save(self):
+		si = frappe.copy_doc(test_records[2])
+		si.insert()
+
+		self.assertTrue(si.payment_schedule)
+		self.assertEqual(si.payment_schedule[0].due_date, si.due_date)
+
 	def test_sales_invoice_calculation_base_currency(self):
 		si = frappe.copy_doc(test_records[2])
 		si.insert()
@@ -886,20 +893,6 @@
 
 		self.assertEquals(si.get("items")[0].serial_no, dn.get("items")[0].serial_no)
 
-	def test_invoice_due_date_against_customers_credit_days(self):
-		# set customer's credit days
-		frappe.db.set_value("Customer", "_Test Customer", "credit_days_based_on", "Fixed Days")
-		frappe.db.set_value("Customer", "_Test Customer", "credit_days", 10)
-
-		si = create_sales_invoice()
-		self.assertEqual(si.due_date, add_days(nowdate(), 10))
-
-		# set customer's credit days is last day of the next month
-		frappe.db.set_value("Customer", "_Test Customer", "credit_days_based_on", "Last Day of the Next Month")
-
-		si1 = create_sales_invoice(posting_date="2015-07-05")
-		self.assertEqual(si1.due_date, "2015-08-31")
-
 	def test_return_sales_invoice(self):
 		set_perpetual_inventory()
 		make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, basic_rate=100)
@@ -1274,6 +1267,38 @@
 		})
 		si.insert()
 		return si
+	
+	def test_gl_entry_based_on_payment_schedule(self):
+		si = create_sales_invoice(do_not_save=True, customer="_Test Customer P")
+		si.append("payment_schedule", {
+			"due_date": add_days(nowdate(), 15),
+			"payment_amount": 20
+		})
+		si.append("payment_schedule", {
+			"due_date": add_days(nowdate(), 45),
+			"payment_amount": 80
+		})
+		
+		si.save()
+		si.submit()
+		
+		gl_entries = frappe.db.sql("""select account, debit, credit, due_date
+			from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
+			order by account asc, debit asc""", si.name, as_dict=1)
+		self.assertTrue(gl_entries)
+
+		expected_gl_entries = sorted([
+			[si.debit_to, 20.0, 0.0, add_days(nowdate(), 15)],
+			[si.debit_to, 80.0, 0.0, add_days(nowdate(), 45)],
+			["Sales - _TC", 0.0, 100.0, None]
+		])
+
+		for i, gle in enumerate(sorted(gl_entries, key=lambda gle: gle.account)):
+			self.assertEquals(expected_gl_entries[i][0], gle.account)
+			self.assertEquals(expected_gl_entries[i][1], gle.debit)
+			self.assertEquals(expected_gl_entries[i][2], gle.credit)
+			self.assertEquals(getdate(expected_gl_entries[i][3]), getdate(gle.due_date))
+
 
 	def test_company_monthly_sales(self):
 		existing_current_month_sales = frappe.db.get_value("Company", "_Test Company", "total_monthly_sales")
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index ceae61c..45d2ef2 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -3,7 +3,7 @@
 
 from __future__ import unicode_literals
 import frappe, erpnext
-from frappe.utils import flt, cstr, cint
+from frappe.utils import flt, cstr, cint, getdate
 from frappe import _
 from frappe.model.meta import get_field_precision
 from erpnext.accounts.doctype.budget.budget import validate_expense_against_budget
@@ -75,7 +75,8 @@
 			and cstr(e.get('against_voucher'))==cstr(gle.get('against_voucher')) \
 			and cstr(e.get('against_voucher_type')) == cstr(gle.get('against_voucher_type')) \
 			and cstr(e.get('cost_center')) == cstr(gle.get('cost_center')) \
-			and cstr(e.get('project')) == cstr(gle.get('project')):
+			and cstr(e.get('project')) == cstr(gle.get('project')) \
+			and getdate(e.get('due_date')) == getdate(gle.get('due_date')):
 				return e
 
 def save_entries(gl_map, adv_adj, update_outstanding, from_repost=False):
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index ba7ae32..a1b737d 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -9,7 +9,7 @@
 from frappe.defaults import get_user_permissions
 from frappe.model.utils import get_fetch_values
 from frappe.utils import (add_days, getdate, formatdate, get_first_day, date_diff,
-	add_years, get_timestamp, nowdate, flt)
+                          add_years, get_timestamp, nowdate, flt, add_months, get_last_day)
 from frappe.contacts.doctype.address.address import (get_address_display,
 	get_default_address, get_company_address)
 from frappe.contacts.doctype.contact.contact import get_contact_details, get_default_contact
@@ -51,6 +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)
 
 	if not out.get("currency"):
 		out["currency"] = currency
@@ -161,7 +162,7 @@
 	out = {
 		party_type.lower(): party,
 		account_fieldname : account,
-		"due_date": get_due_date(posting_date, party_type, party, company)
+		"due_date": get_due_date(posting_date, party_type, party)
 	}
 	return out
 
@@ -258,51 +259,54 @@
 
 		if doc.get("default_currency") and party_account_currency and company_default_currency:
 			if doc.default_currency != party_account_currency and doc.default_currency != company_default_currency:
-				frappe.throw(_("Billing currency must be equal to either default comapany's currency or party account currency"))
+				frappe.throw(_("Billing currency must be equal to either default company's currency or party account currency"))
+
 
 @frappe.whitelist()
-def get_due_date(posting_date, party_type, party, company):
-	"""Set Due Date = Posting Date + Credit Days"""
+def get_due_date(posting_date, party_type, party):
+	"""Get due date from `Payment Terms Template`"""
 	due_date = None
 	if posting_date and party:
 		due_date = posting_date
-		credit_days_based_on, credit_days = get_credit_days(party_type, party, company)
-		if credit_days_based_on == "Fixed Days" and credit_days:
-			due_date = add_days(posting_date, credit_days)
-		elif credit_days_based_on == "Last Day of the Next Month":
-			due_date = (get_first_day(posting_date, 0, 2) + datetime.timedelta(-1)).strftime("%Y-%m-%d")
+		template_name = get_pyt_term_template(party, party_type)
+		if template_name:
+			due_date = get_due_date_from_template(template_name, posting_date).strftime("%Y-%m-%d")
+		else:
+			if party_type == "Supplier":
+				supplier_type = frappe.db.get_value(party_type, party, fieldname="supplier_type")
+				template_name = frappe.db.get_value("Supplier Type", supplier_type, fieldname="payment_terms")
+				if template_name:
+					due_date = get_due_date_from_template(template_name, posting_date).strftime("%Y-%m-%d")
 
 	return due_date
 
-def get_credit_days(party_type, party, company):
-	credit_days = 0
-	if party_type and party:
-		if party_type == "Customer":
-			credit_days_based_on, credit_days, customer_group = \
-				frappe.db.get_value(party_type, party, ["credit_days_based_on", "credit_days", "customer_group"])
+
+def get_due_date_from_template(template_name, posting_date):
+	"""
+	Inspects all `Payment Term`s from the a `Payment Terms Template` and returns the due
+	date after considering all the `Payment Term`s requirements.
+	:param template_name: Name of the `Payment Terms Template`
+	:return: String representing the calculated due date
+	"""
+	due_date = getdate(posting_date)
+	template = frappe.get_doc('Payment Terms Template', template_name)
+
+	for term in template.terms:
+		if term.due_date_based_on == 'Day(s) after invoice date':
+			due_date = max(due_date, add_days(due_date, term.credit_days))
+		elif term.due_date_based_on == 'Day(s) after the end of the invoice month':
+			due_date = max(due_date, add_days(get_last_day(due_date), term.credit_days))
 		else:
-			credit_days_based_on, credit_days, supplier_type = \
-				frappe.db.get_value(party_type, party, ["credit_days_based_on", "credit_days", "supplier_type"])
+			due_date = max(due_date, add_months(get_last_day(due_date), term.credit_months))
 
-	if not credit_days_based_on:
-		if party_type == "Customer" and customer_group:
-			credit_days_based_on, credit_days = \
-				frappe.db.get_value("Customer Group", customer_group, ["credit_days_based_on", "credit_days"])
-		elif party_type == "Supplier" and supplier_type:
-			credit_days_based_on, credit_days = \
-				frappe.db.get_value("Supplier Type", supplier_type, ["credit_days_based_on", "credit_days"])
+	return due_date
 
-	if not credit_days_based_on:
-		credit_days_based_on, credit_days = \
-			frappe.db.get_value("Company", company, ["credit_days_based_on", "credit_days"])
 
-	return credit_days_based_on, credit_days
-
-def validate_due_date(posting_date, due_date, party_type, party, company):
+def validate_due_date(posting_date, due_date, party_type, party):
 	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, company)
+		default_due_date = get_due_date(posting_date, party_type, party)
 		if not default_due_date:
 			return
 
@@ -345,6 +349,16 @@
 
 	return get_tax_template(posting_date, args)
 
+
+@frappe.whitelist()
+def get_pyt_term_template(party_name, party_type):
+	template = None
+	if party_type in ('Customer', 'Supplier'):
+		template = frappe.db.get_value(party_type, party_name, 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.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 9906893..b72a669 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -113,7 +113,7 @@
 						row += [self.get_party_name(gle.party_type, gle.party)]
 
 					# get due date
-					due_date = voucher_details.get(gle.voucher_no, {}).get("due_date", "")
+					due_date = gle.due_date or voucher_details.get(gle.voucher_no, {}).get("due_date", "")
 
 					row += [gle.voucher_type, gle.voucher_no, due_date]
 
@@ -162,8 +162,7 @@
 
 	def get_entries_till(self, report_date, party_type):
 		# returns a generator
-		return (e for e in self.get_gl_entries(party_type)
-			if getdate(e.posting_date) <= report_date)
+		return (e for e in self.get_gl_entries(party_type) if getdate(e.posting_date) <= report_date)
 
 	def is_receivable_or_payable(self, gle, dr_or_cr, future_vouchers):
 		return (
@@ -189,7 +188,8 @@
 		reverse_dr_or_cr = "credit" if dr_or_cr=="debit" else "debit"
 		
 		for e in self.get_gl_entries_for(gle.party, gle.party_type, gle.voucher_type, gle.voucher_no):
-			if getdate(e.posting_date) <= report_date and e.name!=gle.name:
+			if getdate(e.posting_date) <= report_date and e.name!=gle.name \
+				and (not gle.due_date or getdate(e.due_date) == getdate(gle.due_date)):
 				amount = flt(e.get(reverse_dr_or_cr)) - flt(e.get(dr_or_cr))
 				if e.voucher_no not in return_entries:
 					payment_amount += amount
@@ -251,11 +251,11 @@
 				select_fields = "sum(debit) as debit, sum(credit) as credit"
 
 			self.gl_entries = frappe.db.sql("""select name, posting_date, account, party_type, party, 
-				voucher_type, voucher_no, against_voucher_type, against_voucher, 
+				voucher_type, voucher_no, against_voucher_type, against_voucher, due_date,
 				account_currency, remarks, {0}
 				from `tabGL Entry`
 				where docstatus < 2 and party_type=%s and (party is not null and party != '') {1}
-				group by voucher_type, voucher_no, against_voucher_type, against_voucher, party
+				group by voucher_type, voucher_no, against_voucher_type, against_voucher, party, due_date
 				order by posting_date, party"""
 				.format(select_fields, conditions), values, as_dict=True)
 
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 50530f5..6d6aced 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -583,7 +583,7 @@
 	invoice = 'Sales Invoice' if party_type == 'Customer' else 'Purchase Invoice'
 	invoice_list = frappe.db.sql("""
 		select
-			voucher_no,	voucher_type, posting_date, ifnull(sum({dr_or_cr}), 0) as invoice_amount,
+			voucher_no,	voucher_type, posting_date, ifnull(sum({dr_or_cr}), 0) as invoice_amount, due_date,
 			(
 				case when (voucher_type = 'Sales Invoice' or voucher_type = 'Purchase Invoice')
 					then (select due_date from `tab{invoice}` where name = voucher_no)
@@ -597,6 +597,7 @@
 					and payment_gl_entry.party_type = invoice_gl_entry.party_type
 					and payment_gl_entry.party = invoice_gl_entry.party
 					and payment_gl_entry.account = invoice_gl_entry.account
+					and payment_gl_entry.due_date = invoice_gl_entry.due_date
 					and {payment_dr_or_cr} > 0
 			) as payment_amount
 		from
@@ -608,9 +609,9 @@
 			and ((voucher_type = 'Journal Entry'
 					and (against_voucher = '' or against_voucher is null))
 				or (voucher_type not in ('Journal Entry', 'Payment Entry')))
-		group by voucher_type, voucher_no
+		group by voucher_type, voucher_no, due_date
 		having (invoice_amount - payment_amount) > 0.005
-		order by posting_date, name""".format(
+		order by posting_date, name, due_date""".format(
 			dr_or_cr = dr_or_cr,
 			invoice = invoice,
 			payment_dr_or_cr = payment_dr_or_cr,
@@ -622,6 +623,8 @@
 		}, as_dict=True)
 
 	for d in invoice_list:
+		due_date = d.due_date or (frappe.db.get_value(d.voucher_type, d.voucher_no,
+			"posting_date" if party_type=="Employee" else "due_date"))
 		outstanding_invoices.append(frappe._dict({
 			'voucher_no': d.voucher_no,
 			'voucher_type': d.voucher_type,
@@ -630,8 +633,7 @@
 			'invoice_amount': flt(d.invoice_amount),
 			'payment_amount': flt(d.payment_amount),
 			'outstanding_amount': flt(d.invoice_amount - d.payment_amount, precision),
-			'due_date': frappe.db.get_value(d.voucher_type, d.voucher_no, 
-				"posting_date" if party_type=="Employee" else "due_date"),
+			'due_date': due_date
 		}))
 
 	outstanding_invoices = sorted(outstanding_invoices, key=lambda k: k['due_date'] or getdate(nowdate()))
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index c4096cc..1e91ffa 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -2293,6 +2293,98 @@
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 1, 
+   "columns": 0, 
+   "fieldname": "payment_schedule_section", 
+   "fieldtype": "Section Break", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Payment Terms Schedule", 
+   "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, 
+   "fieldname": "payment_terms_template", 
+   "fieldtype": "Link", 
+   "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": "Payment Terms Template", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Payment Terms Template", 
+   "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, 
+   "fieldname": "payment_schedule", 
+   "fieldtype": "Table", 
+   "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": "Payment Schedule", 
+   "length": 0, 
+   "no_copy": 1, 
+   "options": "Payment Schedule", 
+   "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": 1, 
    "collapsible_depends_on": "terms", 
    "columns": 0, 
    "fieldname": "terms_section_break", 
@@ -3395,8 +3487,8 @@
  "is_submittable": 1, 
  "issingle": 0, 
  "istable": 0, 
- "max_attachments": 0, 
- "modified": "2017-08-31 11:22:30.190589", 
+ "max_attachments": 0,
+ "modified": "2017-08-31 11:22:30.190589",
  "modified_by": "Administrator", 
  "module": "Buying", 
  "name": "Purchase Order", 
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 17786aa..44279d5 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -5,8 +5,9 @@
 import unittest
 import frappe
 import frappe.defaults
-from frappe.utils import flt, add_days, nowdate
+from frappe.utils import flt, add_days, nowdate, DATE_FORMAT
 from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt, make_purchase_invoice
+from erpnext.controllers.accounts_controller import get_payment_terms
 
 class TestPurchaseOrder(unittest.TestCase):
 	def test_make_purchase_receipt(self):
@@ -83,6 +84,33 @@
 		self.assertEquals(pi.doctype, "Purchase Invoice")
 		self.assertEquals(len(pi.get("items", [])), 1)
 
+	def test_make_purchase_invoice_with_terms(self):
+		po = create_purchase_order(do_not_save=True)
+
+		self.assertRaises(frappe.ValidationError, make_purchase_invoice, po.name)
+
+		po.update(
+			{"payment_terms_template": "_Test Payment Term Template"}
+		)
+
+		po.save()
+		po.submit()
+
+		self.assertEqual(po.payment_schedule[0].payment_amount, 2500.0)
+		self.assertEqual(po.payment_schedule[0].due_date, po.transaction_date)
+		self.assertEqual(po.payment_schedule[1].payment_amount, 2500.0)
+		self.assertEqual(po.payment_schedule[1].due_date, add_days(po.transaction_date, 30))
+		pi = make_purchase_invoice(po.name)
+		pi.save()
+
+		self.assertEquals(pi.doctype, "Purchase Invoice")
+		self.assertEquals(len(pi.get("items", [])), 1)
+
+		self.assertEqual(pi.payment_schedule[0].payment_amount, 2500.0)
+		self.assertEqual(pi.payment_schedule[0].due_date, po.transaction_date)
+		self.assertEqual(pi.payment_schedule[1].payment_amount, 2500.0)
+		self.assertEqual(pi.payment_schedule[1].due_date, add_days(po.transaction_date, 30))
+
 	def test_subcontracting(self):
 		po = create_purchase_order(item_code="_Test FG Item", is_subcontracted="Yes")
 		self.assertEquals(len(po.get("supplied_items")), 2)
diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json
index 711e05d..e6cea53 100644
--- a/erpnext/buying/doctype/supplier/supplier.json
+++ b/erpnext/buying/doctype/supplier/supplier.json
@@ -597,8 +597,9 @@
    "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, 
@@ -606,10 +607,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, 
@@ -628,36 +629,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": 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": "address_contacts", 
    "fieldtype": "Section Break", 
@@ -970,8 +941,8 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2017-07-06 16:40:46.935608", 
- "modified_by": "Administrator", 
+ "modified": "2017-08-31 16:10:44.049915", 
+ "modified_by": "tundebabzy@gmail.com", 
  "module": "Buying", 
  "name": "Supplier", 
  "name_case": "Title Case", 
diff --git a/erpnext/buying/doctype/supplier/test_records.json b/erpnext/buying/doctype/supplier/test_records.json
index d2b3995..1c78807 100644
--- a/erpnext/buying/doctype/supplier/test_records.json
+++ b/erpnext/buying/doctype/supplier/test_records.json
@@ -1,6 +1,18 @@
 [
  {
   "doctype": "Supplier",
+  "supplier_name": "_Test Supplier With Template 1",
+  "supplier_type": "_Test Supplier Type",
+  "payment_terms": "_Test Payment Term Template 3"
+ },
+ {
+  "doctype": "Supplier",
+  "supplier_name": "_Test Supplier P",
+  "supplier_type": "_Test Supplier Type",
+  "credit_days_based_on": "Fixed Days"
+ },
+ {
+  "doctype": "Supplier",
   "supplier_name": "_Test Supplier with Country",
   "supplier_type": "_Test Supplier Type",
   "country": "Greece"
diff --git a/erpnext/buying/doctype/supplier/test_supplier.py b/erpnext/buying/doctype/supplier/test_supplier.py
index 1d089e7..16dda5c 100644
--- a/erpnext/buying/doctype/supplier/test_supplier.py
+++ b/erpnext/buying/doctype/supplier/test_supplier.py
@@ -5,56 +5,62 @@
 
 import frappe, unittest
 from erpnext.accounts.party import get_due_date
-from erpnext.exceptions import PartyFrozen, PartyDisabled
+from erpnext.exceptions import PartyDisabled
 from frappe.test_runner import make_test_records
 
+test_dependencies = ['Payment Term', 'Payment Terms Template']
 test_records = frappe.get_test_records('Supplier')
 
+
 class TestSupplier(unittest.TestCase):
-    def test_supplier_due_date_against_supplier_credit_limit(self):
-        # Set Credit Limit based on Fixed days
-        frappe.db.set_value("Supplier", "_Test Supplier", "credit_days_based_on", "Fixed Days")
-        frappe.db.set_value("Supplier", "_Test Supplier", "credit_days", 10)
+    def test_supplier_default_payment_terms(self):
+        # Payment Term based on Days after invoice date
+        frappe.db.set_value(
+            "Supplier", "_Test Supplier With Template 1", "payment_terms", "_Test Payment Term Template 3")
 
-        due_date = get_due_date("2016-01-22", "Supplier", "_Test Supplier", "_Test Company")
-        self.assertEqual(due_date, "2016-02-01")
+        due_date = get_due_date("2016-01-22", "Supplier", "_Test Supplier With Template 1")
+        self.assertEqual(due_date, "2016-02-21")
 
-        # Set Credit Limit based on Last day next month
-        frappe.db.set_value("Supplier", "_Test Supplier", "credit_days", 0)
-        frappe.db.set_value("Supplier", "_Test Supplier", "credit_days_based_on",
-                            "Last Day of the Next Month")
+        due_date = get_due_date("2017-01-22", "Supplier", "_Test Supplier With Template 1")
+        self.assertEqual(due_date, "2017-02-21")
 
-        # Leap year
-        due_date = get_due_date("2016-01-22", "Supplier", "_Test Supplier", "_Test Company")
+        # Payment Term based on last day of month
+        frappe.db.set_value(
+            "Supplier", "_Test Supplier With Template 1", "payment_terms", "_Test Payment Term Template 1")
+
+        due_date = get_due_date("2016-01-22", "Supplier", "_Test Supplier With Template 1")
         self.assertEqual(due_date, "2016-02-29")
-        # Non Leap year
-        due_date = get_due_date("2017-01-22", "Supplier", "_Test Supplier", "_Test Company")
+
+        due_date = get_due_date("2017-01-22", "Supplier", "_Test Supplier With Template 1")
         self.assertEqual(due_date, "2017-02-28")
 
-        frappe.db.set_value("Supplier", "_Test Supplier", "credit_days_based_on", "")
+        frappe.db.set_value("Supplier", "_Test Supplier With Template 1", "payment_terms", "")
 
         # Set credit limit for the supplier type instead of supplier and evaluate the due date
-        # based on Fixed days
-        frappe.db.set_value("Supplier Type", "_Test Supplier Type", "credit_days_based_on",
-                            "Fixed Days")
-        frappe.db.set_value("Supplier Type", "_Test Supplier Type", "credit_days", 10)
+        frappe.db.set_value("Supplier Type", "_Test Supplier Type", "payment_terms", "_Test Payment Term Template 3")
 
-        due_date = get_due_date("2016-01-22", "Supplier", "_Test Supplier", "_Test Company")
-        self.assertEqual(due_date, "2016-02-01")
+        due_date = get_due_date("2016-01-22", "Supplier", "_Test Supplier With Template 1")
+        self.assertEqual(due_date, "2016-02-21")
 
-        # Set credit limit for the supplier type instead of supplier and evaluate the due date
-        # based on Last day of next month
-        frappe.db.set_value("Supplier", "_Test Supplier Type", "credit_days", 0)
-        frappe.db.set_value("Supplier Type", "_Test Supplier Type", "credit_days_based_on",
-                            "Last Day of the Next Month")
+        # Payment terms for Supplier Type instead of supplier and evaluate the due date
+        frappe.db.set_value("Supplier Type", "_Test Supplier Type", "payment_terms", "_Test Payment Term Template 1")
 
         # Leap year
-        due_date = get_due_date("2016-01-22", "Supplier", "_Test Supplier", "_Test Company")
+        due_date = get_due_date("2016-01-22", "Supplier", "_Test Supplier With Template 1")
         self.assertEqual(due_date, "2016-02-29")
-        # Non Leap year
-        due_date = get_due_date("2017-01-22", "Supplier", "_Test Supplier", "_Test Company")
+        # # Non Leap year
+        due_date = get_due_date("2017-01-22", "Supplier", "_Test Supplier With Template 1")
         self.assertEqual(due_date, "2017-02-28")
 
+        # Supplier with no default Payment Terms Template
+        frappe.db.set_value("Supplier Type", "_Test Supplier Type", "payment_terms", "")
+        frappe.db.set_value("Supplier", "_Test Supplier", "payment_terms", "")
+
+        due_date = get_due_date("2016-01-22", "Supplier", "_Test Supplier")
+        self.assertEqual(due_date, "2016-01-22")
+        # # Non Leap year
+        due_date = get_due_date("2017-01-22", "Supplier", "_Test Supplier")
+        self.assertEqual(due_date, "2017-01-22")
 
     def test_supplier_disabled(self):
         make_test_records("Item")
@@ -71,7 +77,6 @@
 
         po.save()
 
-
     def test_supplier_country(self):
         # Test that country field exists in Supplier DocType
         supplier = frappe.get_doc('Supplier', '_Test Supplier with Country')
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index d04143d..3464093 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -4,7 +4,7 @@
 from __future__ import unicode_literals
 import frappe, erpnext
 from frappe import _, throw
-from frappe.utils import today, flt, cint, fmt_money, formatdate, getdate
+from frappe.utils import today, flt, cint, fmt_money, formatdate, getdate, add_days, add_months, get_last_day
 from erpnext.setup.utils import get_exchange_rate
 from erpnext.accounts.utils import get_fiscal_years, validate_fiscal_year, get_account_currency
 from erpnext.utilities.transaction_base import TransactionBase
@@ -27,6 +27,9 @@
 
 	def onload(self):
 		self.get("__onload").make_payment_via_journal_entry = frappe.db.get_single_value('Accounts Settings', 'make_payment_via_journal_entry')
+		relevant_docs = ("Quotation", "Purchase Order", "Sales Order", "Purchase Invoice", "Purchase Order")
+		if self.doctype in relevant_docs:
+			self.set_payment_schedule()
 
 	def validate(self):
 		if self.get("_action") and self._action != "update_after_submit":
@@ -43,8 +46,16 @@
 			self.set_total_in_words()
 
 		if self.doctype in ("Sales Invoice", "Purchase Invoice") and not self.is_return:
+			if self.get("payment_schedule"):
+				self.set_due_date()
+				self.validate_payment_schedule()
+			else:
+				self.set_payment_schedule()
+				self.set_due_date()
 			self.validate_due_date()
 			self.validate_advance_entries()
+		elif self.doctype in ("Quotation", "Purchase Order", "Sales Order"):
+			self.set_payment_schedule()
 
 		if self.meta.get_field("taxes_and_charges"):
 			self.validate_enabled_taxes_and_charges()
@@ -109,9 +120,9 @@
 			if not self.due_date:
 				frappe.throw(_("Due Date is mandatory"))
 
-			validate_due_date(self.posting_date, self.due_date, "Customer", self.customer, self.company)
+			validate_due_date(self.posting_date, self.due_date, "Customer", self.customer)
 		elif self.doctype == "Purchase Invoice":
-			validate_due_date(self.posting_date, self.due_date, "Supplier", self.supplier, self.company)
+			validate_due_date(self.posting_date, self.due_date, "Supplier", self.supplier)
 
 	def set_price_list_currency(self, buying_or_selling):
 		if self.meta.get_field("posting_date"):
@@ -601,6 +612,42 @@
 		for item in duplicate_list:
 			self.remove(item)
 
+	def set_payment_schedule(self):
+		posting_date = self.get("posting_date") or self.get("transaction_date")
+		date = self.get("due_date")
+		due_date = date or posting_date
+
+		if self.get("payment_terms_template") and not self.get("payment_schedule"):
+			data = get_payment_terms(self.payment_terms_template, posting_date, self.grand_total)
+			for item in data:
+				self.append("payment_schedule", item)
+		elif not self.get("payment_schedule"):
+			data = dict(due_date=due_date, invoice_portion=100, payment_amount=self.grand_total)
+			self.append("payment_schedule", data)
+
+	def set_due_date(self):
+		self.due_date = max([d.due_date for d in self.get("payment_schedule")])
+
+	def validate_payment_schedule(self):
+		if self.due_date and getdate(self.due_date) < getdate(self.posting_date):
+			frappe.throw(_("Due Date cannot be before posting date"))
+
+		total = 0
+		for d in self.get("payment_schedule"):
+			if getdate(d.due_date) < getdate(self.posting_date):
+				frappe.throw(_("Row {0}: Due Date cannot be before posting date").format(d.idx))
+
+			total += flt(d.payment_amount)
+
+		if total != self.grand_total:
+			# Try to recover if the Payment Term is a very simple one.
+			# If there is just one Payment Term and the invoice portion is 100:
+			if len(self.payment_schedule) == 1 and self.payment_schedule[0].invoice_portion == 100:
+				self.payment_schedule[0].update({'payment_amount': self.grand_total})
+			else:
+				frappe.throw(_("Total Payment Amount in Payment Schedule must be equal to Grand Total"))
+
+
 @frappe.whitelist()
 def get_tax_rate(account_head):
 	return frappe.db.get_value("Account", account_head, ["tax_rate", "account_name"], as_dict=True)
@@ -769,4 +816,43 @@
 		where due_date < CURDATE() and docstatus = 1 and outstanding_amount > 0""")
 
 	frappe.db.sql(""" update `tabPurchase Invoice` set status = 'Overdue'
-		where due_date < CURDATE() and docstatus = 1 and outstanding_amount > 0""")
\ No newline at end of file
+		where due_date < CURDATE() and docstatus = 1 and outstanding_amount > 0""")
+
+@frappe.whitelist()
+def get_payment_terms(terms_template, posting_date=None, grand_total=None):
+	if not terms_template:
+		return
+
+	terms_doc = frappe.get_doc("Payment Terms Template", terms_template)
+
+	schedule = []
+	for d in terms_doc.get("terms"):
+		term_details = get_payment_term_details(d, posting_date, grand_total)
+		schedule.append(term_details)
+
+	return schedule
+
+@frappe.whitelist()
+def get_payment_term_details(term, posting_date=None, grand_total=None):
+	term_details = frappe._dict()
+	if isinstance(term, unicode):
+		term = frappe.get_doc("Payment Term", term)
+	else:
+		term_details.payment_term = term.payment_term
+	term_details.description = term.description
+	term_details.invoice_portion = term.invoice_portion
+	term_details.payment_amount = flt(term.invoice_portion) * flt(grand_total) / 100
+	if posting_date:
+		term_details.due_date = get_due_date(posting_date, term)
+	return term_details
+
+def get_due_date(posting_date, term):
+	due_date = None
+	if term.due_date_based_on == "Day(s) after invoice date":
+		due_date = add_days(posting_date, term.credit_days)
+	elif term.due_date_based_on == "Day(s) after the end of the invoice month":
+		due_date = add_days(get_last_day(posting_date), term.credit_days)
+	elif term.due_date_based_on == "Month(s) after the end of the invoice month":
+		due_date = add_months(get_last_day(posting_date), term.credit_months)
+
+	return due_date
diff --git a/erpnext/controllers/recurring_document.py b/erpnext/controllers/recurring_document.py
new file mode 100644
index 0000000..6919434
--- /dev/null
+++ b/erpnext/controllers/recurring_document.py
@@ -0,0 +1,233 @@
+from __future__ import unicode_literals
+import frappe
+import calendar
+import frappe.utils
+import frappe.defaults
+
+from frappe.utils import cint, cstr, getdate, nowdate, \
+	get_first_day, get_last_day, split_emails
+
+from frappe import _, msgprint, throw
+
+
+month_map = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6, 'Yearly': 12}
+date_field_map = {
+	"Sales Order": "transaction_date",
+	"Sales Invoice": "posting_date",
+	"Purchase Order": "transaction_date",
+	"Purchase Invoice": "posting_date"
+}
+
+def create_recurring_documents():
+	manage_recurring_documents("Sales Order")
+	manage_recurring_documents("Sales Invoice")
+	manage_recurring_documents("Purchase Order")
+	manage_recurring_documents("Purchase Invoice")
+
+def manage_recurring_documents(doctype, next_date=None, commit=True):
+	"""
+		Create recurring documents on specific date by copying the original one
+		and notify the concerned people
+	"""
+	next_date = next_date or nowdate()
+
+	date_field = date_field_map[doctype]
+
+	condition = " and ifnull(status, '') != 'Closed'" if doctype in ("Sales Order", "Purchase Order") else ""
+
+	recurring_documents = frappe.db.sql("""select name, recurring_id
+		from `tab{0}` where is_recurring=1
+		and (docstatus=1 or docstatus=0) and next_date=%s
+		and next_date <= ifnull(end_date, '2199-12-31') {1}""".format(doctype, condition), next_date)
+
+	exception_list = []
+	for ref_document, recurring_id in recurring_documents:
+		if not frappe.db.sql("""select name from `tab%s`
+				where %s=%s and recurring_id=%s and (docstatus=1 or docstatus=0)"""
+				% (doctype, date_field, '%s', '%s'), (next_date, recurring_id)):
+			try:
+				reference_doc = frappe.get_doc(doctype, ref_document)
+				new_doc = make_new_document(reference_doc, date_field, next_date)
+				if reference_doc.notify_by_email:
+					send_notification(new_doc)
+				if commit:
+					frappe.db.commit()
+			except:
+				if commit:
+					frappe.db.rollback()
+
+					frappe.db.begin()
+					frappe.db.sql("update `tab%s` \
+						set is_recurring = 0 where name = %s" % (doctype, '%s'),
+						(ref_document))
+					notify_errors(ref_document, doctype, reference_doc.get("customer") or reference_doc.get("supplier"),
+						reference_doc.owner)
+					frappe.db.commit()
+
+				exception_list.append(frappe.get_traceback())
+			finally:
+				if commit:
+					frappe.db.begin()
+
+	if exception_list:
+		exception_message = "\n\n".join([cstr(d) for d in exception_list])
+		frappe.throw(exception_message)
+
+def make_new_document(reference_doc, date_field, posting_date):
+	from erpnext.controllers.accounts_controller import get_payment_terms
+	new_document = frappe.copy_doc(reference_doc, ignore_no_copy=False)
+	mcount = month_map[reference_doc.recurring_type]
+
+	from_date = get_next_date(reference_doc.from_date, mcount)
+
+	# get last day of the month to maintain period if the from date is first day of its own month
+	# and to date is the last day of its own month
+	if (cstr(get_first_day(reference_doc.from_date)) == cstr(reference_doc.from_date)) and \
+		(cstr(get_last_day(reference_doc.to_date)) == cstr(reference_doc.to_date)):
+			to_date = get_last_day(get_next_date(reference_doc.to_date, mcount))
+	else:
+		to_date = get_next_date(reference_doc.to_date, mcount)
+
+	new_document.update({
+		date_field: posting_date,
+		"from_date": from_date,
+		"to_date": to_date,
+		"next_date": get_next_date(reference_doc.next_date, mcount,cint(reference_doc.repeat_on_day_of_month)),
+		"payment_schedule": get_payment_terms("_Test Payment Term Template 3", posting_date, new_document.grand_total)
+	})
+
+	if new_document.meta.get_field('set_posting_time'):
+		new_document.set('set_posting_time', 1)
+
+	# copy document fields
+	for fieldname in ("owner", "recurring_type", "repeat_on_day_of_month",
+		"recurring_id", "notification_email_address", "is_recurring", "end_date",
+		"title", "naming_series", "select_print_heading", "ignore_pricing_rule",
+		"posting_time", "remarks", 'submit_on_creation'):
+		if new_document.meta.get_field(fieldname):
+			new_document.set(fieldname, reference_doc.get(fieldname))
+
+	# copy item fields
+	for i, item in enumerate(new_document.items):
+		for fieldname in ("page_break",):
+			item.set(fieldname, reference_doc.items[i].get(fieldname))
+
+	new_document.run_method("on_recurring", reference_doc=reference_doc)
+
+	if reference_doc.submit_on_creation:
+		new_document.insert()
+		new_document.submit()
+	else:
+		new_document.docstatus=0
+		new_document.insert()
+
+	return new_document
+
+def get_next_date(dt, mcount, day=None):
+	dt = getdate(dt)
+
+	from dateutil.relativedelta import relativedelta
+	dt += relativedelta(months=mcount, day=day)
+
+	return dt
+
+def send_notification(new_rv):
+	"""Notify concerned persons about recurring document generation"""
+
+	frappe.sendmail(new_rv.notification_email_address,
+		subject=  _("New {0}: #{1}").format(new_rv.doctype, new_rv.name),
+		message = _("Please find attached {0} #{1}").format(new_rv.doctype, new_rv.name),
+		attachments = [frappe.attach_print(new_rv.doctype, new_rv.name, file_name=new_rv.name, print_format=new_rv.recurring_print_format)])
+
+def notify_errors(doc, doctype, party, owner):
+	from frappe.utils.user import get_system_managers
+	recipients = get_system_managers(only_name=True)
+
+	frappe.sendmail(recipients + [frappe.db.get_value("User", owner, "email")],
+		subject="[Urgent] Error while creating recurring %s for %s" % (doctype, doc),
+		message = frappe.get_template("templates/emails/recurring_document_failed.html").render({
+			"type": doctype,
+			"name": doc,
+			"party": party
+		}))
+
+	assign_task_to_owner(doc, doctype, "Recurring Invoice Failed", recipients)
+
+def assign_task_to_owner(doc, doctype, msg, users):
+	for d in users:
+		from frappe.desk.form import assign_to
+		args = {
+			'assign_to' 	:	d,
+			'doctype'		:	doctype,
+			'name'			:	doc,
+			'description'	:	msg,
+			'priority'		:	'High'
+		}
+		assign_to.add(args)
+
+def validate_recurring_document(doc):
+	if doc.is_recurring:
+		validate_notification_email_id(doc)
+		if not doc.recurring_type:
+			frappe.throw(_("Please select {0}").format(doc.meta.get_label("recurring_type")))
+
+		elif not (doc.from_date and doc.to_date):
+			frappe.throw(_("Period From and Period To dates mandatory for recurring {0}").format(doc.doctype))
+
+def validate_recurring_next_date(doc):
+	posting_date = doc.get("posting_date") or doc.get("transaction_date")
+	if getdate(posting_date) > getdate(doc.next_date):
+		frappe.throw(_("Next Date must be greater than Posting Date"))
+
+	next_date = getdate(doc.next_date)
+	if next_date.day != doc.repeat_on_day_of_month:
+
+		# if the repeat day is the last day of the month (31)
+		# and the current month does not have as many days,
+		# then the last day of the current month is a valid date
+		lastday = calendar.monthrange(next_date.year, next_date.month)[1]
+		if doc.repeat_on_day_of_month < lastday:
+
+			# the specified day of the month is not same as the day specified
+			# or the last day of the month
+			frappe.throw(_("Next Date's day and Repeat on Day of Month must be equal"))
+
+def convert_to_recurring(doc, posting_date):
+	if doc.is_recurring:
+		if not doc.recurring_id:
+			doc.db_set("recurring_id", doc.name)
+
+		set_next_date(doc, posting_date)
+
+		if doc.next_date:
+			validate_recurring_next_date(doc)
+
+	elif doc.recurring_id:
+		doc.db_set("recurring_id", None)
+
+def validate_notification_email_id(doc):
+	if doc.notify_by_email:
+		if doc.notification_email_address:
+			email_list = split_emails(doc.notification_email_address.replace("\n", ""))
+
+			from frappe.utils import validate_email_add
+			for email in email_list:
+				if not validate_email_add(email):
+					throw(_("{0} is an invalid email address in 'Notification \
+						Email Address'").format(email))
+
+		else:
+			frappe.throw(_("'Notification Email Addresses' not specified for recurring %s") \
+				% doc.doctype)
+
+def set_next_date(doc, posting_date):
+	""" Set next date on which recurring document will be created"""
+	if not doc.repeat_on_day_of_month:
+		msgprint(_("Please enter 'Repeat on Day of Month' field value"), raise_exception=1)
+
+	next_date = get_next_date(posting_date, month_map[doc.recurring_type],
+		cint(doc.repeat_on_day_of_month))
+
+	doc.db_set('next_date', next_date)
+
+	msgprint(_("Next Recurring {0} will be created on {1}").format(doc.doctype, next_date))
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index 0074560..d609b9e 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -256,6 +256,9 @@
 			target_doc.dn_detail = source_doc.dn_detail
 			target_doc.expense_account = source_doc.expense_account
 
+	def update_terms(source_doc, target_doc, source_parent):
+		target_doc.payment_amount = -source_doc.payment_amount
+
 	doclist = get_mapped_doc(doctype, source_name,	{
 		doctype: {
 			"doctype": doctype,
@@ -272,6 +275,10 @@
 			},
 			"postprocess": update_item
 		},
+		"Payment Schedule": {
+			"doctype": "Payment Schedule",
+			"postprocess": update_terms
+		}
 	}, target_doc, set_missing_values)
 
 	return doclist
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 6829bd4..2a2051e 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -439,4 +439,10 @@
 erpnext.patches.v8_9.add_setup_progress_actions
 erpnext.patches.v8_9.rename_company_sales_target_field
 erpnext.patches.v8_8.set_bom_rate_as_per_uom
-erpnext.patches.v8_7.make_subscription_from_recurring_data
\ No newline at end of file
+erpnext.patches.v8_7.make_subscription_from_recurring_data
+erpnext.patches.v8_10.add_due_date_to_gle
+erpnext.patches.v8_10.update_gl_due_date_for_pi_and_si
+erpnext.patches.v8_10.add_payment_terms_field_to_supplier
+erpnext.patches.v8_10.change_default_customer_credit_days
+erpnext.patches.v8_10.add_payment_terms_field_to_supplier_type
+erpnext.patches.v8_10.change_default_supplier_type_credit_days
diff --git a/erpnext/patches/v8_10/__init__.py b/erpnext/patches/v8_10/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/patches/v8_10/__init__.py
diff --git a/erpnext/patches/v8_10/add_due_date_to_gle.py b/erpnext/patches/v8_10/add_due_date_to_gle.py
new file mode 100644
index 0000000..ec5e003
--- /dev/null
+++ b/erpnext/patches/v8_10/add_due_date_to_gle.py
@@ -0,0 +1,7 @@
+from __future__ import unicode_literals
+import frappe
+
+
+def execute():
+	if not frappe.db.has_column("GL Entry", "due_date"):
+		frappe.db.sql("ALTER TABLE `tabGL Entry` ADD COLUMN `due_date` DATE NULL")
diff --git a/erpnext/patches/v8_10/add_payment_terms_field_to_supplier.py b/erpnext/patches/v8_10/add_payment_terms_field_to_supplier.py
new file mode 100644
index 0000000..b507b2a
--- /dev/null
+++ b/erpnext/patches/v8_10/add_payment_terms_field_to_supplier.py
@@ -0,0 +1,9 @@
+from __future__ import unicode_literals
+import frappe
+
+
+def execute():
+	if not frappe.db.has_column("Customer", "payment_terms"):
+		frappe.db.sql("ALTER TABLE `tabCustomer` ADD COLUMN `payment_terms` VARCHAR(140) NULL")
+	if not frappe.db.has_column("Supplier", "payment_terms"):
+		frappe.db.sql("ALTER TABLE `tabSupplier` ADD COLUMN `payment_terms` VARCHAR(140) NULL")
diff --git a/erpnext/patches/v8_10/add_payment_terms_field_to_supplier_type.py b/erpnext/patches/v8_10/add_payment_terms_field_to_supplier_type.py
new file mode 100644
index 0000000..78b8943
--- /dev/null
+++ b/erpnext/patches/v8_10/add_payment_terms_field_to_supplier_type.py
@@ -0,0 +1,7 @@
+from __future__ import unicode_literals
+import frappe
+
+
+def execute():
+	if not frappe.db.has_column("Supplier Type", "payment_terms"):
+		frappe.db.sql("ALTER TABLE `tabSupplier Type` ADD COLUMN `payment_terms` VARCHAR(140) NULL")
diff --git a/erpnext/patches/v8_10/change_default_customer_credit_days.py b/erpnext/patches/v8_10/change_default_customer_credit_days.py
new file mode 100644
index 0000000..a919713
--- /dev/null
+++ b/erpnext/patches/v8_10/change_default_customer_credit_days.py
@@ -0,0 +1,106 @@
+from __future__ import unicode_literals
+import frappe
+
+
+def execute():
+	frappe.reload_doc("accounts", "doctype", "payment_term")
+	frappe.reload_doc("accounts", "doctype", "payment_terms_template_detail")
+	frappe.reload_doc("accounts", "doctype", "payment_terms_template")
+
+	payment_terms = []
+	customers = []
+	suppliers = []
+	credit_days = frappe.db.sql(
+		"SELECT DISTINCT `credit_days`, `credit_days_based_on`, `customer_name` from "
+		"`tabCustomer` where credit_days_based_on='Fixed Days' or "
+		"credit_days_based_on='Last Day of the Next Month'")
+
+	credit_records = ((record[0], record[1], record[2]) for record in credit_days)
+	for days, based_on, customer_name in credit_records:
+		payment_term = make_payment_term(days, based_on)
+		template = make_template(payment_term)
+		payment_terms.append('WHEN `customer_name`="%s" THEN "%s"' % (customer_name, template.template_name))
+		customers.append(customer_name)
+
+	begin_query_str = "UPDATE `tabCustomer` SET `payment_terms` = CASE "
+	value_query_str = " ".join(payment_terms)
+	cond_query_str = " ELSE `payment_terms` END WHERE "
+
+	if customers:
+		frappe.db.sql(
+			begin_query_str + value_query_str + cond_query_str + '`customer_name` IN %s',
+			(customers,)
+		)
+
+	# reset
+	payment_terms = []
+	credit_days = frappe.db.sql(
+		"SELECT DISTINCT `credit_days`, `credit_days_based_on`, `supplier_name` from "
+		"`tabSupplier` where credit_days_based_on='Fixed Days' or "
+		"credit_days_based_on='Last Day of the Next Month'")
+
+	credit_records = ((record[0], record[1], record[2]) for record in credit_days)
+	for days, based_on, supplier_name in credit_records:
+		if based_on == "Fixed Days":
+			pyt_template_name = 'Default Payment Term - N{0}'.format(days)
+		else:
+			pyt_template_name = 'Default Payment Term - EO2M'
+
+		if not frappe.db.exists("Payment Term Template", pyt_template_name):
+			payment_term = make_payment_term(days, based_on)
+			template = make_template(payment_term)
+		else:
+			template = frappe.get_doc("Payment Term Template", pyt_template_name)
+
+		payment_terms.append('WHEN `supplier_name`="%s" THEN "%s"' % (supplier_name, template.template_name))
+		suppliers.append(supplier_name)
+
+	begin_query_str = "UPDATE `tabSupplier` SET `payment_terms` = CASE "
+	value_query_str = " ".join(payment_terms)
+	cond_query_str = " ELSE `payment_terms` END WHERE "
+
+	if suppliers:
+		frappe.db.sql(
+			begin_query_str + value_query_str + cond_query_str + '`supplier_name` IN %s',
+			(suppliers,)
+		)
+
+
+def make_template(payment_term):
+	doc = frappe.new_doc('Payment Terms Template Detail')
+	doc.payment_term = payment_term.payment_term_name
+	doc.due_date_based_on = payment_term.due_date_based_on
+	doc.invoice_portion = payment_term.invoice_portion
+	doc.description = payment_term.description
+	doc.credit_days = payment_term.credit_days
+	doc.credit_months = payment_term.credit_months
+
+	template = frappe.new_doc('Payment Terms Template')
+	template.template_name = 'Default Payment Term - {0}'.format(payment_term.payment_term_name)
+	template.append('terms', doc)
+	template.save()
+
+	return template
+
+
+def make_payment_term(days, based_on):
+	based_on_map = {
+		'Fixed Days': 'Day(s) after invoice date',
+		'Last Day of the Next Month': 'Month(s) after the end of the invoice month'
+	}
+
+	doc = frappe.new_doc('Payment Term')
+	doc.due_date_based_on = based_on_map.get(based_on)
+	doc.invoice_portion = 100
+
+	if based_on == 'Fixed Days':
+		doc.credit_days = days
+		doc.description = 'Net payable within {0} days'.format(days)
+		doc.payment_term_name = 'N{0}'.format(days)
+	else:
+		doc.credit_months = 1
+		doc.description = 'Net payable by the end of next month'.format(days)
+		doc.payment_term_name = 'EO2M'
+
+	doc.save()
+	return doc
diff --git a/erpnext/patches/v8_10/change_default_supplier_type_credit_days.py b/erpnext/patches/v8_10/change_default_supplier_type_credit_days.py
new file mode 100644
index 0000000..448bdbe
--- /dev/null
+++ b/erpnext/patches/v8_10/change_default_supplier_type_credit_days.py
@@ -0,0 +1,39 @@
+import frappe
+from erpnext.patches.v8_10.change_default_customer_credit_days import make_payment_term, make_template
+
+
+def execute():
+	payment_terms = []
+	supplier_types = []
+
+	credit_days = frappe.db.sql(
+		"SELECT DISTINCT `credit_days`, `credit_days_based_on`, `supplier_type` from "
+		"`tabSupplier Type` where credit_days_based_on='Fixed Days' or "
+		"credit_days_based_on='Last Day of the Next Month'")
+
+	records = ((record[0], record[1], record[2]) for record in credit_days)
+
+	for days, based_on, supplier_type in records:
+		if based_on == "Fixed Days":
+			pyt_term_name = 'N{0}'.format(days)
+		else:
+			pyt_term_name = 'EO2M'
+
+		if not frappe.db.exists("Payment Term", pyt_term_name):
+			payment_term = make_payment_term(days, based_on)
+			make_template(payment_term)
+		else:
+			payment_term = frappe.get_doc("Payment Term", pyt_term_name)
+
+		payment_terms.append('WHEN `supplier_type`="%s" THEN "%s"' % (supplier_type, payment_term.payment_term_name))
+		supplier_types.append(supplier_type)
+
+	begin_query_str = "UPDATE `tabSupplier Type` SET `payment_terms` = CASE "
+	value_query_str = " ".join(payment_terms)
+	cond_query_str = " ELSE `payment_terms` END WHERE "
+
+	if supplier_types:
+		frappe.db.sql(
+			begin_query_str + value_query_str + cond_query_str + '`supplier_type` IN %s',
+			(supplier_types,)
+		)
diff --git a/erpnext/patches/v8_10/update_gl_due_date_for_pi_and_si.py b/erpnext/patches/v8_10/update_gl_due_date_for_pi_and_si.py
new file mode 100644
index 0000000..8ececeb
--- /dev/null
+++ b/erpnext/patches/v8_10/update_gl_due_date_for_pi_and_si.py
@@ -0,0 +1,136 @@
+from __future__ import unicode_literals
+import frappe
+
+"""This will update existing GL Entries by saving its linked Purchase/Sales Invoice's
+and Journal Entry's due date as the due date for the GL Entry"""
+
+
+def execute():
+	kwargs = get_query_kwargs()
+
+	for kwarg in kwargs:
+		for batch in get_result_in_batches(**kwarg):
+			voucher_num_col = kwarg.get('voucher_num_col', 'voucher_no')
+			voucher_type = kwarg.get('use_voucher_type') or kwarg.get('voucher_type')
+			conditions, names = build_conditions(batch, voucher_type, voucher_num_col)
+			if conditions and names:
+				start = 'UPDATE `tabGL Entry` SET `due_date` = CASE '
+				cond = ' '.join(conditions)
+				else_cond = ' ELSE `due_date` END WHERE '
+
+				frappe.db.sql(
+					start + cond + else_cond + voucher_num_col + ' IN %s',
+					values=(names,)
+				)
+
+
+def get_result_in_batches(**kwargs):
+	"""A simple generator to yield slices of GL Entry records"""
+	while True:
+		batch = get_gle_batch(**kwargs)
+		if batch:
+			yield batch
+		else:
+			return
+
+
+def get_gle_batch(**kwargs):
+	"""Returns a slice of records in GL Entry"""
+	doctype = kwargs.get('doctype')
+	fields = kwargs.get('fields')
+	limit_start = kwargs.get('limit_start')
+	limit_page_length = kwargs.get('limit_page_length')
+	filters = kwargs.get('filters')
+	or_filters = kwargs.get('or_filters')
+
+	results = frappe.get_list(
+		doctype, fields=fields, limit_start=limit_start, limit_page_length=limit_page_length,
+		filters=filters, or_filters=or_filters
+	)
+
+	return results
+
+
+def build_conditions(query_results, voucher_type, voucher_num_col):
+	"""
+	builds the string to be used is sql CASE statement. Returns the a tuple of
+	the string for the CASE statement and a tuple of applicable voucher names
+	"""
+	conditions = []
+	invoice_names = []
+
+	for result in query_results:
+		voucher_no = result.get(voucher_num_col)
+		if voucher_no:
+			invoice_names.append("%s" % (voucher_no,))
+
+	# get invoice details
+	invoice_details = frappe.get_list(
+		voucher_type, fields=['name', 'due_date'], filters={'name': ('in', invoice_names)}
+	)
+
+	if invoice_details:
+		for d in invoice_details:
+			conditions.append('WHEN `{voucher_no}`="{number}" THEN "{date}"'.format(
+				number=d.name, date=d.due_date, voucher_no=voucher_num_col))
+
+	return conditions, invoice_names
+
+
+def get_query_kwargs():
+	pi_kwargs = dict(
+		voucher_type='Purchase Invoice', doctype='GL Entry', fields=['voucher_no'],
+		limit_start=0, limit_page_length=5, filters={
+			"ifnull(due_date, '')": ('=', ''), "ifnull(party, '')": ('!=', ''),
+			'voucher_type': 'Purchase Invoice', 'credit': ('!=', '0')
+		}
+	)
+
+	si_kwargs = dict(
+		voucher_type='Sales Invoice', doctype='GL Entry', fields=['voucher_no'],
+		limit_start=0, limit_page_length=5, filters={
+			"ifnull(due_date, '')": ('=', ''), "ifnull(party, '')": ('!=', ''),
+			'voucher_type': 'Sales Invoice', 'debit': ('!=', '0')
+		}
+	)
+
+	journal_kwargs_si = dict(
+		voucher_type='Journal Entry', doctype='GL Entry', fields=['against_voucher'],
+		limit_start=0, limit_page_length=5, filters={
+			"ifnull(due_date, '')": ('=', ''), "ifnull(party, '')": ('!=', ''),
+			'voucher_type': 'Journal Entry', 'against_voucher_type': 'Sales Invoice'
+		},
+		voucher_num_col='against_voucher', use_voucher_type='Sales Invoice',
+	)
+
+	journal_kwargs_pi = dict(
+		voucher_type='Journal Entry', doctype='GL Entry', fields=['against_voucher'],
+		limit_start=0, limit_page_length=5, filters={
+			"ifnull(due_date, '')": ('=', ''), "ifnull(party, '')": ('!=', ''),
+			'voucher_type': 'Journal Entry', 'against_voucher_type': 'Purchase Invoice'
+		},
+		voucher_num_col='against_voucher', use_voucher_type='Purchase Invoice',
+	)
+
+	payment_entry_kwargs_pi = dict(
+		voucher_type='Payment Entry', doctype='GL Entry', fields=['against_voucher'],
+		limit_start=0, limit_page_length=5, filters={
+			"ifnull(due_date, '')": ('=', ''), "ifnull(party, '')": ('!=', ''),
+			'voucher_type': 'Payment Entry', 'against_voucher_type': 'Purchase Invoice'
+		},
+		voucher_num_col='against_voucher', use_voucher_type='Purchase Invoice',
+	)
+
+	payment_entry_kwargs_si = dict(
+		voucher_type='Payment Entry', doctype='GL Entry', fields=['against_voucher'],
+		limit_start=0, limit_page_length=5, filters={
+			"ifnull(due_date, '')": ('=', ''), "ifnull(party, '')": ('!=', ''),
+			'voucher_type': 'Payment Entry', 'against_voucher_type': 'Sales Invoice'
+		},
+		voucher_num_col='against_voucher', use_voucher_type='Sales Invoice',
+	)
+
+	return [
+		pi_kwargs, si_kwargs, journal_kwargs_pi, journal_kwargs_si,
+		payment_entry_kwargs_pi, payment_entry_kwargs_si
+	]
diff --git a/erpnext/public/js/controllers/accounts.js b/erpnext/public/js/controllers/accounts.js
index abd5566..f38084f 100644
--- a/erpnext/public/js/controllers/accounts.js
+++ b/erpnext/public/js/controllers/accounts.js
@@ -62,15 +62,32 @@
 			frappe.model.set_value(cdt, cdn, 'account', account)
 		})
 	}
-})
+});
+
+frappe.ui.form.on("Sales Invoice", {
+	payment_terms_template: function() {
+		cur_frm.trigger("disable_due_date");
+	}
+});
 
 frappe.ui.form.on('Purchase Invoice', {
 	mode_of_payment: function(frm) {
 		get_payment_mode_account(frm, frm.doc.mode_of_payment, function(account){
 			frm.set_value('cash_bank_account', account);
 		})
+	},
+
+	payment_terms_template: function() {
+		cur_frm.trigger("disable_due_date");
 	}
-})
+});
+
+frappe.ui.form.on("Payment Schedule", {
+	payment_schedule_remove: function() {
+		cur_frm.trigger("disable_due_date");
+	},
+
+});
 
 frappe.ui.form.on('Payment Entry', {
 	mode_of_payment: function(frm) {
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index f5bcf1c..6344a96 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -123,6 +123,11 @@
 			}
 		}
 
+		if(this.frm.fields_dict["payment_terms_template"]){
+			console.log("triggered");
+			this.frm.trigger("payment_terms_template");
+		}
+
 		if(this.frm.fields_dict["taxes"]) {
 			this["taxes_remove"] = this.calculate_taxes_and_totals;
 		}
@@ -1115,6 +1120,46 @@
 			}
 		}
 	},
+
+	payment_terms_template: function() {
+		var me = this;
+		if(this.frm.doc.payment_terms_template) {
+			frappe.call({
+				method: "erpnext.controllers.accounts_controller.get_payment_terms",
+				args: {
+					terms_template: this.frm.doc.payment_terms_template,
+					posting_date: this.frm.doc.posting_date || this.frm.doc.transaction_date,
+					grand_total: this.frm.doc.grand_total
+				},
+				callback: function(r) {
+					if(r.message && !r.exc) {
+						me.frm.set_value("payment_schedule", r.message);
+					}
+				}
+			})
+		}
+	},
+
+	payment_term: function(doc, cdt, cdn) {
+		var row = locals[cdt][cdn];
+		if(row.payment_term) {
+			frappe.call({
+				method: "erpnext.controllers.accounts_controller.get_payment_term_details",
+				args: {
+					term: row.payment_term,
+					posting_date: this.frm.doc.posting_date || this.frm.doc.transaction_date,
+					grand_total: this.frm.doc.grand_total
+				},
+				callback: function(r) {
+					if(r.message && !r.exc) {
+						for (var d in r.message) {
+							frappe.model.set_value(cdt, cdn, d, r.message[d]);
+						}
+					}
+				}
+			})
+		}
+	}
 });
 
 erpnext.show_serial_batch_selector = function(frm, d, callback, show_dialog) {
diff --git a/erpnext/selling/doctype/customer/customer.json b/erpnext/selling/doctype/customer/customer.json
index 52c6b6d..222d2e5 100644
--- a/erpnext/selling/doctype/customer/customer.json
+++ b/erpnext/selling/doctype/customer/customer.json
@@ -786,7 +786,7 @@
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 1, 
-   "collapsible_depends_on": "eval:doc.credit_days || doc.credit_limit", 
+   "collapsible_depends_on": "", 
    "columns": 0, 
    "fieldname": "credit_limit_section", 
    "fieldtype": "Section Break", 
@@ -818,69 +818,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.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": 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_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
    "fieldname": "credit_limit", 
    "fieldtype": "Currency", 
    "hidden": 0, 
@@ -911,6 +848,38 @@
    "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "depends_on": "", 
+   "fieldname": "payment_terms", 
+   "fieldtype": "Link", 
+   "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": "Default Payment Terms Template", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Payment Terms Template", 
+   "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": 1, 
    "collapsible_depends_on": "customer_details", 
    "columns": 0, 
@@ -1202,8 +1171,8 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2017-07-24 00:55:07.445783", 
- "modified_by": "Administrator", 
+ "modified": "2017-08-31 15:12:18.637132", 
+ "modified_by": "tundebabzy@gmail.com", 
  "module": "Selling", 
  "name": "Customer", 
  "name_case": "Title Case", 
diff --git a/erpnext/selling/doctype/customer/test_customer.js b/erpnext/selling/doctype/customer/test_customer.js
new file mode 100644
index 0000000..65b81af
--- /dev/null
+++ b/erpnext/selling/doctype/customer/test_customer.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Customer", function (assert) {
+	let done = assert.async();
+
+	// number of asserts
+	assert.expect(1);
+
+	frappe.run_serially([
+		// insert a new Customer
+		() => frappe.tests.make('Customer', [
+			// values to be set
+			{key: 'value'}
+		]),
+		() => {
+			assert.equal(cur_frm.doc.key, 'value');
+		},
+		() => done()
+	]);
+
+});
diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py
index 40ed6f9..45546e3 100644
--- a/erpnext/selling/doctype/customer/test_customer.py
+++ b/erpnext/selling/doctype/customer/test_customer.py
@@ -6,6 +6,7 @@
 import frappe
 import unittest
 
+from erpnext.accounts.party import get_due_date
 from frappe.test_runner import make_test_records
 from erpnext.exceptions import PartyFrozen, PartyDisabled
 from frappe.utils import flt
@@ -13,7 +14,7 @@
 from erpnext.tests.utils import create_test_contact_and_address
 
 test_ignore = ["Price List"]
-
+test_dependencies = ['Payment Term', 'Payment Terms Template']
 test_records = frappe.get_test_records('Customer')
 
 class TestCustomer(unittest.TestCase):
@@ -181,6 +182,35 @@
 		customer.credit_limit = flt(outstanding_amt - 100)
 		self.assertRaises(frappe.ValidationError, customer.save)
 
+	def test_customer_payment_terms(self):
+		frappe.db.set_value(
+			"Customer", "_Test Customer With Template", "payment_terms", "_Test Payment Term Template 3")
+
+		due_date = get_due_date("2016-01-22", "Customer", "_Test Customer With Template")
+		self.assertEqual(due_date, "2016-02-21")
+
+		due_date = get_due_date("2017-01-22", "Customer", "_Test Customer With Template")
+		self.assertEqual(due_date, "2017-02-21")
+
+		frappe.db.set_value(
+			"Customer", "_Test Customer With Template", "payment_terms", "_Test Payment Term Template 1")
+
+		due_date = get_due_date("2016-01-22", "Customer", "_Test Customer With Template")
+		self.assertEqual(due_date, "2016-02-29")
+
+		due_date = get_due_date("2017-01-22", "Customer", "_Test Customer With Template")
+		self.assertEqual(due_date, "2017-02-28")
+
+		frappe.db.set_value("Customer", "_Test Customer With Template", "payment_terms", "")
+
+		# No default payment term template attached
+		due_date = get_due_date("2016-01-22", "Customer", "_Test Customer")
+		self.assertEqual(due_date, "2016-01-22")
+
+		due_date = get_due_date("2017-01-22", "Customer", "_Test Customer")
+		self.assertEqual(due_date, "2017-01-22")
+
+
 def get_customer_dict(customer_name):
 	return {
 		 "customer_group": "_Test Customer Group",
diff --git a/erpnext/selling/doctype/customer/test_records.json b/erpnext/selling/doctype/customer/test_records.json
index 94f14ed..a012c1b 100644
--- a/erpnext/selling/doctype/customer/test_records.json
+++ b/erpnext/selling/doctype/customer/test_records.json
@@ -1,6 +1,20 @@
 [
  {
   "customer_group": "_Test Customer Group",
+  "customer_name": "_Test Customer With Template",
+  "customer_type": "Individual",
+  "doctype": "Customer",
+  "territory": "_Test Territory"
+ },
+ {
+  "customer_group": "_Test Customer Group",
+  "customer_name": "_Test Customer P",
+  "customer_type": "Individual",
+  "doctype": "Customer",
+  "territory": "_Test Territory"
+ },
+ {
+  "customer_group": "_Test Customer Group",
   "customer_name": "_Test Customer",
   "customer_type": "Individual",
   "doctype": "Customer",
diff --git a/erpnext/selling/doctype/quotation/quotation.json b/erpnext/selling/doctype/quotation/quotation.json
index ab879a1..87cc7a3 100644
--- a/erpnext/selling/doctype/quotation/quotation.json
+++ b/erpnext/selling/doctype/quotation/quotation.json
@@ -2094,6 +2094,100 @@
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 1, 
+   "collapsible_depends_on": "eval:!doc.__islocal", 
+   "columns": 0, 
+   "depends_on": "", 
+   "fieldname": "payment_schedule_section", 
+   "fieldtype": "Section Break", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Payment Schedule", 
+   "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, 
+   "fieldname": "payment_terms_template", 
+   "fieldtype": "Link", 
+   "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": "Payment Terms Template", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Payment Terms Template", 
+   "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, 
+   "fieldname": "payment_schedule", 
+   "fieldtype": "Table", 
+   "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": "Payment Schedule", 
+   "length": 0, 
+   "no_copy": 1, 
+   "options": "Payment Schedule", 
+   "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": 1, 
    "collapsible_depends_on": "terms", 
    "columns": 0, 
    "fieldname": "terms_section_break", 
@@ -2694,8 +2788,8 @@
  "istable": 0, 
  "max_attachments": 1, 
  "menu_index": 0, 
- "modified": "2017-08-31 11:22:15.268846", 
- "modified_by": "Administrator", 
+ "modified": "2017-08-31 11:22:15.268846",
+ "modified_by": "Administrator",
  "module": "Selling", 
  "name": "Quotation", 
  "owner": "Administrator", 
diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py
index d7d84c7..bb083ee 100644
--- a/erpnext/selling/doctype/quotation/test_quotation.py
+++ b/erpnext/selling/doctype/quotation/test_quotation.py
@@ -3,7 +3,8 @@
 from __future__ import unicode_literals
 
 import frappe
-from frappe.utils import flt, add_days, nowdate, add_months
+from frappe.utils import flt, add_days, nowdate, add_months, DATE_FORMAT
+from erpnext.controllers.accounts_controller import get_payment_terms
 import unittest
 
 test_dependencies = ["Product Bundle"]
@@ -33,6 +34,46 @@
 		sales_order.transaction_date = nowdate()
 		sales_order.insert()
 
+	def test_make_sales_order_with_terms(self):
+		from erpnext.selling.doctype.quotation.quotation import make_sales_order
+
+		quotation = frappe.copy_doc(test_records[0])
+		quotation.transaction_date = nowdate()
+		quotation.valid_till = add_months(quotation.transaction_date, 1)
+		quotation.update(
+			{"payment_terms_template": "_Test Payment Term Template"}
+		)
+		quotation.insert()
+
+		self.assertRaises(frappe.ValidationError, make_sales_order, quotation.name)
+		quotation.save()
+		quotation.submit()
+
+		self.assertEqual(quotation.payment_schedule[0].payment_amount, 8906.25)
+		self.assertEqual(quotation.payment_schedule[0].due_date, quotation.transaction_date)
+		self.assertEqual(quotation.payment_schedule[1].payment_amount, 8906.25)
+		self.assertEqual(quotation.payment_schedule[1].due_date, add_days(quotation.transaction_date, 30))
+
+		sales_order = make_sales_order(quotation.name)
+
+		self.assertEquals(sales_order.doctype, "Sales Order")
+		self.assertEquals(len(sales_order.get("items")), 1)
+		self.assertEquals(sales_order.get("items")[0].doctype, "Sales Order Item")
+		self.assertEquals(sales_order.get("items")[0].prevdoc_docname, quotation.name)
+		self.assertEquals(sales_order.customer, "_Test Customer")
+
+		sales_order.delivery_date = "2014-01-01"
+		sales_order.naming_series = "_T-Quotation-"
+		sales_order.transaction_date = nowdate()
+		sales_order.insert()
+
+		self.assertEqual(sales_order.payment_schedule[0].payment_amount, 8906.25)
+		self.assertEqual(sales_order.payment_schedule[0].due_date, quotation.transaction_date)
+		self.assertEqual(sales_order.payment_schedule[1].payment_amount, 8906.25)
+		self.assertEqual(
+			sales_order.payment_schedule[1].due_date, add_days(quotation.transaction_date, 30)
+		)
+
 	def test_valid_till(self):
 		from erpnext.selling.doctype.quotation.quotation import make_sales_order
 
diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json
index 3b8eb68..cdb5dcb 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.json
+++ b/erpnext/selling/doctype/sales_order/sales_order.json
@@ -2255,10 +2255,9 @@
    "label": "Packed Items", 
    "length": 0, 
    "no_copy": 0, 
-   "oldfieldname": "packing_details", 
-   "oldfieldtype": "Table", 
    "options": "Packed Item", 
    "permlevel": 0, 
+   "precision": "", 
    "print_hide": 1, 
    "print_hide_if_no_value": 0, 
    "read_only": 1, 
@@ -2274,6 +2273,99 @@
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 1, 
+   "collapsible_depends_on": "eval:!doc.__islocal||doc.payment_schedule", 
+   "columns": 0, 
+   "fieldname": "payment_schedule_section", 
+   "fieldtype": "Section Break", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Payment Terms Schedule", 
+   "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, 
+   "fieldname": "payment_terms_template", 
+   "fieldtype": "Link", 
+   "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": "Payment Terms Template", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Payment Terms Template", 
+   "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, 
+   "fieldname": "payment_schedule", 
+   "fieldtype": "Table", 
+   "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": "Payment Schedule", 
+   "length": 0, 
+   "no_copy": 1, 
+   "options": "Payment Schedule", 
+   "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": 1, 
    "collapsible_depends_on": "terms", 
    "columns": 0, 
    "fieldname": "terms_section_break", 
@@ -3720,8 +3812,8 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2017-08-31 11:21:36.332326", 
- "modified_by": "Administrator", 
+ "modified": "2017-08-31 11:21:36.332326",
+ "modified_by": "Administrator",
  "module": "Selling", 
  "name": "Sales Order", 
  "owner": "Administrator", 
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.js b/erpnext/selling/doctype/sales_order/test_sales_order.js
new file mode 100644
index 0000000..57ed19b
--- /dev/null
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Sales Order", function (assert) {
+	let done = assert.async();
+
+	// number of asserts
+	assert.expect(1);
+
+	frappe.run_serially('Sales Order', [
+		// insert a new Sales Order
+		() => frappe.tests.make([
+			// values to be set
+			{key: 'value'}
+		]),
+		() => {
+			assert.equal(cur_frm.doc.key, 'value');
+		},
+		() => done()
+	]);
+
+});
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index 7c0d7f9..c0bd633 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -2,7 +2,7 @@
 # License: GNU General Public License v3. See license.txt
 from __future__ import unicode_literals
 import frappe
-from frappe.utils import flt, add_days
+from frappe.utils import flt, add_days, DATE_FORMAT
 import frappe.permissions
 import unittest
 from erpnext.stock.doctype.item.test_item import get_total_projected_qty
@@ -11,6 +11,7 @@
 from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
 from frappe.tests.test_permissions import set_user_permission_doctypes
 
+
 class TestSalesOrder(unittest.TestCase):
 	def tearDown(self):
 		frappe.set_user("Administrator")
@@ -58,6 +59,32 @@
 		si1 = make_sales_invoice(so.name)
 		self.assertEquals(len(si1.get("items")), 0)
 
+	def test_make_sales_invoice_with_terms(self):
+		so = make_sales_order(do_not_submit=True)
+
+		self.assertRaises(frappe.ValidationError, make_sales_invoice, so.name)
+
+		so.update({"payment_terms_template": "_Test Payment Term Template"})
+
+		so.save()
+		so.submit()
+		si = make_sales_invoice(so.name)
+
+		self.assertEquals(len(si.get("items")), len(so.get("items")))
+		self.assertEquals(len(si.get("items")), 1)
+
+		si.insert()
+
+		self.assertEqual(si.payment_schedule[0].payment_amount, 500.0)
+		self.assertEqual(si.payment_schedule[0].due_date, so.transaction_date)
+		self.assertEqual(si.payment_schedule[1].payment_amount, 500.0)
+		self.assertEqual(si.payment_schedule[1].due_date, add_days(so.transaction_date, 30))
+
+		si.submit()
+
+		si1 = make_sales_invoice(so.name)
+		self.assertEquals(len(si1.get("items")), 0)
+
 	def test_update_qty(self):
 		so = make_sales_order()
 
@@ -123,7 +150,6 @@
 		so = make_sales_order()
 		self.assertEqual(get_reserved_qty(), existing_reserved_qty + 10)
 
-
 		dn = create_dn_against_so(so.name, 15)
 		self.assertEqual(get_reserved_qty(), existing_reserved_qty)
 
@@ -179,7 +205,6 @@
 		make_stock_entry(target="_Test Warehouse - _TC", qty=10, rate=100)
 		make_stock_entry(item="_Test Item Home Desktop 100", target="_Test Warehouse - _TC", qty=10, rate=100)
 
-
 		existing_reserved_qty_item1 = get_reserved_qty("_Test Item")
 		existing_reserved_qty_item2 = get_reserved_qty("_Test Item Home Desktop 100")
 
diff --git a/erpnext/setup/doctype/supplier_type/supplier_type.json b/erpnext/setup/doctype/supplier_type/supplier_type.json
index 9b40e0f..d7d7084 100644
--- a/erpnext/setup/doctype/supplier_type/supplier_type.json
+++ b/erpnext/setup/doctype/supplier_type/supplier_type.json
@@ -1,5 +1,6 @@
 {
  "allow_copy": 0, 
+ "allow_guest_to_view": 0, 
  "allow_import": 1, 
  "allow_rename": 1, 
  "autoname": "field:supplier_type", 
@@ -12,6 +13,7 @@
  "editable_grid": 0, 
  "fields": [
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -42,6 +44,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 1, 
@@ -71,12 +74,13 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
-   "fieldname": "credit_days_based_on", 
-   "fieldtype": "Select", 
+   "fieldname": "payment_terms", 
+   "fieldtype": "Link", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
    "ignore_xss_filter": 0, 
@@ -84,39 +88,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", 
-   "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, 
-   "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, 
+   "options": "Payment Terms Template", 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
@@ -130,6 +105,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -158,6 +134,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -189,18 +166,18 @@
    "unique": 0
   }
  ], 
+ "has_web_view": 0, 
  "hide_heading": 0, 
  "hide_toolbar": 0, 
  "icon": "fa fa-flag", 
  "idx": 1, 
  "image_view": 0, 
  "in_create": 0, 
- "in_dialog": 0, 
  "is_submittable": 0, 
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2017-02-20 13:25:25.641431", 
+ "modified": "2017-09-04 18:54:10.093500", 
  "modified_by": "Administrator", 
  "module": "Setup", 
  "name": "Supplier Type", 
diff --git a/erpnext/setup/doctype/supplier_type/test_supplier_type.js b/erpnext/setup/doctype/supplier_type/test_supplier_type.js
new file mode 100644
index 0000000..085dddd
--- /dev/null
+++ b/erpnext/setup/doctype/supplier_type/test_supplier_type.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Supplier Type", function (assert) {
+	let done = assert.async();
+
+	// number of asserts
+	assert.expect(1);
+
+	frappe.run_serially([
+		// insert a new Supplier Type
+		() => frappe.tests.make('Supplier Type', [
+			// values to be set
+			{key: 'value'}
+		]),
+		() => {
+			assert.equal(cur_frm.doc.key, 'value');
+		},
+		() => done()
+	]);
+
+});