Merge pull request #24629 from deepeshgarg007/loan_dashboard

feat: Loans Dashboard
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 5a5c448..199a183 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -109,7 +109,7 @@
 	'''
 	if company or frappe.flags.company:
 		return frappe.get_cached_value('Company',
-			company or frappe.flags.company,  'country')
+			company or frappe.flags.company, 'country')
 	elif frappe.flags.country:
 		return frappe.flags.country
 	else:
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json
index cf55d55..5858f10 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json
@@ -30,6 +30,7 @@
    "fieldtype": "Link",
    "label": "Reference Document Type",
    "options": "DocType",
+   "read_only_depends_on": "eval:!doc.__islocal",
    "reqd": 1
   },
   {
@@ -48,7 +49,7 @@
   }
  ],
  "links": [],
- "modified": "2020-03-22 20:34:39.805728",
+ "modified": "2021-02-08 16:37:53.936656",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Accounting Dimension",
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
index ef0d3a3..1bd42f5 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
@@ -29,15 +29,25 @@
 		if exists and self.is_new():
 			frappe.throw("Document Type already used as a dimension")
 
+		if not self.is_new():
+			self.validate_document_type_change()
+
+	def validate_document_type_change(self):
+		doctype_before_save = frappe.db.get_value("Accounting Dimension", self.name, "document_type")
+		if doctype_before_save != self.document_type:
+			message = _("Cannot change Reference Document Type.")
+			message += _("Please create a new Accounting Dimension if required.")
+			frappe.throw(message)
+
 	def after_insert(self):
 		if frappe.flags.in_test:
 			make_dimension_in_accounting_doctypes(doc=self)
 		else:
-			frappe.enqueue(make_dimension_in_accounting_doctypes, doc=self)
+			frappe.enqueue(make_dimension_in_accounting_doctypes, doc=self, queue='long')
 
 	def on_trash(self):
 		if frappe.flags.in_test:
-			delete_accounting_dimension(doc=self)
+			delete_accounting_dimension(doc=self, queue='long')
 		else:
 			frappe.enqueue(delete_accounting_dimension, doc=self)
 
@@ -48,6 +58,9 @@
 		if not self.fieldname:
 			self.fieldname = scrub(self.label)
 
+	def on_update(self):
+		frappe.flags.accounting_dimensions = None
+
 def make_dimension_in_accounting_doctypes(doc):
 	doclist = get_doctypes_with_dimensions()
 	doc_count = len(get_accounting_dimensions())
@@ -176,12 +189,14 @@
 	return doclist
 
 def get_accounting_dimensions(as_list=True):
-	accounting_dimensions = frappe.get_all("Accounting Dimension", fields=["label", "fieldname", "disabled", "document_type"])
+	if frappe.flags.accounting_dimensions is None:
+		frappe.flags.accounting_dimensions = frappe.get_all("Accounting Dimension",
+			fields=["label", "fieldname", "disabled", "document_type"])
 
 	if as_list:
-		return [d.fieldname for d in accounting_dimensions]
+		return [d.fieldname for d in frappe.flags.accounting_dimensions]
 	else:
-		return accounting_dimensions
+		return frappe.flags.accounting_dimensions
 
 def get_checks_for_pl_and_bs_accounts():
 	dimensions = frappe.db.sql("""SELECT p.label, p.disabled, p.fieldname, c.default_dimension, c.company, c.mandatory_for_pl, c.mandatory_for_bs
diff --git a/erpnext/accounts/doctype/bank_account/bank_account.json b/erpnext/accounts/doctype/bank_account/bank_account.json
index b42f1f9..de67ab1 100644
--- a/erpnext/accounts/doctype/bank_account/bank_account.json
+++ b/erpnext/accounts/doctype/bank_account/bank_account.json
@@ -86,6 +86,7 @@
   },
   {
    "default": "0",
+   "description": "Setting the account as a Company Account is necessary for Bank Reconciliation",
    "fieldname": "is_company_account",
    "fieldtype": "Check",
    "label": "Is Company Account"
@@ -207,7 +208,7 @@
   }
  ],
  "links": [],
- "modified": "2020-07-17 13:59:50.795412",
+ "modified": "2020-10-23 16:48:06.303658",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Bank Account",
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/accounts/doctype/bank_reconciliation_tool/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/accounts/doctype/bank_reconciliation_tool/__init__.py
diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js
new file mode 100644
index 0000000..297dd43
--- /dev/null
+++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js
@@ -0,0 +1,162 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+frappe.provide("erpnext.accounts.bank_reconciliation");
+
+frappe.ui.form.on("Bank Reconciliation Tool", {
+	setup: function (frm) {
+		frm.set_query("bank_account", function () {
+			return {
+				filters: {
+					company: ["in", frm.doc.company],
+				},
+			};
+		});
+	},
+
+	refresh: function (frm) {
+		frappe.require("assets/js/bank-reconciliation-tool.min.js", () =>
+			frm.trigger("make_reconciliation_tool")
+		);
+		frm.upload_statement_button = frm.page.set_secondary_action(
+			__("Upload Bank Statement"),
+			() =>
+				frappe.call({
+					method:
+						"erpnext.accounts.doctype.bank_statement_import.bank_statement_import.upload_bank_statement",
+					args: {
+						dt: frm.doc.doctype,
+						dn: frm.doc.name,
+						company: frm.doc.company,
+						bank_account: frm.doc.bank_account,
+					},
+					callback: function (r) {
+						if (!r.exc) {
+							var doc = frappe.model.sync(r.message);
+							frappe.set_route(
+								"Form",
+								doc[0].doctype,
+								doc[0].name
+							);
+						}
+					},
+				})
+		);
+	},
+
+	after_save: function (frm) {
+		frm.trigger("make_reconciliation_tool");
+	},
+
+	bank_account: function (frm) {
+		frappe.db.get_value(
+			"Bank Account",
+			frm.bank_account,
+			"account",
+			(r) => {
+				frappe.db.get_value(
+					"Account",
+					r.account,
+					"account_currency",
+					(r) => {
+						frm.currency = r.account_currency;
+					}
+				);
+			}
+		);
+		frm.trigger("get_account_opening_balance");
+	},
+
+	bank_statement_from_date: function (frm) {
+		frm.trigger("get_account_opening_balance");
+	},
+
+	make_reconciliation_tool(frm) {
+		frm.get_field("reconciliation_tool_cards").$wrapper.empty();
+		if (frm.doc.bank_account && frm.doc.bank_statement_to_date) {
+			frm.trigger("get_cleared_balance").then(() => {
+				if (
+					frm.doc.bank_account &&
+					frm.doc.bank_statement_from_date &&
+					frm.doc.bank_statement_to_date &&
+					frm.doc.bank_statement_closing_balance
+				) {
+					frm.trigger("render_chart");
+					frm.trigger("render");
+					frappe.utils.scroll_to(
+						frm.get_field("reconciliation_tool_cards").$wrapper,
+						true,
+						30
+					);
+				}
+			});
+		}
+	},
+
+	get_account_opening_balance(frm) {
+		if (frm.doc.bank_account && frm.doc.bank_statement_from_date) {
+			frappe.call({
+				method:
+					"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_account_balance",
+				args: {
+					bank_account: frm.doc.bank_account,
+					till_date: frm.doc.bank_statement_from_date,
+				},
+				callback: (response) => {
+					frm.set_value("account_opening_balance", response.message);
+				},
+			});
+		}
+	},
+
+	get_cleared_balance(frm) {
+		if (frm.doc.bank_account && frm.doc.bank_statement_to_date) {
+			return frappe.call({
+				method:
+					"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_account_balance",
+				args: {
+					bank_account: frm.doc.bank_account,
+					till_date: frm.doc.bank_statement_to_date,
+				},
+				callback: (response) => {
+					frm.cleared_balance = response.message;
+				},
+			});
+		}
+	},
+
+	render_chart(frm) {
+		frm.cards_manager = new erpnext.accounts.bank_reconciliation.NumberCardManager(
+			{
+				$reconciliation_tool_cards: frm.get_field(
+					"reconciliation_tool_cards"
+				).$wrapper,
+				bank_statement_closing_balance:
+					frm.doc.bank_statement_closing_balance,
+				cleared_balance: frm.cleared_balance,
+				currency: frm.currency,
+			}
+		);
+	},
+
+	render(frm) {
+		if (frm.doc.bank_account) {
+			frm.bank_reconciliation_data_table_manager = new erpnext.accounts.bank_reconciliation.DataTableManager(
+				{
+					company: frm.doc.company,
+					bank_account: frm.doc.bank_account,
+					$reconciliation_tool_dt: frm.get_field(
+						"reconciliation_tool_dt"
+					).$wrapper,
+					$no_bank_transactions: frm.get_field(
+						"no_bank_transactions"
+					).$wrapper,
+					bank_statement_from_date: frm.doc.bank_statement_from_date,
+					bank_statement_to_date: frm.doc.bank_statement_to_date,
+					bank_statement_closing_balance:
+						frm.doc.bank_statement_closing_balance,
+					cards_manager: frm.cards_manager,
+				}
+			);
+		}
+	},
+});
diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json
new file mode 100644
index 0000000..4837db3
--- /dev/null
+++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json
@@ -0,0 +1,113 @@
+{
+ "actions": [],
+ "creation": "2020-12-02 10:13:02.148040",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "company",
+  "bank_account",
+  "column_break_1",
+  "bank_statement_from_date",
+  "bank_statement_to_date",
+  "column_break_2",
+  "account_opening_balance",
+  "bank_statement_closing_balance",
+  "section_break_1",
+  "reconciliation_tool_cards",
+  "reconciliation_tool_dt",
+  "no_bank_transactions"
+ ],
+ "fields": [
+  {
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "label": "Company",
+   "options": "Company"
+  },
+  {
+   "fieldname": "bank_account",
+   "fieldtype": "Link",
+   "label": "Bank Account",
+   "options": "Bank Account"
+  },
+  {
+   "fieldname": "column_break_1",
+   "fieldtype": "Column Break"
+  },
+  {
+   "depends_on": "eval: doc.bank_account",
+   "fieldname": "bank_statement_from_date",
+   "fieldtype": "Date",
+   "label": "Bank Statement From Date"
+  },
+  {
+   "depends_on": "eval: doc.bank_statement_from_date",
+   "fieldname": "bank_statement_to_date",
+   "fieldtype": "Date",
+   "label": "Bank Statement To Date"
+  },
+  {
+   "fieldname": "column_break_2",
+   "fieldtype": "Column Break"
+  },
+  {
+   "depends_on": "eval: doc.bank_statement_from_date",
+   "fieldname": "account_opening_balance",
+   "fieldtype": "Currency",
+   "label": "Account Opening Balance",
+   "options": "Currency",
+   "read_only": 1
+  },
+  {
+   "depends_on": "eval: doc.bank_statement_to_date",
+   "fieldname": "bank_statement_closing_balance",
+   "fieldtype": "Currency",
+   "label": "Bank Statement Closing Balance",
+   "options": "Currency"
+  },
+  {
+   "depends_on": "eval: doc.bank_statement_closing_balance",
+   "fieldname": "section_break_1",
+   "fieldtype": "Section Break",
+   "label": "Reconcile"
+  },
+  {
+   "fieldname": "reconciliation_tool_cards",
+   "fieldtype": "HTML"
+  },
+  {
+   "fieldname": "reconciliation_tool_dt",
+   "fieldtype": "HTML"
+  },
+  {
+   "fieldname": "no_bank_transactions",
+   "fieldtype": "HTML",
+   "options": "<div class=\"text-muted text-center\">No Matching Bank Transactions Found</div>"
+  }
+ ],
+ "hide_toolbar": 1,
+ "index_web_pages_for_search": 1,
+ "issingle": 1,
+ "links": [],
+ "modified": "2021-02-02 01:35:53.043578",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Bank Reconciliation Tool",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "print": 1,
+   "read": 1,
+   "role": "System Manager",
+   "share": 1,
+   "write": 1
+  }
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC"
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py
new file mode 100644
index 0000000..8a17233
--- /dev/null
+++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py
@@ -0,0 +1,452 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import json
+
+import frappe
+from frappe.model.document import Document
+from frappe import _
+from frappe.utils import flt
+
+from erpnext import get_company_currency
+from erpnext.accounts.utils import get_balance_on
+from erpnext.accounts.report.bank_reconciliation_statement.bank_reconciliation_statement import get_entries, get_amounts_not_reflected_in_system
+from erpnext.accounts.doctype.bank_transaction.bank_transaction import get_paid_amount
+
+
+class BankReconciliationTool(Document):
+	pass
+
+@frappe.whitelist()
+def get_bank_transactions(bank_account, from_date = None, to_date = None):
+	# returns bank transactions for a bank account
+	filters = []
+	filters.append(['bank_account', '=', bank_account])
+	filters.append(['docstatus', '=', 1])
+	filters.append(['unallocated_amount', '>', 0])
+	if to_date:
+		filters.append(['date', '<=', to_date])
+	if from_date:
+		filters.append(['date', '>=', from_date])
+	transactions = frappe.get_all(
+		'Bank Transaction',
+		fields = ['date', 'deposit', 'withdrawal', 'currency',
+		'description', 'name', 'bank_account', 'company',
+		'unallocated_amount', 'reference_number', 'party_type', 'party'],
+		filters = filters
+	)
+	return transactions
+
+@frappe.whitelist()
+def get_account_balance(bank_account, till_date):
+	# returns account balance till the specified date
+	account = frappe.db.get_value('Bank Account', bank_account, 'account')
+	filters = frappe._dict({
+		"account": account,
+		"report_date": till_date,
+		"include_pos_transactions": 1
+	})
+	data = get_entries(filters)
+
+	balance_as_per_system = get_balance_on(filters["account"], filters["report_date"])
+
+	total_debit, total_credit = 0,0
+	for d in data:
+		total_debit += flt(d.debit)
+		total_credit += flt(d.credit)
+
+	amounts_not_reflected_in_system = get_amounts_not_reflected_in_system(filters)
+
+	bank_bal = flt(balance_as_per_system) - flt(total_debit) + flt(total_credit) \
+		+ amounts_not_reflected_in_system
+
+	return bank_bal
+
+
+@frappe.whitelist()
+def update_bank_transaction(bank_transaction_name, reference_number, party_type=None, party=None):
+	# updates bank transaction based on the new parameters provided by the user from Vouchers
+	bank_transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
+	bank_transaction.reference_number = reference_number
+	bank_transaction.party_type = party_type
+	bank_transaction.party = party
+	bank_transaction.save()
+	return frappe.db.get_all('Bank Transaction',
+		filters={
+			'name': bank_transaction_name
+		},
+		fields=['date', 'deposit', 'withdrawal', 'currency',
+			'description', 'name', 'bank_account', 'company',
+			'unallocated_amount', 'reference_number',
+			 'party_type', 'party'],
+	)[0]
+
+
+@frappe.whitelist()
+def create_journal_entry_bts( bank_transaction_name, reference_number=None, reference_date=None, posting_date=None, entry_type=None,
+	second_account=None, mode_of_payment=None, party_type=None, party=None, allow_edit=None):
+	# Create a new journal entry based on the bank transaction
+	bank_transaction = frappe.db.get_values(
+		"Bank Transaction", bank_transaction_name,
+		fieldname=["name", "deposit", "withdrawal", "bank_account"] ,
+		as_dict=True
+	)[0]
+	company_account = frappe.get_value("Bank Account", bank_transaction.bank_account, "account")
+	account_type = frappe.db.get_value("Account", second_account, "account_type")
+	if account_type in ["Receivable", "Payable"]:
+		if not (party_type and party):
+			frappe.throw(_("Party Type and Party is required for Receivable / Payable account {0}").format( second_account))
+	accounts = []
+	# Multi Currency?
+	accounts.append({
+			"account": second_account,
+			"credit_in_account_currency": bank_transaction.deposit
+				if  bank_transaction.deposit > 0
+				else 0,
+			"debit_in_account_currency":bank_transaction.withdrawal
+				if  bank_transaction.withdrawal > 0
+				else 0,
+			"party_type":party_type,
+			"party":party,
+		})
+
+	accounts.append({
+			"account": company_account,
+			"bank_account": bank_transaction.bank_account,
+			"credit_in_account_currency": bank_transaction.withdrawal
+				if  bank_transaction.withdrawal > 0
+				else 0,
+			"debit_in_account_currency":bank_transaction.deposit
+				if  bank_transaction.deposit > 0
+				else 0,
+		})
+
+	company = frappe.get_value("Account", company_account, "company")
+
+	journal_entry_dict = {
+		"voucher_type" : entry_type,
+		"company" : company,
+		"posting_date" : posting_date,
+		"cheque_date" : reference_date,
+		"cheque_no" : reference_number,
+		"mode_of_payment" : mode_of_payment
+	}
+	journal_entry = frappe.new_doc('Journal Entry')
+	journal_entry.update(journal_entry_dict)
+	journal_entry.set("accounts", accounts)
+
+
+	if allow_edit:
+		return journal_entry
+
+	journal_entry.insert()
+	journal_entry.submit()
+
+	if bank_transaction.deposit > 0:
+		paid_amount = bank_transaction.deposit
+	else:
+		paid_amount = bank_transaction.withdrawal
+
+	vouchers = json.dumps([{
+		"payment_doctype":"Journal Entry",
+		"payment_name":journal_entry.name,
+		"amount":paid_amount}])
+
+	return reconcile_vouchers(bank_transaction.name, vouchers)
+
+@frappe.whitelist()
+def create_payment_entry_bts( bank_transaction_name, reference_number=None, reference_date=None, party_type=None, party=None, posting_date=None,
+	mode_of_payment=None, project=None, cost_center=None, allow_edit=None):
+	# Create a new payment entry based on the bank transaction
+	bank_transaction = frappe.db.get_values(
+		"Bank Transaction", bank_transaction_name,
+		fieldname=["name", "unallocated_amount", "deposit", "bank_account"] ,
+		as_dict=True
+	)[0]
+	paid_amount = bank_transaction.unallocated_amount
+	payment_type = "Receive" if bank_transaction.deposit > 0 else "Pay"
+
+	company_account = frappe.get_value("Bank Account", bank_transaction.bank_account, "account")
+	company = frappe.get_value("Account", company_account, "company")
+	payment_entry_dict = {
+		"company" : company,
+		"payment_type" : payment_type,
+		"reference_no" :  reference_number,
+		"reference_date" :  reference_date,
+		"party_type" :  party_type,
+		"party" :  party,
+		"posting_date" :  posting_date,
+		"paid_amount": paid_amount,
+		"received_amount": paid_amount
+	}
+	payment_entry = frappe.new_doc("Payment Entry")
+
+
+	payment_entry.update(payment_entry_dict)
+
+	if mode_of_payment:
+		payment_entry.mode_of_payment =  mode_of_payment
+	if project:
+		payment_entry.project =  project
+	if cost_center:
+		payment_entry.cost_center =  cost_center
+	if payment_type == "Receive":
+		payment_entry.paid_to = company_account
+	else:
+		payment_entry.paid_from = company_account
+
+	payment_entry.validate()
+
+	if allow_edit:
+		return payment_entry
+
+	payment_entry.insert()
+
+	payment_entry.submit()
+	vouchers = json.dumps([{
+		"payment_doctype":"Payment Entry",
+		"payment_name":payment_entry.name,
+		"amount":paid_amount}])
+	return reconcile_vouchers(bank_transaction.name, vouchers)
+
+@frappe.whitelist()
+def reconcile_vouchers(bank_transaction_name, vouchers):
+	# updated clear date of all the vouchers based on the bank transaction
+	vouchers = json.loads(vouchers)
+	transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
+	if transaction.unallocated_amount == 0:
+		frappe.throw(_("This bank transaction is already fully reconciled"))
+	total_amount = 0
+	for voucher in vouchers:
+		voucher['payment_entry'] = frappe.get_doc(voucher['payment_doctype'], voucher['payment_name'])
+		total_amount += get_paid_amount(frappe._dict({
+			'payment_document': voucher['payment_doctype'],
+			'payment_entry': voucher['payment_name'],
+		}), transaction.currency)
+
+	if total_amount > transaction.unallocated_amount:
+		frappe.throw(_("The Sum Total of Amounts of All Selected Vouchers Should be Less than the Unallocated Amount of the Bank Transaction"))
+	account = frappe.db.get_value("Bank Account", transaction.bank_account, "account")
+
+	for voucher in vouchers:
+		gl_entry = frappe.db.get_value("GL Entry", dict(account=account, voucher_type=voucher['payment_doctype'], voucher_no=voucher['payment_name']), ['credit', 'debit'], as_dict=1)
+		gl_amount, transaction_amount = (gl_entry.credit, transaction.deposit) if gl_entry.credit > 0 else (gl_entry.debit, transaction.withdrawal)
+		allocated_amount = gl_amount if gl_amount >= transaction_amount else transaction_amount
+
+		transaction.append("payment_entries", {
+			"payment_document": voucher['payment_entry'].doctype,
+			"payment_entry": voucher['payment_entry'].name,
+			"allocated_amount": allocated_amount
+		})
+
+	transaction.save()
+	transaction.update_allocations()
+	return frappe.get_doc("Bank Transaction", bank_transaction_name)
+
+@frappe.whitelist()
+def get_linked_payments(bank_transaction_name, document_types = None):
+	# get all matching payments for a bank transaction
+	transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
+	bank_account = frappe.db.get_values(
+		"Bank Account",
+		transaction.bank_account,
+		["account", "company"],
+		as_dict=True)[0]
+	(account, company) = (bank_account.account, bank_account.company)
+	matching = check_matching(account, company, transaction, document_types)
+	return matching
+
+def check_matching(bank_account, company, transaction, document_types):
+	# combine all types of vocuhers
+	subquery = get_queries(bank_account, company, transaction, document_types)
+	filters = {
+			"amount": transaction.unallocated_amount,
+			"payment_type" : "Receive" if transaction.deposit > 0 else "Pay",
+			"reference_no": transaction.reference_number,
+			"party_type": transaction.party_type,
+			"party": transaction.party,
+			"bank_account":  bank_account
+		}
+
+	matching_vouchers = []
+	for query in subquery:
+		matching_vouchers.extend(
+			frappe.db.sql(query, filters,)
+		)
+
+	return sorted(matching_vouchers, key = lambda x: x[0], reverse=True) if matching_vouchers else []
+
+def get_queries(bank_account, company, transaction, document_types):
+	# get queries to get matching vouchers
+	amount_condition = "=" if "exact_match" in document_types else "<="
+	account_from_to = "paid_to" if transaction.deposit > 0 else "paid_from"
+	queries = []
+
+	if "payment_entry" in document_types:
+		pe_amount_matching = get_pe_matching_query(amount_condition, account_from_to, transaction)
+		queries.extend([pe_amount_matching])
+
+	if "journal_entry" in document_types:
+		je_amount_matching = get_je_matching_query(amount_condition, transaction)
+		queries.extend([je_amount_matching])
+
+	if transaction.deposit > 0 and "sales_invoice" in document_types:
+		si_amount_matching =  get_si_matching_query(amount_condition)
+		queries.extend([si_amount_matching])
+
+	if transaction.withdrawal > 0:
+		if "purchase_invoice" in document_types:
+			pi_amount_matching = get_pi_matching_query(amount_condition)
+			queries.extend([pi_amount_matching])
+
+		if "expense_claim" in document_types:
+			ec_amount_matching = get_ec_matching_query(bank_account, company, amount_condition)
+			queries.extend([ec_amount_matching])
+
+	return queries
+
+def get_pe_matching_query(amount_condition, account_from_to, transaction):
+	# get matching payment entries query
+	if transaction.deposit > 0:
+		currency_field = "paid_to_account_currency as currency"
+	else:
+		currency_field = "paid_from_account_currency as currency"
+	return  f"""
+	SELECT
+		(CASE WHEN reference_no=%(reference_no)s THEN 1 ELSE 0 END
+		+ CASE WHEN (party_type = %(party_type)s AND party = %(party)s ) THEN 1 ELSE 0  END
+		+ 1 ) AS rank,
+		'Payment Entry' as doctype,
+		name,
+		paid_amount,
+		reference_no,
+		reference_date,
+		party,
+		party_type,
+		posting_date,
+		{currency_field}
+	FROM
+		`tabPayment Entry`
+	WHERE
+		paid_amount {amount_condition} %(amount)s
+		AND docstatus = 1
+		AND payment_type IN (%(payment_type)s, 'Internal Transfer')
+		AND ifnull(clearance_date, '') = ""
+		AND {account_from_to} = %(bank_account)s
+	"""
+
+
+def get_je_matching_query(amount_condition, transaction):
+	# get matching journal entry query
+	cr_or_dr = "credit" if transaction.withdrawal > 0 else "debit"
+	return f"""
+
+		SELECT
+			(CASE WHEN je.cheque_no=%(reference_no)s THEN 1 ELSE 0 END
+			+ 1) AS rank ,
+			'Journal Entry' as doctype,
+			je.name,
+			jea.{cr_or_dr}_in_account_currency as paid_amount,
+			je.cheque_no as reference_no,
+			je.cheque_date as reference_date,
+			je.pay_to_recd_from as party,
+			jea.party_type,
+			je.posting_date,
+			jea.account_currency as currency
+		FROM
+			`tabJournal Entry Account` as jea
+		JOIN
+			`tabJournal Entry` as je
+		ON
+			jea.parent = je.name
+		WHERE
+			(je.clearance_date is null or je.clearance_date='0000-00-00')
+			AND jea.account = %(bank_account)s
+			AND jea.{cr_or_dr}_in_account_currency {amount_condition} %(amount)s
+			AND je.docstatus = 1
+	"""
+
+
+def get_si_matching_query(amount_condition):
+	# get matchin sales invoice query
+	return f"""
+		SELECT
+			( CASE WHEN si.customer = %(party)s  THEN 1 ELSE 0  END
+			+ 1 ) AS rank,
+			'Sales Invoice' as doctype,
+			si.name,
+			sip.amount as paid_amount,
+			'' as reference_no,
+			'' as reference_date,
+			si.customer as party,
+			'Customer' as party_type,
+			si.posting_date,
+			si.currency
+
+		FROM
+			`tabSales Invoice Payment` as sip
+		JOIN
+			`tabSales Invoice` as si
+		ON
+			sip.parent = si.name
+		WHERE (sip.clearance_date is null or sip.clearance_date='0000-00-00')
+			AND sip.account = %(bank_account)s
+			AND sip.amount {amount_condition} %(amount)s
+			AND si.docstatus = 1
+	"""
+
+def get_pi_matching_query(amount_condition):
+	# get matching purchase invoice query
+	return f"""
+		SELECT
+			( CASE WHEN supplier = %(party)s THEN 1 ELSE 0 END
+			+ 1 ) AS rank,
+			'Purchase Invoice' as doctype,
+			name,
+			paid_amount,
+			'' as reference_no,
+			'' as reference_date,
+			supplier as party,
+			'Supplier' as party_type,
+			posting_date,
+			currency
+		FROM
+			`tabPurchase Invoice`
+		WHERE
+			paid_amount {amount_condition} %(amount)s
+			AND docstatus = 1
+			AND is_paid = 1
+			AND ifnull(clearance_date, '') = ""
+			AND cash_bank_account  = %(bank_account)s
+	"""
+
+def get_ec_matching_query(bank_account, company, amount_condition):
+	# get matching Expense Claim query
+	mode_of_payments = [x["parent"] for x in frappe.db.get_list("Mode of Payment Account",
+			filters={"default_account": bank_account}, fields=["parent"])]
+	mode_of_payments = '(\'' + '\', \''.join(mode_of_payments) + '\' )'
+	company_currency = get_company_currency(company)
+	return f"""
+		SELECT
+			( CASE WHEN employee = %(party)s THEN 1 ELSE 0 END
+			+ 1 ) AS rank,
+			'Expense Claim' as doctype,
+			name,
+			total_sanctioned_amount as paid_amount,
+			'' as reference_no,
+			'' as reference_date,
+			employee as party,
+			'Employee' as party_type,
+			posting_date,
+			'{company_currency}' as currency
+		FROM
+			`tabExpense Claim`
+		WHERE
+			total_sanctioned_amount {amount_condition} %(amount)s
+			AND docstatus = 1
+			AND is_paid = 1
+			AND ifnull(clearance_date, '') = ""
+			AND mode_of_payment in {mode_of_payments}
+	"""
diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/test_bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/test_bank_reconciliation_tool.py
new file mode 100644
index 0000000..d96950a
--- /dev/null
+++ b/erpnext/accounts/doctype/bank_reconciliation_tool/test_bank_reconciliation_tool.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+# import frappe
+import unittest
+
+class TestBankReconciliationTool(unittest.TestCase):
+	pass
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/accounts/doctype/bank_statement_import/__init__.py
similarity index 100%
rename from erpnext/accounts/doctype/bank_statement_settings/__init__.py
rename to erpnext/accounts/doctype/bank_statement_import/__init__.py
diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.css b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.css
new file mode 100644
index 0000000..5206540
--- /dev/null
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.css
@@ -0,0 +1,3 @@
+.warnings .warning {
+	margin-bottom: 40px;
+}
diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js
new file mode 100644
index 0000000..ad4ff9e
--- /dev/null
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js
@@ -0,0 +1,574 @@
+// Copyright (c) 2019, Frappe Technologies and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on("Bank Statement Import", {
+	setup(frm) {
+		frappe.realtime.on("data_import_refresh", ({ data_import }) => {
+			frm.import_in_progress = false;
+			if (data_import !== frm.doc.name) return;
+			frappe.model.clear_doc("Bank Statement Import", frm.doc.name);
+			frappe.model
+				.with_doc("Bank Statement Import", frm.doc.name)
+				.then(() => {
+					frm.refresh();
+				});
+		});
+		frappe.realtime.on("data_import_progress", (data) => {
+			frm.import_in_progress = true;
+			if (data.data_import !== frm.doc.name) {
+				return;
+			}
+			let percent = Math.floor((data.current * 100) / data.total);
+			let seconds = Math.floor(data.eta);
+			let minutes = Math.floor(data.eta / 60);
+			let eta_message =
+				// prettier-ignore
+				seconds < 60
+					? __('About {0} seconds remaining', [seconds])
+					: minutes === 1
+						? __('About {0} minute remaining', [minutes])
+						: __('About {0} minutes remaining', [minutes]);
+
+			let message;
+			if (data.success) {
+				let message_args = [data.current, data.total, eta_message];
+				message =
+					frm.doc.import_type === "Insert New Records"
+						? __("Importing {0} of {1}, {2}", message_args)
+						: __("Updating {0} of {1}, {2}", message_args);
+			}
+			if (data.skipping) {
+				message = __(
+					"Skipping {0} of {1}, {2}",
+					[
+						data.current,
+						data.total,
+						eta_message,
+					]
+				);
+			}
+			frm.dashboard.show_progress(
+				__("Import Progress"),
+				percent,
+				message
+			);
+			frm.page.set_indicator(__("In Progress"), "orange");
+
+			// hide progress when complete
+			if (data.current === data.total) {
+				setTimeout(() => {
+					frm.dashboard.hide();
+					frm.refresh();
+				}, 2000);
+			}
+		});
+
+		frm.set_query("reference_doctype", () => {
+			return {
+				filters: {
+					name: ["in", frappe.boot.user.can_import],
+				},
+			};
+		});
+
+		frm.get_field("import_file").df.options = {
+			restrictions: {
+				allowed_file_types: [".csv", ".xls", ".xlsx"],
+			},
+		};
+
+		frm.has_import_file = () => {
+			return frm.doc.import_file || frm.doc.google_sheets_url;
+		};
+	},
+
+	refresh(frm) {
+		frm.page.hide_icon_group();
+		frm.trigger("update_indicators");
+		frm.trigger("import_file");
+		frm.trigger("show_import_log");
+		frm.trigger("show_import_warnings");
+		frm.trigger("toggle_submit_after_import");
+		frm.trigger("show_import_status");
+		frm.trigger("show_report_error_button");
+
+		if (frm.doc.status === "Partial Success") {
+			frm.add_custom_button(__("Export Errored Rows"), () =>
+				frm.trigger("export_errored_rows")
+			);
+		}
+
+		if (frm.doc.status.includes("Success")) {
+			frm.add_custom_button(
+				__("Go to {0} List", [frm.doc.reference_doctype]),
+				() => frappe.set_route("List", frm.doc.reference_doctype)
+			);
+		}
+	},
+
+	onload_post_render(frm) {
+		frm.trigger("update_primary_action");
+	},
+
+	update_primary_action(frm) {
+		if (frm.is_dirty()) {
+			frm.enable_save();
+			return;
+		}
+		frm.disable_save();
+		if (frm.doc.status !== "Success") {
+			if (!frm.is_new() && frm.has_import_file()) {
+				let label =
+					frm.doc.status === "Pending"
+						? __("Start Import")
+						: __("Retry");
+				frm.page.set_primary_action(label, () =>
+					frm.events.start_import(frm)
+				);
+			} else {
+				frm.page.set_primary_action(__("Save"), () => frm.save());
+			}
+		}
+	},
+
+	update_indicators(frm) {
+		const indicator = frappe.get_indicator(frm.doc);
+		if (indicator) {
+			frm.page.set_indicator(indicator[0], indicator[1]);
+		} else {
+			frm.page.clear_indicator();
+		}
+	},
+
+	show_import_status(frm) {
+		let import_log = JSON.parse(frm.doc.import_log || "[]");
+		let successful_records = import_log.filter((log) => log.success);
+		let failed_records = import_log.filter((log) => !log.success);
+		if (successful_records.length === 0) return;
+
+		let message;
+		if (failed_records.length === 0) {
+			let message_args = [successful_records.length];
+			if (frm.doc.import_type === "Insert New Records") {
+				message =
+					successful_records.length > 1
+						? __("Successfully imported {0} records.", message_args)
+						: __("Successfully imported {0} record.", message_args);
+			} else {
+				message =
+					successful_records.length > 1
+						? __("Successfully updated {0} records.", message_args)
+						: __("Successfully updated {0} record.", message_args);
+			}
+		} else {
+			let message_args = [successful_records.length, import_log.length];
+			if (frm.doc.import_type === "Insert New Records") {
+				message =
+					successful_records.length > 1
+						? __(
+							"Successfully imported {0} records out of {1}. Click on Export Errored Rows, fix the errors and import again.",
+							message_args
+						)
+						: __(
+							"Successfully imported {0} record out of {1}. Click on Export Errored Rows, fix the errors and import again.",
+							message_args
+						);
+			} else {
+				message =
+					successful_records.length > 1
+						? __(
+							"Successfully updated {0} records out of {1}. Click on Export Errored Rows, fix the errors and import again.",
+							message_args
+						)
+						: __(
+							"Successfully updated {0} record out of {1}. Click on Export Errored Rows, fix the errors and import again.",
+							message_args
+						);
+			}
+		}
+		frm.dashboard.set_headline(message);
+	},
+
+	show_report_error_button(frm) {
+		if (frm.doc.status === "Error") {
+			frappe.db
+				.get_list("Error Log", {
+					filters: { method: frm.doc.name },
+					fields: ["method", "error"],
+					order_by: "creation desc",
+					limit: 1,
+				})
+				.then((result) => {
+					if (result.length > 0) {
+						frm.add_custom_button("Report Error", () => {
+							let fake_xhr = {
+								responseText: JSON.stringify({
+									exc: result[0].error,
+								}),
+							};
+							frappe.request.report_error(fake_xhr, {});
+						});
+					}
+				});
+		}
+	},
+
+	start_import(frm) {
+		frm.call({
+			method: "form_start_import",
+			args: { data_import: frm.doc.name },
+			btn: frm.page.btn_primary,
+		}).then((r) => {
+			if (r.message === true) {
+				frm.disable_save();
+			}
+		});
+	},
+
+	download_template() {
+		let method =
+			"/api/method/frappe.core.doctype.data_import.data_import.download_template";
+
+		open_url_post(method, {
+			doctype: "Bank Transaction",
+			export_records: "5_records",
+			export_fields: {
+				"Bank Transaction": [
+					"date",
+					"deposit",
+					"withdrawal",
+					"description",
+					"reference_number",
+				],
+			},
+		});
+	},
+
+	reference_doctype(frm) {
+		frm.trigger("toggle_submit_after_import");
+	},
+
+	toggle_submit_after_import(frm) {
+		frm.toggle_display("submit_after_import", false);
+		let doctype = frm.doc.reference_doctype;
+		if (doctype) {
+			frappe.model.with_doctype(doctype, () => {
+				let meta = frappe.get_meta(doctype);
+				frm.toggle_display("submit_after_import", meta.is_submittable);
+			});
+		}
+	},
+
+	google_sheets_url(frm) {
+		if (!frm.is_dirty()) {
+			frm.trigger("import_file");
+		} else {
+			frm.trigger("update_primary_action");
+		}
+	},
+
+	refresh_google_sheet(frm) {
+		frm.trigger("import_file");
+	},
+
+	import_file(frm) {
+		frm.toggle_display("section_import_preview", frm.has_import_file());
+		if (!frm.has_import_file()) {
+			frm.get_field("import_preview").$wrapper.empty();
+			return;
+		} else {
+			frm.trigger("update_primary_action");
+		}
+
+		// load import preview
+		frm.get_field("import_preview").$wrapper.empty();
+		$('<span class="text-muted">')
+			.html(__("Loading import file..."))
+			.appendTo(frm.get_field("import_preview").$wrapper);
+
+		frm.call({
+			method: "get_preview_from_template",
+			args: {
+				data_import: frm.doc.name,
+				import_file: frm.doc.import_file,
+				google_sheets_url: frm.doc.google_sheets_url,
+			},
+			error_handlers: {
+				TimestampMismatchError() {
+					// ignore this error
+				},
+			},
+		}).then((r) => {
+			let preview_data = r.message;
+			frm.events.show_import_preview(frm, preview_data);
+			frm.events.show_import_warnings(frm, preview_data);
+		});
+	},
+	// method: 'frappe.core.doctype.data_import.data_import.get_preview_from_template',
+
+	show_import_preview(frm, preview_data) {
+		let import_log = JSON.parse(frm.doc.import_log || "[]");
+
+		if (
+			frm.import_preview &&
+			frm.import_preview.doctype === frm.doc.reference_doctype
+		) {
+			frm.import_preview.preview_data = preview_data;
+			frm.import_preview.import_log = import_log;
+			frm.import_preview.refresh();
+			return;
+		}
+
+		frappe.require("/assets/js/data_import_tools.min.js", () => {
+			frm.import_preview = new frappe.data_import.ImportPreview({
+				wrapper: frm.get_field("import_preview").$wrapper,
+				doctype: frm.doc.reference_doctype,
+				preview_data,
+				import_log,
+				frm,
+				events: {
+					remap_column(changed_map) {
+						let template_options = JSON.parse(
+							frm.doc.template_options || "{}"
+						);
+						template_options.column_to_field_map =
+							template_options.column_to_field_map || {};
+						Object.assign(
+							template_options.column_to_field_map,
+							changed_map
+						);
+						frm.set_value(
+							"template_options",
+							JSON.stringify(template_options)
+						);
+						frm.save().then(() => frm.trigger("import_file"));
+					},
+				},
+			});
+		});
+	},
+
+	export_errored_rows(frm) {
+		open_url_post(
+			"/api/method/frappe.core.doctype.data_import.data_import.download_errored_template",
+			{
+				data_import_name: frm.doc.name,
+			}
+		);
+	},
+
+	show_import_warnings(frm, preview_data) {
+		let columns = preview_data.columns;
+		let warnings = JSON.parse(frm.doc.template_warnings || "[]");
+		warnings = warnings.concat(preview_data.warnings || []);
+
+		frm.toggle_display("import_warnings_section", warnings.length > 0);
+		if (warnings.length === 0) {
+			frm.get_field("import_warnings").$wrapper.html("");
+			return;
+		}
+
+		// group warnings by row
+		let warnings_by_row = {};
+		let other_warnings = [];
+		for (let warning of warnings) {
+			if (warning.row) {
+				warnings_by_row[warning.row] =
+					warnings_by_row[warning.row] || [];
+				warnings_by_row[warning.row].push(warning);
+			} else {
+				other_warnings.push(warning);
+			}
+		}
+
+		let html = "";
+		html += Object.keys(warnings_by_row)
+			.map((row_number) => {
+				let message = warnings_by_row[row_number]
+					.map((w) => {
+						if (w.field) {
+							let label =
+								w.field.label +
+								(w.field.parent !== frm.doc.reference_doctype
+									? ` (${w.field.parent})`
+									: "");
+							return `<li>${label}: ${w.message}</li>`;
+						}
+						return `<li>${w.message}</li>`;
+					})
+					.join("");
+				return `
+				<div class="warning" data-row="${row_number}">
+					<h5 class="text-uppercase">${__("Row {0}", [row_number])}</h5>
+					<div class="body"><ul>${message}</ul></div>
+				</div>
+			`;
+			})
+			.join("");
+
+		html += other_warnings
+			.map((warning) => {
+				let header = "";
+				if (warning.col) {
+					let column_number = `<span class="text-uppercase">${__(
+						"Column {0}",
+						[warning.col]
+					)}</span>`;
+					let column_header = columns[warning.col].header_title;
+					header = `${column_number} (${column_header})`;
+				}
+				return `
+					<div class="warning" data-col="${warning.col}">
+						<h5>${header}</h5>
+						<div class="body">${warning.message}</div>
+					</div>
+				`;
+			})
+			.join("");
+		frm.get_field("import_warnings").$wrapper.html(`
+			<div class="row">
+				<div class="col-sm-10 warnings">${html}</div>
+			</div>
+		`);
+	},
+
+	show_failed_logs(frm) {
+		frm.trigger("show_import_log");
+	},
+
+	show_import_log(frm) {
+		let import_log = JSON.parse(frm.doc.import_log || "[]");
+		let logs = import_log;
+		frm.toggle_display("import_log", false);
+		frm.toggle_display("import_log_section", logs.length > 0);
+
+		if (logs.length === 0) {
+			frm.get_field("import_log_preview").$wrapper.empty();
+			return;
+		}
+
+		let rows = logs
+			.map((log) => {
+				let html = "";
+				if (log.success) {
+					if (frm.doc.import_type === "Insert New Records") {
+						html = __(
+							"Successfully imported {0}", [
+								`<span class="underline">${frappe.utils.get_form_link(
+									frm.doc.reference_doctype,
+									log.docname,
+									true
+								)}<span>`,
+							]
+						);
+					} else {
+						html = __(
+							"Successfully updated {0}", [
+								`<span class="underline">${frappe.utils.get_form_link(
+									frm.doc.reference_doctype,
+									log.docname,
+									true
+								)}<span>`,
+							]
+						);
+					}
+				} else {
+					let messages = log.messages
+						.map(JSON.parse)
+						.map((m) => {
+							let title = m.title
+								? `<strong>${m.title}</strong>`
+								: "";
+							let message = m.message
+								? `<div>${m.message}</div>`
+								: "";
+							return title + message;
+						})
+						.join("");
+					let id = frappe.dom.get_unique_id();
+					html = `${messages}
+						<button class="btn btn-default btn-xs" type="button" data-toggle="collapse" data-target="#${id}" aria-expanded="false" aria-controls="${id}" style="margin-top: 15px;">
+							${__("Show Traceback")}
+						</button>
+						<div class="collapse" id="${id}" style="margin-top: 15px;">
+							<div class="well">
+								<pre>${log.exception}</pre>
+							</div>
+						</div>`;
+				}
+				let indicator_color = log.success ? "green" : "red";
+				let title = log.success ? __("Success") : __("Failure");
+
+				if (frm.doc.show_failed_logs && log.success) {
+					return "";
+				}
+
+				return `<tr>
+					<td>${log.row_indexes.join(", ")}</td>
+					<td>
+						<div class="indicator ${indicator_color}">${title}</div>
+					</td>
+					<td>
+						${html}
+					</td>
+				</tr>`;
+			})
+			.join("");
+
+		if (!rows && frm.doc.show_failed_logs) {
+			rows = `<tr><td class="text-center text-muted" colspan=3>
+				${__("No failed logs")}
+			</td></tr>`;
+		}
+
+		frm.get_field("import_log_preview").$wrapper.html(`
+			<table class="table table-bordered">
+				<tr class="text-muted">
+					<th width="10%">${__("Row Number")}</th>
+					<th width="10%">${__("Status")}</th>
+					<th width="80%">${__("Message")}</th>
+				</tr>
+				${rows}
+			</table>
+		`);
+	},
+
+	show_missing_link_values(frm, missing_link_values) {
+		let can_be_created_automatically = missing_link_values.every(
+			(d) => d.has_one_mandatory_field
+		);
+
+		let html = missing_link_values
+			.map((d) => {
+				let doctype = d.doctype;
+				let values = d.missing_values;
+				return `
+					<h5>${doctype}</h5>
+					<ul>${values.map((v) => `<li>${v}</li>`).join("")}</ul>
+				`;
+			})
+			.join("");
+
+		if (can_be_created_automatically) {
+			// prettier-ignore
+			let message = __('There are some linked records which needs to be created before we can import your file. Do you want to create the following missing records automatically?');
+			frappe.confirm(message + html, () => {
+				frm.call("create_missing_link_values", {
+					missing_link_values,
+				}).then((r) => {
+					let records = r.message;
+					frappe.msgprint(__(
+						"Created {0} records successfully.", [
+							records.length,
+						]
+					));
+				});
+			});
+		} else {
+			frappe.msgprint(
+				// prettier-ignore
+				__('The following records needs to be created before we can import your file.') + html
+			);
+		}
+	},
+});
diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json
new file mode 100644
index 0000000..5e913cc
--- /dev/null
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json
@@ -0,0 +1,227 @@
+{
+ "actions": [],
+ "autoname": "format:Bank Statement Import on {creation}",
+ "beta": 1,
+ "creation": "2019-08-04 14:16:08.318714",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "company",
+  "bank_account",
+  "bank",
+  "column_break_4",
+  "google_sheets_url",
+  "refresh_google_sheet",
+  "html_5",
+  "import_file",
+  "download_template",
+  "status",
+  "template_options",
+  "import_warnings_section",
+  "template_warnings",
+  "import_warnings",
+  "section_import_preview",
+  "import_preview",
+  "import_log_section",
+  "import_log",
+  "show_failed_logs",
+  "import_log_preview",
+  "reference_doctype",
+  "import_type",
+  "submit_after_import",
+  "mute_emails"
+ ],
+ "fields": [
+  {
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "label": "Company",
+   "options": "Company",
+   "reqd": 1,
+   "set_only_once": 1
+  },
+  {
+   "fieldname": "bank_account",
+   "fieldtype": "Link",
+   "label": "Bank Account",
+   "options": "Bank Account",
+   "reqd": 1,
+   "set_only_once": 1
+  },
+  {
+   "depends_on": "eval:doc.bank_account",
+   "fetch_from": "bank_account.bank",
+   "fieldname": "bank",
+   "fieldtype": "Link",
+   "label": "Bank",
+   "options": "Bank",
+   "read_only": 1,
+   "set_only_once": 1
+  },
+  {
+   "depends_on": "eval:!doc.__islocal",
+   "fieldname": "download_template",
+   "fieldtype": "Button",
+   "label": "Download Template"
+  },
+  {
+   "depends_on": "eval:!doc.__islocal",
+   "fieldname": "import_file",
+   "fieldtype": "Attach",
+   "in_list_view": 1,
+   "label": "Import File"
+  },
+  {
+   "fieldname": "import_preview",
+   "fieldtype": "HTML",
+   "label": "Import Preview"
+  },
+  {
+   "fieldname": "section_import_preview",
+   "fieldtype": "Section Break",
+   "label": "Preview"
+  },
+  {
+   "fieldname": "template_options",
+   "fieldtype": "Code",
+   "hidden": 1,
+   "label": "Template Options",
+   "options": "JSON",
+   "read_only": 1
+  },
+  {
+   "fieldname": "import_log",
+   "fieldtype": "Code",
+   "label": "Import Log",
+   "options": "JSON"
+  },
+  {
+   "fieldname": "import_log_section",
+   "fieldtype": "Section Break",
+   "label": "Import Log"
+  },
+  {
+   "fieldname": "import_log_preview",
+   "fieldtype": "HTML",
+   "label": "Import Log Preview"
+  },
+  {
+   "default": "Pending",
+   "fieldname": "status",
+   "fieldtype": "Select",
+   "hidden": 1,
+   "label": "Status",
+   "options": "Pending\nSuccess\nPartial Success\nError",
+   "read_only": 1
+  },
+  {
+   "fieldname": "template_warnings",
+   "fieldtype": "Code",
+   "hidden": 1,
+   "label": "Template Warnings",
+   "options": "JSON"
+  },
+  {
+   "fieldname": "import_warnings_section",
+   "fieldtype": "Section Break",
+   "label": "Import File Errors and Warnings"
+  },
+  {
+   "fieldname": "import_warnings",
+   "fieldtype": "HTML",
+   "label": "Import Warnings"
+  },
+  {
+   "default": "0",
+   "fieldname": "show_failed_logs",
+   "fieldtype": "Check",
+   "label": "Show Failed Logs"
+  },
+  {
+   "depends_on": "eval:!doc.__islocal && !doc.import_file",
+   "fieldname": "html_5",
+   "fieldtype": "HTML",
+   "options": "<h5 class=\"text-muted uppercase\">Or</h5>"
+  },
+  {
+   "depends_on": "eval:!doc.__islocal && !doc.import_file\n",
+   "description": "Must be a publicly accessible Google Sheets URL",
+   "fieldname": "google_sheets_url",
+   "fieldtype": "Data",
+   "label": "Import from Google Sheets"
+  },
+  {
+   "depends_on": "eval:doc.google_sheets_url && !doc.__unsaved",
+   "fieldname": "refresh_google_sheet",
+   "fieldtype": "Button",
+   "label": "Refresh Google Sheet"
+  },
+  {
+   "default": "Bank Transaction",
+   "fieldname": "reference_doctype",
+   "fieldtype": "Link",
+   "hidden": 1,
+   "in_list_view": 1,
+   "label": "Document Type",
+   "options": "DocType",
+   "reqd": 1,
+   "set_only_once": 1
+  },
+  {
+   "default": "Insert New Records",
+   "fieldname": "import_type",
+   "fieldtype": "Select",
+   "hidden": 1,
+   "in_list_view": 1,
+   "label": "Import Type",
+   "options": "\nInsert New Records\nUpdate Existing Records",
+   "reqd": 1,
+   "set_only_once": 1
+  },
+  {
+   "default": "1",
+   "fieldname": "submit_after_import",
+   "fieldtype": "Check",
+   "hidden": 1,
+   "label": "Submit After Import",
+   "set_only_once": 1
+  },
+  {
+   "default": "1",
+   "fieldname": "mute_emails",
+   "fieldtype": "Check",
+   "hidden": 1,
+   "label": "Don't Send Emails",
+   "set_only_once": 1
+  },
+  {
+   "fieldname": "column_break_4",
+   "fieldtype": "Column Break"
+  }
+ ],
+ "hide_toolbar": 1,
+ "links": [],
+ "modified": "2021-02-10 19:29:59.027325",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Bank Statement Import",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
+   "write": 1
+  }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py
new file mode 100644
index 0000000..9f41b13
--- /dev/null
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py
@@ -0,0 +1,205 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import csv
+import json
+import re
+
+import openpyxl
+from openpyxl.styles import Font
+from openpyxl.utils import get_column_letter
+from six import string_types
+
+import frappe
+from frappe.core.doctype.data_import.importer import Importer, ImportFile
+from frappe.utils.background_jobs import enqueue
+from frappe.utils.xlsxutils import handle_html, ILLEGAL_CHARACTERS_RE
+from frappe import _
+
+from frappe.core.doctype.data_import.data_import import DataImport
+
+class BankStatementImport(DataImport):
+	def __init__(self, *args, **kwargs):
+		super(BankStatementImport, self).__init__(*args, **kwargs)
+
+	def validate(self):
+		doc_before_save = self.get_doc_before_save()
+		if (
+			not (self.import_file or self.google_sheets_url)
+			or (doc_before_save and doc_before_save.import_file != self.import_file)
+			or (doc_before_save and doc_before_save.google_sheets_url != self.google_sheets_url)
+		):
+
+			template_options_dict = {}
+			column_to_field_map = {}
+			bank = frappe.get_doc("Bank", self.bank)
+			for i in bank.bank_transaction_mapping:
+				column_to_field_map[i.file_field] = i.bank_transaction_field
+			template_options_dict["column_to_field_map"] = column_to_field_map
+			self.template_options = json.dumps(template_options_dict)
+
+			self.template_warnings = ""
+
+		self.validate_import_file()
+		self.validate_google_sheets_url()
+
+	def start_import(self):
+
+		from frappe.core.page.background_jobs.background_jobs import get_info
+		from frappe.utils.scheduler import is_scheduler_inactive
+
+		if is_scheduler_inactive() and not frappe.flags.in_test:
+			frappe.throw(
+				_("Scheduler is inactive. Cannot import data."), title=_("Scheduler Inactive")
+			)
+
+		enqueued_jobs = [d.get("job_name") for d in get_info()]
+
+		if self.name not in enqueued_jobs:
+			enqueue(
+				start_import,
+				queue="default",
+				timeout=6000,
+				event="data_import",
+				job_name=self.name,
+				data_import=self.name,
+				bank_account=self.bank_account,
+				import_file_path=self.import_file,
+				bank=self.bank,
+				template_options=self.template_options,
+				now=frappe.conf.developer_mode or frappe.flags.in_test,
+			)
+			return True
+
+		return False
+
+@frappe.whitelist()
+def get_preview_from_template(data_import, import_file=None, google_sheets_url=None):
+	return frappe.get_doc("Bank Statement Import", data_import).get_preview_from_template(
+		import_file, google_sheets_url
+	)
+
+@frappe.whitelist()
+def form_start_import(data_import):
+	return frappe.get_doc("Bank Statement Import", data_import).start_import()
+
+@frappe.whitelist()
+def download_errored_template(data_import_name):
+	data_import = frappe.get_doc("Bank Statement Import", data_import_name)
+	data_import.export_errored_rows()
+
+def start_import(data_import, bank_account, import_file_path, bank, template_options):
+	"""This method runs in background job"""
+
+	update_mapping_db(bank, template_options)
+
+	data_import = frappe.get_doc("Bank Statement Import", data_import)
+
+	import_file = ImportFile("Bank Transaction", file = import_file_path, import_type="Insert New Records")
+	data = import_file.raw_data
+
+	add_bank_account(data, bank_account)
+	write_files(import_file, data)
+
+	try:
+		i = Importer(data_import.reference_doctype, data_import=data_import)
+		i.import_data()
+	except Exception:
+		frappe.db.rollback()
+		data_import.db_set("status", "Error")
+		frappe.log_error(title=data_import.name)
+	finally:
+		frappe.flags.in_import = False
+
+	frappe.publish_realtime("data_import_refresh", {"data_import": data_import.name})
+
+def update_mapping_db(bank, template_options):
+	bank = frappe.get_doc("Bank", bank)
+	for d in bank.bank_transaction_mapping:
+		d.delete()
+
+	for d in json.loads(template_options)["column_to_field_map"].items():
+		bank.append("bank_transaction_mapping", {"bank_transaction_field":  d[1] ,"file_field": d[0]} )
+
+	bank.save()
+
+def add_bank_account(data, bank_account):
+	bank_account_loc = None
+	if "Bank Account" not in data[0]:
+		data[0].append("Bank Account")
+	else:
+		for loc, header in enumerate(data[0]):
+			if header == "Bank Account":
+				bank_account_loc = loc
+
+	for row in data[1:]:
+		if bank_account_loc:
+			row[bank_account_loc] = bank_account
+		else:
+			row.append(bank_account)
+
+def write_files(import_file, data):
+	full_file_path = import_file.file_doc.get_full_path()
+	parts = import_file.file_doc.get_extension()
+	extension = parts[1]
+	extension = extension.lstrip(".")
+
+	if extension == "csv":
+		with open(full_file_path, 'w', newline='') as file:
+			writer = csv.writer(file)
+			writer.writerows(data)
+	elif extension == "xlsx" or "xls":
+		write_xlsx(data, "trans", file_path = full_file_path)
+
+def write_xlsx(data, sheet_name, wb=None, column_widths=None, file_path=None):
+	# from xlsx utils with changes
+	column_widths = column_widths or []
+	if wb is None:
+		wb = openpyxl.Workbook(write_only=True)
+
+	ws = wb.create_sheet(sheet_name, 0)
+
+	for i, column_width in enumerate(column_widths):
+		if column_width:
+			ws.column_dimensions[get_column_letter(i + 1)].width = column_width
+
+	row1 = ws.row_dimensions[1]
+	row1.font = Font(name='Calibri', bold=True)
+
+	for row in data:
+		clean_row = []
+		for item in row:
+			if isinstance(item, string_types) and (sheet_name not in ['Data Import Template', 'Data Export']):
+				value = handle_html(item)
+			else:
+				value = item
+
+			if isinstance(item, string_types) and next(ILLEGAL_CHARACTERS_RE.finditer(value), None):
+				# Remove illegal characters from the string
+				value = re.sub(ILLEGAL_CHARACTERS_RE, '', value)
+
+			clean_row.append(value)
+
+		ws.append(clean_row)
+
+	wb.save(file_path)
+	return True
+
+@frappe.whitelist()
+def upload_bank_statement(**args):
+	args = frappe._dict(args)
+	bsi = frappe.new_doc("Bank Statement Import")
+
+	if args.company:
+		bsi.update({
+			"company": args.company,
+		})
+
+	if args.bank_account:
+		bsi.update({
+			"bank_account": args.bank_account
+		})
+
+	return bsi
diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import_list.js b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import_list.js
new file mode 100644
index 0000000..6c75402
--- /dev/null
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import_list.js
@@ -0,0 +1,36 @@
+let imports_in_progress = [];
+
+frappe.listview_settings['Bank Statement Import'] = {
+	onload(listview) {
+		frappe.realtime.on('data_import_progress', data => {
+			if (!imports_in_progress.includes(data.data_import)) {
+				imports_in_progress.push(data.data_import);
+			}
+		});
+		frappe.realtime.on('data_import_refresh', data => {
+			imports_in_progress = imports_in_progress.filter(
+				d => d !== data.data_import
+			);
+			listview.refresh();
+		});
+	},
+	get_indicator: function(doc) {
+		var colors = {
+			'Pending': 'orange',
+			'Not Started': 'orange',
+			'Partial Success': 'orange',
+			'Success': 'green',
+			'In Progress': 'orange',
+			'Error': 'red'
+		};
+		let status = doc.status;
+		if (imports_in_progress.includes(doc.name)) {
+			status = 'In Progress';
+		}
+		if (status == 'Pending') {
+			status = 'Not Started';
+		}
+		return [__(status), colors[status], 'status,=,' + doc.status];
+	},
+	hide_name_column: true
+};
diff --git a/erpnext/accounts/doctype/bank_statement_import/test_bank_statement_import.py b/erpnext/accounts/doctype/bank_statement_import/test_bank_statement_import.py
new file mode 100644
index 0000000..cd58314
--- /dev/null
+++ b/erpnext/accounts/doctype/bank_statement_import/test_bank_statement_import.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+# import frappe
+import unittest
+
+class TestBankStatementImport(unittest.TestCase):
+	pass
diff --git a/erpnext/accounts/doctype/bank_statement_settings/bank_statement_settings.js b/erpnext/accounts/doctype/bank_statement_settings/bank_statement_settings.js
deleted file mode 100644
index 46aa4f2..0000000
--- a/erpnext/accounts/doctype/bank_statement_settings/bank_statement_settings.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2017, sathishpy@gmail.com and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Bank Statement Settings', {
-	refresh: function(frm) {
-
-	}
-});
diff --git a/erpnext/accounts/doctype/bank_statement_settings/bank_statement_settings.json b/erpnext/accounts/doctype/bank_statement_settings/bank_statement_settings.json
deleted file mode 100644
index 53fbf7d..0000000
--- a/erpnext/accounts/doctype/bank_statement_settings/bank_statement_settings.json
+++ /dev/null
@@ -1,272 +0,0 @@
-{
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 1, 
- "beta": 0, 
- "creation": "2017-11-13 13:38:10.863592", 
- "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": "bank", 
-   "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": "Bank Account", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Bank", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "default": "'%d/%m/%Y'", 
-   "fieldname": "date_format", 
-   "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": "Date Format", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "statement_header_mapping", 
-   "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": "Statement Header Mapping", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "header_items", 
-   "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": "Statement Headers", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Bank Statement Settings Item", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "transaction_data_mapping", 
-   "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": "Transaction Data Mapping", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "mapped_items", 
-   "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": "Mapped Items", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Bank Statement Transaction Settings Item", 
-   "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, 
-   "translatable": 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": "2018-04-07 18:57:04.048423", 
- "modified_by": "Administrator", 
- "module": "Accounts", 
- "name": "Bank Statement Settings", 
- "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
-  }
- ], 
- "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/bank_statement_settings/bank_statement_settings.py b/erpnext/accounts/doctype/bank_statement_settings/bank_statement_settings.py
deleted file mode 100644
index 6c4dd1b..0000000
--- a/erpnext/accounts/doctype/bank_statement_settings/bank_statement_settings.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, sathishpy@gmail.com and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
-
-class BankStatementSettings(Document):
-	def autoname(self):
-		self.name = self.bank + "-Statement-Settings"
diff --git a/erpnext/accounts/doctype/bank_statement_settings/test_bank_statement_settings.js b/erpnext/accounts/doctype/bank_statement_settings/test_bank_statement_settings.js
deleted file mode 100644
index f2381c0..0000000
--- a/erpnext/accounts/doctype/bank_statement_settings/test_bank_statement_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Bank Statement Settings", function (assert) {
-	let done = assert.async();
-
-	// number of asserts
-	assert.expect(1);
-
-	frappe.run_serially([
-		// insert a new Bank Statement Settings
-		() => frappe.tests.make('Bank Statement Settings', [
-			// values to be set
-			{key: 'value'}
-		]),
-		() => {
-			assert.equal(cur_frm.doc.key, 'value');
-		},
-		() => done()
-	]);
-
-});
diff --git a/erpnext/accounts/doctype/bank_statement_settings/test_bank_statement_settings.py b/erpnext/accounts/doctype/bank_statement_settings/test_bank_statement_settings.py
deleted file mode 100644
index aa7fe83..0000000
--- a/erpnext/accounts/doctype/bank_statement_settings/test_bank_statement_settings.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, sathishpy@gmail.com and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import frappe
-import unittest
-
-class TestBankStatementSettings(unittest.TestCase):
-	pass
diff --git a/erpnext/accounts/doctype/bank_statement_settings_item/bank_statement_settings_item.json b/erpnext/accounts/doctype/bank_statement_settings_item/bank_statement_settings_item.json
deleted file mode 100644
index 7c93f26..0000000
--- a/erpnext/accounts/doctype/bank_statement_settings_item/bank_statement_settings_item.json
+++ /dev/null
@@ -1,101 +0,0 @@
-{
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "beta": 0, 
- "creation": "2018-01-08 00:16:42.762980", 
- "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": "mapped_header", 
-   "fieldtype": "Data", 
-   "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": "Mapped Header", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "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": 0, 
-   "fieldname": "stmt_header", 
-   "fieldtype": "Data", 
-   "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": "Bank Header", 
-   "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": 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": "2018-01-08 00:19:14.841134", 
- "modified_by": "Administrator", 
- "module": "Accounts", 
- "name": "Bank Statement Settings Item", 
- "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/bank_statement_settings_item/bank_statement_settings_item.py b/erpnext/accounts/doctype/bank_statement_settings_item/bank_statement_settings_item.py
deleted file mode 100644
index 9438e9a..0000000
--- a/erpnext/accounts/doctype/bank_statement_settings_item/bank_statement_settings_item.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2018, sathishpy@gmail.com and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
-
-class BankStatementSettingsItem(Document):
-	pass
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_entry/__init__.py b/erpnext/accounts/doctype/bank_statement_transaction_entry/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_entry/__init__.py
+++ /dev/null
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_entry/bank_statement_transaction_entry.js b/erpnext/accounts/doctype/bank_statement_transaction_entry/bank_statement_transaction_entry.js
deleted file mode 100644
index 736ed35..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_entry/bank_statement_transaction_entry.js
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright (c) 2017, sathishpy@gmail.com and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Bank Statement Transaction Entry', {
-	setup: function(frm) {
-		frm.events.account_filters(frm)
-		frm.events.invoice_filter(frm)
-	},
-	refresh: function(frm) {
-		frm.set_df_property("bank_account", "read_only", frm.doc.__islocal ? 0 : 1);
-		frm.set_df_property("from_date", "read_only", frm.doc.__islocal ? 0 : 1);
-		frm.set_df_property("to_date", "read_only", frm.doc.__islocal ? 0 : 1);
-	},
-	invoke_doc_function(frm, method) {
-		frappe.call({
-			doc: frm.doc,
-			method: method,
-			callback: function(r) {
-				if(!r.exe) {
-					frm.refresh_fields();
-				}
-			}
-		});
-	},
-	account_filters: function(frm) {
-		frm.fields_dict['bank_account'].get_query = function(doc, dt, dn) {
-			return {
-				filters:[
-					["Account", "account_type", "in", ["Bank"]]
-				]
-			}
-		};
-		frm.fields_dict['receivable_account'].get_query = function(doc, dt, dn) {
-			return {
-				filters: {"account_type": "Receivable"}
-			}
-		};
-		frm.fields_dict['payable_account'].get_query = function(doc, dt, dn) {
-			return {
-				filters: {"account_type": "Payable"}
-			}
-		};
-	},
-
-	invoice_filter: function(frm) {
-		frm.set_query("invoice", "payment_invoice_items", function(doc, cdt, cdn) {
-			let row = locals[cdt][cdn]
-			if (row.party_type == "Customer") {
-				return {
-					filters:[[row.invoice_type, "customer", "in", [row.party]],
-									[row.invoice_type, "status", "!=", "Cancelled" ],
-									[row.invoice_type, "posting_date", "<", row.transaction_date ],
-									[row.invoice_type, "outstanding_amount", ">", 0 ]]
-				}
-			} else if (row.party_type == "Supplier") {
-				return {
-					filters:[[row.invoice_type, "supplier", "in", [row.party]],
-									[row.invoice_type, "status", "!=", "Cancelled" ],
-									[row.invoice_type, "posting_date", "<", row.transaction_date ],
-									[row.invoice_type, "outstanding_amount", ">", 0 ]]
-				}
-			}
-		});
-	},
-
-	match_invoices: function(frm) {
-		frm.events.invoke_doc_function(frm, "populate_matching_invoices");
-	},
-	create_payments: function(frm) {
-		frm.events.invoke_doc_function(frm, "create_payment_entries");
-	},
-	submit_payments: function(frm) {
-		frm.events.invoke_doc_function(frm, "submit_payment_entries");
-	},
-});
-
-
-frappe.ui.form.on('Bank Statement Transaction Invoice Item', {
-	party_type: function(frm, cdt, cdn) {
-		let row = locals[cdt][cdn];
-		if (row.party_type == "Customer") {
-			row.invoice_type = "Sales Invoice";
-		} else if (row.party_type == "Supplier") {
-			row.invoice_type = "Purchase Invoice";
-		} else if (row.party_type == "Account") {
-			row.invoice_type = "Journal Entry";
-		}
-		refresh_field("invoice_type", row.name, "payment_invoice_items");
-
-	},
-	invoice_type: function(frm, cdt, cdn) {
-		let row = locals[cdt][cdn];
-		if (row.invoice_type == "Purchase Invoice") {
-			row.party_type = "Supplier";
-		} else if (row.invoice_type == "Sales Invoice") {
-			row.party_type = "Customer";
-		}
-		refresh_field("party_type", row.name, "payment_invoice_items");
-	}
-});
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_entry/bank_statement_transaction_entry.json b/erpnext/accounts/doctype/bank_statement_transaction_entry/bank_statement_transaction_entry.json
deleted file mode 100644
index fb80169..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_entry/bank_statement_transaction_entry.json
+++ /dev/null
@@ -1,792 +0,0 @@
-{
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 1, 
- "beta": 0, 
- "creation": "2017-11-07 13:48:13.123185", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 1, 
- "engine": "InnoDB", 
- "fields": [
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "bank_account", 
-   "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": "Bank Account", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Account", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "from_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": "From 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": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "to_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": "To 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": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "bank_settings", 
-   "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": "Bank Statement Settings", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Bank Statement Settings", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "bank", 
-   "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": "Bank", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Bank", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "receivable_account", 
-   "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": "Receivable Account", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Account", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "payable_account", 
-   "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": "Payable Account", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Account", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "bank_statement", 
-   "fieldtype": "Attach", 
-   "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": "Bank Statement", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "depends_on": "", 
-   "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, 
-   "label": "Bank Transaction Entries", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "new_transaction_items", 
-   "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": "New Transactions", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Bank Statement Transaction Payment Item", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "depends_on": "eval:doc.new_transaction_items && doc.new_transaction_items.length", 
-   "fieldname": "section_break_9", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "depends_on": "", 
-   "fieldname": "match_invoices", 
-   "fieldtype": "Button", 
-   "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": "Match Transaction to Invoices", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break_14", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "create_payments", 
-   "fieldtype": "Button", 
-   "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": "Create New Payment/Journal Entry", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break_16", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "submit_payments", 
-   "fieldtype": "Button", 
-   "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": "Submit/Reconcile Payments", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "depends_on": "eval:doc.new_transaction_items && doc.new_transaction_items.length", 
-   "fieldname": "section_break_18", 
-   "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": "Matching Invoices", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "payment_invoice_items", 
-   "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 Invoice Items", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Bank Statement Transaction Invoice Item", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "reconciled_transactions", 
-   "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": "Reconciled Transactions", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "reconciled_transaction_items", 
-   "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": "Reconciled Transactions", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Bank Statement Transaction Payment Item", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "amended_from", 
-   "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": "Amended From", 
-   "length": 0, 
-   "no_copy": 1, 
-   "options": "Bank Statement Transaction Entry", 
-   "permlevel": 0, 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }
- ], 
- "has_web_view": 0, 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "idx": 0, 
- "image_view": 0, 
- "in_create": 0, 
- "is_submittable": 1, 
- "issingle": 0, 
- "istable": 0, 
- "max_attachments": 0, 
- "modified": "2018-09-14 18:04:44.170455", 
- "modified_by": "Administrator", 
- "module": "Accounts", 
- "name": "Bank Statement Transaction Entry", 
- "name_case": "", 
- "owner": "Administrator", 
- "permissions": [
-  {
-   "amend": 1, 
-   "cancel": 1, 
-   "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": 1, 
-   "write": 1
-  }, 
-  {
-   "amend": 1, 
-   "cancel": 1, 
-   "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": 1, 
-   "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/bank_statement_transaction_entry/bank_statement_transaction_entry.py b/erpnext/accounts/doctype/bank_statement_transaction_entry/bank_statement_transaction_entry.py
deleted file mode 100644
index 27dd8e4..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_entry/bank_statement_transaction_entry.py
+++ /dev/null
@@ -1,443 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, sathishpy@gmail.com and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe import _
-from frappe.model.document import Document
-from erpnext.accounts.utils import get_outstanding_invoices
-from frappe.utils import nowdate
-from datetime import datetime
-import csv, os, re, io
-import difflib
-import copy
-
-class BankStatementTransactionEntry(Document):
-	def autoname(self):
-		self.name = self.bank_account + "-" + self.from_date + "-" + self.to_date
-		if self.bank:
-			mapper_name = self.bank + "-Statement-Settings"
-			if not frappe.db.exists("Bank Statement Settings", mapper_name):
-				self.create_settings(self.bank)
-			self.bank_settings = mapper_name
-
-	def create_settings(self, bank):
-		mapper = frappe.new_doc("Bank Statement Settings")
-		mapper.bank = bank
-		mapper.date_format = "%Y-%m-%d"
-		mapper.bank_account = self.bank_account
-		for header in ["Date", "Particulars", "Withdrawals", "Deposits", "Balance"]:
-			header_item = mapper.append("header_items", {})
-			header_item.mapped_header = header_item.stmt_header = header
-		mapper.save()
-
-	def on_update(self):
-		if (not self.bank_statement):
-			self.reconciled_transaction_items = self.new_transaction_items = []
-			return
-
-		if len(self.new_transaction_items + self.reconciled_transaction_items) == 0:
-			self.populate_payment_entries()
-		else:
-			self.match_invoice_to_payment()
-
-	def validate(self):
-		if not self.new_transaction_items:
-			self.populate_payment_entries()
-
-	def get_statement_headers(self):
-		if not self.bank_settings:
-			frappe.throw(_("Bank Data mapper doesn't exist"))
-		mapper_doc = frappe.get_doc("Bank Statement Settings", self.bank_settings)
-		headers = {entry.mapped_header:entry.stmt_header for entry in mapper_doc.header_items}
-		return headers
-
-	def populate_payment_entries(self):
-		if self.bank_statement is None: return
-		file_url = self.bank_statement
-		if (len(self.new_transaction_items + self.reconciled_transaction_items) > 0):
-			frappe.throw(_("Transactions already retreived from the statement"))
-
-		date_format = frappe.get_value("Bank Statement Settings", self.bank_settings, "date_format")
-		if (date_format is None):
-			date_format = '%Y-%m-%d'
-		if self.bank_settings:
-			mapped_items = frappe.get_doc("Bank Statement Settings", self.bank_settings).mapped_items
-		statement_headers = self.get_statement_headers()
-		transactions = get_transaction_entries(file_url, statement_headers)
-		for entry in transactions:
-			date = entry[statement_headers["Date"]].strip()
-			#print("Processing entry DESC:{0}-W:{1}-D:{2}-DT:{3}".format(entry["Particulars"], entry["Withdrawals"], entry["Deposits"], entry["Date"]))
-			if (not date): continue
-			transaction_date = datetime.strptime(date, date_format).date()
-			if (self.from_date and transaction_date < datetime.strptime(self.from_date, '%Y-%m-%d').date()): continue
-			if (self.to_date and transaction_date > datetime.strptime(self.to_date, '%Y-%m-%d').date()): continue
-			bank_entry = self.append('new_transaction_items', {})
-			bank_entry.transaction_date = transaction_date
-			bank_entry.description = entry[statement_headers["Particulars"]]
-
-			mapped_item = next((entry for entry in mapped_items if entry.mapping_type == "Transaction" and frappe.safe_decode(entry.bank_data.lower()) in frappe.safe_decode(bank_entry.description.lower())), None)
-			if (mapped_item is not None):
-				bank_entry.party_type = mapped_item.mapped_data_type
-				bank_entry.party = mapped_item.mapped_data
-			else:
-				bank_entry.party_type = "Supplier" if not entry[statement_headers["Deposits"]].strip() else "Customer"
-				party_list = frappe.get_all(bank_entry.party_type, fields=["name"])
-				parties = [party.name for party in party_list]
-				matches = difflib.get_close_matches(frappe.safe_decode(bank_entry.description.lower()), parties, 1, 0.4)
-				if len(matches) > 0: bank_entry.party = matches[0]
-			bank_entry.amount = -float(entry[statement_headers["Withdrawals"]]) if not entry[statement_headers["Deposits"]].strip() else float(entry[statement_headers["Deposits"]])
-		self.map_unknown_transactions()
-		self.map_transactions_on_journal_entry()
-
-	def map_transactions_on_journal_entry(self):
-		for entry in self.new_transaction_items:
-			vouchers = frappe.db.sql("""select name, posting_date from `tabJournal Entry`
-										where posting_date='{0}' and total_credit={1} and cheque_no='{2}' and docstatus != 2
-									""".format(entry.transaction_date, abs(entry.amount), frappe.safe_decode(entry.description)), as_dict=True)
-			if (len(vouchers) == 1):
-				entry.reference_name = vouchers[0].name
-
-	def populate_matching_invoices(self):
-		self.payment_invoice_items = []
-		self.map_unknown_transactions()
-		added_invoices = []
-		for entry in self.new_transaction_items:
-			if (not entry.party or entry.party_type == "Account"): continue
-			account = self.receivable_account if entry.party_type == "Customer" else self.payable_account
-			invoices = get_outstanding_invoices(entry.party_type, entry.party, account)
-			transaction_date = datetime.strptime(entry.transaction_date, "%Y-%m-%d").date()
-			outstanding_invoices = [invoice for invoice in invoices if invoice.posting_date <= transaction_date]
-			amount = abs(entry.amount)
-			matching_invoices = [invoice for invoice in outstanding_invoices if invoice.outstanding_amount == amount]
-			sorted(outstanding_invoices, key=lambda k: k['posting_date'])
-			for e in (matching_invoices + outstanding_invoices):
-				added = next((inv for inv in added_invoices if inv == e.get('voucher_no')), None)
-				if (added is not None): continue
-				ent = self.append('payment_invoice_items', {})
-				ent.transaction_date = entry.transaction_date
-				ent.payment_description = frappe.safe_decode(entry.description)
-				ent.party_type = entry.party_type
-				ent.party = entry.party
-				ent.invoice = e.get('voucher_no')
-				added_invoices += [ent.invoice]
-				ent.invoice_type = "Sales Invoice" if entry.party_type == "Customer" else "Purchase Invoice"
-				ent.invoice_date = e.get('posting_date')
-				ent.outstanding_amount = e.get('outstanding_amount')
-				ent.allocated_amount = min(float(e.get('outstanding_amount')), amount)
-				amount -= float(e.get('outstanding_amount'))
-				if (amount <= 5): break
-		self.match_invoice_to_payment()
-		self.populate_matching_vouchers()
-		self.map_transactions_on_journal_entry()
-
-	def match_invoice_to_payment(self):
-		added_payments = []
-		for entry in self.new_transaction_items:
-			if (not entry.party or entry.party_type == "Account"): continue
-			entry.account = self.receivable_account if entry.party_type == "Customer" else self.payable_account
-			amount = abs(entry.amount)
-			payment, matching_invoices = None, []
-			for inv_entry in self.payment_invoice_items:
-				if (inv_entry.payment_description != frappe.safe_decode(entry.description) or inv_entry.transaction_date != entry.transaction_date): continue
-				if (inv_entry.party != entry.party): continue
-				matching_invoices += [inv_entry.invoice_type + "|" + inv_entry.invoice]
-				payment = get_payments_matching_invoice(inv_entry.invoice, entry.amount, entry.transaction_date)
-				doc = frappe.get_doc(inv_entry.invoice_type, inv_entry.invoice)
-				inv_entry.invoice_date = doc.posting_date
-				inv_entry.outstanding_amount = doc.outstanding_amount
-				inv_entry.allocated_amount = min(float(doc.outstanding_amount), amount)
-				amount -= inv_entry.allocated_amount
-				if (amount < 0): break
-
-			amount = abs(entry.amount)
-			if (payment is None):
-				order_doctype = "Sales Order" if entry.party_type=="Customer" else "Purchase Order"
-				from erpnext.controllers.accounts_controller import get_advance_payment_entries
-				payment_entries = get_advance_payment_entries(entry.party_type, entry.party, entry.account, order_doctype, against_all_orders=True)
-				payment_entries += self.get_matching_payments(entry.party, amount, entry.transaction_date)
-				payment = next((payment for payment in payment_entries if payment.amount == amount and payment not in added_payments), None)
-				if (payment is None):
-					print("Failed to find payments for {0}:{1}".format(entry.party, amount))
-					continue
-			added_payments += [payment]
-			entry.reference_type = payment.reference_type
-			entry.reference_name = payment.reference_name
-			entry.mode_of_payment = "Wire Transfer"
-			entry.outstanding_amount = min(amount, 0)
-			if (entry.payment_reference is None):
-				entry.payment_reference = frappe.safe_decode(entry.description)
-			entry.invoices = ",".join(matching_invoices)
-			#print("Matching payment is {0}:{1}".format(entry.reference_type, entry.reference_name))
-
-	def get_matching_payments(self, party, amount, pay_date):
-		query = """select 'Payment Entry' as reference_type, name as reference_name, paid_amount as amount
-					from `tabPayment Entry` where party='{0}' and paid_amount={1} and posting_date='{2}' and docstatus != 2
-					""".format(party, amount, pay_date)
-		matching_payments = frappe.db.sql(query, as_dict=True)
-		return matching_payments
-
-	def map_unknown_transactions(self):
-		for entry in self.new_transaction_items:
-			if (entry.party): continue
-			inv_type = "Sales Invoice" if (entry.amount > 0) else "Purchase Invoice"
-			party_type = "customer" if (entry.amount > 0) else "supplier"
-
-			query = """select posting_date, name, {0}, outstanding_amount
-							from `tab{1}` where ROUND(outstanding_amount)={2} and posting_date < '{3}'
-							""".format(party_type, inv_type, round(abs(entry.amount)), entry.transaction_date)
-			invoices = frappe.db.sql(query, as_dict = True)
-			if(len(invoices) > 0):
-				entry.party = invoices[0].get(party_type)
-
-	def populate_matching_vouchers(self):
-		for entry in self.new_transaction_items:
-			if (not entry.party or entry.reference_name): continue
-			print("Finding matching voucher for {0}".format(frappe.safe_decode(entry.description)))
-			amount = abs(entry.amount)
-			invoices = []
-			vouchers = get_matching_journal_entries(self.from_date, self.to_date, entry.party, self.bank_account, amount)
-			if len(vouchers) == 0: continue
-			for voucher in vouchers:
-				added = next((entry.invoice for entry in self.payment_invoice_items if entry.invoice == voucher.voucher_no), None)
-				if (added):
-					print("Found voucher {0}".format(added))
-					continue
-				print("Adding voucher {0} {1} {2}".format(voucher.voucher_no, voucher.posting_date, voucher.debit))
-				ent = self.append('payment_invoice_items', {})
-				ent.invoice_date = voucher.posting_date
-				ent.invoice_type = "Journal Entry"
-				ent.invoice = voucher.voucher_no
-				ent.payment_description = frappe.safe_decode(entry.description)
-				ent.allocated_amount = max(voucher.debit, voucher.credit)
-
-				invoices += [ent.invoice_type + "|" + ent.invoice]
-				entry.reference_type = "Journal Entry"
-				entry.mode_of_payment = "Wire Transfer"
-				entry.reference_name = ent.invoice
-				#entry.account = entry.party
-				entry.invoices = ",".join(invoices)
-				break
-
-
-	def create_payment_entries(self):
-		for payment_entry in self.new_transaction_items:
-			if (not payment_entry.party): continue
-			if (payment_entry.reference_name): continue
-			print("Creating payment entry for {0}".format(frappe.safe_decode(payment_entry.description)))
-			if (payment_entry.party_type == "Account"):
-				payment = self.create_journal_entry(payment_entry)
-				invoices = [payment.doctype + "|" + payment.name]
-				payment_entry.invoices = ",".join(invoices)
-			else:
-				payment = self.create_payment_entry(payment_entry)
-				invoices = [entry.reference_doctype + "|" + entry.reference_name for entry in payment.references if entry is not None]
-				payment_entry.invoices = ",".join(invoices)
-				payment_entry.mode_of_payment = payment.mode_of_payment
-				payment_entry.account = self.receivable_account if payment_entry.party_type == "Customer" else self.payable_account
-			payment_entry.reference_name = payment.name
-			payment_entry.reference_type = payment.doctype
-		frappe.msgprint(_("Successfully created payment entries"))
-
-	def create_payment_entry(self, pe):
-		payment = frappe.new_doc("Payment Entry")
-		payment.posting_date = pe.transaction_date
-		payment.payment_type = "Receive" if pe.party_type == "Customer" else "Pay"
-		payment.mode_of_payment = "Wire Transfer"
-		payment.party_type = pe.party_type
-		payment.party = pe.party
-		payment.paid_to = self.bank_account if pe.party_type == "Customer" else self.payable_account
-		payment.paid_from = self.receivable_account if pe.party_type == "Customer" else self.bank_account
-		payment.paid_amount = payment.received_amount = abs(pe.amount)
-		payment.reference_no = pe.description
-		payment.reference_date = pe.transaction_date
-		payment.save()
-		for inv_entry in self.payment_invoice_items:
-			if (pe.description != inv_entry.payment_description or pe.transaction_date != inv_entry.transaction_date): continue
-			if (pe.party != inv_entry.party): continue
-			reference = payment.append("references", {})
-			reference.reference_doctype = inv_entry.invoice_type
-			reference.reference_name = inv_entry.invoice
-			reference.allocated_amount = inv_entry.allocated_amount
-			print ("Adding invoice {0} {1}".format(reference.reference_name, reference.allocated_amount))
-		payment.setup_party_account_field()
-		payment.set_missing_values()
-		#payment.set_exchange_rate()
-		#payment.set_amounts()
-		#print("Created payment entry {0}".format(payment.as_dict()))
-		payment.save()
-		return payment
-
-	def create_journal_entry(self, pe):
-		je = frappe.new_doc("Journal Entry")
-		je.is_opening = "No"
-		je.voucher_type = "Bank Entry"
-		je.cheque_no = pe.description
-		je.cheque_date = pe.transaction_date
-		je.remark = pe.description
-		je.posting_date = pe.transaction_date
-		if (pe.amount < 0):
-			je.append("accounts", {"account": pe.party, "debit_in_account_currency": abs(pe.amount)})
-			je.append("accounts", {"account": self.bank_account, "credit_in_account_currency": abs(pe.amount)})
-		else:
-			je.append("accounts", {"account": pe.party, "credit_in_account_currency": pe.amount})
-			je.append("accounts", {"account": self.bank_account, "debit_in_account_currency": pe.amount})
-		je.save()
-		return je
-
-	def update_payment_entry(self, payment):
-		lst = []
-		invoices = payment.invoices.strip().split(',')
-		if (len(invoices) == 0): return
-		amount = float(abs(payment.amount))
-		for invoice_entry in invoices:
-			if (not invoice_entry.strip()): continue
-			invs = invoice_entry.split('|')
-			invoice_type, invoice = invs[0], invs[1]
-			outstanding_amount = frappe.get_value(invoice_type, invoice, 'outstanding_amount')
-
-			lst.append(frappe._dict({
-				'voucher_type': payment.reference_type,
-				'voucher_no' : payment.reference_name,
-				'against_voucher_type' : invoice_type,
-				'against_voucher'  : invoice,
-				'account' : payment.account,
-				'party_type': payment.party_type,
-				'party': frappe.get_value("Payment Entry", payment.reference_name, "party"),
-				'unadjusted_amount' : float(amount),
-				'allocated_amount' : min(outstanding_amount, amount)
-			}))
-			amount -= outstanding_amount
-		if lst:
-			from erpnext.accounts.utils import reconcile_against_document
-			try:
-				reconcile_against_document(lst)
-			except:
-				frappe.throw(_("Exception occurred while reconciling {0}").format(payment.reference_name))
-
-	def submit_payment_entries(self):
-		for payment in self.new_transaction_items:
-			if payment.reference_name is None: continue
-			doc = frappe.get_doc(payment.reference_type, payment.reference_name)
-			if doc.docstatus == 1:
-				if (payment.reference_type == "Journal Entry"): continue
-				if doc.unallocated_amount == 0: continue
-				print("Reconciling payment {0}".format(payment.reference_name))
-				self.update_payment_entry(payment)
-			else:
-				print("Submitting payment {0}".format(payment.reference_name))
-				if (payment.reference_type == "Payment Entry"):
-					if (payment.payment_reference):
-						doc.reference_no = payment.payment_reference
-					doc.mode_of_payment = payment.mode_of_payment
-				doc.save()
-				doc.submit()
-		self.move_reconciled_entries()
-		self.populate_matching_invoices()
-
-	def move_reconciled_entries(self):
-		idx = 0
-		while idx < len(self.new_transaction_items):
-			entry = self.new_transaction_items[idx]
-			try:
-				print("Checking transaction {0}: {2} in {1} entries".format(idx, len(self.new_transaction_items), frappe.safe_decode(entry.description)))
-			except UnicodeEncodeError:
-				pass
-			idx += 1
-			if entry.reference_name is None: continue
-			doc = frappe.get_doc(entry.reference_type, entry.reference_name)
-			if doc.docstatus == 1 and (entry.reference_type == "Journal Entry" or doc.unallocated_amount == 0):
-				self.remove(entry)
-				rc_entry = self.append('reconciled_transaction_items', {})
-				dentry = entry.as_dict()
-				dentry.pop('idx', None)
-				rc_entry.update(dentry)
-				idx -= 1
-
-
-def get_matching_journal_entries(from_date, to_date, account, against, amount):
-	query = """select voucher_no, posting_date, account, against, debit_in_account_currency as debit, credit_in_account_currency as credit
-							      from `tabGL Entry`
-								  where posting_date between '{0}' and '{1}' and account = '{2}' and against = '{3}' and debit = '{4}'
-								  """.format(from_date, to_date, account, against, amount)
-	jv_entries = frappe.db.sql(query, as_dict=True)
-	#print("voucher query:{0}\n Returned {1} entries".format(query, len(jv_entries)))
-	return jv_entries
-
-def get_payments_matching_invoice(invoice, amount, pay_date):
-	query = """select pe.name as reference_name, per.reference_doctype as reference_type, per.outstanding_amount, per.allocated_amount
-				from `tabPayment Entry Reference` as per JOIN `tabPayment Entry` as pe on pe.name = per.parent
-				where per.reference_name='{0}' and (posting_date='{1}' or reference_date='{1}') and pe.docstatus != 2
-				""".format(invoice, pay_date)
-	payments = frappe.db.sql(query, as_dict=True)
-	if (len(payments) == 0): return
-	payment = next((payment for payment in payments if payment.allocated_amount == amount), payments[0])
-	#Hack: Update the reference type which is set to invoice type
-	payment.reference_type = "Payment Entry"
-	return payment
-
-def is_headers_present(headers, row):
-	for header in headers:
-		if header not in row:
-			return False
-	return True
-
-def get_header_index(headers, row):
-	header_index = {}
-	for header in headers:
-		if header in row:
-			header_index[header] = row.index(header)
-	return header_index
-
-def get_transaction_info(headers, header_index, row):
-	transaction = {}
-	for header in headers:
-		transaction[header] = row[header_index[header]]
-		if (transaction[header] == None):
-			transaction[header] = ""
-	return transaction
-
-def get_transaction_entries(file_url, headers):
-	header_index = {}
-	rows, transactions = [], []
-
-	if (file_url.lower().endswith("xlsx")):
-		from frappe.utils.xlsxutils import read_xlsx_file_from_attached_file
-		rows = read_xlsx_file_from_attached_file(file_url=file_url)
-	elif (file_url.lower().endswith("csv")):
-		from frappe.utils.csvutils import read_csv_content
-		_file = frappe.get_doc("File", {"file_url": file_url})
-		filepath = _file.get_full_path()
-		with open(filepath,'rb') as csvfile:
-			rows = read_csv_content(csvfile.read())
-	elif (file_url.lower().endswith("xls")):
-		filename = file_url.split("/")[-1]
-		rows = get_rows_from_xls_file(filename)
-	else:
-		frappe.throw(_("Only .csv and .xlsx files are supported currently"))
-
-	stmt_headers = headers.values()
-	for row in rows:
-		if len(row) == 0 or row[0] == None or not row[0]: continue
-		#print("Processing row {0}".format(row))
-		if header_index:
-			transaction = get_transaction_info(stmt_headers, header_index, row)
-			transactions.append(transaction)
-		elif is_headers_present(stmt_headers, row):
-			header_index = get_header_index(stmt_headers, row)
-	return transactions
-
-def get_rows_from_xls_file(filename):
-	_file = frappe.get_doc("File", {"file_name": filename})
-	filepath = _file.get_full_path()
-	import xlrd
-	book = xlrd.open_workbook(filepath)
-	sheets = book.sheets()
-	rows = []
-	for row in range(1, sheets[0].nrows):
-		row_values = []
-		for col in range(1, sheets[0].ncols):
-			row_values.append(sheets[0].cell_value(row, col))
-		rows.append(row_values)
-	return rows
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_entry/test_bank_statement_transaction_entry.js b/erpnext/accounts/doctype/bank_statement_transaction_entry/test_bank_statement_transaction_entry.js
deleted file mode 100644
index 46d570f..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_entry/test_bank_statement_transaction_entry.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Bank Statement Transaction Entry", function (assert) {
-	let done = assert.async();
-
-	// number of asserts
-	assert.expect(1);
-
-	frappe.run_serially([
-		// insert a new Bank Statement Transaction Entry
-		() => frappe.tests.make('Bank Statement Transaction Entry', [
-			// values to be set
-			{key: 'value'}
-		]),
-		() => {
-			assert.equal(cur_frm.doc.key, 'value');
-		},
-		() => done()
-	]);
-
-});
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_entry/test_bank_statement_transaction_entry.py b/erpnext/accounts/doctype/bank_statement_transaction_entry/test_bank_statement_transaction_entry.py
deleted file mode 100644
index 4589483..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_entry/test_bank_statement_transaction_entry.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, sathishpy@gmail.com and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import frappe
-import unittest
-
-class TestBankStatementTransactionEntry(unittest.TestCase):
-	pass
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_invoice_item/__init__.py b/erpnext/accounts/doctype/bank_statement_transaction_invoice_item/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_invoice_item/__init__.py
+++ /dev/null
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_invoice_item/bank_statement_transaction_invoice_item.json b/erpnext/accounts/doctype/bank_statement_transaction_invoice_item/bank_statement_transaction_invoice_item.json
deleted file mode 100644
index d96c94d..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_invoice_item/bank_statement_transaction_invoice_item.json
+++ /dev/null
@@ -1,365 +0,0 @@
-{
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "beta": 0, 
- "creation": "2017-11-07 13:58:53.827058", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 1, 
- "engine": "InnoDB", 
- "fields": [
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "transaction_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": "Transaction 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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 4, 
-   "fieldname": "payment_description", 
-   "fieldtype": "Data", 
-   "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 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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "party_type", 
-   "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": "Party Type", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Customer\nSupplier\nAccount", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "party", 
-   "fieldtype": "Dynamic 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": "Party", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "party_type", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break_4", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 2, 
-   "fieldname": "invoice_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": "Invoice Date", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "invoice_type", 
-   "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": "Invoice Type", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Sales Invoice\nPurchase Invoice\nJournal Entry", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 2, 
-   "fieldname": "invoice", 
-   "fieldtype": "Dynamic 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": "invoice", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "invoice_type", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 1, 
-   "fieldname": "outstanding_amount", 
-   "fieldtype": "Data", 
-   "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": "Outstanding Amount", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 1, 
-   "fieldname": "allocated_amount", 
-   "fieldtype": "Data", 
-   "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": "Allocated Amount", 
-   "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, 
-   "translatable": 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": "2018-09-14 19:03:30.949831", 
- "modified_by": "Administrator", 
- "module": "Accounts", 
- "name": "Bank Statement Transaction Invoice Item", 
- "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, 
- "track_views": 0
-}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_invoice_item/bank_statement_transaction_invoice_item.py b/erpnext/accounts/doctype/bank_statement_transaction_invoice_item/bank_statement_transaction_invoice_item.py
deleted file mode 100644
index cb1b158..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_invoice_item/bank_statement_transaction_invoice_item.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, sathishpy@gmail.com and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
-
-class BankStatementTransactionInvoiceItem(Document):
-	pass
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_payment_item/__init__.py b/erpnext/accounts/doctype/bank_statement_transaction_payment_item/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_payment_item/__init__.py
+++ /dev/null
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_payment_item/bank_statement_transaction_payment_item.json b/erpnext/accounts/doctype/bank_statement_transaction_payment_item/bank_statement_transaction_payment_item.json
deleted file mode 100644
index 177dccd..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_payment_item/bank_statement_transaction_payment_item.json
+++ /dev/null
@@ -1,494 +0,0 @@
-{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2017-11-07 14:03:05.651413",
- "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": 1,
-   "fieldname": "transaction_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": "Transaction Date",
-   "length": 0,
-   "no_copy": 0,
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 1,
-   "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": 4,
-   "fieldname": "description",
-   "fieldtype": "Data",
-   "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,
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 1,
-   "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": 1,
-   "fieldname": "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": "Amount",
-   "length": 0,
-   "no_copy": 0,
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 1,
-   "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": 0,
-   "collapsible": 0,
-   "columns": 1,
-   "fieldname": "party_type",
-   "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": "Party Type",
-   "length": 0,
-   "no_copy": 0,
-   "options": "Customer\nSupplier\nAccount",
-   "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": "party",
-   "fieldtype": "Dynamic 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": "Party",
-   "length": 0,
-   "no_copy": 0,
-   "options": "party_type",
-   "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": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "fieldname": "reference_type",
-   "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 Type",
-   "length": 0,
-   "no_copy": 0,
-   "options": "Payment Entry\nJournal Entry",
-   "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,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
-   "label": "Account",
-   "length": 0,
-   "no_copy": 0,
-   "options": "Account",
-   "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": "mode_of_payment",
-   "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": "Mode of Payment",
-   "length": 0,
-   "no_copy": 0,
-   "options": "Mode of Payment",
-   "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": "outstanding_amount",
-   "fieldtype": "Currency",
-   "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": "outstanding_amount",
-   "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_10",
-   "fieldtype": "Column Break",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
-   "length": 0,
-   "no_copy": 0,
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "unique": 0
-  },
-  {
-   "allow_bulk_edit": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 2,
-   "fieldname": "reference_name",
-   "fieldtype": "Dynamic 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": "Reference Name",
-   "length": 0,
-   "no_copy": 0,
-   "options": "reference_type",
-   "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_reference",
-   "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 Reference",
-   "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": "invoices",
-   "fieldtype": "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": "Invoices",
-   "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-11-15 19:18:52.876221",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Bank Statement Transaction Payment Item",
- "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
-}
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_payment_item/bank_statement_transaction_payment_item.py b/erpnext/accounts/doctype/bank_statement_transaction_payment_item/bank_statement_transaction_payment_item.py
deleted file mode 100644
index 9840c0d..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_payment_item/bank_statement_transaction_payment_item.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, sathishpy@gmail.com and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
-
-class BankStatementTransactionPaymentItem(Document):
-	pass
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_settings/__init__.py b/erpnext/accounts/doctype/bank_statement_transaction_settings/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_settings/__init__.py
+++ /dev/null
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_settings/bank_statement_transaction_settings.js b/erpnext/accounts/doctype/bank_statement_transaction_settings/bank_statement_transaction_settings.js
deleted file mode 100644
index 46aa4f2..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_settings/bank_statement_transaction_settings.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2017, sathishpy@gmail.com and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Bank Statement Settings', {
-	refresh: function(frm) {
-
-	}
-});
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_settings/bank_statement_transaction_settings.json b/erpnext/accounts/doctype/bank_statement_transaction_settings/bank_statement_transaction_settings.json
deleted file mode 100644
index 474bb90..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_settings/bank_statement_transaction_settings.json
+++ /dev/null
@@ -1,266 +0,0 @@
-{
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 1, 
- "beta": 0, 
- "creation": "2017-11-13 13:38:10.863592", 
- "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": "bank_account", 
-   "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": "Bank Account", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Account", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "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": 0, 
-   "default": "'%d/%m/%Y'", 
-   "fieldname": "date_format", 
-   "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": "Date Format", 
-   "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": "statement_header_mapping", 
-   "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": "Statement Header Mapping", 
-   "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": "header_items", 
-   "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": "Statement Headers", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Bank Statement Settings Item", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "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": "transaction_data_mapping", 
-   "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": "Transaction Data Mapping", 
-   "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": "mapped_items", 
-   "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": "Mapped Items", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Bank Statement Transaction Settings Item", 
-   "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": "2018-01-12 10:34:32.840487", 
- "modified_by": "Administrator", 
- "module": "Accounts", 
- "name": "Bank Statement Settings", 
- "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
-  }
- ], 
- "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/bank_statement_transaction_settings/bank_statement_transaction_settings.py b/erpnext/accounts/doctype/bank_statement_transaction_settings/bank_statement_transaction_settings.py
deleted file mode 100644
index de9a85f..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_settings/bank_statement_transaction_settings.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, sathishpy@gmail.com and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
-
-class BankStatementSettings(Document):
-	def autoname(self):
-		self.name = self.bank_account + "-Mappings"
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_settings/test_bank_statement_transaction_settings.js b/erpnext/accounts/doctype/bank_statement_transaction_settings/test_bank_statement_transaction_settings.js
deleted file mode 100644
index f2381c0..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_settings/test_bank_statement_transaction_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Bank Statement Settings", function (assert) {
-	let done = assert.async();
-
-	// number of asserts
-	assert.expect(1);
-
-	frappe.run_serially([
-		// insert a new Bank Statement Settings
-		() => frappe.tests.make('Bank Statement Settings', [
-			// values to be set
-			{key: 'value'}
-		]),
-		() => {
-			assert.equal(cur_frm.doc.key, 'value');
-		},
-		() => done()
-	]);
-
-});
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_settings/test_bank_statement_transaction_settings.py b/erpnext/accounts/doctype/bank_statement_transaction_settings/test_bank_statement_transaction_settings.py
deleted file mode 100644
index aa7fe83..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_settings/test_bank_statement_transaction_settings.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, sathishpy@gmail.com and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import frappe
-import unittest
-
-class TestBankStatementSettings(unittest.TestCase):
-	pass
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_settings_item/__init__.py b/erpnext/accounts/doctype/bank_statement_transaction_settings_item/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_settings_item/__init__.py
+++ /dev/null
diff --git a/erpnext/accounts/doctype/bank_statement_transaction_settings_item/bank_statement_transaction_settings_item.json b/erpnext/accounts/doctype/bank_statement_transaction_settings_item/bank_statement_transaction_settings_item.json
deleted file mode 100644
index 47c3209..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_settings_item/bank_statement_transaction_settings_item.json
+++ /dev/null
@@ -1,166 +0,0 @@
-{
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "beta": 0, 
- "creation": "2017-11-13 13:42:00.335432", 
- "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, 
-   "default": "Transaction", 
-   "fieldname": "mapping_type", 
-   "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": "Mapping Type", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Transaction", 
-   "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": 0, 
-   "fieldname": "bank_data", 
-   "fieldtype": "Data", 
-   "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": "Bank Data", 
-   "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": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "default": "Account", 
-   "fieldname": "mapped_data_type", 
-   "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": "Mapped Data Type", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Account\nCustomer\nSupplier\nAccount", 
-   "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": "mapped_data", 
-   "fieldtype": "Dynamic 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": "Mapped Data", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "mapped_data_type", 
-   "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": "2018-01-08 00:13:49.973501", 
- "modified_by": "Administrator", 
- "module": "Accounts", 
- "name": "Bank Statement Transaction Settings Item", 
- "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/bank_statement_transaction_settings_item/bank_statement_transaction_settings_item.py b/erpnext/accounts/doctype/bank_statement_transaction_settings_item/bank_statement_transaction_settings_item.py
deleted file mode 100644
index bf0a590..0000000
--- a/erpnext/accounts/doctype/bank_statement_transaction_settings_item/bank_statement_transaction_settings_item.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, sathishpy@gmail.com and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
-
-class BankStatementTransactionSettingsItem(Document):
-	pass
diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.js b/erpnext/accounts/doctype/bank_transaction/bank_transaction.js
index 8b1bab1..3758b52 100644
--- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.js
+++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.js
@@ -1,32 +1,70 @@
 // Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
 // For license information, please see license.txt
 
-frappe.ui.form.on('Bank Transaction', {
+frappe.ui.form.on("Bank Transaction", {
 	onload(frm) {
-		frm.set_query('payment_document', 'payment_entries', function() {
+		frm.set_query("payment_document", "payment_entries", function () {
 			return {
-				"filters": {
-					"name": ["in", ["Payment Entry", "Journal Entry", "Sales Invoice", "Purchase Invoice", "Expense Claim"]]
-				}
+				filters: {
+					name: [
+						"in",
+						[
+							"Payment Entry",
+							"Journal Entry",
+							"Sales Invoice",
+							"Purchase Invoice",
+							"Expense Claim",
+						],
+					],
+				},
 			};
 		});
-	}
+	},
+	bank_account: function (frm) {
+		set_bank_statement_filter(frm);
+	},
+
+	setup: function (frm) {
+		frm.set_query("party_type", function () {
+			return {
+				filters: {
+					name: ["in", Object.keys(frappe.boot.party_account_types)],
+				},
+			};
+		});
+	},
 });
 
-frappe.ui.form.on('Bank Transaction Payments', {
-	payment_entries_remove: function(frm, cdt, cdn) {
+frappe.ui.form.on("Bank Transaction Payments", {
+	payment_entries_remove: function (frm, cdt, cdn) {
 		update_clearance_date(frm, cdt, cdn);
-	}
+	},
 });
 
 const update_clearance_date = (frm, cdt, cdn) => {
 	if (frm.doc.docstatus === 1) {
-		frappe.xcall('erpnext.accounts.doctype.bank_transaction.bank_transaction.unclear_reference_payment',
-			{doctype: cdt, docname: cdn})
-			.then(e => {
+		frappe
+			.xcall(
+				"erpnext.accounts.doctype.bank_transaction.bank_transaction.unclear_reference_payment",
+				{ doctype: cdt, docname: cdn }
+			)
+			.then((e) => {
 				if (e == "success") {
-					frappe.show_alert({message:__("Document {0} successfully uncleared", [e]), indicator:'green'});
+					frappe.show_alert({
+						message: __("Document {0} successfully uncleared", [e]),
+						indicator: "green",
+					});
 				}
 			});
 	}
-};
\ No newline at end of file
+};
+
+function set_bank_statement_filter(frm) {
+	frm.set_query("bank_statement", function () {
+		return {
+			filters: {
+				bank_account: frm.doc.bank_account,
+			},
+		};
+	});
+}
diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.json b/erpnext/accounts/doctype/bank_transaction/bank_transaction.json
index 39937bb..69ee497 100644
--- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.json
+++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.json
@@ -1,833 +1,245 @@
 {
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
+ "actions": [],
  "allow_import": 1,
- "allow_rename": 0,
  "autoname": "naming_series:",
- "beta": 0,
  "creation": "2018-10-22 18:19:02.784533",
- "custom": 0,
- "docstatus": 0,
  "doctype": "DocType",
- "document_type": "",
  "editable_grid": 1,
  "engine": "InnoDB",
+ "field_order": [
+  "naming_series",
+  "date",
+  "column_break_2",
+  "status",
+  "bank_account",
+  "company",
+  "section_break_4",
+  "deposit",
+  "withdrawal",
+  "column_break_7",
+  "currency",
+  "section_break_10",
+  "description",
+  "section_break_14",
+  "reference_number",
+  "transaction_id",
+  "payment_entries",
+  "section_break_18",
+  "allocated_amount",
+  "amended_from",
+  "column_break_17",
+  "unallocated_amount",
+  "party_section",
+  "party_type",
+  "party"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "default": "ACC-BTN-.YYYY.-",
-   "fetch_if_empty": 0,
    "fieldname": "naming_series",
    "fieldtype": "Select",
    "hidden": 1,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
    "label": "Series",
-   "length": 0,
    "no_copy": 1,
    "options": "ACC-BTN-.YYYY.-",
-   "permlevel": 0,
-   "precision": "",
    "print_hide": 1,
-   "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": 1,
-   "translatable": 0,
-   "unique": 0
+   "set_only_once": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "fetch_if_empty": 0,
    "fieldname": "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": "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,
-   "translatable": 0,
-   "unique": 0
+   "label": "Date"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "fetch_if_empty": 0,
    "fieldname": "column_break_2",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "fieldtype": "Column Break"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "default": "Pending",
-   "fetch_if_empty": 0,
    "fieldname": "status",
    "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": 1,
    "label": "Status",
-   "length": 0,
-   "no_copy": 0,
-   "options": "\nPending\nSettled\nUnreconciled\nReconciled",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "options": "\nPending\nSettled\nUnreconciled\nReconciled"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "fetch_if_empty": 0,
    "fieldname": "bank_account",
    "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": 1,
    "label": "Bank Account",
-   "length": 0,
-   "no_copy": 0,
-   "options": "Bank Account",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "options": "Bank Account"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "default": "",
    "fetch_from": "bank_account.company",
-   "fetch_if_empty": 0,
    "fieldname": "company",
    "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": 1,
    "label": "Company",
-   "length": 0,
-   "no_copy": 0,
    "options": "Company",
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 1,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "read_only": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "fetch_if_empty": 0,
    "fieldname": "section_break_4",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "fieldtype": "Section Break"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "fetch_if_empty": 0,
-   "fieldname": "debit",
-   "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": "Debit",
-   "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,
-   "translatable": 0,
-   "unique": 0
-  },
-  {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "fetch_if_empty": 0,
-   "fieldname": "credit",
-   "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": "Credit",
-   "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,
-   "translatable": 0,
-   "unique": 0
-  },
-  {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "fetch_if_empty": 0,
    "fieldname": "column_break_7",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "fieldtype": "Column Break"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "fetch_if_empty": 0,
    "fieldname": "currency",
    "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": "Currency",
-   "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": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "options": "Currency"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "fetch_if_empty": 0,
    "fieldname": "section_break_10",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "fieldtype": "Section Break"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "fetch_if_empty": 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": 1,
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "label": "Description"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "fetch_if_empty": 0,
    "fieldname": "section_break_14",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "fieldtype": "Section Break"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "fetch_if_empty": 0,
+   "allow_on_submit": 1,
    "fieldname": "reference_number",
    "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": "Reference Number",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "label": "Reference Number"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "fetch_if_empty": 0,
    "fieldname": "transaction_id",
    "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": "Transaction ID",
-   "length": 0,
-   "no_copy": 0,
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
    "read_only": 1,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
    "unique": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
    "allow_on_submit": 1,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "fetch_if_empty": 0,
    "fieldname": "payment_entries",
    "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 Entries",
-   "length": 0,
-   "no_copy": 0,
-   "options": "Bank Transaction Payments",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "options": "Bank Transaction Payments"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "fetch_if_empty": 0,
    "fieldname": "section_break_18",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "fieldtype": "Section Break"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "fetch_if_empty": 0,
    "fieldname": "allocated_amount",
    "fieldtype": "Currency",
-   "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": "Allocated Amount",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "label": "Allocated Amount"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "fetch_if_empty": 0,
    "fieldname": "amended_from",
    "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": "Amended From",
-   "length": 0,
    "no_copy": 1,
    "options": "Bank Transaction",
-   "permlevel": 0,
    "print_hide": 1,
-   "print_hide_if_no_value": 0,
-   "read_only": 1,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "read_only": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "fetch_if_empty": 0,
    "fieldname": "column_break_17",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "fieldtype": "Column Break"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "depends_on": "",
-   "fetch_if_empty": 0,
    "fieldname": "unallocated_amount",
    "fieldtype": "Currency",
-   "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": "Unallocated Amount",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "label": "Unallocated Amount"
+  },
+  {
+   "fieldname": "party_section",
+   "fieldtype": "Section Break",
+   "label": "Payment From / To"
+  },
+  {
+   "allow_on_submit": 1,
+   "fieldname": "party_type",
+   "fieldtype": "Link",
+   "label": "Party Type",
+   "options": "DocType"
+  },
+  {
+   "allow_on_submit": 1,
+   "fieldname": "party",
+   "fieldtype": "Dynamic Link",
+   "label": "Party",
+   "options": "party_type"
+  },
+  {
+   "fieldname": "deposit",
+   "oldfieldname": "debit",
+   "fieldtype": "Currency",
+   "in_list_view": 1,
+   "label": "Deposit"
+  },
+  {
+   "fieldname": "withdrawal",
+   "oldfieldname": "credit",
+   "fieldtype": "Currency",
+   "in_list_view": 1,
+   "label": "Withdrawal"
   }
  ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
  "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-05-11 05:27:55.244721",
+ "links": [],
+ "modified": "2020-12-30 19:40:54.221070",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Bank Transaction",
- "name_case": "",
  "owner": "Administrator",
  "permissions": [
   {
-   "amend": 0,
    "cancel": 1,
    "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": 1,
    "write": 1
   },
   {
-   "amend": 0,
    "cancel": 1,
    "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": 1,
    "write": 1
   },
   {
-   "amend": 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": 1,
    "write": 1
   }
  ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
  "sort_field": "date",
  "sort_order": "DESC",
  "title_field": "bank_account",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
index 0e45db3..5246baa 100644
--- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
+++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
@@ -11,7 +11,7 @@
 
 class BankTransaction(StatusUpdater):
 	def after_insert(self):
-		self.unallocated_amount = abs(flt(self.credit) - flt(self.debit))
+		self.unallocated_amount = abs(flt(self.withdrawal) - flt(self.deposit))
 
 	def on_submit(self):
 		self.clear_linked_payment_entries()
@@ -30,13 +30,13 @@
 
 		if allocated_amount:
 			frappe.db.set_value(self.doctype, self.name, "allocated_amount", flt(allocated_amount))
-			frappe.db.set_value(self.doctype, self.name, "unallocated_amount", abs(flt(self.credit) - flt(self.debit)) - flt(allocated_amount))
+			frappe.db.set_value(self.doctype, self.name, "unallocated_amount", abs(flt(self.withdrawal) - flt(self.deposit)) - flt(allocated_amount))
 
 		else:
 			frappe.db.set_value(self.doctype, self.name, "allocated_amount", 0)
-			frappe.db.set_value(self.doctype, self.name, "unallocated_amount", abs(flt(self.credit) - flt(self.debit)))
+			frappe.db.set_value(self.doctype, self.name, "unallocated_amount", abs(flt(self.withdrawal) - flt(self.deposit)))
 
-		amount = self.debit or self.credit
+		amount = self.deposit or self.withdrawal
 		if amount == self.allocated_amount:
 			frappe.db.set_value(self.doctype, self.name, "status", "Reconciled")
 
@@ -44,18 +44,11 @@
 
 	def clear_linked_payment_entries(self):
 		for payment_entry in self.payment_entries:
-			allocated_amount = get_total_allocated_amount(payment_entry)
-			paid_amount = get_paid_amount(payment_entry, self.currency)
+			if payment_entry.payment_document in ["Payment Entry", "Journal Entry", "Purchase Invoice", "Expense Claim"]:
+				self.clear_simple_entry(payment_entry)
 
-			if paid_amount and allocated_amount:
-				if  flt(allocated_amount[0]["allocated_amount"]) > flt(paid_amount):
-					frappe.throw(_("The total allocated amount ({0}) is greated than the paid amount ({1}).").format(flt(allocated_amount[0]["allocated_amount"]), flt(paid_amount)))
-				else:
-					if payment_entry.payment_document in ["Payment Entry", "Journal Entry", "Purchase Invoice", "Expense Claim"]:
-						self.clear_simple_entry(payment_entry)
-
-					elif payment_entry.payment_document == "Sales Invoice":
-						self.clear_sales_invoice(payment_entry)
+			elif payment_entry.payment_document == "Sales Invoice":
+				self.clear_sales_invoice(payment_entry)
 
 	def clear_simple_entry(self, payment_entry):
 		frappe.db.set_value(payment_entry.payment_document, payment_entry.payment_entry, "clearance_date", self.date)
@@ -112,3 +105,4 @@
 			frappe.db.set_value(doc.payment_document, doc.payment_entry, "clearance_date", None)
 
 		return doc.payment_entry
+
diff --git a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py
index e9fc5f0..3b14e4e 100644
--- a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py
+++ b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py
@@ -5,10 +5,11 @@
 
 import frappe
 import unittest
+import json
 from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
 from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
 from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
-from erpnext.accounts.page.bank_reconciliation.bank_reconciliation import reconcile, get_linked_payments
+from erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool import reconcile_vouchers, get_linked_payments
 from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
 
 test_dependencies = ["Item", "Cost Center"]
@@ -17,7 +18,7 @@
 	def setUp(self):
 		make_pos_profile()
 		add_transactions()
-		add_payments()
+		add_vouchers()
 
 	def tearDown(self):
 		for bt in frappe.get_all("Bank Transaction"):
@@ -38,14 +39,18 @@
 	# This test checks if ERPNext is able to provide a linked payment for a bank transaction based on the amount of the bank transaction.
 	def test_linked_payments(self):
 		bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Re 95282925234 FE/000002917 AT171513000281183046 Conrad Electronic"))
-		linked_payments = get_linked_payments(bank_transaction.name)
-		self.assertTrue(linked_payments[0].party == "Conrad Electronic")
+		linked_payments = get_linked_payments(bank_transaction.name, ['payment_entry', 'exact_match'])
+		self.assertTrue(linked_payments[0][6] == "Conrad Electronic")
 
 	# This test validates a simple reconciliation leading to the clearance of the bank transaction and the payment
 	def test_reconcile(self):
 		bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G"))
 		payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1200))
-		reconcile(bank_transaction.name, "Payment Entry", payment.name)
+		vouchers = json.dumps([{
+		"payment_doctype":"Payment Entry",
+		"payment_name":payment.name,
+		"amount":bank_transaction.unallocated_amount}])
+		reconcile_vouchers(bank_transaction.name, vouchers)
 
 		unallocated_amount = frappe.db.get_value("Bank Transaction", bank_transaction.name, "unallocated_amount")
 		self.assertTrue(unallocated_amount == 0)
@@ -53,45 +58,40 @@
 		clearance_date = frappe.db.get_value("Payment Entry", payment.name, "clearance_date")
 		self.assertTrue(clearance_date is not None)
 
-	# Check if ERPNext can correctly fetch a linked payment based on the party
-	def test_linked_payments_based_on_party(self):
-		bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000003025 OPSKATTUZWXXX AT776000000098709849 Herr G"))
-		linked_payments = get_linked_payments(bank_transaction.name)
-		self.assertTrue(len(linked_payments)==1)
-
 	# Check if ERPNext can correctly filter a linked payments based on the debit/credit amount
 	def test_debit_credit_output(self):
 		bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07"))
-		linked_payments = get_linked_payments(bank_transaction.name)
-		self.assertTrue(linked_payments[0].payment_type == "Pay")
+		linked_payments = get_linked_payments(bank_transaction.name, ['payment_entry', 'exact_match'])
+		print(linked_payments)
+		self.assertTrue(linked_payments[0][3])
 
 	# Check error if already reconciled
 	def test_already_reconciled(self):
 		bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G"))
 		payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1200))
-		reconcile(bank_transaction.name, "Payment Entry", payment.name)
+		vouchers = json.dumps([{
+			"payment_doctype":"Payment Entry",
+			"payment_name":payment.name,
+			"amount":bank_transaction.unallocated_amount}])
+		reconcile_vouchers(bank_transaction.name, vouchers)
 
 		bank_transaction = frappe.get_doc("Bank Transaction", dict(description="1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G"))
 		payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1200))
-		self.assertRaises(frappe.ValidationError, reconcile, bank_transaction=bank_transaction.name, payment_doctype="Payment Entry", payment_name=payment.name)
-
-	# Raise an error if creditor transaction vs creditor payment
-	def test_invalid_creditor_reconcilation(self):
-		bank_transaction = frappe.get_doc("Bank Transaction", dict(description="I2015000011 VD/000002514 ATWWXXX AT4701345000003510057 Bio"))
-		payment = frappe.get_doc("Payment Entry", dict(party="Conrad Electronic", paid_amount=690))
-		self.assertRaises(frappe.ValidationError, reconcile, bank_transaction=bank_transaction.name, payment_doctype="Payment Entry", payment_name=payment.name)
-
-	# Raise an error if debitor transaction vs debitor payment
-	def test_invalid_debitor_reconcilation(self):
-		bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07"))
-		payment = frappe.get_doc("Payment Entry", dict(party="Fayva", paid_amount=109080))
-		self.assertRaises(frappe.ValidationError, reconcile, bank_transaction=bank_transaction.name, payment_doctype="Payment Entry", payment_name=payment.name)
+		vouchers = json.dumps([{
+			"payment_doctype":"Payment Entry",
+			"payment_name":payment.name,
+			"amount":bank_transaction.unallocated_amount}])
+		self.assertRaises(frappe.ValidationError, reconcile_vouchers, bank_transaction_name=bank_transaction.name, vouchers=vouchers)
 
 	# Raise an error if debitor transaction vs debitor payment
 	def test_clear_sales_invoice(self):
 		bank_transaction = frappe.get_doc("Bank Transaction", dict(description="I2015000011 VD/000002514 ATWWXXX AT4701345000003510057 Bio"))
 		payment = frappe.get_doc("Sales Invoice", dict(customer="Fayva", status=["=", "Paid"]))
-		reconcile(bank_transaction.name, "Sales Invoice", payment.name)
+		vouchers = json.dumps([{
+			"payment_doctype":"Sales Invoice",
+			"payment_name":payment.name,
+			"amount":bank_transaction.unallocated_amount}])
+		reconcile_vouchers(bank_transaction.name, vouchers=vouchers)
 
 		self.assertEqual(frappe.db.get_value("Bank Transaction", bank_transaction.name, "unallocated_amount"), 0)
 		self.assertTrue(frappe.db.get_value("Sales Invoice Payment", dict(parent=payment.name), "clearance_date") is not None)
@@ -126,7 +126,7 @@
 		"doctype": "Bank Transaction",
 		"description":"1512567 BG/000002918 OPSKATTUZWXXX AT776000000098709837 Herr G",
 		"date": "2018-10-23",
-		"debit": 1200,
+		"deposit": 1200,
 		"currency": "INR",
 		"bank_account": "Checking Account - Citi Bank"
 	}).insert()
@@ -136,7 +136,7 @@
 		"doctype": "Bank Transaction",
 		"description":"1512567 BG/000003025 OPSKATTUZWXXX AT776000000098709849 Herr G",
 		"date": "2018-10-23",
-		"debit": 1700,
+		"deposit": 1700,
 		"currency": "INR",
 		"bank_account": "Checking Account - Citi Bank"
 	}).insert()
@@ -146,7 +146,7 @@
 		"doctype": "Bank Transaction",
 		"description":"Re 95282925234 FE/000002917 AT171513000281183046 Conrad Electronic",
 		"date": "2018-10-26",
-		"debit": 690,
+		"withdrawal": 690,
 		"currency": "INR",
 		"bank_account": "Checking Account - Citi Bank"
 	}).insert()
@@ -156,7 +156,7 @@
 		"doctype": "Bank Transaction",
 		"description":"Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07",
 		"date": "2018-10-27",
-		"debit": 3900,
+		"deposit": 3900,
 		"currency": "INR",
 		"bank_account": "Checking Account - Citi Bank"
 	}).insert()
@@ -166,7 +166,7 @@
 		"doctype": "Bank Transaction",
 		"description":"I2015000011 VD/000002514 ATWWXXX AT4701345000003510057 Bio",
 		"date": "2018-10-27",
-		"credit": 109080,
+		"withdrawal": 109080,
 		"currency": "INR",
 		"bank_account": "Checking Account - Citi Bank"
 	}).insert()
@@ -174,7 +174,7 @@
 
 	frappe.flags.test_bank_transactions_created = True
 
-def add_payments():
+def add_vouchers():
 	if frappe.flags.test_payments_created:
 		return
 
@@ -192,6 +192,7 @@
 		pass
 
 	pi = make_purchase_invoice(supplier="Conrad Electronic", qty=1, rate=690)
+
 	pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
 	pe.reference_no = "Conrad Oct 18"
 	pe.reference_date = "2018-10-24"
@@ -242,10 +243,15 @@
 	except frappe.DuplicateEntryError:
 		pass
 
-	pi = make_purchase_invoice(supplier="Poore Simon's", qty=1, rate=3900)
+	pi = make_purchase_invoice(supplier="Poore Simon's", qty=1, rate=3900, is_paid=1, do_not_save =1)
+	pi.cash_bank_account = "_Test Bank - _TC"
+	pi.insert()
+	pi.submit()
 	pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
 	pe.reference_no = "Poore Simon's Oct 18"
 	pe.reference_date = "2018-10-28"
+	pe.paid_amount = 690
+	pe.received_amount = 690
 	pe.insert()
 	pe.submit()
 
@@ -295,4 +301,4 @@
 	si.save()
 	si.submit()
 
-	frappe.flags.test_payments_created = True
\ No newline at end of file
+	frappe.flags.test_payments_created = True
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index b0a864f..ce76d0a 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -27,30 +27,30 @@
 
 	def validate(self):
 		self.flags.ignore_submit_comment = True
-		self.check_mandatory()
 		self.validate_and_set_fiscal_year()
 		self.pl_must_have_cost_center()
-		self.validate_cost_center()
 
 		if not self.flags.from_repost:
+			self.check_mandatory()
+			self.validate_cost_center()
 			self.check_pl_account()
 			self.validate_party()
 			self.validate_currency()
 
-	def on_update_with_args(self, adv_adj, update_outstanding = 'Yes', from_repost=False):
-		if not from_repost:
+	def on_update(self):
+		adv_adj = self.flags.adv_adj
+		if not self.flags.from_repost:
 			self.validate_account_details(adv_adj)
 			self.validate_dimensions_for_pl_and_bs()
 			self.validate_allowed_dimensions()
+			validate_balance_type(self.account, adv_adj)
+			validate_frozen_account(self.account, adv_adj)
 
-		validate_frozen_account(self.account, adv_adj)
-		validate_balance_type(self.account, adv_adj)
-
-		# Update outstanding amt on against voucher
-		if self.against_voucher_type in ['Journal Entry', 'Sales Invoice', 'Purchase Invoice', 'Fees'] \
-			and self.against_voucher and update_outstanding == 'Yes' and not from_repost:
-				update_outstanding_amt(self.account, self.party_type, self.party, self.against_voucher_type,
-					self.against_voucher)
+			# Update outstanding amt on against voucher
+			if (self.against_voucher_type in ['Journal Entry', 'Sales Invoice', 'Purchase Invoice', 'Fees']
+				and self.against_voucher and self.flags.update_outstanding == 'Yes'):
+					update_outstanding_amt(self.account, self.party_type, self.party, self.against_voucher_type,
+						self.against_voucher)
 
 	def check_mandatory(self):
 		mandatory = ['account','voucher_type','voucher_no','company']
@@ -58,7 +58,7 @@
 			if not self.get(k):
 				frappe.throw(_("{0} is required").format(_(self.meta.get_label(k))))
 
-		account_type = frappe.db.get_value("Account", self.account, "account_type")
+		account_type = frappe.get_cached_value("Account", self.account, "account_type")
 		if not (self.party_type and self.party):
 			if account_type == "Receivable":
 				frappe.throw(_("{0} {1}: Customer is required against Receivable account {2}")
@@ -73,7 +73,7 @@
 				.format(self.voucher_type, self.voucher_no, self.account))
 
 	def pl_must_have_cost_center(self):
-		if frappe.db.get_value("Account", self.account, "report_type") == "Profit and Loss":
+		if frappe.get_cached_value("Account", self.account, "report_type") == "Profit and Loss":
 			if not self.cost_center and self.voucher_type != 'Period Closing Voucher':
 				frappe.throw(_("{0} {1}: Cost Center is required for 'Profit and Loss' account {2}. Please set up a default Cost Center for the Company.")
 					.format(self.voucher_type, self.voucher_no, self.account))
@@ -140,25 +140,16 @@
 				.format(self.voucher_type, self.voucher_no, self.account, self.company))
 
 	def validate_cost_center(self):
-		if not hasattr(self, "cost_center_company"):
-			self.cost_center_company = {}
+		if not self.cost_center: return
 
-		def _get_cost_center_company():
-			if not self.cost_center_company.get(self.cost_center):
-				self.cost_center_company[self.cost_center] = frappe.db.get_value(
-					"Cost Center", self.cost_center, "company")
+		is_group, company = frappe.get_cached_value('Cost Center',
+			self.cost_center, ['is_group', 'company'])
 
-			return self.cost_center_company[self.cost_center]
-
-		def _check_is_group():
-			return cint(frappe.get_cached_value('Cost Center', self.cost_center, 'is_group'))
-
-		if self.cost_center and _get_cost_center_company() != self.company:
+		if company != self.company:
 			frappe.throw(_("{0} {1}: Cost Center {2} does not belong to Company {3}")
 				.format(self.voucher_type, self.voucher_no, self.cost_center, self.company))
 
-		if not self.flags.from_repost and not self.voucher_type == 'Period Closing Voucher' \
-			and self.cost_center and _check_is_group():
+		if (self.voucher_type != 'Period Closing Voucher' and is_group):
 			frappe.throw(_("""{0} {1}: Cost Center {2} is a group cost center and group cost centers cannot be used in transactions""").format(
 				self.voucher_type, self.voucher_no, frappe.bold(self.cost_center)))
 
@@ -184,7 +175,6 @@
 		if not self.fiscal_year:
 			self.fiscal_year = get_fiscal_year(self.posting_date, company=self.company)[0]
 
-
 def validate_balance_type(account, adv_adj=False):
 	if not adv_adj and account:
 		balance_must_be = frappe.db.get_value("Account", account, "balance_must_be")
@@ -250,7 +240,7 @@
 
 
 def validate_frozen_account(account, adv_adj=None):
-	frozen_account = frappe.db.get_value("Account", account, "freeze_account")
+	frozen_account = frappe.get_cached_value("Account", account, "freeze_account")
 	if frozen_account == 'Yes' and not adv_adj:
 		frozen_accounts_modifier = frappe.db.get_value( 'Accounts Settings', None,
 			'frozen_accounts_modifier')
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index cb90f80..3419bb6 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -102,7 +102,7 @@
 			if account_currency == previous_account_currency:
 				if self.total_credit != doc.total_debit or self.total_debit != doc.total_credit:
 					frappe.throw(_("Total Credit/ Debit Amount should be same as linked Journal Entry"))
-	
+
 	def validate_stock_accounts(self):
 		stock_accounts = get_stock_accounts(self.company, self.doctype, self.name)
 		for account in stock_accounts:
@@ -229,11 +229,11 @@
 			if d.reference_type=="Journal Entry":
 				account_root_type = frappe.db.get_value("Account", d.account, "root_type")
 				if account_root_type == "Asset" and flt(d.debit) > 0:
-					frappe.throw(_("For {0}, only credit accounts can be linked against another debit entry")
-						.format(d.account))
+					frappe.throw(_("Row #{0}: For {1}, you can select reference document only if account gets credited")
+						.format(d.idx, d.account))
 				elif account_root_type == "Liability" and flt(d.credit) > 0:
-					frappe.throw(_("For {0}, only debit accounts can be linked against another credit entry")
-						.format(d.account))
+					frappe.throw(_("Row #{0}: For {1}, you can select reference document only if account gets debited")
+						.format(d.idx, d.account))
 
 				if d.reference_name == self.name:
 					frappe.throw(_("You can not enter current voucher in 'Against Journal Entry' column"))
@@ -1077,4 +1077,4 @@
 		},
 	}, target_doc)
 
-	return doclist
\ No newline at end of file
+	return doclist
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index 791b03a..f7a15c0 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -88,19 +88,19 @@
 		voucher_type = ('Sales Invoice'
 			if self.party_type == 'Customer' else "Purchase Invoice")
 
-		return frappe.db.sql(""" SELECT `tab{doc}`.name as reference_name, %(voucher_type)s as reference_type,
-				(sum(`tabGL Entry`.{dr_or_cr}) - sum(`tabGL Entry`.{reconciled_dr_or_cr})) as amount,
+		return frappe.db.sql(""" SELECT doc.name as reference_name, %(voucher_type)s as reference_type,
+				(sum(gl.{dr_or_cr}) - sum(gl.{reconciled_dr_or_cr})) as amount,
 				account_currency as currency
-			FROM `tab{doc}`, `tabGL Entry`
+			FROM `tab{doc}` doc, `tabGL Entry` gl
 			WHERE
-				(`tab{doc}`.name = `tabGL Entry`.against_voucher or `tab{doc}`.name = `tabGL Entry`.voucher_no)
-				and `tab{doc}`.{party_type_field} = %(party)s
-				and `tab{doc}`.is_return = 1 and `tab{doc}`.return_against IS NULL
-				and `tabGL Entry`.against_voucher_type = %(voucher_type)s
-				and `tab{doc}`.docstatus = 1 and `tabGL Entry`.party = %(party)s
-				and `tabGL Entry`.party_type = %(party_type)s and `tabGL Entry`.account = %(account)s
-				and `tabGL Entry`.is_cancelled = 0
-			GROUP BY `tab{doc}`.name
+				(doc.name = gl.against_voucher or doc.name = gl.voucher_no)
+				and doc.{party_type_field} = %(party)s
+				and doc.is_return = 1 and ifnull(doc.return_against, "") = ""
+				and gl.against_voucher_type = %(voucher_type)s
+				and doc.docstatus = 1 and gl.party = %(party)s
+				and gl.party_type = %(party_type)s and gl.account = %(account)s
+				and gl.is_cancelled = 0
+			GROUP BY doc.name
 			Having
 				amount > 0
 		""".format(
@@ -113,7 +113,7 @@
 				'party_type': self.party_type,
 				'voucher_type': voucher_type,
 				'account': self.receivable_payable_account
-			}, as_dict=1)
+			}, as_dict=1, debug=1)
 
 	def add_payment_entries(self, entries):
 		self.set('payments', [])
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py
index 1b97050..53ac996 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.py
+++ b/erpnext/accounts/doctype/payment_request/payment_request.py
@@ -3,6 +3,7 @@
 # For license information, please see license.txt
 
 from __future__ import unicode_literals
+import json
 import frappe
 from frappe import _
 from frappe.model.document import Document
@@ -82,18 +83,37 @@
 			self.make_communication_entry()
 
 		elif self.payment_channel == "Phone":
-			controller = get_payment_gateway_controller(self.payment_gateway)
-			payment_record = dict(
-				reference_doctype="Payment Request",
-				reference_docname=self.name,
-				payment_reference=self.reference_name,
-				grand_total=self.grand_total,
-				sender=self.email_to,
-				currency=self.currency,
-				payment_gateway=self.payment_gateway
-			)
-			controller.validate_transaction_currency(self.currency)
-			controller.request_for_payment(**payment_record)
+			self.request_phone_payment()
+
+	def request_phone_payment(self):
+		controller = get_payment_gateway_controller(self.payment_gateway)
+		request_amount = self.get_request_amount()
+
+		payment_record = dict(
+			reference_doctype="Payment Request",
+			reference_docname=self.name,
+			payment_reference=self.reference_name,
+			request_amount=request_amount,
+			sender=self.email_to,
+			currency=self.currency,
+			payment_gateway=self.payment_gateway
+		)
+
+		controller.validate_transaction_currency(self.currency)
+		controller.request_for_payment(**payment_record)
+	
+	def get_request_amount(self):
+		data_of_completed_requests = frappe.get_all("Integration Request", filters={
+			'reference_doctype': self.doctype,
+			'reference_docname': self.name,
+			'status': 'Completed'
+		}, pluck="data")
+
+		if not data_of_completed_requests:
+			return self.grand_total
+
+		request_amounts = sum([json.loads(d).get('request_amount') for d in data_of_completed_requests])
+		return request_amounts
 
 	def on_cancel(self):
 		self.check_if_payment_entry_exists()
@@ -351,8 +371,8 @@
 		if args.order_type == "Shopping Cart" or args.mute_email:
 			pr.flags.mute_email = True
 
+		pr.insert(ignore_permissions=True)
 		if args.submit_doc:
-			pr.insert(ignore_permissions=True)
 			pr.submit()
 
 	if args.order_type == "Shopping Cart":
@@ -412,8 +432,8 @@
 
 def get_gateway_details(args):
 	"""return gateway and payment account of default payment gateway"""
-	if args.get("payment_gateway"):
-		return get_payment_gateway_account(args.get("payment_gateway"))
+	if args.get("payment_gateway_account"):
+		return get_payment_gateway_account(args.get("payment_gateway_account"))
 
 	if args.order_type == "Shopping Cart":
 		payment_gateway_account = frappe.get_doc("Shopping Cart Settings").payment_gateway_account
diff --git a/erpnext/accounts/doctype/payment_request/test_payment_request.py b/erpnext/accounts/doctype/payment_request/test_payment_request.py
index 8a10e2c..5eba62c 100644
--- a/erpnext/accounts/doctype/payment_request/test_payment_request.py
+++ b/erpnext/accounts/doctype/payment_request/test_payment_request.py
@@ -45,7 +45,8 @@
 
 	def test_payment_request_linkings(self):
 		so_inr = make_sales_order(currency="INR")
-		pr = make_payment_request(dt="Sales Order", dn=so_inr.name, recipient_id="saurabh@erpnext.com")
+		pr = make_payment_request(dt="Sales Order", dn=so_inr.name, recipient_id="saurabh@erpnext.com",
+			payment_gateway_account="_Test Gateway - INR")
 
 		self.assertEqual(pr.reference_doctype, "Sales Order")
 		self.assertEqual(pr.reference_name, so_inr.name)
@@ -54,7 +55,8 @@
 		conversion_rate = get_exchange_rate("USD", "INR")
 
 		si_usd = create_sales_invoice(currency="USD", conversion_rate=conversion_rate)
-		pr = make_payment_request(dt="Sales Invoice", dn=si_usd.name, recipient_id="saurabh@erpnext.com")
+		pr = make_payment_request(dt="Sales Invoice", dn=si_usd.name, recipient_id="saurabh@erpnext.com",
+			payment_gateway_account="_Test Gateway - USD")
 
 		self.assertEqual(pr.reference_doctype, "Sales Invoice")
 		self.assertEqual(pr.reference_name, si_usd.name)
@@ -68,7 +70,7 @@
 
 		so_inr = make_sales_order(currency="INR")
 		pr = make_payment_request(dt="Sales Order", dn=so_inr.name, recipient_id="saurabh@erpnext.com",
-			mute_email=1, submit_doc=1, return_doc=1)
+			mute_email=1, payment_gateway_account="_Test Gateway - INR", submit_doc=1, return_doc=1)
 		pe = pr.set_as_paid()
 
 		so_inr = frappe.get_doc("Sales Order", so_inr.name)
@@ -79,7 +81,7 @@
 			currency="USD", conversion_rate=50)
 
 		pr = make_payment_request(dt="Sales Invoice", dn=si_usd.name, recipient_id="saurabh@erpnext.com",
-			mute_email=1, payment_gateway="_Test Gateway - USD", submit_doc=1, return_doc=1)
+			mute_email=1, payment_gateway_account="_Test Gateway - USD", submit_doc=1, return_doc=1)
 
 		pe = pr.set_as_paid()
 
@@ -106,7 +108,7 @@
 			currency="USD", conversion_rate=50)
 
 		pr = make_payment_request(dt="Sales Invoice", dn=si_usd.name, recipient_id="saurabh@erpnext.com",
-			mute_email=1, payment_gateway="_Test Gateway - USD", submit_doc=1, return_doc=1)
+			mute_email=1, payment_gateway_account="_Test Gateway - USD", submit_doc=1, return_doc=1)
 
 		pe = pr.create_payment_entry()
 		pr.load_from_db()
diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
index 73367fd..9ea616f 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
@@ -21,7 +21,7 @@
 			return { filters: { 'status': 'Open', 'docstatus': 1 } };
 		});
 		
-		if (frm.doc.docstatus === 0) frm.set_value("period_end_date", frappe.datetime.now_datetime());
+		if (frm.doc.docstatus === 0 && !frm.doc.amended_from) frm.set_value("period_end_date", frappe.datetime.now_datetime());
 		if (frm.doc.docstatus === 1) set_html_data(frm);
 	},
 
diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py
index edf3d5a..f5224a2 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py
@@ -20,11 +20,16 @@
 		self.validate_pos_invoices()
 	
 	def validate_pos_closing(self):
-		user = frappe.get_all("POS Closing Entry", 
-			filters = { "user": self.user, "docstatus": 1, "pos_profile": self.pos_profile },
-			or_filters = {
-				"period_start_date": ("between", [self.period_start_date, self.period_end_date]),
-				"period_end_date": ("between", [self.period_start_date, self.period_end_date])
+		user = frappe.db.sql("""
+			SELECT name FROM `tabPOS Closing Entry`
+			WHERE
+				user = %(user)s AND docstatus = 1 AND pos_profile = %(profile)s AND
+				(period_start_date between %(start)s and %(end)s OR period_end_date between %(start)s and %(end)s)
+			""", {
+				'user': self.user,
+				'profile': self.pos_profile,
+				'start': self.period_start_date,
+				'end': self.period_end_date
 			})
 
 		if user:
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.js b/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
index 07c8e44..493bd44 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
@@ -195,18 +195,43 @@
 	},
 
 	request_for_payment: function (frm) {
+		if (!frm.doc.contact_mobile) {
+			frappe.throw(__('Please enter mobile number first.'));
+		}
+		frm.dirty();
 		frm.save().then(() => {
-			frappe.dom.freeze();
-			frappe.call({
-				method: 'create_payment_request',
-				doc: frm.doc,
-			})
+			frappe.dom.freeze(__('Waiting for payment...'));
+			frappe
+				.call({
+					method: 'create_payment_request',
+					doc: frm.doc
+				})
 				.fail(() => {
 					frappe.dom.unfreeze();
-					frappe.msgprint('Payment request failed');
+					frappe.msgprint(__('Payment request failed'));
 				})
-				.then(() => {
-					frappe.msgprint('Payment request sent successfully');
+				.then(({ message }) => {
+					const payment_request_name = message.name;
+					setTimeout(() => {
+						frappe.db.get_value('Payment Request', payment_request_name, ['status', 'grand_total']).then(({ message }) => {
+							if (message.status != 'Paid') {
+								frappe.dom.unfreeze();
+								frappe.msgprint({
+									message: __('Payment Request took too long to respond. Please try requesting for payment again.'),
+									title: __('Request Timeout')
+								});
+							} else if (frappe.dom.freeze_count != 0) {
+								frappe.dom.unfreeze();
+								cur_frm.reload_doc();
+								cur_pos.payment.events.submit_invoice();
+
+								frappe.show_alert({
+									message: __("Payment of {0} received successfully.", [format_currency(message.grand_total, frm.doc.currency, 0)]),
+									indicator: 'green'
+								});
+							}
+						});
+					}, 60000);
 				});
 		});
 	}
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
index 8d8babb..76e0092 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
@@ -179,10 +179,18 @@
 			if d.get("serial_no"):
 				serial_nos = get_serial_nos(d.serial_no)
 				for sr in serial_nos:
-					serial_no_exists = frappe.db.exists("POS Invoice Item", {
-						"parent": self.return_against, 
-						"serial_no": ["like", d.get("serial_no")]
-					})
+					serial_no_exists = frappe.db.sql("""
+						SELECT name
+						FROM `tabPOS Invoice Item`
+						WHERE
+							parent = %s
+							and (serial_no = %s
+								or serial_no like %s
+								or serial_no like %s
+								or serial_no like %s
+							)
+					""", (self.return_against, sr, sr+'\n%', '%\n'+sr, '%\n'+sr+'\n%'))
+
 					if not serial_no_exists:
 						bold_return_against = frappe.bold(self.return_against)
 						bold_serial_no = frappe.bold(sr)
@@ -190,7 +198,7 @@
 							_("Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {}")
 							.format(d.idx, bold_serial_no, bold_return_against)
 						)
-	
+
 	def validate_non_stock_items(self):
 		for d in self.get("items"):
 			is_stock_item = frappe.get_cached_value("Item", d.get("item_code"), "is_stock_item")
@@ -292,7 +300,7 @@
 
 		if not self.get('payments') and not for_validate:
 			update_multi_mode_option(self, profile)
-		
+
 		if self.is_return and not for_validate:
 			add_return_modes(self, profile)
 
@@ -317,13 +325,14 @@
 				)
 				customer_group_price_list = frappe.db.get_value("Customer Group", customer_group, 'default_price_list')
 				selling_price_list = customer_price_list or customer_group_price_list or profile.get('selling_price_list')
+				if customer_currency != profile.get('currency'):
+					self.set('currency', customer_currency)
+
 			else:
 				selling_price_list = profile.get('selling_price_list')
 
 			if selling_price_list:
 				self.set('selling_price_list', selling_price_list)
-			if customer_currency != profile.get('currency'):
-				self.set('currency', customer_currency)
 
 			# set pos values in items
 			for item in self.get("items"):
@@ -383,22 +392,48 @@
 				if not self.contact_mobile:
 					frappe.throw(_("Please enter the phone number first"))
 
-				payment_gateway = frappe.db.get_value("Payment Gateway Account", {
-					"payment_account": pay.account,
-				})
-				record = {
-					"payment_gateway": payment_gateway,
-					"dt": "POS Invoice",
-					"dn": self.name,
-					"payment_request_type": "Inward",
-					"party_type": "Customer",
-					"party": self.customer,
-					"mode_of_payment": pay.mode_of_payment,
-					"recipient_id": self.contact_mobile,
-					"submit_doc": True
-				}
+				pay_req = self.get_existing_payment_request(pay)
+				if not pay_req:
+					pay_req = self.get_new_payment_request(pay)
+					pay_req.submit()
+				else:
+					pay_req.request_phone_payment()
 
-				return make_payment_request(**record)
+				return pay_req
+	
+	def get_new_payment_request(self, mop):
+		payment_gateway_account = frappe.db.get_value("Payment Gateway Account", {
+			"payment_account": mop.account,
+		}, ["name"])
+
+		args = {
+			"dt": "POS Invoice",
+			"dn": self.name,
+			"recipient_id": self.contact_mobile,
+			"mode_of_payment": mop.mode_of_payment,
+			"payment_gateway_account": payment_gateway_account,
+			"payment_request_type": "Inward",
+			"party_type": "Customer",
+			"party": self.customer,
+			"return_doc": True
+		}
+		return make_payment_request(**args)
+
+	def get_existing_payment_request(self, pay):
+		payment_gateway_account = frappe.db.get_value("Payment Gateway Account", {
+			"payment_account": pay.account,
+		}, ["name"])
+
+		args = {
+			'doctype': 'Payment Request',
+			'reference_doctype': 'POS Invoice',
+			'reference_name': self.name,
+			'payment_gateway_account': payment_gateway_account,
+			'email_to': self.contact_mobile
+		}
+		pr = frappe.db.exists(args)
+		if pr:
+			return frappe.get_doc('Payment Request', pr[0][0])
 
 @frappe.whitelist()
 def get_stock_availability(item_code, warehouse):
diff --git a/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
index 57a23af..15875af 100644
--- a/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
@@ -198,6 +198,65 @@
 		self.assertEqual(pos_return.get('payments')[0].amount, -500)
 		self.assertEqual(pos_return.get('payments')[1].amount, -500)
 
+	def test_pos_return_for_serialized_item(self):
+		from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
+		from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+
+		se = make_serialized_item(company='_Test Company',
+			target_warehouse="Stores - _TC", cost_center='Main - _TC', expense_account='Cost of Goods Sold - _TC')
+
+		serial_nos = get_serial_nos(se.get("items")[0].serial_no)
+
+		pos = create_pos_invoice(company='_Test Company', debit_to='Debtors - _TC',
+			account_for_change_amount='Cash - _TC', warehouse='Stores - _TC', income_account='Sales - _TC',
+			expense_account='Cost of Goods Sold - _TC', cost_center='Main - _TC',
+			item=se.get("items")[0].item_code, rate=1000, do_not_save=1)
+
+		pos.get("items")[0].serial_no = serial_nos[0]
+		pos.append("payments", {'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 1000, 'default': 1})
+
+		pos.insert()
+		pos.submit()
+
+		pos_return = make_sales_return(pos.name)
+
+		pos_return.insert()
+		pos_return.submit()
+		self.assertEqual(pos_return.get('items')[0].serial_no, serial_nos[0])
+
+	def test_partial_pos_returns(self):
+		from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
+		from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+
+		se = make_serialized_item(company='_Test Company',
+			target_warehouse="Stores - _TC", cost_center='Main - _TC', expense_account='Cost of Goods Sold - _TC')
+
+		serial_nos = get_serial_nos(se.get("items")[0].serial_no)
+
+		pos = create_pos_invoice(company='_Test Company', debit_to='Debtors - _TC',
+			account_for_change_amount='Cash - _TC', warehouse='Stores - _TC', income_account='Sales - _TC',
+			expense_account='Cost of Goods Sold - _TC', cost_center='Main - _TC',
+			item=se.get("items")[0].item_code, qty=2, rate=1000, do_not_save=1)
+
+		pos.get("items")[0].serial_no = serial_nos[0] + "\n" + serial_nos[1]
+		pos.append("payments", {'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 1000, 'default': 1})
+
+		pos.insert()
+		pos.submit()
+
+		pos_return1 = make_sales_return(pos.name)
+
+		# partial return 1
+		pos_return1.get('items')[0].qty = -1
+		pos_return1.get('items')[0].serial_no = serial_nos[0]
+		pos_return1.insert()
+		pos_return1.submit()
+
+		# partial return 2
+		pos_return2 = make_sales_return(pos.name)
+		self.assertEqual(pos_return2.get('items')[0].qty, -1)
+		self.assertEqual(pos_return2.get('items')[0].serial_no, serial_nos[1])
+
 	def test_pos_change_amount(self):
 		pos = create_pos_invoice(company= "_Test Company", debit_to="Debtors - _TC",
 			income_account = "Sales - _TC", expense_account = "Cost of Goods Sold - _TC", rate=105,
diff --git a/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json b/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json
index 2b6e7de..8b71eb0 100644
--- a/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json
+++ b/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json
@@ -87,6 +87,7 @@
   "edit_references",
   "sales_order",
   "so_detail",
+  "pos_invoice_item",
   "column_break_74",
   "delivery_note",
   "dn_detail",
@@ -790,11 +791,20 @@
    "fieldtype": "Link",
    "label": "Project",
    "options": "Project"
+  },
+  {
+   "fieldname": "pos_invoice_item",
+   "fieldtype": "Data",
+   "ignore_user_permissions": 1,
+   "label": "POS Invoice Item",
+   "no_copy": 1,
+   "print_hide": 1,
+   "read_only": 1
   }
  ],
  "istable": 1,
  "links": [],
- "modified": "2020-07-22 13:40:34.418346",
+ "modified": "2021-01-04 17:34:49.924531",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "POS Invoice Item",
diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
index 58409cd..40f77b4 100644
--- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
+++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
@@ -29,7 +29,7 @@
 		for d in self.pos_invoices:
 			status, docstatus, is_return, return_against = frappe.db.get_value(
 				'POS Invoice', d.pos_invoice, ['status', 'docstatus', 'is_return', 'return_against'])
-			
+
 			bold_pos_invoice = frappe.bold(d.pos_invoice)
 			bold_status = frappe.bold(status)
 			if docstatus != 1:
@@ -58,7 +58,7 @@
 		sales_invoice, credit_note = "", ""
 		if sales:
 			sales_invoice = self.process_merging_into_sales_invoice(sales)
-		
+
 		if returns:
 			credit_note = self.process_merging_into_credit_note(returns)
 
@@ -74,7 +74,7 @@
 
 	def process_merging_into_sales_invoice(self, data):
 		sales_invoice = self.get_new_sales_invoice()
-		
+
 		sales_invoice = self.merge_pos_invoice_into(sales_invoice, data)
 
 		sales_invoice.is_consolidated = 1
@@ -98,19 +98,19 @@
 		self.consolidated_credit_note = credit_note.name
 
 		return credit_note.name
-	
+
 	def merge_pos_invoice_into(self, invoice, data):
 		items, payments, taxes = [], [], []
 		loyalty_amount_sum, loyalty_points_sum = 0, 0
 		for doc in data:
 			map_doc(doc, invoice, table_map={ "doctype": invoice.doctype })
-			
+
 			if doc.redeem_loyalty_points:
 				invoice.loyalty_redemption_account = doc.loyalty_redemption_account
 				invoice.loyalty_redemption_cost_center = doc.loyalty_redemption_cost_center
 				loyalty_points_sum += doc.loyalty_points
 				loyalty_amount_sum += doc.loyalty_amount
-			
+
 			for item in doc.get('items'):
 				found = False
 				for i in items:
@@ -118,12 +118,13 @@
 						i.uom == item.uom and i.net_rate == item.net_rate):
 						found = True
 						i.qty = i.qty + item.qty
+
 				if not found:
 					item.rate = item.net_rate
 					item.price_list_rate = 0
 					si_item = map_child_doc(item, invoice, {"doctype": "Sales Invoice Item"})
 					items.append(si_item)
-			
+
 			for tax in doc.get('taxes'):
 				found = False
 				for t in taxes:
@@ -162,7 +163,7 @@
 		invoice.ignore_pricing_rule = 1
 
 		return invoice
-	
+
 	def get_new_sales_invoice(self):
 		sales_invoice = frappe.new_doc('Sales Invoice')
 		sales_invoice.customer = self.customer
@@ -194,7 +195,7 @@
 	}
 	pos_invoices = frappe.db.get_all('POS Invoice', filters=filters,
 		fields=["name as pos_invoice", 'posting_date', 'grand_total', 'customer'])
-	
+
 	return pos_invoices
 
 def get_invoice_customer_map(pos_invoices):
@@ -204,7 +205,7 @@
 		customer = invoice.get('customer')
 		pos_invoice_customer_map.setdefault(customer, [])
 		pos_invoice_customer_map[customer].append(invoice)
-	
+
 	return pos_invoice_customer_map
 
 def consolidate_pos_invoices(pos_invoices=[], closing_entry={}):
@@ -212,8 +213,8 @@
 	invoice_by_customer = get_invoice_customer_map(invoices)
 
 	if len(invoices) >= 5 and closing_entry:
-		enqueue_job(create_merge_logs, invoice_by_customer, closing_entry)
 		closing_entry.set_status(update=True, status='Queued')
+		enqueue_job(create_merge_logs, invoice_by_customer, closing_entry)
 	else:
 		create_merge_logs(invoice_by_customer, closing_entry)
 
@@ -225,8 +226,8 @@
 	)
 
 	if len(merge_logs) >= 5:
-		enqueue_job(cancel_merge_logs, merge_logs, closing_entry)
 		closing_entry.set_status(update=True, status='Queued')
+		enqueue_job(cancel_merge_logs, merge_logs, closing_entry)
 	else:
 		cancel_merge_logs(merge_logs, closing_entry)
 
diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
index 1f7853d..07e75ac 100644
--- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
+++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
@@ -40,6 +40,7 @@
   "base_rate",
   "base_amount",
   "pricing_rules",
+  "stock_uom_rate",
   "is_free_item",
   "section_break_22",
   "net_rate",
@@ -784,6 +785,14 @@
    "read_only": 1
   },
   {
+   "depends_on": "eval: doc.uom != doc.stock_uom",
+   "fieldname": "stock_uom_rate",
+   "fieldtype": "Currency",
+   "label": "Rate of Stock UOM",
+   "options": "currency",
+   "read_only": 1
+  },
+  {
    "fieldname": "sales_invoice_item",
    "fieldtype": "Data",
    "label": "Sales Invoice Item",
@@ -795,7 +804,7 @@
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-12-26 17:20:36.415791",
+ "modified": "2021-01-30 21:43:21.488258",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Purchase Invoice Item",
diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
index 7a98aff..b403c7b 100644
--- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
+++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
@@ -45,6 +45,7 @@
   "base_rate",
   "base_amount",
   "pricing_rules",
+  "stock_uom_rate",
   "is_free_item",
   "section_break_21",
   "net_rate",
@@ -811,12 +812,20 @@
    "no_copy": 1,
    "print_hide": 1,
    "read_only": 1
+  },
+  {
+   "depends_on": "eval: doc.uom != doc.stock_uom",
+   "fieldname": "stock_uom_rate",
+   "fieldtype": "Currency",
+   "label": "Rate of Stock UOM",
+   "options": "currency",
+   "read_only": 1
   }
  ],
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-12-26 17:25:04.090630",
+ "modified": "2021-01-30 21:42:37.796771",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Sales Invoice Item",
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index 287c79f..b42c0c6 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -44,9 +44,9 @@
 		frappe.throw(_("You cannot create or cancel any accounting entries with in the closed Accounting Period {0}")
 			.format(frappe.bold(accounting_periods[0].name)), ClosedAccountingPeriod)
 
-def process_gl_map(gl_map, merge_entries=True):
+def process_gl_map(gl_map, merge_entries=True, precision=None):
 	if merge_entries:
-		gl_map = merge_similar_entries(gl_map)
+		gl_map = merge_similar_entries(gl_map, precision)
 	for entry in gl_map:
 		# toggle debit, credit if negative entry
 		if flt(entry.debit) < 0:
@@ -69,7 +69,7 @@
 
 	return gl_map
 
-def merge_similar_entries(gl_map):
+def merge_similar_entries(gl_map, precision=None):
 	merged_gl_map = []
 	accounting_dimensions = get_accounting_dimensions()
 	for entry in gl_map:
@@ -88,7 +88,9 @@
 
 	company = gl_map[0].company if gl_map else erpnext.get_default_company()
 	company_currency = erpnext.get_company_currency(company)
-	precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"), company_currency)
+
+	if not precision:
+		precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"), company_currency)
 
 	# filter zero debit and credit entries
 	merged_gl_map = filter(lambda x: flt(x.debit, precision)!=0 or flt(x.credit, precision)!=0, merged_gl_map)
@@ -132,8 +134,8 @@
 	gle.update(args)
 	gle.flags.ignore_permissions = 1
 	gle.flags.from_repost = from_repost
-	gle.insert()
-	gle.run_method("on_update_with_args", adv_adj, update_outstanding, from_repost)
+	gle.flags.adv_adj = adv_adj
+	gle.flags.update_outstanding = update_outstanding or 'Yes'
 	gle.submit()
 
 	if not from_repost:
diff --git a/erpnext/accounts/page/bank_reconciliation/__init__.py b/erpnext/accounts/page/bank_reconciliation/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/accounts/page/bank_reconciliation/__init__.py
+++ /dev/null
diff --git a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js b/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js
deleted file mode 100644
index 6ae81d7..0000000
--- a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js
+++ /dev/null
@@ -1,583 +0,0 @@
-frappe.provide("erpnext.accounts");
-
-frappe.pages['bank-reconciliation'].on_page_load = function(wrapper) {
-	new erpnext.accounts.bankReconciliation(wrapper);
-}
-
-erpnext.accounts.bankReconciliation = class BankReconciliation {
-	constructor(wrapper) {
-		this.page = frappe.ui.make_app_page({
-			parent: wrapper,
-			title: __("Bank Reconciliation"),
-			single_column: true
-		});
-		this.parent = wrapper;
-		this.page = this.parent.page;
-
-		this.check_plaid_status();
-		this.make();
-	}
-
-	make() {
-		const me = this;
-
-		me.$main_section = $(`<div class="reconciliation page-main-content"></div>`).appendTo(me.page.main);
-		const empty_state = __("Upload a bank statement, link or reconcile a bank account")
-		me.$main_section.append(`<div class="flex justify-center align-center text-muted"
-			style="height: 50vh; display: flex;"><h5 class="text-muted">${empty_state}</h5></div>`)
-
-		me.page.add_field({
-			fieldtype: 'Link',
-			label: __('Company'),
-			fieldname: 'company',
-			options: "Company",
-			onchange: function() {
-				if (this.value) {
-					me.company = this.value;
-				} else {
-					me.company = null;
-					me.bank_account = null;
-				}
-			}
-		})
-		me.page.add_field({
-			fieldtype: 'Link',
-			label: __('Bank Account'),
-			fieldname: 'bank_account',
-			options: "Bank Account",
-			get_query: function() {
-				if(!me.company) {
-					frappe.throw(__("Please select company first"));
-					return
-				}
-
-				return {
-					filters: {
-						"company": me.company
-					}
-				}
-			},
-			onchange: function() {
-				if (this.value) {
-					me.bank_account = this.value;
-					me.add_actions();
-				} else {
-					me.bank_account = null;
-					me.page.hide_actions_menu();
-				}
-			}
-		})
-	}
-
-	check_plaid_status() {
-		const me = this;
-		frappe.db.get_value("Plaid Settings", "Plaid Settings", "enabled", (r) => {
-			if (r && r.enabled === "1") {
-				me.plaid_status = "active"
-			} else {
-				me.plaid_status = "inactive"
-			}
-		})
-	}
-
-	add_actions() {
-		const me = this;
-
-		me.page.show_menu()
-
-		me.page.add_menu_item(__("Upload a statement"), function() {
-			me.clear_page_content();
-			new erpnext.accounts.bankTransactionUpload(me);
-		}, true)
-
-		if (me.plaid_status==="active") {
-			me.page.add_menu_item(__("Synchronize this account"), function() {
-				me.clear_page_content();
-				new erpnext.accounts.bankTransactionSync(me);
-			}, true)
-		}
-
-		me.page.add_menu_item(__("Reconcile this account"), function() {
-			me.clear_page_content();
-			me.make_reconciliation_tool();
-		}, true)
-	}
-
-	clear_page_content() {
-		const me = this;
-		$(me.page.body).find('.frappe-list').remove();
-		me.$main_section.empty();
-	}
-
-	make_reconciliation_tool() {
-		const me = this;
-		frappe.model.with_doctype("Bank Transaction", () => {
-			erpnext.accounts.ReconciliationList = new erpnext.accounts.ReconciliationTool({
-				parent: me.parent,
-				doctype: "Bank Transaction"
-			});
-		})
-	}
-}
-
-
-erpnext.accounts.bankTransactionUpload = class bankTransactionUpload {
-	constructor(parent) {
-		this.parent = parent;
-		this.data = [];
-
-		const assets = [
-			"/assets/frappe/css/frappe-datatable.css",
-			"/assets/frappe/js/lib/clusterize.min.js",
-			"/assets/frappe/js/lib/Sortable.min.js",
-			"/assets/frappe/js/lib/frappe-datatable.js"
-		];
-
-		frappe.require(assets, () => {
-			this.make();
-		});
-	}
-
-	make() {
-		const me = this;
-		new frappe.ui.FileUploader({
-			method: 'erpnext.accounts.doctype.bank_transaction.bank_transaction_upload.upload_bank_statement',
-			allow_multiple: 0,
-			on_success: function(attachment, r) {
-				if (!r.exc && r.message) {
-					me.data = r.message;
-					me.setup_transactions_dom();
-					me.create_datatable();
-					me.add_primary_action();
-				}
-			}
-		})
-	}
-
-	setup_transactions_dom() {
-		const me = this;
-		me.parent.$main_section.append('<div class="transactions-table"></div>');
-	}
-
-	create_datatable() {
-		try {
-			this.datatable = new DataTable('.transactions-table', {
-				columns: this.data.columns,
-				data: this.data.data
-			})
-		}
-		catch(err) {
-			let msg = __("Your file could not be processed. It should be a standard CSV or XLSX file with headers in the first row.");
-			frappe.throw(msg)
-		}
-
-	}
-
-	add_primary_action() {
-		const me = this;
-		me.parent.page.set_primary_action(__("Submit"), function() {
-			me.add_bank_entries()
-		}, null, __("Creating bank entries..."))
-	}
-
-	add_bank_entries() {
-		const me = this;
-		frappe.xcall('erpnext.accounts.doctype.bank_transaction.bank_transaction_upload.create_bank_entries',
-			{columns: this.datatable.datamanager.columns, data: this.datatable.datamanager.data, bank_account: me.parent.bank_account}
-		).then((result) => {
-			let result_title = result.errors == 0 ? __("{0} bank transaction(s) created", [result.success]) : __("{0} bank transaction(s) created and {1} errors", [result.success, result.errors])
-			let result_msg = `
-				<div class="flex justify-center align-center text-muted" style="height: 50vh; display: flex;">
-					<h5 class="text-muted">${result_title}</h5>
-				</div>`
-			me.parent.page.clear_primary_action();
-			me.parent.$main_section.empty();
-			me.parent.$main_section.append(result_msg);
-			if (result.errors == 0) {
-				frappe.show_alert({message:__("All bank transactions have been created"), indicator:'green'});
-			} else {
-				frappe.show_alert({message:__("Please check the error log for details about the import errors"), indicator:'red'});
-			}
-		})
-	}
-}
-
-erpnext.accounts.bankTransactionSync = class bankTransactionSync {
-	constructor(parent) {
-		this.parent = parent;
-		this.data = [];
-
-		this.init_config()
-	}
-
-	init_config() {
-		const me = this;
-		frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.get_plaid_configuration')
-			.then(result => {
-				me.plaid_env = result.plaid_env;
-				me.client_name = result.client_name;
-				me.link_token = result.link_token;
-				me.sync_transactions();
-			})
-	}
-
-	sync_transactions() {
-		const me = this;
-		frappe.db.get_value("Bank Account", me.parent.bank_account, "bank", (r) => {
-			frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.sync_transactions', {
-				bank: r.bank,
-				bank_account: me.parent.bank_account,
-				freeze: true
-			})
-			.then((result) => {
-				let result_title = (result && result.length > 0)
-					? __("{0} bank transaction(s) created", [result.length])
-					: __("This bank account is already synchronized");
-
-				let result_msg = `
-				<div class="flex justify-center align-center text-muted" style="height: 50vh; display: flex;">
-					<h5 class="text-muted">${result_title}</h5>
-				</div>`
-
-				this.parent.$main_section.append(result_msg)
-				frappe.show_alert({ message: __("Bank account '{0}' has been synchronized", [me.parent.bank_account]), indicator: 'green' });
-			})
-		})
-	}
-}
-
-
-erpnext.accounts.ReconciliationTool = class ReconciliationTool extends frappe.views.BaseList {
-	constructor(opts) {
-		super(opts);
-		this.show();
-	}
-
-	setup_defaults() {
-		super.setup_defaults();
-
-		this.page_title = __("Bank Reconciliation");
-		this.doctype = 'Bank Transaction';
-		this.fields = ['date', 'description', 'debit', 'credit', 'currency']
-
-	}
-
-	setup_view() {
-		this.render_header();
-	}
-
-	setup_side_bar() {
-		//
-	}
-
-	make_standard_filters() {
-		//
-	}
-
-	freeze() {
-		this.$result.find('.list-count').html(`<span>${__('Refreshing')}...</span>`);
-	}
-
-	get_args() {
-		const args = super.get_args();
-
-		return Object.assign({}, args, {
-			...args.filters.push(["Bank Transaction", "docstatus", "=", 1],
-				["Bank Transaction", "unallocated_amount", ">", 0])
-		});
-
-	}
-
-	update_data(r) {
-		let data = r.message || [];
-
-		if (this.start === 0) {
-			this.data = data;
-		} else {
-			this.data = this.data.concat(data);
-		}
-	}
-
-	render() {
-		const me = this;
-		this.$result.find('.list-row-container').remove();
-		$('[data-fieldname="name"]').remove();
-		me.data.map((value) => {
-			const row = $('<div class="list-row-container">').data("data", value).appendTo(me.$result).get(0);
-			new erpnext.accounts.ReconciliationRow(row, value);
-		})
-	}
-
-	render_header() {
-		const me = this;
-		if ($(this.wrapper).find('.transaction-header').length === 0) {
-			me.$result.append(frappe.render_template("bank_transaction_header"));
-		}
-	}
-}
-
-erpnext.accounts.ReconciliationRow = class ReconciliationRow {
-	constructor(row, data) {
-		this.data = data;
-		this.row = row;
-		this.make();
-		this.bind_events();
-	}
-
-	make() {
-		$(this.row).append(frappe.render_template("bank_transaction_row", this.data))
-	}
-
-	bind_events() {
-		const me = this;
-		$(me.row).on('click', '.clickable-section', function() {
-			me.bank_entry = $(this).attr("data-name");
-			me.show_dialog($(this).attr("data-name"));
-		})
-
-		$(me.row).on('click', '.new-reconciliation', function() {
-			me.bank_entry = $(this).attr("data-name");
-			me.show_dialog($(this).attr("data-name"));
-		})
-
-		$(me.row).on('click', '.new-payment', function() {
-			me.bank_entry = $(this).attr("data-name");
-			me.new_payment();
-		})
-
-		$(me.row).on('click', '.new-invoice', function() {
-			me.bank_entry = $(this).attr("data-name");
-			me.new_invoice();
-		})
-
-		$(me.row).on('click', '.new-expense', function() {
-			me.bank_entry = $(this).attr("data-name");
-			me.new_expense();
-		})
-	}
-
-	new_payment() {
-		const me = this;
-		const paid_amount = me.data.credit > 0 ? me.data.credit : me.data.debit;
-		const payment_type = me.data.credit > 0 ? "Receive": "Pay";
-		const party_type = me.data.credit > 0 ? "Customer": "Supplier";
-
-		frappe.new_doc("Payment Entry", {"payment_type": payment_type, "paid_amount": paid_amount,
-			"party_type": party_type, "paid_from": me.data.bank_account})
-	}
-
-	new_invoice() {
-		const me = this;
-		const invoice_type = me.data.credit > 0 ? "Sales Invoice" : "Purchase Invoice";
-
-		frappe.new_doc(invoice_type)
-	}
-
-	new_expense() {
-		frappe.new_doc("Expense Claim")
-	}
-
-
-	show_dialog(data) {
-		const me = this;
-
-		frappe.db.get_value("Bank Account", me.data.bank_account, "account", (r) => {
-			me.gl_account = r.account;
-		})
-
-		frappe.xcall('erpnext.accounts.page.bank_reconciliation.bank_reconciliation.get_linked_payments',
-			{ bank_transaction: data, freeze: true, freeze_message: __("Finding linked payments") }
-		).then((result) => {
-			me.make_dialog(result)
-		})
-	}
-
-	make_dialog(data) {
-		const me = this;
-		me.selected_payment = null;
-
-		const fields = [
-			{
-				fieldtype: 'Section Break',
-				fieldname: 'section_break_1',
-				label: __('Automatic Reconciliation')
-			},
-			{
-				fieldtype: 'HTML',
-				fieldname: 'payment_proposals'
-			},
-			{
-				fieldtype: 'Section Break',
-				fieldname: 'section_break_2',
-				label: __('Search for a payment')
-			},
-			{
-				fieldtype: 'Link',
-				fieldname: 'payment_doctype',
-				options: 'DocType',
-				label: 'Payment DocType',
-				get_query: () => {
-					return {
-						filters : {
-							"name": ["in", ["Payment Entry", "Journal Entry", "Sales Invoice", "Purchase Invoice", "Expense Claim"]]
-						}
-					}
-				},
-			},
-			{
-				fieldtype: 'Column Break',
-				fieldname: 'column_break_1',
-			},
-			{
-				fieldtype: 'Dynamic Link',
-				fieldname: 'payment_entry',
-				options: 'payment_doctype',
-				label: 'Payment Document',
-				get_query: () => {
-					let dt = this.dialog.fields_dict.payment_doctype.value;
-					if (dt === "Payment Entry") {
-						return {
-							query: "erpnext.accounts.page.bank_reconciliation.bank_reconciliation.payment_entry_query",
-							filters : {
-								"bank_account": this.data.bank_account,
-								"company": this.data.company
-							}
-						}
-					} else if (dt === "Journal Entry") {
-						return {
-							query: "erpnext.accounts.page.bank_reconciliation.bank_reconciliation.journal_entry_query",
-							filters : {
-								"bank_account": this.data.bank_account,
-								"company": this.data.company
-							}
-						}
-					} else if (dt === "Sales Invoice") {
-						return {
-							query: "erpnext.accounts.page.bank_reconciliation.bank_reconciliation.sales_invoices_query"
-						}
-					} else if (dt === "Purchase Invoice") {
-						return {
-							filters : [
-								["Purchase Invoice", "ifnull(clearance_date, '')", "=", ""],
-								["Purchase Invoice", "docstatus", "=", 1],
-								["Purchase Invoice", "company", "=", this.data.company]
-							]
-						}
-					} else if (dt === "Expense Claim") {
-						return {
-							filters : [
-								["Expense Claim", "ifnull(clearance_date, '')", "=", ""],
-								["Expense Claim", "docstatus", "=", 1],
-								["Expense Claim", "company", "=", this.data.company]
-							]
-						}
-					}
-				},
-				onchange: function() {
-					if (me.selected_payment !== this.value) {
-						me.selected_payment = this.value;
-						me.display_payment_details(this);
-					}
-				}
-			},
-			{
-				fieldtype: 'Section Break',
-				fieldname: 'section_break_3'
-			},
-			{
-				fieldtype: 'HTML',
-				fieldname: 'payment_details'
-			},
-		];
-
-		me.dialog = new frappe.ui.Dialog({
-			title: __("Choose a corresponding payment"),
-			fields: fields,
-			size: "large"
-		});
-
-		const proposals_wrapper = me.dialog.fields_dict.payment_proposals.$wrapper;
-		if (data && data.length > 0) {
-			proposals_wrapper.append(frappe.render_template("linked_payment_header"));
-			data.map(value => {
-				proposals_wrapper.append(frappe.render_template("linked_payment_row", value))
-			})
-		} else {
-			const empty_data_msg = __("ERPNext could not find any matching payment entry")
-			proposals_wrapper.append(`<div class="text-center"><h5 class="text-muted">${empty_data_msg}</h5></div>`)
-		}
-
-		$(me.dialog.body).on('click', '.reconciliation-btn', (e) => {
-			const payment_entry = $(e.target).attr('data-name');
-			const payment_doctype = $(e.target).attr('data-doctype');
-			frappe.xcall('erpnext.accounts.page.bank_reconciliation.bank_reconciliation.reconcile',
-				{bank_transaction: me.bank_entry, payment_doctype: payment_doctype, payment_name: payment_entry})
-			.then((result) => {
-				setTimeout(function(){
-					erpnext.accounts.ReconciliationList.refresh();
-				}, 2000);
-				me.dialog.hide();
-			})
-		})
-
-		me.dialog.show();
-	}
-
-	display_payment_details(event) {
-		const me = this;
-		if (event.value) {
-			let dt = me.dialog.fields_dict.payment_doctype.value;
-			me.dialog.fields_dict['payment_details'].$wrapper.empty();
-			frappe.db.get_doc(dt, event.value)
-			.then(doc => {
-				let displayed_docs = []
-				let payment = []
-				if (dt === "Payment Entry") {
-					payment.currency = doc.payment_type == "Receive" ? doc.paid_to_account_currency : doc.paid_from_account_currency;
-					payment.doctype = dt
-					payment.posting_date = doc.posting_date;
-					payment.party = doc.party;
-					payment.reference_no = doc.reference_no;
-					payment.reference_date = doc.reference_date;
-					payment.paid_amount = doc.paid_amount;
-					payment.name = doc.name;
-					displayed_docs.push(payment);
-				} else if (dt === "Journal Entry") {
-					doc.accounts.forEach(payment => {
-						if (payment.account === me.gl_account) {
-							payment.doctype = dt;
-							payment.posting_date = doc.posting_date;
-							payment.party = doc.pay_to_recd_from;
-							payment.reference_no = doc.cheque_no;
-							payment.reference_date = doc.cheque_date;
-							payment.currency = payment.account_currency;
-							payment.paid_amount = payment.credit > 0 ? payment.credit : payment.debit;
-							payment.name = doc.name;
-							displayed_docs.push(payment);
-						}
-					})
-				} else if (dt === "Sales Invoice") {
-					doc.payments.forEach(payment => {
-						if (payment.clearance_date === null || payment.clearance_date === "") {
-							payment.doctype = dt;
-							payment.posting_date = doc.posting_date;
-							payment.party = doc.customer;
-							payment.reference_no = doc.remarks;
-							payment.currency = doc.currency;
-							payment.paid_amount = payment.amount;
-							payment.name = doc.name;
-							displayed_docs.push(payment);
-						}
-					})
-				}
-
-				const details_wrapper = me.dialog.fields_dict.payment_details.$wrapper;
-				details_wrapper.append(frappe.render_template("linked_payment_header"));
-				displayed_docs.forEach(payment => {
-					details_wrapper.append(frappe.render_template("linked_payment_row", payment));
-				})
-			})
-		}
-
-	}
-}
diff --git a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.json b/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.json
deleted file mode 100644
index feea368..0000000
--- a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "content": null, 
- "creation": "2018-11-24 12:03:14.646669", 
- "docstatus": 0, 
- "doctype": "Page", 
- "idx": 0, 
- "modified": "2018-11-24 12:03:14.646669", 
- "modified_by": "Administrator", 
- "module": "Accounts", 
- "name": "bank-reconciliation", 
- "owner": "Administrator", 
- "page_name": "bank-reconciliation", 
- "roles": [
-  {
-   "role": "System Manager"
-  }, 
-  {
-   "role": "Accounts Manager"
-  }, 
-  {
-   "role": "Accounts User"
-  }
- ], 
- "script": null, 
- "standard": "Yes", 
- "style": null, 
- "system_page": 0, 
- "title": "Bank Reconciliation"
-}
\ No newline at end of file
diff --git a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py b/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py
deleted file mode 100644
index 8abe20c..0000000
--- a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py
+++ /dev/null
@@ -1,369 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe import _
-import difflib
-from frappe.utils import flt
-from six import iteritems
-from erpnext import get_company_currency
-
-@frappe.whitelist()
-def reconcile(bank_transaction, payment_doctype, payment_name):
-	transaction = frappe.get_doc("Bank Transaction", bank_transaction)
-	payment_entry = frappe.get_doc(payment_doctype, payment_name)
-
-	account = frappe.db.get_value("Bank Account", transaction.bank_account, "account")
-	gl_entry = frappe.get_doc("GL Entry", dict(account=account, voucher_type=payment_doctype, voucher_no=payment_name))
-
-	if payment_doctype == "Payment Entry" and payment_entry.unallocated_amount > transaction.unallocated_amount:
-		frappe.throw(_("The unallocated amount of Payment Entry {0} is greater than the Bank Transaction's unallocated amount").format(payment_name))
-
-	if transaction.unallocated_amount == 0:
-		frappe.throw(_("This bank transaction is already fully reconciled"))
-
-	if transaction.credit > 0 and gl_entry.credit > 0:
-		frappe.throw(_("The selected payment entry should be linked with a debtor bank transaction"))
-
-	if transaction.debit > 0 and gl_entry.debit > 0:
-		frappe.throw(_("The selected payment entry should be linked with a creditor bank transaction"))
-
-	add_payment_to_transaction(transaction, payment_entry, gl_entry)
-
-	return 'reconciled'
-
-def add_payment_to_transaction(transaction, payment_entry, gl_entry):
-	gl_amount, transaction_amount = (gl_entry.credit, transaction.debit) if gl_entry.credit > 0 else (gl_entry.debit, transaction.credit)
-	allocated_amount = gl_amount if gl_amount <= transaction_amount else transaction_amount
-	transaction.append("payment_entries", {
-		"payment_document": payment_entry.doctype,
-		"payment_entry": payment_entry.name,
-		"allocated_amount": allocated_amount
-	})
-
-	transaction.save()
-	transaction.update_allocations()
-
-@frappe.whitelist()
-def get_linked_payments(bank_transaction):
-	transaction = frappe.get_doc("Bank Transaction", bank_transaction)
-	bank_account = frappe.db.get_values("Bank Account", transaction.bank_account, ["account", "company"], as_dict=True)
-
-	# Get all payment entries with a matching amount
-	amount_matching = check_matching_amount(bank_account[0].account, bank_account[0].company, transaction)
-
-	# Get some data from payment entries linked to a corresponding bank transaction
-	description_matching = get_matching_descriptions_data(bank_account[0].company, transaction)
-
-	if amount_matching:
-		return check_amount_vs_description(amount_matching, description_matching)
-
-	elif description_matching:
-		description_matching = filter(lambda x: not x.get('clearance_date'), description_matching)
-		if not description_matching:
-			return []
-
-		return sorted(list(description_matching), key = lambda x: x["posting_date"], reverse=True)
-
-	else:
-		return []
-
-def check_matching_amount(bank_account, company, transaction):
-	payments = []
-	amount = transaction.credit if transaction.credit > 0 else transaction.debit
-
-	payment_type = "Receive" if transaction.credit > 0 else "Pay"
-	account_from_to = "paid_to" if transaction.credit > 0 else "paid_from"
-	currency_field = "paid_to_account_currency as currency" if transaction.credit > 0 else "paid_from_account_currency as currency"
-
-	payment_entries = frappe.get_all("Payment Entry", fields=["'Payment Entry' as doctype", "name", "paid_amount", "payment_type", "reference_no", "reference_date",
-		"party", "party_type", "posting_date", "{0}".format(currency_field)], filters=[["paid_amount", "like", "{0}%".format(amount)],
-		["docstatus", "=", "1"], ["payment_type", "=", [payment_type, "Internal Transfer"]], ["ifnull(clearance_date, '')", "=", ""], ["{0}".format(account_from_to), "=", "{0}".format(bank_account)]])
-
-	jea_side = "debit" if transaction.credit > 0 else "credit"
-	journal_entries = frappe.db.sql(f"""
-		SELECT
-			'Journal Entry' as doctype, je.name, je.posting_date, je.cheque_no as reference_no,
-			jea.account_currency as currency, je.pay_to_recd_from as party, je.cheque_date as reference_date,
-			jea.{jea_side}_in_account_currency as paid_amount
-		FROM
-			`tabJournal Entry Account` as jea
-		JOIN
-			`tabJournal Entry` as je
-		ON
-			jea.parent = je.name
-		WHERE
-			(je.clearance_date is null or je.clearance_date='0000-00-00')
-		AND
-			jea.account = %(bank_account)s
-		AND
-			jea.{jea_side}_in_account_currency like %(txt)s
-		AND
-			je.docstatus = 1
-	""", {
-		'bank_account': bank_account,
-		'txt': '%%%s%%' % amount
-	}, as_dict=True)
-
-	if transaction.credit > 0:
-		sales_invoices = frappe.db.sql("""
-			SELECT
-				'Sales Invoice' as doctype, si.name, si.customer as party,
-				si.posting_date, sip.amount as paid_amount
-			FROM
-				`tabSales Invoice Payment` as sip
-			JOIN
-				`tabSales Invoice` as si
-			ON
-				sip.parent = si.name
-			WHERE
-				(sip.clearance_date is null or sip.clearance_date='0000-00-00')
-			AND
-				sip.account = %s
-			AND
-				sip.amount like %s
-			AND
-				si.docstatus = 1
-		""", (bank_account, amount), as_dict=True)
-	else:
-		sales_invoices = []
-
-	if transaction.debit > 0:
-		purchase_invoices = frappe.get_all("Purchase Invoice",
-			fields = ["'Purchase Invoice' as doctype", "name", "paid_amount", "supplier as party", "posting_date", "currency"],
-			filters=[
-				["paid_amount", "like", "{0}%".format(amount)],
-				["docstatus", "=", "1"],
-				["is_paid", "=", "1"],
-				["ifnull(clearance_date, '')", "=", ""],
-				["cash_bank_account", "=", "{0}".format(bank_account)]
-			]
-		)
-
-		mode_of_payments = [x["parent"] for x in frappe.db.get_list("Mode of Payment Account",
-			filters={"default_account": bank_account}, fields=["parent"])]
-
-		company_currency = get_company_currency(company)
-
-		expense_claims = frappe.get_all("Expense Claim",
-			fields=["'Expense Claim' as doctype", "name", "total_sanctioned_amount as paid_amount",
-				"employee as party", "posting_date", "'{0}' as currency".format(company_currency)],
-			filters=[
-				["total_sanctioned_amount", "like", "{0}%".format(amount)],
-				["docstatus", "=", "1"],
-				["is_paid", "=", "1"],
-				["ifnull(clearance_date, '')", "=", ""],
-				["mode_of_payment", "in", "{0}".format(tuple(mode_of_payments))]
-			]
-		)
-	else:
-		purchase_invoices = expense_claims = []
-
-	for data in [payment_entries, journal_entries, sales_invoices, purchase_invoices, expense_claims]:
-		if data:
-			payments.extend(data)
-
-	return payments
-
-def get_matching_descriptions_data(company, transaction):
-	if not transaction.description :
-		return []
-
-	bank_transactions = frappe.db.sql("""
-		SELECT
-			bt.name, bt.description, bt.date, btp.payment_document, btp.payment_entry
-		FROM
-			`tabBank Transaction` as bt
-		LEFT JOIN
-			`tabBank Transaction Payments` as btp
-		ON
-			bt.name = btp.parent
-		WHERE
-			bt.allocated_amount > 0
-		AND
-			bt.docstatus = 1
-		""", as_dict=True)
-
-	selection = []
-	for bank_transaction in bank_transactions:
-		if bank_transaction.description:
-			seq=difflib.SequenceMatcher(lambda x: x == " ", transaction.description, bank_transaction.description)
-
-			if seq.ratio() > 0.6:
-				bank_transaction["ratio"] = seq.ratio()
-				selection.append(bank_transaction)
-
-	document_types = set([x["payment_document"] for x in selection])
-
-	links = {}
-	for document_type in document_types:
-		links[document_type] = [x["payment_entry"] for x in selection if x["payment_document"]==document_type]
-
-
-	data = []
-	company_currency = get_company_currency(company)
-	for key, value in iteritems(links):
-		if key == "Payment Entry":
-			data.extend(frappe.get_all("Payment Entry", filters=[["name", "in", value]],
-				fields=["'Payment Entry' as doctype", "posting_date", "party", "reference_no",
-					"reference_date", "paid_amount", "paid_to_account_currency as currency", "clearance_date"]))
-		if key == "Journal Entry":
-			journal_entries = frappe.get_all("Journal Entry", filters=[["name", "in", value]],
-				fields=["name", "'Journal Entry' as doctype", "posting_date",
-					"pay_to_recd_from as party", "cheque_no as reference_no", "cheque_date as reference_date",
-					"total_credit as paid_amount", "clearance_date"])
-			for journal_entry in journal_entries:
-				journal_entry_accounts = frappe.get_all("Journal Entry Account", filters={"parenttype": journal_entry["doctype"], "parent": journal_entry["name"]}, fields=["account_currency"])
-				journal_entry["currency"] = journal_entry_accounts[0]["account_currency"] if journal_entry_accounts else company_currency
-			data.extend(journal_entries)
-		if key == "Sales Invoice":
-			data.extend(frappe.get_all("Sales Invoice", filters=[["name", "in", value]], fields=["'Sales Invoice' as doctype", "posting_date", "customer_name as party", "paid_amount", "currency"]))
-		if key == "Purchase Invoice":
-			data.extend(frappe.get_all("Purchase Invoice", filters=[["name", "in", value]], fields=["'Purchase Invoice' as doctype", "posting_date", "supplier_name as party", "paid_amount", "currency"]))
-		if key == "Expense Claim":
-			expense_claims = frappe.get_all("Expense Claim", filters=[["name", "in", value]], fields=["'Expense Claim' as doctype", "posting_date", "employee_name as party", "total_amount_reimbursed as paid_amount"])
-			data.extend([dict(x,**{"currency": company_currency}) for x in expense_claims])
-
-	return data
-
-def check_amount_vs_description(amount_matching, description_matching):
-	result = []
-
-	if description_matching:
-		for am_match in amount_matching:
-			for des_match in description_matching:
-				if des_match.get("clearance_date"):
-					continue
-
-				if am_match["party"] == des_match["party"]:
-					if am_match not in result:
-						result.append(am_match)
-						continue
-
-				if "reference_no" in am_match and "reference_no" in des_match:
-					# Sequence Matcher does not handle None as input
-					am_reference = am_match["reference_no"] or ""
-					des_reference = des_match["reference_no"] or ""
-
-					if difflib.SequenceMatcher(lambda x: x == " ", am_reference, des_reference).ratio() > 70:
-						if am_match not in result:
-							result.append(am_match)
-		if result:
-			return sorted(result, key = lambda x: x["posting_date"], reverse=True)
-		else:
-			return sorted(amount_matching, key = lambda x: x["posting_date"], reverse=True)
-
-	else:
-		return sorted(amount_matching, key = lambda x: x["posting_date"], reverse=True)
-
-def get_matching_transactions_payments(description_matching):
-	payments = [x["payment_entry"] for x in description_matching]
-
-	payment_by_ratio = {x["payment_entry"]: x["ratio"] for x in description_matching}
-
-	if payments:
-		reference_payment_list = frappe.get_all("Payment Entry", fields=["name", "paid_amount", "payment_type", "reference_no", "reference_date",
-			"party", "party_type", "posting_date", "paid_to_account_currency"], filters=[["name", "in", payments]])
-
-		return sorted(reference_payment_list, key=lambda x: payment_by_ratio[x["name"]])
-
-	else:
-		return []
-
-@frappe.whitelist()
-@frappe.validate_and_sanitize_search_inputs
-def payment_entry_query(doctype, txt, searchfield, start, page_len, filters):
-	account = frappe.db.get_value("Bank Account", filters.get("bank_account"), "account")
-	if not account:
-		return
-
-	return frappe.db.sql("""
-		SELECT
-			name, party, paid_amount, received_amount, reference_no
-		FROM
-			`tabPayment Entry`
-		WHERE
-			(clearance_date is null or clearance_date='0000-00-00')
-			AND (paid_from = %(account)s or paid_to = %(account)s)
-			AND (name like %(txt)s or party like %(txt)s)
-			AND docstatus = 1
-		ORDER BY
-			if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999), name
-		LIMIT
-			%(start)s, %(page_len)s""",
-		{
-			'txt': "%%%s%%" % txt,
-			'_txt': txt.replace("%", ""),
-			'start': start,
-			'page_len': page_len,
-			'account': account
-		}
-	)
-
-@frappe.whitelist()
-@frappe.validate_and_sanitize_search_inputs
-def journal_entry_query(doctype, txt, searchfield, start, page_len, filters):
-	account = frappe.db.get_value("Bank Account", filters.get("bank_account"), "account")
-
-	return frappe.db.sql("""
-		SELECT
-			jea.parent, je.pay_to_recd_from,
-			if(jea.debit_in_account_currency > 0, jea.debit_in_account_currency, jea.credit_in_account_currency)
-		FROM
-			`tabJournal Entry Account` as jea
-		LEFT JOIN
-			`tabJournal Entry` as je
-		ON
-			jea.parent = je.name
-		WHERE
-			(je.clearance_date is null or je.clearance_date='0000-00-00')
-		AND
-			jea.account = %(account)s
-		AND
-			(jea.parent like %(txt)s or je.pay_to_recd_from like %(txt)s)
-		AND
-			je.docstatus = 1
-		ORDER BY
-			if(locate(%(_txt)s, jea.parent), locate(%(_txt)s, jea.parent), 99999),
-			jea.parent
-		LIMIT
-			%(start)s, %(page_len)s""",
-		{
-			'txt': "%%%s%%" % txt,
-			'_txt': txt.replace("%", ""),
-			'start': start,
-			'page_len': page_len,
-			'account': account
-		}
-	)
-
-@frappe.whitelist()
-@frappe.validate_and_sanitize_search_inputs
-def sales_invoices_query(doctype, txt, searchfield, start, page_len, filters):
-	return frappe.db.sql("""
-		SELECT
-			sip.parent, si.customer, sip.amount, sip.mode_of_payment
-		FROM
-			`tabSales Invoice Payment` as sip
-		LEFT JOIN
-			`tabSales Invoice` as si
-		ON
-			sip.parent = si.name
-		WHERE
-			(sip.clearance_date is null or sip.clearance_date='0000-00-00')
-		AND
-			(sip.parent like %(txt)s or si.customer like %(txt)s)
-		ORDER BY
-			if(locate(%(_txt)s, sip.parent), locate(%(_txt)s, sip.parent), 99999),
-			sip.parent
-		LIMIT
-			%(start)s, %(page_len)s""",
-		{
-			'txt': "%%%s%%" % txt,
-			'_txt': txt.replace("%", ""),
-			'start': start,
-			'page_len': page_len
-		}
-	)
diff --git a/erpnext/accounts/page/bank_reconciliation/bank_transaction_header.html b/erpnext/accounts/page/bank_reconciliation/bank_transaction_header.html
deleted file mode 100644
index 94f183b..0000000
--- a/erpnext/accounts/page/bank_reconciliation/bank_transaction_header.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<div class="transaction-header">
-	<div class="level list-row list-row-head text-muted small">
-		<div class="col-sm-2 ellipsis hidden-xs">
-			{{ __("Date") }}
-		</div>
-		<div class="col-xs-11 col-sm-4 ellipsis list-subject">
-			{{ __("Description") }}
-		</div>
-		<div class="col-sm-2 ellipsis hidden-xs">
-			{{ __("Debit") }}
-		</div>
-		<div class="col-sm-2 ellipsis hidden-xs">
-			{{ __("Credit") }}
-		</div>
-		<div class="col-sm-1 ellipsis hidden-xs">
-			{{ __("Currency") }}
-		</div>
-		<div class="col-sm-1 ellipsis">
-		</div>
-	</div>
-</div>
diff --git a/erpnext/accounts/page/bank_reconciliation/bank_transaction_row.html b/erpnext/accounts/page/bank_reconciliation/bank_transaction_row.html
deleted file mode 100644
index 742b84c..0000000
--- a/erpnext/accounts/page/bank_reconciliation/bank_transaction_row.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<div class="list-row transaction-item">
-	<div>
-		<div class="clickable-section" data-name={{ name }}>
-			<div class="col-sm-2 ellipsis hidden-xs">
-				{%= frappe.datetime.str_to_user(date) %}
-			</div>
-			<div class="col-xs-8 col-sm-4 ellipsis list-subject">
-				{{ description }}
-			</div>
-			<div class="col-sm-2 ellipsis hidden-xs">
-				{%= format_currency(debit, currency) %}
-			</div>
-			<div class="col-sm-2 ellipsis hidden-xs">
-				{%= format_currency(credit, currency) %}
-			</div>
-			<div class="col-sm-1 ellipsis hidden-xs">
-				{{ currency }}
-			</div>
-		</div>
-		<div class="col-xs-3 col-sm-1">
-			<div class="btn-group">
-				<a class="dropdown-toggle btn btn-default btn-xs" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-					<span>Actions </span>
-					<span class="caret"></span>
-				</a>
-				<ul class="dropdown-menu reports-dropdown" style="max-height: 300px; overflow-y: auto; right: 0px; left: auto;">
-					<li><a class="new-reconciliation" data-name={{ name }}>{{ __("Reconcile") }}</a></li>
-					<li class="divider"></li>
-					<li><a class="new-payment" data-name={{ name }}>{{ __("New Payment") }}</a></li>
-					<li><a class="new-invoice" data-name={{ name }}>{{ __("New Invoice") }}</a></li>
-					<li><a class="new-expense" data-name={{ name }}>{{ __("New Expense") }}</a></li>
-				</ul>
-			</div>
-		</div>
-	</div>
-</div>
diff --git a/erpnext/accounts/page/bank_reconciliation/linked_payment_header.html b/erpnext/accounts/page/bank_reconciliation/linked_payment_header.html
deleted file mode 100644
index 4542c36..0000000
--- a/erpnext/accounts/page/bank_reconciliation/linked_payment_header.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<div class="transaction-header">
-	<div class="level list-row list-row-head text-muted small">
-		<div class="col-xs-3 col-sm-2 ellipsis">
-			{{ __("Payment Name") }}
-		</div>
-		<div class="col-xs-3 col-sm-2 ellipsis">
-			{{ __("Reference Date") }}
-		</div>
-		<div class="col-sm-2 ellipsis hidden-xs">
-			{{ __("Amount") }}
-		</div>
-		<div class="col-sm-2 ellipsis hidden-xs">
-			{{ __("Party") }}
-		</div>
-		<div class="col-xs-3 col-sm-2 ellipsis">
-			{{ __("Reference Number") }}
-		</div>
-		<div class="col-xs-2 col-sm-2">
-		</div>
-	</div>
-</div>
diff --git a/erpnext/accounts/page/bank_reconciliation/linked_payment_row.html b/erpnext/accounts/page/bank_reconciliation/linked_payment_row.html
deleted file mode 100644
index bdbc9fc..0000000
--- a/erpnext/accounts/page/bank_reconciliation/linked_payment_row.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<div class="list-row">
-	<div>
-		<div class="col-xs-3 col-sm-2 ellipsis">
-			{{ name }}
-		</div>
-		<div class="col-xs-3 col-sm-2 ellipsis">
-			{% if (typeof reference_date !== "undefined") %}
-				{%= frappe.datetime.str_to_user(reference_date) %}
-			{% else %}
-				{% if (typeof posting_date !== "undefined") %}
-					{%= frappe.datetime.str_to_user(posting_date) %}
-				{% endif %}
-			{% endif %}
-		</div>
-		<div class="col-sm-2 ellipsis hidden-xs">
-			{{ format_currency(paid_amount, currency) }}
-		</div>
-		<div class="col-sm-2 ellipsis hidden-xs">
-			{% if (typeof party !== "undefined") %}
-				{{ party }}
-			{% endif %}
-		</div>
-		<div class="col-xs-3 col-sm-2 ellipsis">
-			{% if (typeof reference_no !== "undefined") %}
-				{{ reference_no }}
-			{% else %}
-				{{ "" }}
-			{% endif %}
-		</div>
-		<div class="col-xs-2 col-sm-2">
-			<div class="text-right margin-bottom">
-				<button class="btn btn-primary btn-xs reconciliation-btn" data-doctype="{{ doctype }}" data-name="{{ name }}">{{ __("Reconcile") }}</button>
-			</div>
-		</div>
-	</div>
-</div>
\ No newline at end of file
diff --git a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py
index 0861b20..79b0a6f 100644
--- a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py
+++ b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py
@@ -15,15 +15,51 @@
 	return columns, data
 
 def get_columns():
-	return [
-		_("Payment Document") + "::130",
-		_("Payment Entry") + ":Dynamic Link/"+_("Payment Document")+":110",
-		_("Posting Date") + ":Date:100",
-		_("Cheque/Reference No") + "::120",
-		_("Clearance Date") + ":Date:100",
-		_("Against Account") + ":Link/Account:170",
-		_("Amount") + ":Currency:120"
-	]
+	columns = [{
+			"label": _("Payment Document Type"),
+			"fieldname": "payment_document_type",
+			"fieldtype": "Link",
+			"options": "Doctype",
+			"width": 130
+		},
+		{
+			"label": _("Payment Entry"),
+			"fieldname": "payment_entry",
+			"fieldtype": "Dynamic Link",
+			"options": "payment_document_type",
+			"width": 140
+		},
+		{
+			"label": _("Posting Date"),
+			"fieldname": "posting_date",
+			"fieldtype": "Date",
+			"width": 100
+		},
+		{
+			"label": _("Cheque/Reference No"),
+			"fieldname": "cheque_no",
+			"width": 120
+		},
+		{
+			"label": _("Clearance Date"),
+			"fieldname": "clearance_date",
+			"fieldtype": "Date",
+			"width": 100
+		},
+		{
+			"label": _("Against Account"),
+			"fieldname": "against",
+			"fieldtype": "Link",
+			"options": "Account",
+			"width": 170
+		},
+		{
+			"label": _("Amount"),
+			"fieldname": "amount",
+			"width": 120
+		}]
+
+	return columns
 
 def get_conditions(filters):
 	conditions = ""
diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
index d011689..76f3c50 100644
--- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
+++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
@@ -222,7 +222,7 @@
 
 		set_gl_entries_by_account(start_date,
 			end_date, root.lft, root.rgt, filters,
-			gl_entries_by_account, accounts_by_name, ignore_closing_entries=False)
+			gl_entries_by_account, accounts_by_name, accounts, ignore_closing_entries=False)
 
 	calculate_values(accounts_by_name, gl_entries_by_account, companies, start_date, filters)
 	accumulate_values_into_parents(accounts, accounts_by_name, companies)
@@ -339,7 +339,7 @@
 	return data
 
 def set_gl_entries_by_account(from_date, to_date, root_lft, root_rgt, filters, gl_entries_by_account,
-	accounts_by_name, ignore_closing_entries=False):
+	accounts_by_name, accounts, ignore_closing_entries=False):
 	"""Returns a dict like { "account": [gl entries], ... }"""
 
 	company_lft, company_rgt = frappe.get_cached_value('Company',
@@ -382,15 +382,31 @@
 
 		for entry in gl_entries:
 			key = entry.account_number or entry.account_name
-			validate_entries(key, entry, accounts_by_name)
+			validate_entries(key, entry, accounts_by_name, accounts)
 			gl_entries_by_account.setdefault(key, []).append(entry)
 
 	return gl_entries_by_account
 
-def validate_entries(key, entry, accounts_by_name):
+def get_account_details(account):
+	return frappe.get_cached_value('Account', account, ['name', 'report_type', 'root_type', 'company',
+		'is_group', 'account_name', 'account_number', 'parent_account', 'lft', 'rgt'], as_dict=1)
+
+def validate_entries(key, entry, accounts_by_name, accounts):
 	if key not in accounts_by_name:
-		field = "Account number" if entry.account_number else "Account name"
-		frappe.throw(_("{0} {1} is not present in the parent company").format(field, key))
+		args = get_account_details(entry.account)
+
+		if args.parent_account:
+			parent_args = get_account_details(args.parent_account)
+
+			args.update({
+				'lft': parent_args.lft + 1,
+				'rgt': parent_args.rgt - 1,
+				'root_type': parent_args.root_type,
+				'report_type': parent_args.report_type
+			})
+
+		accounts_by_name.setdefault(key, args)
+		accounts.append(args)
 
 def get_additional_conditions(from_date, ignore_closing_entries, filters):
 	additional_conditions = []
diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
index 998003a..928b373 100644
--- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
+++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
@@ -52,8 +52,8 @@
 
 		row = {
 			'item_code': d.item_code,
-			'item_name': item_record.item_name,
-			'item_group': item_record.item_group,
+			'item_name': item_record.item_name if item_record else d.item_name,
+			'item_group': item_record.item_group if item_record else d.item_group,
 			'description': d.description,
 			'invoice': d.parent,
 			'posting_date': d.posting_date,
@@ -383,6 +383,7 @@
 			`tabSales Invoice`.project, `tabSales Invoice`.customer, `tabSales Invoice`.remarks,
 			`tabSales Invoice`.territory, `tabSales Invoice`.company, `tabSales Invoice`.base_net_total,
 			`tabSales Invoice Item`.item_code, `tabSales Invoice Item`.description,
+			`tabSales Invoice Item`.`item_name`, `tabSales Invoice Item`.`item_group`,
 			`tabSales Invoice Item`.sales_order, `tabSales Invoice Item`.delivery_note,
 			`tabSales Invoice Item`.income_account, `tabSales Invoice Item`.cost_center,
 			`tabSales Invoice Item`.stock_qty, `tabSales Invoice Item`.stock_uom,
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 67c7fd2..5eb2aab 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -82,7 +82,7 @@
 	error_msg = _("""{0} {1} is not in any active Fiscal Year""").format(label, formatdate(transaction_date))
 	if company:
 		error_msg = _("""{0} for {1}""").format(error_msg, frappe.bold(company))
-	
+
 	if verbose==1: frappe.msgprint(error_msg)
 	raise FiscalYearError(error_msg)
 
@@ -888,19 +888,23 @@
 
 def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
 		warehouse_account=None, company=None):
+	stock_vouchers = get_future_stock_vouchers(posting_date, posting_time, for_warehouses, for_items, company)
+	repost_gle_for_stock_vouchers(stock_vouchers, posting_date, company, warehouse_account)
+
+
+def repost_gle_for_stock_vouchers(stock_vouchers, posting_date, company=None, warehouse_account=None):
 	def _delete_gl_entries(voucher_type, voucher_no):
 		frappe.db.sql("""delete from `tabGL Entry`
 			where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
 
+
 	if not warehouse_account:
 		warehouse_account = get_warehouse_account_map(company)
 
-	future_stock_vouchers = get_future_stock_vouchers(posting_date, posting_time, for_warehouses, for_items)
-	gle = get_voucherwise_gl_entries(future_stock_vouchers, posting_date)
-
-	for voucher_type, voucher_no in future_stock_vouchers:
+	gle = get_voucherwise_gl_entries(stock_vouchers, posting_date)
+	for voucher_type, voucher_no in stock_vouchers:
 		existing_gle = gle.get((voucher_type, voucher_no), [])
-		voucher_obj = frappe.get_doc(voucher_type, voucher_no)
+		voucher_obj = frappe.get_cached_doc(voucher_type, voucher_no)
 		expected_gle = voucher_obj.get_gl_entries(warehouse_account)
 		if expected_gle:
 			if not existing_gle or not compare_existing_and_expected_gle(existing_gle, expected_gle):
@@ -909,7 +913,7 @@
 		else:
 			_delete_gl_entries(voucher_type, voucher_no)
 
-def get_future_stock_vouchers(posting_date, posting_time, for_warehouses=None, for_items=None):
+def get_future_stock_vouchers(posting_date, posting_time, for_warehouses=None, for_items=None, company=None):
 	future_stock_vouchers = []
 
 	values = []
@@ -922,6 +926,10 @@
 		condition += " and warehouse in ({})".format(", ".join(["%s"] * len(for_warehouses)))
 		values += for_warehouses
 
+	if company:
+		condition += " and company = %s"
+		values.append(company)
+
 	for d in frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no
 		from `tabStock Ledger Entry` sle
 		where
@@ -982,7 +990,7 @@
 			error_reason = _("Stock Value ({0}) and Account Balance ({1}) are out of sync for account {2} and it's linked warehouses as on {3}.").format(
 				stock_bal, account_bal, frappe.bold(account), posting_date)
 			error_resolution = _("Please create an adjustment Journal Entry for amount {0} on {1}")\
-				.format(frappe.bold(diff), frappe.bold(posting_date))			
+				.format(frappe.bold(diff), frappe.bold(posting_date))
 
 			frappe.msgprint(
 				msg="""{0}<br></br>{1}<br></br>""".format(error_reason, error_resolution),
diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
index c691e9f..75b2954 100644
--- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
+++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
@@ -40,6 +40,7 @@
   "base_rate",
   "base_amount",
   "pricing_rules",
+  "stock_uom_rate",
   "is_free_item",
   "section_break_29",
   "net_rate",
@@ -726,13 +727,21 @@
    "fieldname": "more_info_section_break",
    "fieldtype": "Section Break",
    "label": "More Information"
+  },
+  {
+   "depends_on": "eval: doc.uom != doc.stock_uom",
+   "fieldname": "stock_uom_rate",
+   "fieldtype": "Currency",
+   "label": "Rate of Stock UOM",
+   "options": "currency",
+   "read_only": 1
   }
  ],
  "idx": 1,
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-12-07 11:59:47.670951",
+ "modified": "2021-01-30 21:44:41.816974",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Purchase Order Item",
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
index a51498e..7cf22f8 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
@@ -127,6 +127,10 @@
 				'link_doctype': 'Supplier',
 				'link_name': rfq_supplier.supplier
 			})
+			contact.append('email_ids', {
+				'email_id': user.name,
+				'is_primary': 1
+			})
 
 		if not contact.email_id and not contact.user:
 			contact.email_id = user.name
diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json
index 40362b1..4cc5753 100644
--- a/erpnext/buying/doctype/supplier/supplier.json
+++ b/erpnext/buying/doctype/supplier/supplier.json
@@ -26,7 +26,6 @@
   "supplier_group",
   "supplier_type",
   "pan",
-  "language",
   "allow_purchase_invoice_creation_without_purchase_order",
   "allow_purchase_invoice_creation_without_purchase_receipt",
   "disabled",
@@ -57,6 +56,7 @@
   "website",
   "supplier_details",
   "column_break_30",
+  "language",
   "is_frozen"
  ],
  "fields": [
@@ -384,7 +384,7 @@
  "idx": 370,
  "image_field": "image",
  "links": [],
- "modified": "2020-06-17 23:18:20",
+ "modified": "2021-01-06 19:51:40.939087",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Supplier",
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 21874fe..12a81c7 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1309,45 +1309,28 @@
 					})
 				tax_row.db_insert()
 
-def set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, trans_item):
+def set_order_defaults(parent_doctype, parent_doctype_name, child_doctype, child_docname, trans_item):
 	"""
-	Returns a Sales Order Item child item containing the default values
+	Returns a Sales/Purchase Order Item child item containing the default values
 	"""
 	p_doc = frappe.get_doc(parent_doctype, parent_doctype_name)
-	child_item = frappe.new_doc('Sales Order Item', p_doc, child_docname)
+	child_item = frappe.new_doc(child_doctype, p_doc, child_docname)
 	item = frappe.get_doc("Item", trans_item.get('item_code'))
-	child_item.item_code = item.item_code
-	child_item.item_name = item.item_name
-	child_item.description = item.description
-	child_item.delivery_date = trans_item.get('delivery_date') or p_doc.delivery_date
+	for field in ("item_code", "item_name", "description", "item_group"):
+	    child_item.update({field: item.get(field)})
+	date_fieldname = "delivery_date" if child_doctype == "Sales Order Item" else "schedule_date"
+	child_item.update({date_fieldname: trans_item.get(date_fieldname) or p_doc.get(date_fieldname)})
 	child_item.uom = trans_item.get("uom") or item.stock_uom
 	conversion_factor = flt(get_conversion_factor(item.item_code, child_item.uom).get("conversion_factor"))
 	child_item.conversion_factor = flt(trans_item.get('conversion_factor')) or conversion_factor
-	set_child_tax_template_and_map(item, child_item, p_doc)
-	add_taxes_from_tax_template(child_item, p_doc)
-	child_item.warehouse = get_item_warehouse(item, p_doc, overwrite_warehouse=True)
-	if not child_item.warehouse:
-		frappe.throw(_("Cannot find {} for item {}. Please set the same in Item Master or Stock Settings.")
-			.format(frappe.bold("default warehouse"), frappe.bold(item.item_code)))
-	return child_item
-
-
-def set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docname, trans_item):
-	"""
-	Returns a Purchase Order Item child item containing the default values
-	"""
-	p_doc = frappe.get_doc(parent_doctype, parent_doctype_name)
-	child_item = frappe.new_doc('Purchase Order Item', p_doc, child_docname)
-	item = frappe.get_doc("Item", trans_item.get('item_code'))
-	child_item.item_code = item.item_code
-	child_item.item_name = item.item_name
-	child_item.description = item.description
-	child_item.schedule_date = trans_item.get('schedule_date') or p_doc.schedule_date
-	child_item.uom = trans_item.get("uom") or item.stock_uom
-	conversion_factor = flt(get_conversion_factor(item.item_code, child_item.uom).get("conversion_factor"))
-	child_item.conversion_factor = flt(trans_item.get('conversion_factor')) or conversion_factor
-	child_item.base_rate = 1 # Initiallize value will update in parent validation
-	child_item.base_amount = 1 # Initiallize value will update in parent validation
+	if child_doctype == "Purchase Order Item":
+		child_item.base_rate = 1 # Initiallize value will update in parent validation
+		child_item.base_amount = 1 # Initiallize value will update in parent validation
+	if child_doctype == "Sales Order Item":
+		child_item.warehouse = get_item_warehouse(item, p_doc, overwrite_warehouse=True)
+		if not child_item.warehouse:
+			frappe.throw(_("Cannot find {} for item {}. Please set the same in Item Master or Stock Settings.")
+				.format(frappe.bold("default warehouse"), frappe.bold(item.item_code)))
 	set_child_tax_template_and_map(item, child_item, p_doc)
 	add_taxes_from_tax_template(child_item, p_doc)
 	return child_item
@@ -1411,8 +1394,8 @@
 			)
 
 	def get_new_child_item(item_row):
-		new_child_function = set_sales_order_defaults if parent_doctype == "Sales Order" else set_purchase_order_defaults
-		return new_child_function(parent_doctype, parent_doctype_name, child_docname, item_row)
+		child_doctype = "Sales Order Item" if parent_doctype == "Sales Order" else "Purchase Order Item" 
+		return set_order_defaults(parent_doctype, parent_doctype_name, child_doctype, child_docname, item_row)
 
 	def validate_quantity(child_item, d):
 		if parent_doctype == "Sales Order" and flt(d.get("qty")) < flt(child_item.delivered_qty):
@@ -1521,6 +1504,7 @@
 	parent.flags.ignore_validate_update_after_submit = True
 	parent.set_qty_as_per_stock_uom()
 	parent.calculate_taxes_and_totals()
+	parent.set_total_in_words()
 	if parent_doctype == "Sales Order":
 		make_packing_list(parent)
 		parent.set_gross_profit()
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index 0e1829a..de61b35 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -204,8 +204,6 @@
 	return items
 
 def get_returned_qty_map_for_row(row_name, doctype):
-	if doctype == "POS Invoice": return {}
-
 	child_doctype = doctype + " Item"
 	reference_field = "dn_detail" if doctype == "Delivery Note" else frappe.scrub(child_doctype)
 
@@ -354,7 +352,12 @@
 			target_doc.so_detail = source_doc.so_detail
 			target_doc.dn_detail = source_doc.dn_detail
 			target_doc.expense_account = source_doc.expense_account
-			target_doc.sales_invoice_item = source_doc.name
+
+			if doctype == "Sales Invoice":
+				target_doc.sales_invoice_item = source_doc.name
+			else:
+				target_doc.pos_invoice_item = source_doc.name
+
 			target_doc.price_list_rate = 0
 			if default_warehouse_for_sales_return:
 				target_doc.warehouse = default_warehouse_for_sales_return
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 6abfe04..c61b67b 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -446,9 +446,13 @@
 		check_list, chk_dupl_itm = [], []
 		if cint(frappe.db.get_single_value("Selling Settings", "allow_multiple_items")):
 			return
+		if self.doctype == "Sales Invoice" and self.is_consolidated:
+			return
+		if self.doctype == "POS Invoice":
+			return
 
 		for d in self.get('items'):
-			if self.doctype in ["POS Invoice","Sales Invoice"]:
+			if self.doctype == "Sales Invoice":
 				stock_items = [d.item_code, d.description, d.warehouse, d.sales_order or d.delivery_note, d.batch_no or '']
 				non_stock_items = [d.item_code, d.description, d.sales_order or d.delivery_note]
 			elif self.doctype == "Delivery Note":
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 4b5e347..e0031c9 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -24,6 +24,7 @@
 			self.validate_inspection()
 		self.validate_serialized_batch()
 		self.validate_customer_provided_item()
+		self.set_rate_of_stock_uom()
 		self.validate_internal_transfer()
 		self.validate_putaway_capacity()
 
@@ -73,7 +74,7 @@
 
 		gl_list = []
 		warehouse_with_no_account = []
-		precision = frappe.get_precision("GL Entry", "debit_in_account_currency")
+		precision = self.get_debit_field_precision()
 		for item_row in voucher_details:
 
 			sle_list = sle_map.get(item_row.name)
@@ -130,7 +131,13 @@
 				if frappe.db.get_value("Warehouse", wh, "company"):
 					frappe.throw(_("Warehouse {0} is not linked to any account, please mention the account in the warehouse record or set default inventory account in company {1}.").format(wh, self.company))
 
-		return process_gl_map(gl_list)
+		return process_gl_map(gl_list, precision=precision)
+
+	def get_debit_field_precision(self):
+		if not frappe.flags.debit_field_precision:
+			frappe.flags.debit_field_precision = frappe.get_precision("GL Entry", "debit_in_account_currency")
+
+		return frappe.flags.debit_field_precision
 
 	def update_stock_ledger_entries(self, sle):
 		sle.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
@@ -243,7 +250,7 @@
 				.format(item.idx, frappe.bold(item.item_code), msg), title=_("Expense Account Missing"))
 
 		else:
-			is_expense_account = frappe.db.get_value("Account",
+			is_expense_account = frappe.get_cached_value("Account",
 				item.get("expense_account"), "report_type")=="Profit and Loss"
 			if self.doctype not in ("Purchase Receipt", "Purchase Invoice", "Stock Reconciliation", "Stock Entry") and not is_expense_account:
 				frappe.throw(_("Expense / Difference account ({0}) must be a 'Profit or Loss' account")
@@ -313,7 +320,7 @@
 		return serialized_items
 
 	def validate_warehouse(self):
-		from erpnext.stock.utils import validate_warehouse_company
+		from erpnext.stock.utils import validate_warehouse_company, validate_disabled_warehouse
 
 		warehouses = list(set([d.warehouse for d in
 			self.get("items") if getattr(d, "warehouse", None)]))
@@ -329,6 +336,7 @@
 		warehouses.extend(from_warehouse)
 
 		for w in warehouses:
+			validate_disabled_warehouse(w)
 			validate_warehouse_company(w, self.company)
 
 	def update_billing_percentage(self, update_modified=True):
@@ -395,6 +403,11 @@
 			if frappe.db.get_value('Item', d.item_code, 'is_customer_provided_item'):
 				d.allow_zero_valuation_rate = 1
 
+	def set_rate_of_stock_uom(self):
+		if self.doctype in ["Purchase Receipt", "Purchase Invoice", "Purchase Order", "Sales Invoice", "Sales Order", "Delivery Note", "Quotation"]:
+			for d in self.get("items"):
+				d.stock_uom_rate = d.rate / d.conversion_factor
+
 	def validate_internal_transfer(self):
 		if self.doctype in ('Sales Invoice', 'Delivery Note', 'Purchase Invoice', 'Purchase Receipt') \
 			and self.is_internal_transfer():
@@ -481,7 +494,6 @@
 			"voucher_no": self.name,
 			"company": self.company
 		})
-
 		if check_if_future_sle_exists(args):
 			create_repost_item_valuation_entry(args)
 		elif not is_reposting_pending():
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index cfa4991..10271cb 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -15,6 +15,8 @@
 class calculate_taxes_and_totals(object):
 	def __init__(self, doc):
 		self.doc = doc
+		frappe.flags.round_off_applicable_accounts = []
+		get_round_off_applicable_accounts(self.doc.company, frappe.flags.round_off_applicable_accounts)
 		self.calculate()
 
 	def calculate(self):
@@ -332,10 +334,18 @@
 		elif tax.charge_type == "On Item Quantity":
 			current_tax_amount = tax_rate * item.qty
 
+		current_tax_amount = self.get_final_current_tax_amount(tax, current_tax_amount)
 		self.set_item_wise_tax(item, tax, tax_rate, current_tax_amount)
 
 		return current_tax_amount
 
+	def get_final_current_tax_amount(self, tax, current_tax_amount):
+		# Some countries need individual tax components to be rounded
+		# Handeled via regional doctypess
+		if tax.account_head in frappe.flags.round_off_applicable_accounts:
+			current_tax_amount = round(current_tax_amount, 0)
+		return current_tax_amount
+
 	def set_item_wise_tax(self, item, tax, tax_rate, current_tax_amount):
 		# store tax breakup for each item
 		key = item.item_code or item.item_name
@@ -693,6 +703,15 @@
 		)
 	)
 
+@frappe.whitelist()
+def get_round_off_applicable_accounts(company, account_list):
+	account_list = get_regional_round_off_accounts(company, account_list)
+
+	return account_list
+
+@erpnext.allow_regional
+def get_regional_round_off_accounts(company, account_list):
+	pass
 
 @erpnext.allow_regional
 def update_itemised_tax_data(doc):
diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json
index 2df1793..1b33fd7 100644
--- a/erpnext/crm/doctype/lead/lead.json
+++ b/erpnext/crm/doctype/lead/lead.json
@@ -49,6 +49,7 @@
   "phone",
   "mobile_no",
   "fax",
+  "website",
   "more_info",
   "type",
   "market_segment",
@@ -56,8 +57,8 @@
   "request_type",
   "column_break3",
   "company",
-  "website",
   "territory",
+  "language",
   "unsubscribed",
   "blog_subscriber",
   "title"
@@ -447,13 +448,19 @@
    "fieldtype": "Select",
    "label": "Address Type",
    "options": "Billing\nShipping\nOffice\nPersonal\nPlant\nPostal\nShop\nSubsidiary\nWarehouse\nCurrent\nPermanent\nOther"
+  },
+  {
+   "fieldname": "language",
+   "fieldtype": "Link",
+   "label": "Print Language",
+   "options": "Language"
   }
  ],
  "icon": "fa fa-user",
  "idx": 5,
  "image_field": "image",
  "links": [],
- "modified": "2020-10-13 15:24:00.094811",
+ "modified": "2021-01-06 19:39:58.748978",
  "modified_by": "Administrator",
  "module": "CRM",
  "name": "Lead",
diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py
index 938cbfd..d1d0968 100644
--- a/erpnext/crm/doctype/lead/lead.py
+++ b/erpnext/crm/doctype/lead/lead.py
@@ -352,7 +352,7 @@
 	leads = frappe.get_all('Lead', or_filters={
 		'phone': ['like', '%{}'.format(number)],
 		'mobile_no': ['like', '%{}'.format(number)]
-	}, limit=1)
+	}, limit=1, order_by="creation DESC")
 
 	lead = leads[0].name if leads else None
 
@@ -361,4 +361,4 @@
 def daily_open_lead():
 	leads = frappe.get_all("Lead", filters = [["contact_date", "Between", [nowdate(), nowdate()]]])
 	for lead in leads:
-		frappe.db.set_value("Lead", lead.name, "status", "Open")
\ No newline at end of file
+		frappe.db.set_value("Lead", lead.name, "status", "Open")
diff --git a/erpnext/crm/doctype/opportunity/opportunity.js b/erpnext/crm/doctype/opportunity/opportunity.js
index 08958b7..ac374a9 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.js
+++ b/erpnext/crm/doctype/opportunity/opportunity.js
@@ -24,6 +24,12 @@
 			frm.trigger('set_contact_link');
 		}
 	},
+	contact_date: function(frm) {
+		if(frm.doc.contact_date < frappe.datetime.now_datetime()){
+			frm.set_value("contact_date", "");
+			frappe.throw(__("Next follow up date should be greater than now."))
+		}
+	},
 
 	onload_post_render: function(frm) {
 		frm.get_field("items").grid.set_multiple_add("item_code", "qty");
diff --git a/erpnext/crm/doctype/opportunity/opportunity.json b/erpnext/crm/doctype/opportunity/opportunity.json
index eee13f7..2e09a76 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.json
+++ b/erpnext/crm/doctype/opportunity/opportunity.json
@@ -54,6 +54,7 @@
   "campaign",
   "column_break1",
   "transaction_date",
+  "language",
   "amended_from",
   "lost_reasons"
  ],
@@ -419,12 +420,18 @@
    "fieldtype": "Duration",
    "label": "First Response Time",
    "read_only": 1
+  },
+  {
+   "fieldname": "language",
+   "fieldtype": "Link",
+   "label": "Print Language",
+   "options": "Language"
   }
  ],
  "icon": "fa fa-info-sign",
  "idx": 195,
  "links": [],
- "modified": "2020-08-12 17:34:35.066961",
+ "modified": "2021-01-06 19:42:46.190051",
  "modified_by": "Administrator",
  "module": "CRM",
  "name": "Opportunity",
diff --git a/erpnext/crm/doctype/utils.py b/erpnext/crm/doctype/utils.py
index 4ccd9bd..f244daf 100644
--- a/erpnext/crm/doctype/utils.py
+++ b/erpnext/crm/doctype/utils.py
@@ -78,7 +78,9 @@
 
 def strip_number(number):
 	if not number: return
-	# strip 0 from the start of the number for proper number comparisions
+	# strip + and 0 from the start of the number for proper number comparisions
+	# eg. +7888383332 should match with 7888383332
 	# eg. 07888383332 should match with 7888383332
+	number = number.lstrip('+')
 	number = number.lstrip('0')
 	return number
diff --git a/erpnext/crm/report/prospects_engaged_but_not_converted/prospects_engaged_but_not_converted.py b/erpnext/crm/report/prospects_engaged_but_not_converted/prospects_engaged_but_not_converted.py
index b538a58..3a9d57d 100644
--- a/erpnext/crm/report/prospects_engaged_but_not_converted/prospects_engaged_but_not_converted.py
+++ b/erpnext/crm/report/prospects_engaged_but_not_converted/prospects_engaged_but_not_converted.py
@@ -19,15 +19,50 @@
 	if not filters.get('lead_age'): filters["lead_age"] = 60
 
 def get_columns():
-	return [
-		_("Lead") + ":Link/Lead:100",
-		_("Name") + "::100",
-		_("Organization") + "::100",
-		_("Reference Document") + "::150",
-		_("Reference Name") + ":Dynamic Link/"+_("Reference Document")+":120",
-		_("Last Communication") + ":Data:200",
-		_("Last Communication Date") + ":Date:180"
-	]
+	columns = [{
+			"label": _("Lead"),
+			"fieldname": "lead",
+			"fieldtype": "Link",
+			"options": "Lead",
+			"width": 130
+		},
+		{
+			"label": _("Name"),
+			"fieldname": "name",
+			"width": 120
+		},
+		{
+			"label": _("Organization"),
+			"fieldname": "organization",
+			"width": 120
+		},
+		{
+			"label": _("Reference Document Type"),
+			"fieldname": "reference_document_type",
+			"fieldtype": "Link",
+			"options": "Doctype",
+			"width": 100
+		},
+		{
+			"label": _("Reference Name"),
+			"fieldname": "reference_name",
+			"fieldtype": "Dynamic Link",
+			"options": "reference_document_type",
+			"width": 140
+		},
+		{
+			"label": _("Last Communication"),
+			"fieldname": "last_communication",
+			"fieldtype": "Data",
+			"width": 200
+		},
+		{
+			"label": _("Last Communication Date"),
+			"fieldname": "last_communication_date",
+			"fieldtype": "Date",
+			"width": 100
+		}]
+	return columns
 
 def get_data(filters):
 	lead_details = []
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_connector.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_connector.py
index d33b0a7..554c6b0 100644
--- a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_connector.py
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_connector.py
@@ -5,7 +5,7 @@
 
 class MpesaConnector():
 	def __init__(self, env="sandbox", app_key=None, app_secret=None, sandbox_url="https://sandbox.safaricom.co.ke",
-		live_url="https://safaricom.co.ke"):
+		live_url="https://api.safaricom.co.ke"):
 		"""Setup configuration for Mpesa connector and generate new access token."""
 		self.env = env
 		self.app_key = app_key
@@ -102,14 +102,14 @@
 			"BusinessShortCode": business_shortcode,
 			"Password": encoded.decode("utf-8"),
 			"Timestamp": time,
-			"TransactionType": "CustomerPayBillOnline",
 			"Amount": amount,
 			"PartyA": int(phone_number),
-			"PartyB": business_shortcode,
+			"PartyB": reference_code,
 			"PhoneNumber": int(phone_number),
 			"CallBackURL": callback_url,
 			"AccountReference": reference_code,
-			"TransactionDesc": description
+			"TransactionDesc": description,
+			"TransactionType": "CustomerPayBillOnline" if self.env == "sandbox" else "CustomerBuyGoodsOnline"
 		}
 		headers = {'Authorization': 'Bearer {0}'.format(self.authentication_token), 'Content-Type': "application/json"}
 
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.json b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.json
index fc7b310..407f826 100644
--- a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.json
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.json
@@ -11,8 +11,10 @@
   "consumer_secret",
   "initiator_name",
   "till_number",
+  "transaction_limit",
   "sandbox",
   "column_break_4",
+  "business_shortcode",
   "online_passkey",
   "security_credential",
   "get_account_balance",
@@ -84,10 +86,24 @@
    "fieldname": "get_account_balance",
    "fieldtype": "Button",
    "label": "Get Account Balance"
+  },
+  {
+   "depends_on": "eval:(doc.sandbox==0)",
+   "fieldname": "business_shortcode",
+   "fieldtype": "Data",
+   "label": "Business Shortcode",
+   "mandatory_depends_on": "eval:(doc.sandbox==0)"
+  },
+  {
+   "default": "150000",
+   "fieldname": "transaction_limit",
+   "fieldtype": "Float",
+   "label": "Transaction Limit",
+   "non_negative": 1
   }
  ],
  "links": [],
- "modified": "2020-09-25 20:21:38.215494",
+ "modified": "2021-01-29 12:02:16.106942",
  "modified_by": "Administrator",
  "module": "ERPNext Integrations",
  "name": "Mpesa Settings",
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py
index 1cad84d..b571802 100644
--- a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py
@@ -33,13 +33,34 @@
 		create_mode_of_payment('Mpesa-' + self.payment_gateway_name, payment_type="Phone")
 
 	def request_for_payment(self, **kwargs):
-		if frappe.flags.in_test:
-			from erpnext.erpnext_integrations.doctype.mpesa_settings.test_mpesa_settings import get_payment_request_response_payload
-			response = frappe._dict(get_payment_request_response_payload())
-		else:
-			response = frappe._dict(generate_stk_push(**kwargs))
+		args = frappe._dict(kwargs)
+		request_amounts = self.split_request_amount_according_to_transaction_limit(args)
 
-		self.handle_api_response("CheckoutRequestID", kwargs, response)
+		for i, amount in enumerate(request_amounts):
+			args.request_amount = amount
+			if frappe.flags.in_test:
+				from erpnext.erpnext_integrations.doctype.mpesa_settings.test_mpesa_settings import get_payment_request_response_payload
+				response = frappe._dict(get_payment_request_response_payload(amount))
+			else:
+				response = frappe._dict(generate_stk_push(**args))
+
+			self.handle_api_response("CheckoutRequestID", args, response)
+
+	def split_request_amount_according_to_transaction_limit(self, args):
+		request_amount = args.request_amount
+		if request_amount > self.transaction_limit:
+			# make multiple requests
+			request_amounts = []
+			requests_to_be_made = frappe.utils.ceil(request_amount / self.transaction_limit) # 480/150 = ceil(3.2) = 4
+			for i in range(requests_to_be_made):
+				amount = self.transaction_limit
+				if i == requests_to_be_made - 1:
+					amount = request_amount - (self.transaction_limit * i) # for 4th request, 480 - (150 * 3) = 30
+				request_amounts.append(amount)
+		else:
+			request_amounts = [request_amount]
+		
+		return request_amounts
 
 	def get_account_balance_info(self):
 		payload = dict(
@@ -67,7 +88,8 @@
 			req_name = getattr(response, global_id)
 			error = None
 
-		create_request_log(request_dict, "Host", "Mpesa", req_name, error)
+		if not frappe.db.exists('Integration Request', req_name):
+			create_request_log(request_dict, "Host", "Mpesa", req_name, error)
 
 		if error:
 			frappe.throw(_(getattr(response, "errorMessage")), title=_("Transaction Error"))
@@ -80,6 +102,8 @@
 
 		mpesa_settings = frappe.get_doc("Mpesa Settings", args.payment_gateway[6:])
 		env = "production" if not mpesa_settings.sandbox else "sandbox"
+		# for sandbox, business shortcode is same as till number
+		business_shortcode = mpesa_settings.business_shortcode if env == "production" else mpesa_settings.till_number
 
 		connector = MpesaConnector(env=env,
 			app_key=mpesa_settings.consumer_key,
@@ -87,10 +111,12 @@
 
 		mobile_number = sanitize_mobile_number(args.sender)
 
-		response = connector.stk_push(business_shortcode=mpesa_settings.till_number,
-			passcode=mpesa_settings.get_password("online_passkey"), amount=args.grand_total,
+		response = connector.stk_push(
+			business_shortcode=business_shortcode, amount=args.request_amount,
+			passcode=mpesa_settings.get_password("online_passkey"),
 			callback_url=callback_url, reference_code=mpesa_settings.till_number,
-			phone_number=mobile_number, description="POS Payment")
+			phone_number=mobile_number, description="POS Payment"
+		)
 
 		return response
 
@@ -108,29 +134,72 @@
 	transaction_response = frappe._dict(kwargs["Body"]["stkCallback"])
 
 	checkout_id = getattr(transaction_response, "CheckoutRequestID", "")
-	request = frappe.get_doc("Integration Request", checkout_id)
-	transaction_data = frappe._dict(loads(request.data))
+	integration_request = frappe.get_doc("Integration Request", checkout_id)
+	transaction_data = frappe._dict(loads(integration_request.data))
+	total_paid = 0 # for multiple integration request made against a pos invoice
+	success = False # for reporting successfull callback to point of sale ui
 
 	if transaction_response['ResultCode'] == 0:
-		if request.reference_doctype and request.reference_docname:
+		if integration_request.reference_doctype and integration_request.reference_docname:
 			try:
-				doc = frappe.get_doc(request.reference_doctype,
-					request.reference_docname)
-				doc.run_method("on_payment_authorized", 'Completed')
-
 				item_response = transaction_response["CallbackMetadata"]["Item"]
+				amount = fetch_param_value(item_response, "Amount", "Name")
 				mpesa_receipt = fetch_param_value(item_response, "MpesaReceiptNumber", "Name")
-				frappe.db.set_value("POS Invoice", doc.reference_name, "mpesa_receipt_number", mpesa_receipt)
-				request.handle_success(transaction_response)
+				pr = frappe.get_doc(integration_request.reference_doctype, integration_request.reference_docname)
+
+				mpesa_receipts, completed_payments = get_completed_integration_requests_info(
+					integration_request.reference_doctype,
+					integration_request.reference_docname,
+					checkout_id
+				)
+
+				total_paid = amount + sum(completed_payments)
+				mpesa_receipts = ', '.join(mpesa_receipts + [mpesa_receipt])
+
+				if total_paid >= pr.grand_total:
+					pr.run_method("on_payment_authorized", 'Completed')
+					success = True
+
+				frappe.db.set_value("POS Invoice", pr.reference_name, "mpesa_receipt_number", mpesa_receipts)
+				integration_request.handle_success(transaction_response)
 			except Exception:
-				request.handle_failure(transaction_response)
+				integration_request.handle_failure(transaction_response)
 				frappe.log_error(frappe.get_traceback())
 
 	else:
-		request.handle_failure(transaction_response)
+		integration_request.handle_failure(transaction_response)
 
-	frappe.publish_realtime('process_phone_payment', doctype="POS Invoice",
-		docname=transaction_data.payment_reference, user=request.owner, message=transaction_response)
+	frappe.publish_realtime(
+		event='process_phone_payment',
+		doctype="POS Invoice",
+		docname=transaction_data.payment_reference,
+		user=integration_request.owner,
+		message={
+			'amount': total_paid,
+			'success': success,
+			'failure_message': transaction_response["ResultDesc"] if transaction_response['ResultCode'] != 0 else ''
+		},
+	)
+
+def get_completed_integration_requests_info(reference_doctype, reference_docname, checkout_id):
+	output_of_other_completed_requests = frappe.get_all("Integration Request", filters={
+		'name': ['!=', checkout_id],
+		'reference_doctype': reference_doctype,
+		'reference_docname': reference_docname,
+		'status': 'Completed'
+	}, pluck="output")
+
+	mpesa_receipts, completed_payments = [], []
+
+	for out in output_of_other_completed_requests:
+		out = frappe._dict(loads(out))
+		item_response = out["CallbackMetadata"]["Item"]
+		completed_amount = fetch_param_value(item_response, "Amount", "Name")
+		completed_mpesa_receipt = fetch_param_value(item_response, "MpesaReceiptNumber", "Name")
+		completed_payments.append(completed_amount)
+		mpesa_receipts.append(completed_mpesa_receipt)
+	
+	return mpesa_receipts, completed_payments
 
 def get_account_balance(request_payload):
 	"""Call account balance API to send the request to the Mpesa Servers."""
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py
index 49f6d95..2948796 100644
--- a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py
@@ -9,6 +9,10 @@
 from erpnext.accounts.doctype.pos_invoice.test_pos_invoice import create_pos_invoice
 
 class TestMpesaSettings(unittest.TestCase):
+	def tearDown(self):
+		frappe.db.sql('delete from `tabMpesa Settings`')
+		frappe.db.sql('delete from `tabIntegration Request` where integration_request_service = "Mpesa"')
+
 	def test_creation_of_payment_gateway(self):
 		create_mpesa_settings(payment_gateway_name="_Test")
 
@@ -40,6 +44,8 @@
 			}
 		}))
 
+		integration_request.delete()
+
 	def test_processing_of_callback_payload(self):
 		create_mpesa_settings(payment_gateway_name="Payment")
 		mpesa_account = frappe.db.get_value("Payment Gateway Account", {"payment_gateway": 'Mpesa-Payment'}, "payment_account")
@@ -56,10 +62,16 @@
 		# test payment request creation
 		self.assertEquals(pr.payment_gateway, "Mpesa-Payment")
 
-		callback_response = get_payment_callback_payload()
+		# submitting payment request creates integration requests with random id
+		integration_req_ids = frappe.get_all("Integration Request", filters={
+			'reference_doctype': pr.doctype,
+			'reference_docname': pr.name,
+		}, pluck="name")
+
+		callback_response = get_payment_callback_payload(Amount=500, CheckoutRequestID=integration_req_ids[0])
 		verify_transaction(**callback_response)
 		# test creation of integration request
-		integration_request = frappe.get_doc("Integration Request", "ws_CO_061020201133231972")
+		integration_request = frappe.get_doc("Integration Request", integration_req_ids[0])
 
 		# test integration request creation and successful update of the status on receiving callback response
 		self.assertTrue(integration_request)
@@ -69,8 +81,120 @@
 		integration_request.reload()
 		self.assertEquals(pos_invoice.mpesa_receipt_number, "LGR7OWQX0R")
 		self.assertEquals(integration_request.status, "Completed")
+		
+		frappe.db.set_value("Customer", "_Test Customer", "default_currency", "")
+		integration_request.delete()
+		pr.reload()
+		pr.cancel()
+		pr.delete()
+		pos_invoice.delete()
+
+	def test_processing_of_multiple_callback_payload(self):
+		create_mpesa_settings(payment_gateway_name="Payment")
+		mpesa_account = frappe.db.get_value("Payment Gateway Account", {"payment_gateway": 'Mpesa-Payment'}, "payment_account")
+		frappe.db.set_value("Account", mpesa_account, "account_currency", "KES")
+		frappe.db.set_value("Mpesa Settings", "Payment", "transaction_limit", "500")
+		frappe.db.set_value("Customer", "_Test Customer", "default_currency", "KES")
+
+		pos_invoice = create_pos_invoice(do_not_submit=1)
+		pos_invoice.append("payments", {'mode_of_payment': 'Mpesa-Payment', 'account': mpesa_account, 'amount': 1000})
+		pos_invoice.contact_mobile = "093456543894"
+		pos_invoice.currency = "KES"
+		pos_invoice.save()
+
+		pr = pos_invoice.create_payment_request()
+		# test payment request creation
+		self.assertEquals(pr.payment_gateway, "Mpesa-Payment")
+
+		# submitting payment request creates integration requests with random id
+		integration_req_ids = frappe.get_all("Integration Request", filters={
+			'reference_doctype': pr.doctype,
+			'reference_docname': pr.name,
+		}, pluck="name")
+
+		# create random receipt nos and send it as response to callback handler
+		mpesa_receipt_numbers = [frappe.utils.random_string(5) for d in integration_req_ids]
+
+		integration_requests = []
+		for i in range(len(integration_req_ids)):
+			callback_response = get_payment_callback_payload(
+				Amount=500,
+				CheckoutRequestID=integration_req_ids[i],
+				MpesaReceiptNumber=mpesa_receipt_numbers[i]
+			)
+			# handle response manually
+			verify_transaction(**callback_response)
+			# test completion of integration request
+			integration_request = frappe.get_doc("Integration Request", integration_req_ids[i])
+			self.assertEquals(integration_request.status, "Completed")
+			integration_requests.append(integration_request)
+
+		# check receipt number once all the integration requests are completed
+		pos_invoice.reload()
+		self.assertEquals(pos_invoice.mpesa_receipt_number, ', '.join(mpesa_receipt_numbers))
 
 		frappe.db.set_value("Customer", "_Test Customer", "default_currency", "")
+		[d.delete() for d in integration_requests]
+		pr.reload()
+		pr.cancel()
+		pr.delete()
+		pos_invoice.delete()
+	
+	def test_processing_of_only_one_succes_callback_payload(self):
+		create_mpesa_settings(payment_gateway_name="Payment")
+		mpesa_account = frappe.db.get_value("Payment Gateway Account", {"payment_gateway": 'Mpesa-Payment'}, "payment_account")
+		frappe.db.set_value("Account", mpesa_account, "account_currency", "KES")
+		frappe.db.set_value("Mpesa Settings", "Payment", "transaction_limit", "500")
+		frappe.db.set_value("Customer", "_Test Customer", "default_currency", "KES")
+
+		pos_invoice = create_pos_invoice(do_not_submit=1)
+		pos_invoice.append("payments", {'mode_of_payment': 'Mpesa-Payment', 'account': mpesa_account, 'amount': 1000})
+		pos_invoice.contact_mobile = "093456543894"
+		pos_invoice.currency = "KES"
+		pos_invoice.save()
+
+		pr = pos_invoice.create_payment_request()
+		# test payment request creation
+		self.assertEquals(pr.payment_gateway, "Mpesa-Payment")
+
+		# submitting payment request creates integration requests with random id
+		integration_req_ids = frappe.get_all("Integration Request", filters={
+			'reference_doctype': pr.doctype,
+			'reference_docname': pr.name,
+		}, pluck="name")
+
+		# create random receipt nos and send it as response to callback handler
+		mpesa_receipt_numbers = [frappe.utils.random_string(5) for d in integration_req_ids]
+
+		callback_response = get_payment_callback_payload(
+			Amount=500,
+			CheckoutRequestID=integration_req_ids[0],
+			MpesaReceiptNumber=mpesa_receipt_numbers[0]
+		)
+		# handle response manually
+		verify_transaction(**callback_response)
+		# test completion of integration request
+		integration_request = frappe.get_doc("Integration Request", integration_req_ids[0])
+		self.assertEquals(integration_request.status, "Completed")
+
+		# now one request is completed
+		# second integration request fails
+		# now retrying payment request should make only one integration request again
+		pr = pos_invoice.create_payment_request()
+		new_integration_req_ids = frappe.get_all("Integration Request", filters={
+			'reference_doctype': pr.doctype,
+			'reference_docname': pr.name,
+			'name': ['not in', integration_req_ids]
+		}, pluck="name")
+
+		self.assertEquals(len(new_integration_req_ids), 1)
+
+		frappe.db.set_value("Customer", "_Test Customer", "default_currency", "")
+		frappe.db.sql("delete from `tabIntegration Request` where integration_request_service = 'Mpesa'")
+		pr.reload()
+		pr.cancel()
+		pr.delete()
+		pos_invoice.delete()
 
 def create_mpesa_settings(payment_gateway_name="Express"):
 	if frappe.db.exists("Mpesa Settings", payment_gateway_name):
@@ -160,16 +284,19 @@
 	}
 		}
 
-def get_payment_request_response_payload():
+def get_payment_request_response_payload(Amount=500):
 	"""Response received after successfully calling the stk push process request API."""
+
+	CheckoutRequestID = frappe.utils.random_string(10)
+
 	return {
 		"MerchantRequestID": "8071-27184008-1",
-		"CheckoutRequestID": "ws_CO_061020201133231972",
+		"CheckoutRequestID": CheckoutRequestID,
 		"ResultCode": 0,
 		"ResultDesc": "The service request is processed successfully.",
 		"CallbackMetadata": {
 			"Item": [
-				{ "Name": "Amount", "Value": 500.0 },
+				{ "Name": "Amount", "Value": Amount },
 				{ "Name": "MpesaReceiptNumber", "Value": "LGR7OWQX0R" },
 				{ "Name": "TransactionDate", "Value": 20201006113336 },
 				{ "Name": "PhoneNumber", "Value": 254723575670 }
@@ -177,41 +304,26 @@
 		}
 	}
 
-
-def get_payment_callback_payload():
+def get_payment_callback_payload(Amount=500, CheckoutRequestID="ws_CO_061020201133231972", MpesaReceiptNumber="LGR7OWQX0R"):
 	"""Response received from the server as callback after calling the stkpush process request API."""
 	return {
 		"Body":{
-		"stkCallback":{
-			"MerchantRequestID":"19465-780693-1",
-			"CheckoutRequestID":"ws_CO_061020201133231972",
-			"ResultCode":0,
-			"ResultDesc":"The service request is processed successfully.",
-			"CallbackMetadata":{
-			"Item":[
-				{
-				"Name":"Amount",
-				"Value":500
-				},
-				{
-				"Name":"MpesaReceiptNumber",
-				"Value":"LGR7OWQX0R"
-				},
-				{
-				"Name":"Balance"
-				},
-				{
-				"Name":"TransactionDate",
-				"Value":20170727154800
-				},
-				{
-				"Name":"PhoneNumber",
-				"Value":254721566839
+			"stkCallback":{
+				"MerchantRequestID":"19465-780693-1",
+				"CheckoutRequestID":CheckoutRequestID,
+				"ResultCode":0,
+				"ResultDesc":"The service request is processed successfully.",
+				"CallbackMetadata":{
+					"Item":[
+						{ "Name":"Amount", "Value":Amount },
+						{ "Name":"MpesaReceiptNumber", "Value":MpesaReceiptNumber },
+						{ "Name":"Balance" },
+						{ "Name":"TransactionDate", "Value":20170727154800 },
+						{ "Name":"PhoneNumber", "Value":254721566839 }
+					]
 				}
-			]
 			}
 		}
-		}
 	}
 
 def get_account_balance_callback_payload():
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
index 66d0e5f..5f990cd 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
@@ -20,7 +20,7 @@
 			client_id=self.settings.plaid_client_id,
 			secret=self.settings.get_password("plaid_secret"),
 			environment=self.settings.plaid_env,
-			api_version="2019-05-29"
+			api_version="2020-09-14"
 		)
 
 	def get_access_token(self, public_token):
@@ -29,7 +29,7 @@
 		response = self.client.Item.public_token.exchange(public_token)
 		access_token = response["access_token"]
 		return access_token
-	
+
 	def get_token_request(self, update_mode=False):
 		country_codes = ["US", "CA", "FR", "IE", "NL", "ES", "GB"] if self.settings.enable_european_access else ["US", "CA"]
 		args = {
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
index 70c7f3f..21f6fee 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
@@ -204,8 +204,8 @@
 				"date": getdate(transaction["date"]),
 				"status": status,
 				"bank_account": bank_account,
-				"debit": debit,
-				"credit": credit,
+				"deposit": debit,
+				"withdrawal": credit,
 				"currency": transaction["iso_currency_code"],
 				"transaction_id": transaction["transaction_id"],
 				"reference_number": transaction["payment_meta"]["reference_number"],
diff --git a/erpnext/healthcare/doctype/appointment_type/appointment_type.js b/erpnext/healthcare/doctype/appointment_type/appointment_type.js
index 15916a5..861675a 100644
--- a/erpnext/healthcare/doctype/appointment_type/appointment_type.js
+++ b/erpnext/healthcare/doctype/appointment_type/appointment_type.js
@@ -2,4 +2,82 @@
 // For license information, please see license.txt
 
 frappe.ui.form.on('Appointment Type', {
+	refresh: function(frm) {
+		frm.set_query('price_list', function() {
+			return {
+				filters: {'selling': 1}
+			};
+		});
+
+		frm.set_query('medical_department', 'items', function(doc) {
+			let item_list = doc.items.map(({medical_department}) => medical_department);
+			return {
+				filters: [
+					['Medical Department', 'name', 'not in', item_list]
+				]
+			};
+		});
+
+		frm.set_query('op_consulting_charge_item', 'items', function() {
+			return {
+				filters: {
+					is_stock_item: 0
+				}
+			};
+		});
+
+		frm.set_query('inpatient_visit_charge_item', 'items', function() {
+			return {
+				filters: {
+					is_stock_item: 0
+				}
+			};
+		});
+	}
 });
+
+frappe.ui.form.on('Appointment Type Service Item', {
+	op_consulting_charge_item: function(frm, cdt, cdn) {
+		let d = locals[cdt][cdn];
+		if (frm.doc.price_list && d.op_consulting_charge_item) {
+			frappe.call({
+				'method': 'frappe.client.get_value',
+				args: {
+					'doctype': 'Item Price',
+					'filters': {
+						'item_code': d.op_consulting_charge_item,
+						'price_list': frm.doc.price_list
+					},
+					'fieldname': ['price_list_rate']
+				},
+				callback: function(data) {
+					if (data.message.price_list_rate) {
+						frappe.model.set_value(cdt, cdn, 'op_consulting_charge', data.message.price_list_rate);
+					}
+				}
+			});
+		}
+	},
+
+	inpatient_visit_charge_item: function(frm, cdt, cdn) {
+		let d = locals[cdt][cdn];
+		if (frm.doc.price_list && d.inpatient_visit_charge_item) {
+			frappe.call({
+				'method': 'frappe.client.get_value',
+				args: {
+					'doctype': 'Item Price',
+					'filters': {
+						'item_code': d.inpatient_visit_charge_item,
+						'price_list': frm.doc.price_list
+					},
+					'fieldname': ['price_list_rate']
+				},
+				callback: function (data) {
+					if (data.message.price_list_rate) {
+						frappe.model.set_value(cdt, cdn, 'inpatient_visit_charge', data.message.price_list_rate);
+					}
+				}
+			});
+		}
+	}
+});
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/appointment_type/appointment_type.json b/erpnext/healthcare/doctype/appointment_type/appointment_type.json
index 58753bb..3872318 100644
--- a/erpnext/healthcare/doctype/appointment_type/appointment_type.json
+++ b/erpnext/healthcare/doctype/appointment_type/appointment_type.json
@@ -12,7 +12,10 @@
   "appointment_type",
   "ip",
   "default_duration",
-  "color"
+  "color",
+  "billing_section",
+  "price_list",
+  "items"
  ],
  "fields": [
   {
@@ -52,10 +55,27 @@
    "label": "Color",
    "no_copy": 1,
    "report_hide": 1
+  },
+  {
+   "fieldname": "billing_section",
+   "fieldtype": "Section Break",
+   "label": "Billing"
+  },
+  {
+   "fieldname": "price_list",
+   "fieldtype": "Link",
+   "label": "Price List",
+   "options": "Price List"
+  },
+  {
+   "fieldname": "items",
+   "fieldtype": "Table",
+   "label": "Appointment Type Service Items",
+   "options": "Appointment Type Service Item"
   }
  ],
  "links": [],
- "modified": "2020-02-03 21:06:05.833050",
+ "modified": "2021-01-22 09:41:05.010524",
  "modified_by": "Administrator",
  "module": "Healthcare",
  "name": "Appointment Type",
diff --git a/erpnext/healthcare/doctype/appointment_type/appointment_type.py b/erpnext/healthcare/doctype/appointment_type/appointment_type.py
index 1dacffa..67a24f3 100644
--- a/erpnext/healthcare/doctype/appointment_type/appointment_type.py
+++ b/erpnext/healthcare/doctype/appointment_type/appointment_type.py
@@ -4,6 +4,53 @@
 
 from __future__ import unicode_literals
 from frappe.model.document import Document
+import frappe
 
 class AppointmentType(Document):
-	pass
+	def validate(self):
+		if self.items and self.price_list:
+			for item in self.items:
+				existing_op_item_price = frappe.db.exists('Item Price', {
+					'item_code': item.op_consulting_charge_item,
+					'price_list': self.price_list
+				})
+
+				if not existing_op_item_price and item.op_consulting_charge_item and item.op_consulting_charge:
+					make_item_price(self.price_list, item.op_consulting_charge_item, item.op_consulting_charge)
+
+				existing_ip_item_price = frappe.db.exists('Item Price', {
+					'item_code': item.inpatient_visit_charge_item,
+					'price_list': self.price_list
+				})
+
+				if not existing_ip_item_price and item.inpatient_visit_charge_item and item.inpatient_visit_charge:
+					make_item_price(self.price_list, item.inpatient_visit_charge_item, item.inpatient_visit_charge)
+
+@frappe.whitelist()
+def get_service_item_based_on_department(appointment_type, department):
+	item_list = frappe.db.get_value('Appointment Type Service Item',
+		filters = {'medical_department': department, 'parent': appointment_type},
+		fieldname = ['op_consulting_charge_item',
+			'inpatient_visit_charge_item', 'op_consulting_charge', 'inpatient_visit_charge'],
+		as_dict = 1
+	)
+
+	# if department wise items are not set up
+	# use the generic items
+	if not item_list:
+		item_list = frappe.db.get_value('Appointment Type Service Item',
+			filters = {'parent': appointment_type},
+			fieldname = ['op_consulting_charge_item',
+				'inpatient_visit_charge_item', 'op_consulting_charge', 'inpatient_visit_charge'],
+			as_dict = 1
+		)
+
+	return item_list
+
+def make_item_price(price_list, item, item_price):
+	frappe.get_doc({
+		'doctype': 'Item Price',
+		'price_list': price_list,
+		'item_code': item,
+		'price_list_rate': item_price
+	}).insert(ignore_permissions=True, ignore_mandatory=True)
diff --git a/erpnext/accounts/doctype/bank_statement_settings_item/__init__.py b/erpnext/healthcare/doctype/appointment_type_service_item/__init__.py
similarity index 100%
rename from erpnext/accounts/doctype/bank_statement_settings_item/__init__.py
rename to erpnext/healthcare/doctype/appointment_type_service_item/__init__.py
diff --git a/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.json b/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.json
new file mode 100644
index 0000000..5ff68cd
--- /dev/null
+++ b/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.json
@@ -0,0 +1,67 @@
+{
+ "actions": [],
+ "creation": "2021-01-22 09:34:53.373105",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "medical_department",
+  "op_consulting_charge_item",
+  "op_consulting_charge",
+  "column_break_4",
+  "inpatient_visit_charge_item",
+  "inpatient_visit_charge"
+ ],
+ "fields": [
+  {
+   "fieldname": "medical_department",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Medical Department",
+   "options": "Medical Department"
+  },
+  {
+   "fieldname": "op_consulting_charge_item",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Out Patient Consulting Charge Item",
+   "options": "Item"
+  },
+  {
+   "fieldname": "op_consulting_charge",
+   "fieldtype": "Currency",
+   "in_list_view": 1,
+   "label": "Out Patient Consulting Charge"
+  },
+  {
+   "fieldname": "column_break_4",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "inpatient_visit_charge_item",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Inpatient Visit Charge Item",
+   "options": "Item"
+  },
+  {
+   "fieldname": "inpatient_visit_charge",
+   "fieldtype": "Currency",
+   "in_list_view": 1,
+   "label": "Inpatient Visit Charge Item"
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-01-22 09:35:26.503443",
+ "modified_by": "Administrator",
+ "module": "Healthcare",
+ "name": "Appointment Type Service Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.py b/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.py
new file mode 100644
index 0000000..b2e0e82
--- /dev/null
+++ b/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class AppointmentTypeServiceItem(Document):
+	pass
diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
index c324228..325c209 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
+++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
@@ -121,6 +121,7 @@
 
 		stock_entry.stock_entry_type = 'Material Receipt'
 		stock_entry.to_warehouse = self.warehouse
+		stock_entry.company = self.company
 		expense_account = get_account(None, 'expense_account', 'Healthcare Settings', self.company)
 		for item in self.items:
 			if item.qty > item.actual_qty:
diff --git a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
index 4ee5f6b..fb72073 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
+++ b/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+	# -*- coding: utf-8 -*-
 # Copyright (c) 2017, ESS LLP and Contributors
 # See license.txt
 from __future__ import unicode_literals
@@ -60,6 +60,7 @@
 	procedure.practitioner = practitioner
 	procedure.consume_stock = procedure_template.allow_stock_consumption
 	procedure.items = procedure_template.items
-	procedure.warehouse = frappe.db.get_single_value('Stock Settings', 'default_warehouse')
+	procedure.company = "_Test Company"
+	procedure.warehouse = "_Test Warehouse - _TC"
 	procedure.submit()
 	return procedure
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.json b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.json
index cb747f9..8162f03 100644
--- a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.json
+++ b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.json
@@ -159,6 +159,7 @@
    "fieldname": "op_consulting_charge",
    "fieldtype": "Currency",
    "label": "Out Patient Consulting Charge",
+   "mandatory_depends_on": "op_consulting_charge_item",
    "options": "Currency"
   },
   {
@@ -174,7 +175,8 @@
   {
    "fieldname": "inpatient_visit_charge",
    "fieldtype": "Currency",
-   "label": "Inpatient Visit Charge"
+   "label": "Inpatient Visit Charge",
+   "mandatory_depends_on": "inpatient_visit_charge_item"
   },
   {
    "depends_on": "eval: !doc.__islocal",
@@ -280,7 +282,7 @@
  ],
  "image_field": "image",
  "links": [],
- "modified": "2020-04-06 13:44:24.759623",
+ "modified": "2021-01-22 10:14:43.187675",
  "modified_by": "Administrator",
  "module": "Healthcare",
  "name": "Healthcare Practitioner",
diff --git a/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py b/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py
index 8a918b0..a8c7720 100644
--- a/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py
+++ b/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py
@@ -139,12 +139,13 @@
 	inpatient_record.phone = patient_obj.phone
 	inpatient_record.inpatient = "Scheduled"
 	inpatient_record.scheduled_date = today()
+	inpatient_record.company = "_Test Company"
 	return inpatient_record
 
 
 def get_healthcare_service_unit(unit_name=None):
 	if not unit_name:
-		service_unit = get_random("Healthcare Service Unit", filters={"inpatient_occupancy": 1})
+		service_unit = get_random("Healthcare Service Unit", filters={"inpatient_occupancy": 1, "company": "_Test Company"})
 	else:
 		service_unit = frappe.db.exists("Healthcare Service Unit", {"healthcare_service_unit_name": unit_name})
 
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js
index 3d5073b..0354733 100644
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js
+++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js
@@ -24,11 +24,13 @@
 		});
 
 		frm.set_query('practitioner', function() {
-			return {
-				filters: {
-					'department': frm.doc.department
-				}
-			};
+			if (frm.doc.department) {
+				return {
+					filters: {
+						'department': frm.doc.department
+					}
+				};
+			}
 		});
 
 		frm.set_query('service_unit', function() {
@@ -140,6 +142,20 @@
 	patient: function(frm) {
 		if (frm.doc.patient) {
 			frm.trigger('toggle_payment_fields');
+			frappe.call({
+				method: 'frappe.client.get',
+				args: {
+					doctype: 'Patient',
+					name: frm.doc.patient
+				},
+				callback: function (data) {
+					let age = null;
+					if (data.message.dob) {
+						age = calculate_age(data.message.dob);
+					}
+					frappe.model.set_value(frm.doctype, frm.docname, 'patient_age', age);
+				}
+			});
 		} else {
 			frm.set_value('patient_name', '');
 			frm.set_value('patient_sex', '');
@@ -148,6 +164,37 @@
 		}
 	},
 
+	practitioner: function(frm) {
+		if (frm.doc.practitioner ) {
+			frm.events.set_payment_details(frm);
+		}
+	},
+
+	appointment_type: function(frm) {
+		if (frm.doc.appointment_type) {
+			frm.events.set_payment_details(frm);
+		}
+	},
+
+	set_payment_details: function(frm) {
+		frappe.db.get_single_value('Healthcare Settings', 'automate_appointment_invoicing').then(val => {
+			if (val) {
+				frappe.call({
+					method: 'erpnext.healthcare.utils.get_service_item_and_practitioner_charge',
+					args: {
+						doc: frm.doc
+					},
+					callback: function(data) {
+						if (data.message) {
+							frappe.model.set_value(frm.doctype, frm.docname, 'paid_amount', data.message.practitioner_charge);
+							frappe.model.set_value(frm.doctype, frm.docname, 'billing_item', data.message.service_item);
+						}
+					}
+				});
+			}
+		});
+	},
+
 	therapy_plan: function(frm) {
 		frm.trigger('set_therapy_type_filter');
 	},
@@ -190,14 +237,18 @@
 					// show payment fields as non-mandatory
 					frm.toggle_display('mode_of_payment', 0);
 					frm.toggle_display('paid_amount', 0);
+					frm.toggle_display('billing_item', 0);
 					frm.toggle_reqd('mode_of_payment', 0);
 					frm.toggle_reqd('paid_amount', 0);
+					frm.toggle_reqd('billing_item', 0);
 				} else {
 					// if automated appointment invoicing is disabled, hide fields
 					frm.toggle_display('mode_of_payment', data.message ? 1 : 0);
 					frm.toggle_display('paid_amount', data.message ? 1 : 0);
+					frm.toggle_display('billing_item', data.message ? 1 : 0);
 					frm.toggle_reqd('mode_of_payment', data.message ? 1 : 0);
 					frm.toggle_reqd('paid_amount', data.message ? 1 :0);
+					frm.toggle_reqd('billing_item', data.message ? 1 : 0);
 				}
 			}
 		});
@@ -540,57 +591,6 @@
 	);
 };
 
-frappe.ui.form.on('Patient Appointment', 'practitioner', function(frm) {
-	if (frm.doc.practitioner) {
-		frappe.call({
-			method: 'frappe.client.get',
-			args: {
-				doctype: 'Healthcare Practitioner',
-				name: frm.doc.practitioner
-			},
-			callback: function (data) {
-				frappe.model.set_value(frm.doctype, frm.docname, 'department', data.message.department);
-				frappe.model.set_value(frm.doctype, frm.docname, 'paid_amount', data.message.op_consulting_charge);
-				frappe.model.set_value(frm.doctype, frm.docname, 'billing_item', data.message.op_consulting_charge_item);
-			}
-		});
-	}
-});
-
-frappe.ui.form.on('Patient Appointment', 'patient', function(frm) {
-	if (frm.doc.patient) {
-		frappe.call({
-			method: 'frappe.client.get',
-			args: {
-				doctype: 'Patient',
-				name: frm.doc.patient
-			},
-			callback: function (data) {
-				let age = null;
-				if (data.message.dob) {
-					age = calculate_age(data.message.dob);
-				}
-				frappe.model.set_value(frm.doctype,frm.docname, 'patient_age', age);
-			}
-		});
-	}
-});
-
-frappe.ui.form.on('Patient Appointment', 'appointment_type', function(frm) {
-	if (frm.doc.appointment_type) {
-		frappe.call({
-			method: 'frappe.client.get',
-			args: {
-				doctype: 'Appointment Type',
-				name: frm.doc.appointment_type
-			},
-			callback: function(data) {
-				frappe.model.set_value(frm.doctype,frm.docname, 'duration',data.message.default_duration);
-			}
-		});
-	}
-});
-
 let calculate_age = function(birth) {
 	let ageMS = Date.parse(Date()) - Date.parse(birth);
 	let age = new Date();
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json
index 35600e4..83c92af 100644
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json
+++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json
@@ -19,19 +19,19 @@
   "inpatient_record",
   "column_break_1",
   "company",
+  "practitioner",
+  "practitioner_name",
+  "department",
   "service_unit",
+  "section_break_12",
+  "appointment_type",
+  "duration",
   "procedure_template",
   "get_procedure_from_encounter",
   "procedure_prescription",
   "therapy_plan",
   "therapy_type",
   "get_prescribed_therapies",
-  "practitioner",
-  "practitioner_name",
-  "department",
-  "section_break_12",
-  "appointment_type",
-  "duration",
   "column_break_17",
   "appointment_date",
   "appointment_time",
@@ -79,6 +79,7 @@
    "set_only_once": 1
   },
   {
+   "fetch_from": "appointment_type.default_duration",
    "fieldname": "duration",
    "fieldtype": "Int",
    "in_filter": 1,
@@ -144,7 +145,6 @@
    "in_standard_filter": 1,
    "label": "Healthcare Practitioner",
    "options": "Healthcare Practitioner",
-   "read_only": 1,
    "reqd": 1,
    "search_index": 1,
    "set_only_once": 1
@@ -158,7 +158,6 @@
    "in_standard_filter": 1,
    "label": "Department",
    "options": "Medical Department",
-   "read_only": 1,
    "search_index": 1,
    "set_only_once": 1
   },
@@ -227,12 +226,14 @@
    "fieldname": "mode_of_payment",
    "fieldtype": "Link",
    "label": "Mode of Payment",
-   "options": "Mode of Payment"
+   "options": "Mode of Payment",
+   "read_only_depends_on": "invoiced"
   },
   {
    "fieldname": "paid_amount",
    "fieldtype": "Currency",
-   "label": "Paid Amount"
+   "label": "Paid Amount",
+   "read_only_depends_on": "invoiced"
   },
   {
    "fieldname": "column_break_2",
@@ -302,7 +303,8 @@
    "fieldname": "therapy_plan",
    "fieldtype": "Link",
    "label": "Therapy Plan",
-   "options": "Therapy Plan"
+   "options": "Therapy Plan",
+   "set_only_once": 1
   },
   {
    "fieldname": "ref_sales_invoice",
@@ -347,7 +349,7 @@
   }
  ],
  "links": [],
- "modified": "2020-12-16 13:16:58.578503",
+ "modified": "2021-02-08 13:13:15.116833",
  "modified_by": "Administrator",
  "module": "Healthcare",
  "name": "Patient Appointment",
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
index f2b94b8..1f76cd6 100755
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
+++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
@@ -26,6 +26,7 @@
 
 	def after_insert(self):
 		self.update_prescription_details()
+		self.set_payment_details()
 		invoice_appointment(self)
 		self.update_fee_validity()
 		send_confirmation_msg(self)
@@ -85,6 +86,13 @@
 	def set_appointment_datetime(self):
 		self.appointment_datetime = "%s %s" % (self.appointment_date, self.appointment_time or "00:00:00")
 
+	def set_payment_details(self):
+		if frappe.db.get_single_value('Healthcare Settings', 'automate_appointment_invoicing'):
+			details = get_service_item_and_practitioner_charge(self)
+			self.db_set('billing_item', details.get('service_item'))
+			if not self.paid_amount:
+				self.db_set('paid_amount', details.get('practitioner_charge'))
+
 	def validate_customer_created(self):
 		if frappe.db.get_single_value('Healthcare Settings', 'automate_appointment_invoicing'):
 			if not frappe.db.get_value('Patient', self.patient, 'customer'):
@@ -148,31 +156,37 @@
 		fee_validity = None
 
 	if automate_invoicing and not appointment_invoiced and not fee_validity:
-		sales_invoice = frappe.new_doc('Sales Invoice')
-		sales_invoice.patient = appointment_doc.patient
-		sales_invoice.customer = frappe.get_value('Patient', appointment_doc.patient, 'customer')
-		sales_invoice.appointment = appointment_doc.name
-		sales_invoice.due_date = getdate()
-		sales_invoice.company = appointment_doc.company
-		sales_invoice.debit_to = get_receivable_account(appointment_doc.company)
+		create_sales_invoice(appointment_doc)
 
-		item = sales_invoice.append('items', {})
-		item = get_appointment_item(appointment_doc, item)
 
-		# Add payments if payment details are supplied else proceed to create invoice as Unpaid
-		if appointment_doc.mode_of_payment and appointment_doc.paid_amount:
-			sales_invoice.is_pos = 1
-			payment = sales_invoice.append('payments', {})
-			payment.mode_of_payment = appointment_doc.mode_of_payment
-			payment.amount = appointment_doc.paid_amount
+def create_sales_invoice(appointment_doc):
+	sales_invoice = frappe.new_doc('Sales Invoice')
+	sales_invoice.patient = appointment_doc.patient
+	sales_invoice.customer = frappe.get_value('Patient', appointment_doc.patient, 'customer')
+	sales_invoice.appointment = appointment_doc.name
+	sales_invoice.due_date = getdate()
+	sales_invoice.company = appointment_doc.company
+	sales_invoice.debit_to = get_receivable_account(appointment_doc.company)
 
-		sales_invoice.set_missing_values(for_validate=True)
-		sales_invoice.flags.ignore_mandatory = True
-		sales_invoice.save(ignore_permissions=True)
-		sales_invoice.submit()
-		frappe.msgprint(_('Sales Invoice {0} created').format(sales_invoice.name), alert=True)
-		frappe.db.set_value('Patient Appointment', appointment_doc.name, 'invoiced', 1)
-		frappe.db.set_value('Patient Appointment', appointment_doc.name, 'ref_sales_invoice', sales_invoice.name)
+	item = sales_invoice.append('items', {})
+	item = get_appointment_item(appointment_doc, item)
+
+	# Add payments if payment details are supplied else proceed to create invoice as Unpaid
+	if appointment_doc.mode_of_payment and appointment_doc.paid_amount:
+		sales_invoice.is_pos = 1
+		payment = sales_invoice.append('payments', {})
+		payment.mode_of_payment = appointment_doc.mode_of_payment
+		payment.amount = appointment_doc.paid_amount
+
+	sales_invoice.set_missing_values(for_validate=True)
+	sales_invoice.flags.ignore_mandatory = True
+	sales_invoice.save(ignore_permissions=True)
+	sales_invoice.submit()
+	frappe.msgprint(_('Sales Invoice {0} created').format(sales_invoice.name), alert=True)
+	frappe.db.set_value('Patient Appointment', appointment_doc.name, {
+		'invoiced': 1,
+		'ref_sales_invoice': sales_invoice.name
+	})
 
 
 def check_is_new_patient(patient, name=None):
@@ -187,13 +201,14 @@
 
 
 def get_appointment_item(appointment_doc, item):
-	service_item, practitioner_charge = get_service_item_and_practitioner_charge(appointment_doc)
-	item.item_code = service_item
+	details = get_service_item_and_practitioner_charge(appointment_doc)
+	charge = appointment_doc.paid_amount or details.get('practitioner_charge')
+	item.item_code = details.get('service_item')
 	item.description = _('Consulting Charges: {0}').format(appointment_doc.practitioner)
 	item.income_account = get_income_account(appointment_doc.practitioner, appointment_doc.company)
 	item.cost_center = frappe.get_cached_value('Company', appointment_doc.company, 'cost_center')
-	item.rate = practitioner_charge
-	item.amount = practitioner_charge
+	item.rate = charge
+	item.amount = charge
 	item.qty = 1
 	item.reference_dt = 'Patient Appointment'
 	item.reference_dn = appointment_doc.name
diff --git a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
index f7ec6f5..2bb8a53 100644
--- a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
+++ b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
@@ -32,7 +32,8 @@
 		patient, medical_department, practitioner = create_healthcare_docs()
 		frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1)
 		appointment = create_appointment(patient, practitioner, add_days(nowdate(), 4), invoice = 1)
-		self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'invoiced'), 1)
+		appointment.reload()
+		self.assertEqual(appointment.invoiced, 1)
 		encounter = make_encounter(appointment.name)
 		self.assertTrue(encounter)
 		self.assertEqual(encounter.company, appointment.company)
@@ -41,7 +42,7 @@
 		# invoiced flag mapped from appointment
 		self.assertEqual(encounter.invoiced, frappe.db.get_value('Patient Appointment', appointment.name, 'invoiced'))
 
-	def test_invoicing(self):
+	def test_auto_invoicing(self):
 		patient, medical_department, practitioner = create_healthcare_docs()
 		frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0)
 		frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 0)
@@ -57,6 +58,50 @@
 		self.assertEqual(frappe.db.get_value('Sales Invoice', sales_invoice_name, 'patient'), appointment.patient)
 		self.assertEqual(frappe.db.get_value('Sales Invoice', sales_invoice_name, 'paid_amount'), appointment.paid_amount)
 
+	def test_auto_invoicing_based_on_department(self):
+		patient, medical_department, practitioner = create_healthcare_docs()
+		frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0)
+		frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1)
+		appointment_type = create_appointment_type()
+
+		appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2),
+			invoice=1, appointment_type=appointment_type.name, department='_Test Medical Department')
+		appointment.reload()
+
+		self.assertEqual(appointment.invoiced, 1)
+		self.assertEqual(appointment.billing_item, 'HLC-SI-001')
+		self.assertEqual(appointment.paid_amount, 200)
+
+		sales_invoice_name = frappe.db.get_value('Sales Invoice Item', {'reference_dn': appointment.name}, 'parent')
+		self.assertTrue(sales_invoice_name)
+		self.assertEqual(frappe.db.get_value('Sales Invoice', sales_invoice_name, 'paid_amount'), appointment.paid_amount)
+
+	def test_auto_invoicing_according_to_appointment_type_charge(self):
+		patient, medical_department, practitioner = create_healthcare_docs()
+		frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0)
+		frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1)
+
+		item = create_healthcare_service_items()
+		items = [{
+				'op_consulting_charge_item': item,
+				'op_consulting_charge': 300
+		}]
+		appointment_type = create_appointment_type(args={
+				'name': 'Generic Appointment Type charge',
+				'items': items
+			})
+
+		appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2),
+			invoice=1, appointment_type=appointment_type.name)
+		appointment.reload()
+
+		self.assertEqual(appointment.invoiced, 1)
+		self.assertEqual(appointment.billing_item, item)
+		self.assertEqual(appointment.paid_amount, 300)
+
+		sales_invoice_name = frappe.db.get_value('Sales Invoice Item', {'reference_dn': appointment.name}, 'parent')
+		self.assertTrue(sales_invoice_name)
+
 	def test_appointment_cancel(self):
 		patient, medical_department, practitioner = create_healthcare_docs()
 		frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 1)
@@ -178,14 +223,15 @@
 		encounter.submit()
 		return encounter
 
-def create_appointment(patient, practitioner, appointment_date, invoice=0, procedure_template=0, service_unit=None, save=1):
+def create_appointment(patient, practitioner, appointment_date, invoice=0, procedure_template=0,
+	service_unit=None, appointment_type=None, save=1, department=None):
 	item = create_healthcare_service_items()
 	frappe.db.set_value('Healthcare Settings', None, 'inpatient_visit_charge_item', item)
 	frappe.db.set_value('Healthcare Settings', None, 'op_consulting_charge_item', item)
 	appointment = frappe.new_doc('Patient Appointment')
 	appointment.patient = patient
 	appointment.practitioner = practitioner
-	appointment.department = '_Test Medical Department'
+	appointment.department = department or '_Test Medical Department'
 	appointment.appointment_date = appointment_date
 	appointment.company = '_Test Company'
 	appointment.duration = 15
@@ -193,7 +239,8 @@
 		appointment.service_unit = service_unit
 	if invoice:
 		appointment.mode_of_payment = 'Cash'
-		appointment.paid_amount = 500
+	if appointment_type:
+		appointment.appointment_type = appointment_type
 	if procedure_template:
 		appointment.procedure_template = create_clinical_procedure_template().get('name')
 	if save:
@@ -223,4 +270,29 @@
 	template.description = 'Knee Surgery and Rehab'
 	template.rate = 50000
 	template.save()
-	return template
\ No newline at end of file
+	return template
+
+def create_appointment_type(args=None):
+	if not args:
+		args =  frappe.local.form_dict
+
+	name = args.get('name') or 'Test Appointment Type wise Charge'
+
+	if frappe.db.exists('Appointment Type', name):
+		return frappe.get_doc('Appointment Type', name)
+
+	else:
+		item = create_healthcare_service_items()
+		items = [{
+				'medical_department': '_Test Medical Department',
+				'op_consulting_charge_item': item,
+				'op_consulting_charge': 200
+		}]
+		return frappe.get_doc({
+			'doctype': 'Appointment Type',
+			'appointment_type': args.get('name') or 'Test Appointment Type wise Charge',
+			'default_duration': args.get('default_duration') or 20,
+			'color': args.get('color') or '#7575ff',
+			'price_list': args.get('price_list') or frappe.db.get_value("Price List", {"selling": 1}),
+			'items': args.get('items') or items
+		}).insert()
\ No newline at end of file
diff --git a/erpnext/healthcare/report/inpatient_medication_orders/test_inpatient_medication_orders.py b/erpnext/healthcare/report/inpatient_medication_orders/test_inpatient_medication_orders.py
index 0d3f45f..4b461f1 100644
--- a/erpnext/healthcare/report/inpatient_medication_orders/test_inpatient_medication_orders.py
+++ b/erpnext/healthcare/report/inpatient_medication_orders/test_inpatient_medication_orders.py
@@ -119,7 +119,7 @@
 	ip_record.expected_length_of_stay = 0
 	ip_record.save()
 	ip_record.reload()
-	service_unit = get_healthcare_service_unit()
+	service_unit = get_healthcare_service_unit('Test Service Unit Ip Occupancy')
 	admit_patient(ip_record, service_unit, now_datetime())
 
 	ipmo = create_ipmo(patient)
diff --git a/erpnext/healthcare/utils.py b/erpnext/healthcare/utils.py
index d4027df..d3d22c8 100644
--- a/erpnext/healthcare/utils.py
+++ b/erpnext/healthcare/utils.py
@@ -5,9 +5,11 @@
 from __future__ import unicode_literals
 import math
 import frappe
+import json
 from frappe import _
 from frappe.utils.formatters import format_value
 from frappe.utils import time_diff_in_hours, rounded
+from six import string_types
 from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_income_account
 from erpnext.healthcare.doctype.fee_validity.fee_validity import create_fee_validity
 from erpnext.healthcare.doctype.lab_test.lab_test import create_multiple
@@ -64,7 +66,9 @@
 			income_account = None
 			service_item = None
 			if appointment.practitioner:
-				service_item, practitioner_charge = get_service_item_and_practitioner_charge(appointment)
+				details = get_service_item_and_practitioner_charge(appointment)
+				service_item = details.get('service_item')
+				practitioner_charge = details.get('practitioner_charge')
 				income_account = get_income_account(appointment.practitioner, appointment.company)
 			appointments_to_invoice.append({
 				'reference_type': 'Patient Appointment',
@@ -97,7 +101,9 @@
 						frappe.db.get_single_value('Healthcare Settings', 'do_not_bill_inpatient_encounters'):
 						continue
 
-					service_item, practitioner_charge = get_service_item_and_practitioner_charge(encounter)
+					details = get_service_item_and_practitioner_charge(encounter)
+					service_item = details.get('service_item')
+					practitioner_charge = details.get('practitioner_charge')
 					income_account = get_income_account(encounter.practitioner, encounter.company)
 
 				encounters_to_invoice.append({
@@ -173,7 +179,7 @@
 		if procedure.invoice_separately_as_consumables and procedure.consume_stock \
 			and procedure.status == 'Completed' and not procedure.consumption_invoiced:
 
-			service_item = get_healthcare_service_item('clinical_procedure_consumable_item')
+			service_item = frappe.db.get_single_value('Healthcare Settings', 'clinical_procedure_consumable_item')
 			if not service_item:
 				msg = _('Please Configure Clinical Procedure Consumable Item in ')
 				msg += '''<b><a href='/app/Form/Healthcare Settings'>Healthcare Settings</a></b>'''
@@ -304,24 +310,50 @@
 
 	return therapy_sessions_to_invoice
 
-
+@frappe.whitelist()
 def get_service_item_and_practitioner_charge(doc):
+	if isinstance(doc, string_types):
+		doc = json.loads(doc)
+		doc = frappe.get_doc(doc)
+
+	service_item = None
+	practitioner_charge = None
+	department = doc.medical_department if doc.doctype == 'Patient Encounter' else doc.department
+
 	is_inpatient = doc.inpatient_record
-	if is_inpatient:
-		service_item = get_practitioner_service_item(doc.practitioner, 'inpatient_visit_charge_item')
+
+	if doc.get('appointment_type'):
+		service_item, practitioner_charge = get_appointment_type_service_item(doc.appointment_type, department, is_inpatient)
+
+	if not service_item and not practitioner_charge:
+		service_item, practitioner_charge = get_practitioner_service_item(doc.practitioner, is_inpatient)
 		if not service_item:
-			service_item = get_healthcare_service_item('inpatient_visit_charge_item')
-	else:
-		service_item = get_practitioner_service_item(doc.practitioner, 'op_consulting_charge_item')
-		if not service_item:
-			service_item = get_healthcare_service_item('op_consulting_charge_item')
+			service_item = get_healthcare_service_item(is_inpatient)
+
 	if not service_item:
 		throw_config_service_item(is_inpatient)
 
-	practitioner_charge = get_practitioner_charge(doc.practitioner, is_inpatient)
 	if not practitioner_charge:
 		throw_config_practitioner_charge(is_inpatient, doc.practitioner)
 
+	return {'service_item': service_item, 'practitioner_charge': practitioner_charge}
+
+
+def get_appointment_type_service_item(appointment_type, department, is_inpatient):
+	from erpnext.healthcare.doctype.appointment_type.appointment_type import get_service_item_based_on_department
+
+	item_list = get_service_item_based_on_department(appointment_type, department)
+	service_item = None
+	practitioner_charge = None
+
+	if item_list:
+		if is_inpatient:
+			service_item = item_list.get('inpatient_visit_charge_item')
+			practitioner_charge = item_list.get('inpatient_visit_charge')
+		else:
+			service_item = item_list.get('op_consulting_charge_item')
+			practitioner_charge = item_list.get('op_consulting_charge')
+
 	return service_item, practitioner_charge
 
 
@@ -345,12 +377,27 @@
 	frappe.throw(msg, title=_('Missing Configuration'))
 
 
-def get_practitioner_service_item(practitioner, service_item_field):
-	return frappe.db.get_value('Healthcare Practitioner', practitioner, service_item_field)
+def get_practitioner_service_item(practitioner, is_inpatient):
+	service_item = None
+	practitioner_charge = None
+
+	if is_inpatient:
+		service_item, practitioner_charge = frappe.db.get_value('Healthcare Practitioner', practitioner, ['inpatient_visit_charge_item', 'inpatient_visit_charge'])
+	else:
+		service_item, practitioner_charge = frappe.db.get_value('Healthcare Practitioner', practitioner, ['op_consulting_charge_item', 'op_consulting_charge'])
+
+	return service_item, practitioner_charge
 
 
-def get_healthcare_service_item(service_item_field):
-	return frappe.db.get_single_value('Healthcare Settings', service_item_field)
+def get_healthcare_service_item(is_inpatient):
+	service_item = None
+
+	if is_inpatient:
+		service_item = frappe.db.get_single_value('Healthcare Settings', 'inpatient_visit_charge_item')
+	else:
+		service_item = frappe.db.get_single_value('Healthcare Settings', 'op_consulting_charge_item')
+
+	return service_item
 
 
 def get_practitioner_charge(practitioner, is_inpatient):
@@ -381,7 +428,8 @@
 		invoiced = True
 
 	if item.reference_dt == 'Clinical Procedure':
-		if get_healthcare_service_item('clinical_procedure_consumable_item') == item.item_code:
+		service_item = frappe.db.get_single_value('Healthcare Settings', 'clinical_procedure_consumable_item')
+		if service_item == item.item_code:
 			frappe.db.set_value(item.reference_dt, item.reference_dn, 'consumption_invoiced', invoiced)
 		else:
 			frappe.db.set_value(item.reference_dt, item.reference_dn, 'invoiced', invoiced)
@@ -403,7 +451,8 @@
 
 
 def validate_invoiced_on_submit(item):
-	if item.reference_dt == 'Clinical Procedure' and get_healthcare_service_item('clinical_procedure_consumable_item') == item.item_code:
+	if item.reference_dt == 'Clinical Procedure' and \
+		frappe.db.get_single_value('Healthcare Settings', 'clinical_procedure_consumable_item') == item.item_code:
 		is_invoiced = frappe.db.get_value(item.reference_dt, item.reference_dn, 'consumption_invoiced')
 	else:
 		is_invoiced = frappe.db.get_value(item.reference_dt, item.reference_dn, 'invoiced')
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index bc1d762..39d3659 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -78,7 +78,7 @@
 	"Job Opening", "Student Admission"]
 
 website_context = {
-	"favicon": 	"/assets/erpnext/images/favicon.png",
+	"favicon": 	"/assets/erpnext/images/erpnext-favicon.svg",
 	"splash_image": "/assets/erpnext/images/erpnext-logo.svg"
 }
 
@@ -272,6 +272,9 @@
 	'Address': {
 		'validate': ['erpnext.regional.india.utils.validate_gstin_for_india', 'erpnext.regional.italy.utils.set_state_code', 'erpnext.regional.india.utils.update_gst_category']
 	},
+	'Supplier': {
+		'validate': 'erpnext.regional.india.utils.validate_pan_for_india'
+	},
 	('Sales Invoice', 'Sales Order', 'Delivery Note', 'Purchase Invoice', 'Purchase Order', 'Purchase Receipt'): {
 		'validate': ['erpnext.regional.india.utils.set_place_of_supply']
 	},
@@ -399,6 +402,7 @@
 		'erpnext.controllers.taxes_and_totals.get_itemised_tax_breakup_header': 'erpnext.regional.india.utils.get_itemised_tax_breakup_header',
 		'erpnext.controllers.taxes_and_totals.get_itemised_tax_breakup_data': 'erpnext.regional.india.utils.get_itemised_tax_breakup_data',
 		'erpnext.accounts.party.get_regional_address_details': 'erpnext.regional.india.utils.get_regional_address_details',
+		'erpnext.controllers.taxes_and_totals.get_regional_round_off_accounts': 'erpnext.regional.india.utils.get_regional_round_off_accounts',
 		'erpnext.hr.utils.calculate_annual_eligible_hra_exemption': 'erpnext.regional.india.utils.calculate_annual_eligible_hra_exemption',
 		'erpnext.hr.utils.calculate_hra_exemption_for_period': 'erpnext.regional.india.utils.calculate_hra_exemption_for_period',
 		'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_regional_gl_entries': 'erpnext.regional.india.utils.make_regional_gl_entries',
diff --git a/erpnext/hr/doctype/employee/test_employee.py b/erpnext/hr/doctype/employee/test_employee.py
index f4b214a..c0e614a 100644
--- a/erpnext/hr/doctype/employee/test_employee.py
+++ b/erpnext/hr/doctype/employee/test_employee.py
@@ -16,11 +16,13 @@
 		employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
 		employee.date_of_birth = "1992" + frappe.utils.nowdate()[4:]
 		employee.company_email = "test@example.com"
+		employee.company = "_Test Company"
 		employee.save()
 
 		from erpnext.hr.doctype.employee.employee import get_employees_who_are_born_today, send_birthday_reminders
 
-		self.assertTrue(employee.name in [e.name for e in get_employees_who_are_born_today()])
+		employees_born_today = get_employees_who_are_born_today()
+		self.assertTrue(employees_born_today.get("_Test Company"))
 
 		frappe.db.sql("delete from `tabEmail Queue`")
 
diff --git a/erpnext/hr/doctype/job_offer/job_offer.py b/erpnext/hr/doctype/job_offer/job_offer.py
index c397a3f..7e650f7 100644
--- a/erpnext/hr/doctype/job_offer/job_offer.py
+++ b/erpnext/hr/doctype/job_offer/job_offer.py
@@ -16,7 +16,7 @@
 
 	def validate(self):
 		self.validate_vacancies()
-		job_offer = frappe.db.exists("Job Offer",{"job_applicant": self.job_applicant})
+		job_offer = frappe.db.exists("Job Offer",{"job_applicant": self.job_applicant, "docstatus": ["!=", 2]})
 		if job_offer and job_offer != self.name:
 			frappe.throw(_("Job Offer: {0} is already for Job Applicant: {1}").format(frappe.bold(job_offer), frappe.bold(self.job_applicant)))
 
diff --git a/erpnext/hr/doctype/leave_application/leave_application_dashboard.html b/erpnext/hr/doctype/leave_application/leave_application_dashboard.html
index 6324b04..9f667a6 100644
--- a/erpnext/hr/doctype/leave_application/leave_application_dashboard.html
+++ b/erpnext/hr/doctype/leave_application/leave_application_dashboard.html
@@ -4,11 +4,11 @@
 	<thead>
 		<tr>
 			<th style="width: 16%">{{ __("Leave Type") }}</th>
-			<th style="width: 16%" class="text-right">{{ __("Total Allocated Leaves") }}</th>
-			<th style="width: 16%" class="text-right">{{ __("Expired Leaves") }}</th>
-			<th style="width: 16%" class="text-right">{{ __("Used Leaves") }}</th>
-			<th style="width: 16%" class="text-right">{{ __("Pending Leaves") }}</th>
-			<th style="width: 16%" class="text-right">{{ __("Available Leaves") }}</th>
+			<th style="width: 16%" class="text-right">{{ __("Total Allocated Leave") }}</th>
+			<th style="width: 16%" class="text-right">{{ __("Expired Leave") }}</th>
+			<th style="width: 16%" class="text-right">{{ __("Used Leave") }}</th>
+			<th style="width: 16%" class="text-right">{{ __("Pending Leave") }}</th>
+			<th style="width: 16%" class="text-right">{{ __("Available Leave") }}</th>
 		</tr>
 	</thead>
 	<tbody>
@@ -25,5 +25,5 @@
 	</tbody>
 </table>
 {% else %}
-<p style="margin-top: 30px;"> No Leaves have been allocated. </p>
-{% endif %}
\ No newline at end of file
+<p style="margin-top: 30px;"> No Leave has been allocated. </p>
+{% endif %}
diff --git a/erpnext/hr/doctype/leave_application/leave_application_list.js b/erpnext/hr/doctype/leave_application/leave_application_list.js
index cbb4b73..a3c03b1 100644
--- a/erpnext/hr/doctype/leave_application/leave_application_list.js
+++ b/erpnext/hr/doctype/leave_application/leave_application_list.js
@@ -1,5 +1,6 @@
 frappe.listview_settings['Leave Application'] = {
 	add_fields: ["leave_type", "employee", "employee_name", "total_leave_days", "from_date", "to_date"],
+	has_indicator_for_draft: 1,
 	get_indicator: function (doc) {
 		if (doc.status === "Approved") {
 			return [__("Approved"), "green", "status,=,Approved"];
diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
index 1b92358..06f9160 100644
--- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
+++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
@@ -40,17 +40,17 @@
 		'fieldname': 'opening_balance',
 		'width': 130,
 	}, {
-		'label': _('Leaves Allocated'),
+		'label': _('Leave Allocated'),
 		'fieldtype': 'float',
 		'fieldname': 'leaves_allocated',
 		'width': 130,
 	}, {
-		'label': _('Leaves Taken'),
+		'label': _('Leave Taken'),
 		'fieldtype': 'float',
 		'fieldname': 'leaves_taken',
 		'width': 130,
 	}, {
-		'label': _('Leaves Expired'),
+		'label': _('Leave Expired'),
 		'fieldtype': 'float',
 		'fieldname': 'leaves_expired',
 		'width': 130,
diff --git a/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py b/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py
index 4608212..c5929c6 100644
--- a/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py
+++ b/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py
@@ -36,6 +36,8 @@
 	conditions, filters = get_conditions(filters)
 	columns, days = get_columns(filters)
 	att_map = get_attendance_list(conditions, filters)
+	if not att_map:
+		return columns, [], None, None
 
 	if filters.group_by:
 		emp_map, group_by_parameters = get_employee_details(filters.group_by, filters.company)
@@ -65,10 +67,14 @@
 	if filters.group_by:
 		emp_att_map = {}
 		for parameter in group_by_parameters:
-			data.append([ "<b>"+ parameter + "</b>"])
-			record, aaa = add_data(emp_map[parameter], att_map, filters, holiday_map, conditions, default_holiday_list, leave_list=leave_list)
-			emp_att_map.update(aaa)
-			data += record
+			emp_map_set = set([key for key in emp_map[parameter].keys()])
+			att_map_set = set([key for key in att_map.keys()])
+			if (att_map_set & emp_map_set):
+				parameter_row = ["<b>"+ parameter + "</b>"] + ['' for day in range(filters["total_days_in_month"] + 2)]
+				data.append(parameter_row)
+				record, emp_att_data = add_data(emp_map[parameter], att_map, filters, holiday_map, conditions, default_holiday_list, leave_list=leave_list)
+				emp_att_map.update(emp_att_data)
+				data += record
 	else:
 		record, emp_att_map = add_data(emp_map, att_map, filters, holiday_map, conditions, default_holiday_list, leave_list=leave_list)
 		data += record
@@ -237,6 +243,9 @@
 		status from tabAttendance where docstatus = 1 %s order by employee, attendance_date""" %
 		conditions, filters, as_dict=1)
 
+	if not attendance_list:
+		msgprint(_("No attendance record found"), alert=True, indicator="orange")
+
 	att_map = {}
 	for d in attendance_list:
 		att_map.setdefault(d.employee, frappe._dict()).setdefault(d.day_of_month, "")
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py
index ec28eb7..662a06b 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card.py
@@ -267,6 +267,17 @@
 			fields = ["sum(total_time_in_mins) as time_in_mins", "sum(total_completed_qty) as completed_qty"],
 			filters = {"docstatus": 1, "work_order": self.work_order, "operation_id": self.operation_id})
 
+	def set_transferred_qty_in_job_card(self, ste_doc):
+		for row in ste_doc.items:
+			if not row.job_card_item: continue
+
+			qty = frappe.db.sql(""" SELECT SUM(qty) from `tabStock Entry Detail` sed, `tabStock Entry` se
+				WHERE  sed.job_card_item = %s and se.docstatus = 1 and sed.parent = se.name and
+				se.purpose = 'Material Transfer for Manufacture'
+			""", (row.job_card_item))[0][0]
+
+			frappe.db.set_value('Job Card Item', row.job_card_item, 'transferred_qty', flt(qty))
+
 	def set_transferred_qty(self, update_status=False):
 		if not self.items:
 			self.transferred_qty = self.for_quantity if self.docstatus == 1 else 0
@@ -279,7 +290,8 @@
 			self.transferred_qty = frappe.db.get_value('Stock Entry', {
 				'job_card': self.name,
 				'work_order': self.work_order,
-				'docstatus': 1
+				'docstatus': 1,
+				'purpose': 'Material Transfer for Manufacture'
 			}, 'sum(fg_completed_qty)') or 0
 
 		self.db_set("transferred_qty", self.transferred_qty)
@@ -420,6 +432,7 @@
 		target.purpose = "Material Transfer for Manufacture"
 		target.from_bom = 1
 		target.fg_completed_qty = source.get('for_quantity', 0) - source.get('transferred_qty', 0)
+		target.set_transfer_qty()
 		target.calculate_rate_and_amount()
 		target.set_missing_values()
 		target.set_stock_entry_type()
@@ -437,9 +450,10 @@
 			"field_map": {
 				"source_warehouse": "s_warehouse",
 				"required_qty": "qty",
-				"uom": "stock_uom"
+				"name": "job_card_item"
 			},
 			"postprocess": update_item,
+			"condition": lambda doc: doc.required_qty > 0
 		}
 	}, target_doc, set_missing_values)
 
diff --git a/erpnext/manufacturing/doctype/job_card_item/job_card_item.json b/erpnext/manufacturing/doctype/job_card_item/job_card_item.json
index bc9fe10..100ef4c 100644
--- a/erpnext/manufacturing/doctype/job_card_item/job_card_item.json
+++ b/erpnext/manufacturing/doctype/job_card_item/job_card_item.json
@@ -1,363 +1,120 @@
 {
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "beta": 0, 
- "creation": "2018-07-09 17:20:44.737289", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 1, 
- "engine": "InnoDB", 
+ "actions": [],
+ "creation": "2018-07-09 17:20:44.737289",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "item_code",
+  "source_warehouse",
+  "uom",
+  "item_group",
+  "column_break_3",
+  "stock_uom",
+  "item_name",
+  "description",
+  "qty_section",
+  "required_qty",
+  "column_break_9",
+  "transferred_qty",
+  "allow_alternative_item"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "item_code", 
-   "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": "Item Code", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Item", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "item_code",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Item Code",
+   "options": "Item",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "source_warehouse", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 1, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Source Warehouse", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Warehouse", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "source_warehouse",
+   "fieldtype": "Link",
+   "ignore_user_permissions": 1,
+   "in_list_view": 1,
+   "label": "Source Warehouse",
+   "options": "Warehouse"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "uom", 
-   "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": "UOM", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "UOM", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "uom",
+   "fieldtype": "Link",
+   "label": "UOM",
+   "options": "UOM"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "column_break_3",
+   "fieldtype": "Column Break"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "item_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": "Item Name", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "item_name",
+   "fieldtype": "Data",
+   "label": "Item Name",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "description", 
-   "fieldtype": "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": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "description",
+   "fieldtype": "Text",
+   "label": "Description",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "qty_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": "Qty", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "qty_section",
+   "fieldtype": "Section Break",
+   "label": "Qty"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "required_qty", 
-   "fieldtype": "Float", 
-   "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": "Required Qty", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "required_qty",
+   "fieldtype": "Float",
+   "in_list_view": 1,
+   "label": "Required Qty",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break_9", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "column_break_9",
+   "fieldtype": "Column Break"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "allow_alternative_item", 
-   "fieldtype": "Check", 
-   "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": "Allow Alternative Item", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
+   "default": "0",
+   "fieldname": "allow_alternative_item",
+   "fieldtype": "Check",
+   "label": "Allow Alternative Item"
+  },
+  {
+   "fetch_from": "item_code.item_group",
+   "fieldname": "item_group",
+   "fieldtype": "Link",
+   "label": "Item Group",
+   "options": "Item Group",
+   "read_only": 1
+  },
+  {
+   "fetch_from": "item_code.stock_uom",
+   "fieldname": "stock_uom",
+   "fieldtype": "Link",
+   "label": "Stock UOM",
+   "options": "UOM"
+  },
+  {
+   "fieldname": "transferred_qty",
+   "fieldtype": "Float",
+   "label": "Transferred Qty",
+   "no_copy": 1,
+   "print_hide": 1,
+   "read_only": 1
   }
- ], 
- "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": "2018-08-28 15:23:48.099459", 
- "modified_by": "Administrator", 
- "module": "Manufacturing", 
- "name": "Job Card Item", 
- "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, 
- "track_views": 0
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-02-11 13:50:13.804108",
+ "modified_by": "Administrator",
+ "module": "Manufacturing",
+ "name": "Job Card Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py
index 06a8e19..00e8c54 100644
--- a/erpnext/manufacturing/doctype/work_order/test_work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py
@@ -94,11 +94,11 @@
 		wo_order = make_wo_order_test_record(item="_Test FG Item", qty=2,
 			source_warehouse=warehouse, skip_transfer=1)
 
-		bin1_on_submit = get_bin(item, warehouse)
+		reserved_qty_on_submission = cint(get_bin(item, warehouse).reserved_qty_for_production)
 
 		# reserved qty for production is updated
-		self.assertEqual(cint(bin1_at_start.reserved_qty_for_production) + 2,
-			cint(bin1_on_submit.reserved_qty_for_production))
+		self.assertEqual(cint(bin1_at_start.reserved_qty_for_production) + 2, reserved_qty_on_submission)
+
 
 		test_stock_entry.make_stock_entry(item_code="_Test Item",
 			target=warehouse, qty=100, basic_rate=100)
@@ -109,9 +109,9 @@
 		s.submit()
 
 		bin1_at_completion = get_bin(item, warehouse)
-
+		
 		self.assertEqual(cint(bin1_at_completion.reserved_qty_for_production),
-			cint(bin1_on_submit.reserved_qty_for_production) - 1)
+			reserved_qty_on_submission - 1)
 
 	def test_production_item(self):
 		wo_order = make_wo_order_test_record(item="_Test FG Item", qty=1, do_not_save=True)
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 3b7c6ab..ba31fee 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -752,3 +752,7 @@
 erpnext.patches.v13_0.convert_qi_parameter_to_link_field
 erpnext.patches.v13_0.setup_patient_history_settings_for_standard_doctypes
 erpnext.patches.v13_0.add_naming_series_to_old_projects # 1-02-2021
+erpnext.patches.v12_0.add_state_code_for_ladakh
+erpnext.patches.v13_0.item_reposting_for_incorrect_sl_and_gl
+erpnext.patches.v13_0.delete_old_bank_reconciliation_doctypes
+erpnext.patches.v13_0.update_vehicle_no_reqd_condition
diff --git a/erpnext/patches/v11_0/refactor_autoname_naming.py b/erpnext/patches/v11_0/refactor_autoname_naming.py
index 5dc5d3b..b997ba2 100644
--- a/erpnext/patches/v11_0/refactor_autoname_naming.py
+++ b/erpnext/patches/v11_0/refactor_autoname_naming.py
@@ -20,7 +20,7 @@
 	'Certified Consultant': 'NPO-CONS-.YYYY.-.#####',
 	'Chat Room': 'CHAT-ROOM-.#####',
 	'Compensatory Leave Request': 'HR-CMP-.YY.-.MM.-.#####',
-	'Custom Script': 'SYS-SCR-.#####',
+	'Client Script': 'SYS-SCR-.#####',
 	'Employee Benefit Application': 'HR-BEN-APP-.YY.-.MM.-.#####',
 	'Employee Benefit Application Detail': '',
 	'Employee Benefit Claim': 'HR-BEN-CLM-.YY.-.MM.-.#####',
diff --git a/erpnext/patches/v11_1/update_bank_transaction_status.py b/erpnext/patches/v11_1/update_bank_transaction_status.py
index 1acdfcc..544bc5e 100644
--- a/erpnext/patches/v11_1/update_bank_transaction_status.py
+++ b/erpnext/patches/v11_1/update_bank_transaction_status.py
@@ -7,9 +7,20 @@
 def execute():
     frappe.reload_doc("accounts", "doctype", "bank_transaction")
 
-    frappe.db.sql(""" UPDATE `tabBank Transaction`
-        SET status = 'Reconciled'
-        WHERE
-            status = 'Settled' and (debit = allocated_amount or credit = allocated_amount)
-            and ifnull(allocated_amount, 0) > 0
-    """)
\ No newline at end of file
+    bank_transaction_fields = frappe.get_meta("Bank Transaction").get_valid_columns()
+
+    if 'debit' in bank_transaction_fields:
+        frappe.db.sql(""" UPDATE `tabBank Transaction`
+            SET status = 'Reconciled'
+            WHERE
+                status = 'Settled' and (debit = allocated_amount or credit = allocated_amount)
+                and ifnull(allocated_amount, 0) > 0
+        """)
+
+    elif 'deposit' in bank_transaction_fields:
+        frappe.db.sql(""" UPDATE `tabBank Transaction`
+            SET status = 'Reconciled'
+            WHERE
+                status = 'Settled' and (deposit = allocated_amount or withdrawal = allocated_amount)
+                and ifnull(allocated_amount, 0) > 0
+        """)
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/add_state_code_for_ladakh.py b/erpnext/patches/v12_0/add_state_code_for_ladakh.py
new file mode 100644
index 0000000..d41101c
--- /dev/null
+++ b/erpnext/patches/v12_0/add_state_code_for_ladakh.py
@@ -0,0 +1,16 @@
+import frappe
+from erpnext.regional.india import states
+
+def execute():
+
+	company = frappe.get_all('Company', filters = {'country': 'India'})
+	if not company:
+		return
+
+	custom_fields = ['Address-gst_state', 'Tax Category-gst_state']
+
+	# Update options in gst_state custom fields
+	for field in custom_fields:
+		gst_state_field = frappe.get_doc('Custom Field', field)
+		gst_state_field.options = '\n'.join(states)
+		gst_state_field.save()
diff --git a/erpnext/patches/v13_0/delete_old_bank_reconciliation_doctypes.py b/erpnext/patches/v13_0/delete_old_bank_reconciliation_doctypes.py
new file mode 100644
index 0000000..af1f6e7
--- /dev/null
+++ b/erpnext/patches/v13_0/delete_old_bank_reconciliation_doctypes.py
@@ -0,0 +1,26 @@
+# Copyright (c) 2019, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+
+import frappe
+from frappe.model.utils.rename_field import rename_field
+
+def execute():
+	doctypes = [
+		"Bank Statement Settings",
+		"Bank Statement Settings Item",
+		"Bank Statement Transaction Entry",
+		"Bank Statement Transaction Invoice Item",
+		"Bank Statement Transaction Payment Item",
+		"Bank Statement Transaction Settings Item",
+		"Bank Statement Transaction Settings",
+	]
+
+	for doctype in doctypes:
+		frappe.delete_doc("DocType", doctype, force=1)
+
+	frappe.delete_doc("Page", "bank-reconciliation", force=1)
+
+	rename_field("Bank Transaction", "debit", "deposit")
+	rename_field("Bank Transaction", "credit", "withdrawal")
diff --git a/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py b/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py
new file mode 100644
index 0000000..06f7f98
--- /dev/null
+++ b/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py
@@ -0,0 +1,46 @@
+import frappe
+from frappe import _
+from erpnext.stock.stock_ledger import update_entries_after
+from erpnext.accounts.utils import update_gl_entries_after
+
+def execute():
+	frappe.reload_doc('stock', 'doctype', 'repost_item_valuation')
+
+	reposting_project_deployed_on = frappe.db.get_value("DocType", "Repost Item Valuation", "creation")
+
+	data = frappe.db.sql('''
+		SELECT
+			name, item_code, warehouse, voucher_type, voucher_no, posting_date, posting_time
+		FROM
+			`tabStock Ledger Entry`
+		WHERE
+			creation > %s
+			and is_cancelled = 0
+		ORDER BY timestamp(posting_date, posting_time) asc, creation asc
+	''', reposting_project_deployed_on, as_dict=1)
+
+	frappe.db.auto_commit_on_many_writes = 1
+	print("Reposting Stock Ledger Entries...")
+	total_sle = len(data)
+	i = 0
+	for d in data:
+		update_entries_after({
+			"item_code": d.item_code,
+			"warehouse": d.warehouse,
+			"posting_date": d.posting_date,
+			"posting_time": d.posting_time,
+			"voucher_type": d.voucher_type,
+			"voucher_no": d.voucher_no,
+			"sle_id": d.name
+		}, allow_negative_stock=True)
+
+		i += 1
+		if i%100 == 0:
+			print(i, "/", total_sle)
+
+
+	print("Reposting General Ledger Entries...")
+	for row in frappe.get_all('Company', filters= {'enable_perpetual_inventory': 1}):
+		update_gl_entries_after('2020-12-25', '01:58:55', company=row.name)
+
+	frappe.db.auto_commit_on_many_writes = 0
diff --git a/erpnext/patches/v13_0/update_vehicle_no_reqd_condition.py b/erpnext/patches/v13_0/update_vehicle_no_reqd_condition.py
new file mode 100644
index 0000000..c26cddb
--- /dev/null
+++ b/erpnext/patches/v13_0/update_vehicle_no_reqd_condition.py
@@ -0,0 +1,9 @@
+import frappe
+
+def execute():
+	company = frappe.get_all('Company', filters = {'country': 'India'})
+	if not company:
+		return
+
+	if frappe.db.exists('Custom Field', { 'fieldname': 'vehicle_no' }):
+		frappe.db.set_value('Custom Field', { 'fieldname': 'vehicle_no' }, 'mandatory_depends_on', '')
diff --git a/erpnext/patches/v5_0/replace_renamed_fields_in_custom_scripts_and_print_formats.py b/erpnext/patches/v5_0/replace_renamed_fields_in_custom_scripts_and_print_formats.py
index ef3f1d6..c564f8b 100644
--- a/erpnext/patches/v5_0/replace_renamed_fields_in_custom_scripts_and_print_formats.py
+++ b/erpnext/patches/v5_0/replace_renamed_fields_in_custom_scripts_and_print_formats.py
@@ -9,7 +9,7 @@
 	# NOTE: sequence is important
 	renamed_fields = get_all_renamed_fields()
 
-	for dt, script_field, ref_dt_field in (("Custom Script", "script", "dt"), ("Print Format", "html", "doc_type")):
+	for dt, script_field, ref_dt_field in (("Client Script", "script", "dt"), ("Print Format", "html", "doc_type")):
 
 		cond1 = " or ".join("""{0} like "%%{1}%%" """.format(script_field, d[0].replace("_", "\\_")) for d in renamed_fields)
 		cond2 = " and standard = 'No'" if dt == "Print Format" else ""
diff --git a/erpnext/patches/v7_0/remove_doctypes_and_reports.py b/erpnext/patches/v7_0/remove_doctypes_and_reports.py
index 746cae0..2356e2f 100644
--- a/erpnext/patches/v7_0/remove_doctypes_and_reports.py
+++ b/erpnext/patches/v7_0/remove_doctypes_and_reports.py
@@ -7,7 +7,7 @@
 			where name in('Time Log Batch', 'Time Log Batch Detail', 'Time Log')""")
 
 	frappe.db.sql("""delete from `tabDocField` where parent in ('Time Log', 'Time Log Batch')""")
-	frappe.db.sql("""update `tabCustom Script` set dt = 'Timesheet' where dt = 'Time Log'""")
+	frappe.db.sql("""update `tabClient Script` set dt = 'Timesheet' where dt = 'Time Log'""")
 
 	for data in frappe.db.sql(""" select label, fieldname from  `tabCustom Field` where dt = 'Time Log'""", as_dict=1):
 		custom_field = frappe.get_doc({
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py
index 2d3bc57..60aff02 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py
@@ -1103,10 +1103,10 @@
 			self.calculate_total_for_salary_slip_based_on_timesheet()
 		else:
 			self.total_deduction = 0.0
-			if self.earnings:
+			if hasattr(self, "earnings"):
 				for earning in self.earnings:
 					self.gross_pay += flt(earning.amount, earning.precision("amount"))
-			if self.deductions:
+			if hasattr(self, "deductions"):
 				for deduction in self.deductions:
 					self.total_deduction += flt(deduction.amount, deduction.precision("amount"))
 			self.net_pay = flt(self.gross_pay) - flt(self.total_deduction) - flt(self.total_loan_repayment)
diff --git a/erpnext/portal/product_configurator/utils.py b/erpnext/portal/product_configurator/utils.py
index 4693d44..21fd7c2 100644
--- a/erpnext/portal/product_configurator/utils.py
+++ b/erpnext/portal/product_configurator/utils.py
@@ -386,7 +386,8 @@
 		r.description = r.web_long_description or r.description
 		r.image = r.website_image or r.image
 		product_info = get_product_info_for_website(r.item_code, skip_quotation_creation=True).get('product_info')
-		r.formatted_price = product_info['price'].get('formatted_price') if product_info['price'] else None
+		if product_info:
+			r.formatted_price = product_info['price'].get('formatted_price') if product_info['price'] else None
 
 	return results
 
diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py
index 9e807f7..ea81b3e 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.py
+++ b/erpnext/projects/doctype/timesheet/timesheet.py
@@ -288,7 +288,7 @@
 def make_salary_slip(source_name, target_doc=None):
 	target = frappe.new_doc("Salary Slip")
 	set_missing_values(source_name, target)
-	target.run_method("get_emp_and_leave_details")
+	target.run_method("get_emp_and_working_day_details")
 
 	return target
 
diff --git a/erpnext/public/build.json b/erpnext/public/build.json
index 4a40e8e..7a3cb83 100644
--- a/erpnext/public/build.json
+++ b/erpnext/public/build.json
@@ -2,7 +2,7 @@
 	"css/erpnext.css": [
 		"public/less/erpnext.less",
 		"public/less/hub.less",
-		"public/less/call_popup.less",
+		"public/scss/call_popup.scss",
 		"public/scss/point-of-sale.scss"
 	],
 	"css/marketplace.css": [
@@ -61,5 +61,10 @@
 		"selling/page/point_of_sale/pos_past_order_list.js",
 		"selling/page/point_of_sale/pos_past_order_summary.js",
 		"selling/page/point_of_sale/pos_controller.js"
+	],
+	"js/bank-reconciliation-tool.min.js": [
+		"public/js/bank_reconciliation_tool/data_table_manager.js",
+		"public/js/bank_reconciliation_tool/number_card.js",
+		"public/js/bank_reconciliation_tool/dialog_manager.js"
 	]
 }
diff --git a/erpnext/public/images/erp-icon.svg b/erpnext/public/images/erp-icon.svg
deleted file mode 100644
index 6bec40c..0000000
--- a/erpnext/public/images/erp-icon.svg
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="88px" height="88px" viewBox="0 0 88 88" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-    <!-- Generator: Sketch 44.1 (41455) - http://www.bohemiancoding.com/sketch -->
-    <title>erpnext-logo</title>
-    <desc>Created with Sketch.</desc>
-    <defs></defs>
-    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g id="erpnext-logo" transform="translate(-2.000000, -2.000000)" fill-rule="nonzero">
-            <g id="g1422-7-2" transform="translate(0.025630, 0.428785)" fill="#5E64FF">
-                <g id="g1418-4-6" transform="translate(0.268998, 0.867736)">
-                    <g id="g1416-4-9" transform="translate(0.749997, 0.000000)">
-                        <path d="M14.1845844,0.703479866 L75.0387175,0.703479866 C82.3677094,0.703479866 88.2679029,6.60367875 88.2679029,13.9326374 L88.2679029,74.7868158 C88.2679029,82.1157744 82.3677094,88.0159833 75.0387175,88.0159833 L14.1845844,88.0159833 C6.85569246,88.0159833 0.955398949,82.1157744 0.955398949,74.7868158 L0.955398949,13.9326374 C0.955398949,6.60367875 6.85569246,0.703479866 14.1845844,0.703479866 L14.1845844,0.703479866 Z" id="path1414-3-4"></path>
-                    </g>
-                </g>
-            </g>
-            <g id="g1444-6-7" transform="translate(27.708247, 23.320960)" fill="#FFFFFF">
-                <path d="M4.06942472,0.507006595 C3.79457554,0.507006595 3.52673783,0.534925429 3.26792241,0.587619847 C3.00908052,0.640314265 2.75926093,0.717948309 2.52171801,0.818098395 C2.40292009,0.868173438 2.28745592,0.924056085 2.17495509,0.985013441 C1.94997987,1.10692286 1.73828674,1.24983755 1.54244215,1.41134187 C0.661062132,2.13811791 0.100674618,3.23899362 0.100674618,4.4757567 L0.100674618,4.71760174 L0.100674618,39.9531653 L0.100674618,40.1945182 C0.100674618,42.3932057 1.87073716,44.1632683 4.06942472,44.1632683 L31.8263867,44.1632683 C34.0250742,44.1632683 35.7951368,42.3932057 35.7951368,40.1945182 L35.7951368,39.9531653 C35.7951368,37.7544777 34.0250742,35.9844152 31.8263867,35.9844152 L8.28000399,35.9844152 L8.28000399,26.0992376 L25.7874571,26.0992376 C27.9861447,26.0992376 29.7562072,24.3291751 29.7562072,22.1304875 L29.7562072,21.8891611 C29.7562072,19.6904735 27.9861447,17.920411 25.7874571,17.920411 L8.28000399,17.920411 L8.28000399,8.68635184 L31.8263867,8.68635184 C34.0250742,8.68635184 35.7951368,6.9162893 35.7951368,4.71760174 L35.7951368,4.4757567 C35.7951368,2.27706914 34.0250742,0.507006595 31.8263867,0.507006595 L4.06942472,0.507006595 Z" id="rect1436-8-4"></path>
-            </g>
-        </g>
-    </g>
-</svg>
\ No newline at end of file
diff --git a/erpnext/public/images/erpnext-12.svg b/erpnext/public/images/erpnext-12.svg
deleted file mode 100644
index fcc8e46..0000000
--- a/erpnext/public/images/erpnext-12.svg
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="165px" height="88px" viewBox="0 0 165 88" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-    <!-- Generator: Sketch 44.1 (41455) - http://www.bohemiancoding.com/sketch -->
-    <title>version-12</title>
-    <desc>Created with Sketch.</desc>
-    <defs></defs>
-    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g id="version-12" transform="translate(-2.000000, -2.000000)">
-            <g id="erp-icon" fill-rule="nonzero">
-                <g id="g1422-7-2" transform="translate(0.025630, 0.428785)" fill="#5E64FF">
-                    <g id="g1418-4-6" transform="translate(0.268998, 0.867736)">
-                        <g id="g1416-4-9" transform="translate(0.749997, 0.000000)">
-                            <path d="M14.1845844,0.703479866 L75.0387175,0.703479866 C82.3677094,0.703479866 88.2679029,6.60367875 88.2679029,13.9326374 L88.2679029,74.7868158 C88.2679029,82.1157744 82.3677094,88.0159833 75.0387175,88.0159833 L14.1845844,88.0159833 C6.85569246,88.0159833 0.955398949,82.1157744 0.955398949,74.7868158 L0.955398949,13.9326374 C0.955398949,6.60367875 6.85569246,0.703479866 14.1845844,0.703479866 L14.1845844,0.703479866 Z" id="path1414-3-4"></path>
-                        </g>
-                    </g>
-                </g>
-                <g id="g1444-6-7" transform="translate(27.708247, 23.320960)" fill="#FFFFFF">
-                    <path d="M4.06942472,0.507006595 C3.79457554,0.507006595 3.52673783,0.534925429 3.26792241,0.587619847 C3.00908052,0.640314265 2.75926093,0.717948309 2.52171801,0.818098395 C2.40292009,0.868173438 2.28745592,0.924056085 2.17495509,0.985013441 C1.94997987,1.10692286 1.73828674,1.24983755 1.54244215,1.41134187 C0.661062132,2.13811791 0.100674618,3.23899362 0.100674618,4.4757567 L0.100674618,4.71760174 L0.100674618,39.9531653 L0.100674618,40.1945182 C0.100674618,42.3932057 1.87073716,44.1632683 4.06942472,44.1632683 L31.8263867,44.1632683 C34.0250742,44.1632683 35.7951368,42.3932057 35.7951368,40.1945182 L35.7951368,39.9531653 C35.7951368,37.7544777 34.0250742,35.9844152 31.8263867,35.9844152 L8.28000399,35.9844152 L8.28000399,26.0992376 L25.7874571,26.0992376 C27.9861447,26.0992376 29.7562072,24.3291751 29.7562072,22.1304875 L29.7562072,21.8891611 C29.7562072,19.6904735 27.9861447,17.920411 25.7874571,17.920411 L8.28000399,17.920411 L8.28000399,8.68635184 L31.8263867,8.68635184 C34.0250742,8.68635184 35.7951368,6.9162893 35.7951368,4.71760174 L35.7951368,4.4757567 C35.7951368,2.27706914 34.0250742,0.507006595 31.8263867,0.507006595 L4.06942472,0.507006595 Z" id="rect1436-8-4"></path>
-                </g>
-            </g>
-            <text id="12" font-family="SourceSansPro-Regular, Source Sans Pro" font-size="72" font-weight="normal" letter-spacing="-0.386831313" fill="#D1D8DD">
-                <tspan x="99" y="71">12</tspan>
-            </text>
-        </g>
-    </g>
-</svg>
\ No newline at end of file
diff --git a/erpnext/public/images/erpnext-favicon.svg b/erpnext/public/images/erpnext-favicon.svg
new file mode 100644
index 0000000..a3ac3bb
--- /dev/null
+++ b/erpnext/public/images/erpnext-favicon.svg
@@ -0,0 +1,5 @@
+<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M0 12C0 5.37258 5.37258 0 12 0H88C94.6274 0 100 5.37258 100 12V88C100 94.6274 94.6274 100 88 100H12C5.37258 100 0 94.6274 0 88V12Z" fill="#0089FF"/>
+<path d="M65.7097 32.9462H67.3871V24H33V32.9462H43.9032H65.7097Z" fill="white"/>
+<path d="M43.9032 66.2151V53.914H65.7097V44.9677H43.9032H33V75.1613H67.6667V66.2151H43.9032Z" fill="white"/>
+</svg>
\ No newline at end of file
diff --git a/erpnext/public/images/erpnext-footer.png b/erpnext/public/images/erpnext-footer.png
deleted file mode 100644
index ffff775..0000000
--- a/erpnext/public/images/erpnext-footer.png
+++ /dev/null
Binary files differ
diff --git a/erpnext/public/images/erpnext-logo.png b/erpnext/public/images/erpnext-logo.png
index 115faaa..3090727 100644
--- a/erpnext/public/images/erpnext-logo.png
+++ b/erpnext/public/images/erpnext-logo.png
Binary files differ
diff --git a/erpnext/public/images/erpnext_logo.svg b/erpnext/public/images/erpnext_logo.svg
deleted file mode 100644
index af3a849..0000000
--- a/erpnext/public/images/erpnext_logo.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
-	<path d="M5.45455 0H30.5454C33.5673 0 36 2.43272 36 5.45454V30.5455C36 33.5673 33.5673 36 30.5454 36H5.45455C2.43276 36 0 33.5673 0 30.5455V5.45454C0 2.43272 2.43276 0 5.45455 0Z" fill="#2996F1"/>
-	<path d="M12.277 8.99994C12.1637 8.99994 12.0532 9.01145 11.9465 9.03318C11.8398 9.0549 11.7368 9.08691 11.6389 9.12821C11.5899 9.14885 11.5423 9.17189 11.4959 9.19703C11.4031 9.24729 11.3158 9.30622 11.2351 9.37281C10.8717 9.67247 10.6406 10.1264 10.6406 10.6363V10.736V25.2641V25.3636C10.6406 26.2701 11.3704 26.9999 12.277 26.9999H23.7215C24.6281 26.9999 25.3579 26.2701 25.3579 25.3636V25.2641C25.3579 24.3575 24.6281 23.6277 23.7215 23.6277H14.0131V19.5519H21.2316C22.1381 19.5519 22.868 18.8221 22.868 17.9156V17.8161C22.868 16.9095 22.1381 16.1797 21.2316 16.1797H14.0131V12.3724H23.7215C24.6281 12.3724 25.3579 11.6426 25.3579 10.736V10.6363C25.3579 9.72976 24.6281 8.99994 23.7215 8.99994H12.277Z" fill="white"/>
-</svg>
\ No newline at end of file
diff --git a/erpnext/public/images/favicon.png b/erpnext/public/images/favicon.png
deleted file mode 100644
index b694885..0000000
--- a/erpnext/public/images/favicon.png
+++ /dev/null
Binary files differ
diff --git a/erpnext/public/images/splash.png b/erpnext/public/images/splash.png
deleted file mode 100644
index 8e5d055..0000000
--- a/erpnext/public/images/splash.png
+++ /dev/null
Binary files differ
diff --git a/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js b/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js
new file mode 100644
index 0000000..5bb58fa
--- /dev/null
+++ b/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js
@@ -0,0 +1,220 @@
+frappe.provide("erpnext.accounts.bank_reconciliation");
+
+erpnext.accounts.bank_reconciliation.DataTableManager = class DataTableManager {
+	constructor(opts) {
+		Object.assign(this, opts);
+		this.dialog_manager = new erpnext.accounts.bank_reconciliation.DialogManager(
+			this.company,
+			this.bank_account
+		);
+		this.make_dt();
+	}
+
+	make_dt() {
+		var me = this;
+		frappe.call({
+			method:
+				"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_bank_transactions",
+			args: {
+				bank_account: this.bank_account,
+			},
+			callback: function (response) {
+				me.format_data(response.message);
+				me.get_dt_columns();
+				me.get_datatable();
+				me.set_listeners();
+			},
+		});
+	}
+
+	get_dt_columns() {
+		this.columns = [
+			{
+				name: "Date",
+				editable: false,
+				width: 100,
+			},
+
+			{
+				name: "Party Type",
+				editable: false,
+				width: 95,
+			},
+			{
+				name: "Party",
+				editable: false,
+				width: 100,
+			},
+			{
+				name: "Description",
+				editable: false,
+				width: 350,
+			},
+			{
+				name: "Deposit",
+				editable: false,
+				width: 100,
+				format: (value) =>
+					"<span style='color:green;'>" +
+					format_currency(value, this.currency) +
+					"</span>",
+			},
+			{
+				name: "Withdrawal",
+				editable: false,
+				width: 100,
+				format: (value) =>
+					"<span style='color:red;'>" +
+					format_currency(value, this.currency) +
+					"</span>",
+			},
+			{
+				name: "Unallocated Amount",
+				editable: false,
+				width: 100,
+				format: (value) =>
+					"<span style='color:blue;'>" +
+					format_currency(value, this.currency) +
+					"</span>",
+			},
+			{
+				name: "Reference Number",
+				editable: false,
+				width: 140,
+			},
+			{
+				name: "Actions",
+				editable: false,
+				sortable: false,
+				focusable: false,
+				dropdown: false,
+				width: 80,
+			},
+		];
+	}
+
+	format_data(transactions) {
+		this.transactions = [];
+		if (transactions[0]) {
+			this.currency = transactions[0]["currency"];
+		}
+		this.transaction_dt_map = {};
+		let length;
+		transactions.forEach((row) => {
+			length = this.transactions.push(this.format_row(row));
+			this.transaction_dt_map[row["name"]] = length - 1;
+		});
+	}
+
+	format_row(row) {
+		return [
+			row["date"],
+			row["party_type"],
+			row["party"],
+			row["description"],
+			row["deposit"],
+			row["withdrawal"],
+			row["unallocated_amount"],
+			row["reference_number"],
+			`
+			<Button class="btn btn-primary btn-xs center"  data-name = ${row["name"]} >
+				Actions
+			</a>
+			`,
+		];
+	}
+
+	get_datatable() {
+		const datatable_options = {
+			columns: this.columns,
+			data: this.transactions,
+			dynamicRowHeight: true,
+			checkboxColumn: false,
+			inlineFilters: true,
+		};
+		this.datatable = new frappe.DataTable(
+			this.$reconciliation_tool_dt.get(0),
+			datatable_options
+		);
+		$(`.${this.datatable.style.scopeClass} .dt-scrollable`).css(
+			"max-height",
+			"calc(100vh - 400px)"
+		);
+
+		if (this.transactions.length > 0) {
+			this.$reconciliation_tool_dt.show();
+			this.$no_bank_transactions.hide();
+		} else {
+			this.$reconciliation_tool_dt.hide();
+			this.$no_bank_transactions.show();
+		}
+	}
+
+	set_listeners() {
+		var me = this;
+		$(`.${this.datatable.style.scopeClass} .dt-scrollable`).on(
+			"click",
+			`.btn`,
+			function () {
+				me.dialog_manager.show_dialog(
+					$(this).attr("data-name"),
+					(bank_transaction) => me.update_dt_cards(bank_transaction)
+				);
+				return true;
+			}
+		);
+	}
+
+	update_dt_cards(bank_transaction) {
+		const transaction_index = this.transaction_dt_map[
+			bank_transaction.name
+		];
+		if (bank_transaction.unallocated_amount > 0) {
+			this.transactions[transaction_index] = this.format_row(
+				bank_transaction
+			);
+		} else {
+			this.transactions.splice(transaction_index, 1);
+		}
+		this.datatable.refresh(this.transactions, this.columns);
+
+		if (this.transactions.length == 0) {
+			this.$reconciliation_tool_dt.hide();
+			this.$no_bank_transactions.show();
+		}
+
+		// this.make_dt();
+		this.get_cleared_balance().then(() => {
+			this.cards_manager.$cards[1].set_value(
+				format_currency(this.cleared_balance),
+				this.currency
+			);
+			this.cards_manager.$cards[2].set_value(
+				format_currency(
+					this.bank_statement_closing_balance - this.cleared_balance
+				),
+				this.currency
+			);
+			this.cards_manager.$cards[2].set_value_color(
+				this.bank_statement_closing_balance - this.cleared_balance == 0
+					? "text-success"
+					: "text-danger"
+			);
+		});
+	}
+
+	get_cleared_balance() {
+		if (this.bank_account && this.bank_statement_to_date) {
+			return frappe.call({
+				method:
+					"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_account_balance",
+				args: {
+					bank_account: this.bank_account,
+					till_date: this.bank_statement_to_date,
+				},
+				callback: (response) =>
+					(this.cleared_balance = response.message),
+			});
+		}
+	}
+};
diff --git a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js
new file mode 100644
index 0000000..142fe79
--- /dev/null
+++ b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js
@@ -0,0 +1,594 @@
+frappe.provide("erpnext.accounts.bank_reconciliation");
+
+erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager {
+	constructor(company, bank_account) {
+		this.bank_account = bank_account;
+		this.company = company;
+		this.make_dialog();
+	}
+
+	show_dialog(bank_transaction_name, update_dt_cards) {
+		this.bank_transaction_name = bank_transaction_name;
+		this.update_dt_cards = update_dt_cards;
+		frappe.call({
+			method: "frappe.client.get_value",
+			args: {
+				doctype: "Bank Transaction",
+				filters: { name: this.bank_transaction_name },
+				fieldname: [
+					"date",
+					"deposit",
+					"withdrawal",
+					"currency",
+					"description",
+					"name",
+					"bank_account",
+					"company",
+					"reference_number",
+					"party_type",
+					"party",
+					"unallocated_amount",
+					"allocated_amount",
+				],
+			},
+			callback: (r) => {
+				if (r.message) {
+					this.bank_transaction = r.message;
+					r.message.payment_entry = 1;
+					this.dialog.set_values(r.message);
+					this.dialog.show();
+				}
+			},
+		});
+	}
+
+	get_linked_vouchers(document_types) {
+		frappe.call({
+			method:
+				"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_linked_payments",
+			args: {
+				bank_transaction_name: this.bank_transaction_name,
+				document_types: document_types,
+			},
+
+			callback: (result) => {
+				const data = result.message;
+
+
+				if (data && data.length > 0) {
+					const proposals_wrapper = this.dialog.fields_dict.payment_proposals.$wrapper;
+					proposals_wrapper.show();
+					this.dialog.fields_dict.no_matching_vouchers.$wrapper.hide();
+					this.data = [];
+					data.forEach((row) => {
+						const reference_date = row[5] ? row[5] : row[8];
+						this.data.push([
+							row[1],
+							row[2],
+							reference_date,
+							format_currency(row[3], row[9]),
+							row[6],
+							row[4],
+						]);
+					});
+					this.get_dt_columns();
+					this.get_datatable(proposals_wrapper);
+				} else {
+					const proposals_wrapper = this.dialog.fields_dict.payment_proposals.$wrapper;
+					proposals_wrapper.hide();
+					this.dialog.fields_dict.no_matching_vouchers.$wrapper.show();
+
+				}
+				this.dialog.show();
+			},
+		});
+	}
+
+	get_dt_columns() {
+		this.columns = [
+			{
+				name: "Document Type",
+				editable: false,
+				width: 125,
+			},
+			{
+				name: "Document Name",
+				editable: false,
+				width: 150,
+			},
+			{
+				name: "Reference Date",
+				editable: false,
+				width: 120,
+			},
+			{
+				name: "Amount",
+				editable: false,
+				width: 100,
+			},
+			{
+				name: "Party",
+				editable: false,
+				width: 120,
+			},
+
+			{
+				name: "Reference Number",
+				editable: false,
+				width: 140,
+			},
+		];
+	}
+
+	get_datatable(proposals_wrapper) {
+		if (!this.datatable) {
+			const datatable_options = {
+				columns: this.columns,
+				data: this.data,
+				dynamicRowHeight: true,
+				checkboxColumn: true,
+				inlineFilters: true,
+			};
+			this.datatable = new frappe.DataTable(
+				proposals_wrapper.get(0),
+				datatable_options
+			);
+		} else {
+			this.datatable.refresh(this.data, this.columns);
+			this.datatable.rowmanager.checkMap = [];
+		}
+	}
+
+	make_dialog() {
+		const me = this;
+		me.selected_payment = null;
+
+		const fields = [
+			{
+				label: __("Action"),
+				fieldname: "action",
+				fieldtype: "Select",
+				options: `Match Against Voucher\nCreate Voucher\nUpdate Bank Transaction`,
+				default: "Match Against Voucher",
+			},
+			{
+				fieldname: "column_break_4",
+				fieldtype: "Column Break",
+			},
+			{
+				label: __("Document Type"),
+				fieldname: "document_type",
+				fieldtype: "Select",
+				options: `Payment Entry\nJournal Entry`,
+				default: "Payment Entry",
+				depends_on: "eval:doc.action=='Create Voucher'",
+			},
+			{
+				fieldtype: "Section Break",
+				fieldname: "section_break_1",
+				label: __("Filters"),
+				depends_on: "eval:doc.action=='Match Against Voucher'",
+			},
+			{
+				fieldtype: "Check",
+				label: "Payment Entry",
+				fieldname: "payment_entry",
+				onchange: () => this.update_options(),
+			},
+			{
+				fieldtype: "Check",
+				label: "Journal Entry",
+				fieldname: "journal_entry",
+				onchange: () => this.update_options(),
+			},
+			{
+				fieldname: "column_break_5",
+				fieldtype: "Column Break",
+			},
+			{
+				fieldtype: "Check",
+				label: "Sales Invoice",
+				fieldname: "sales_invoice",
+				onchange: () => this.update_options(),
+			},
+
+			{
+				fieldtype: "Check",
+				label: "Purchase Invoice",
+				fieldname: "purchase_invoice",
+				onchange: () => this.update_options(),
+			},
+			{
+				fieldname: "column_break_5",
+				fieldtype: "Column Break",
+			},
+			{
+				fieldtype: "Check",
+				label: "Expense Claim",
+				fieldname: "expense_claim",
+				onchange: () => this.update_options(),
+			},
+			{
+				fieldtype: "Check",
+				label: "Show Only Exact Amount",
+				fieldname: "exact_match",
+				onchange: () => this.update_options(),
+			},
+			{
+				fieldtype: "Section Break",
+				fieldname: "section_break_1",
+				label: __("Select Vouchers to Match"),
+				depends_on: "eval:doc.action=='Match Against Voucher'",
+			},
+			{
+				fieldtype: "HTML",
+				fieldname: "payment_proposals",
+			},
+			{
+				fieldtype: "HTML",
+				fieldname: "no_matching_vouchers",
+				options: "<div class='text-muted text-center'>No Matching Vouchers Found</div>"
+			},
+			{
+				fieldtype: "Section Break",
+				fieldname: "details",
+				label: "Details",
+				depends_on: "eval:doc.action!='Match Against Voucher'",
+			},
+			{
+				fieldname: "reference_number",
+				fieldtype: "Data",
+				label: "Reference Number",
+				mandatory_depends_on: "eval:doc.action=='Create Voucher'",
+			},
+			{
+				default: "Today",
+				fieldname: "posting_date",
+				fieldtype: "Date",
+				label: "Posting Date",
+				reqd: 1,
+				depends_on: "eval:doc.action=='Create Voucher'",
+			},
+			{
+				fieldname: "reference_date",
+				fieldtype: "Date",
+				label: "Cheque/Reference Date",
+				mandatory_depends_on: "eval:doc.action=='Create Voucher'",
+				depends_on: "eval:doc.action=='Create Voucher'",
+				reqd: 1,
+			},
+			{
+				fieldname: "mode_of_payment",
+				fieldtype: "Link",
+				label: "Mode of Payment",
+				options: "Mode of Payment",
+				depends_on: "eval:doc.action=='Create Voucher'",
+			},
+			{
+				fieldname: "edit_in_full_page",
+				fieldtype: "Button",
+				label: "Edit in Full Page",
+				click: () => {
+					this.edit_in_full_page();
+				},
+				depends_on:
+					"eval:doc.action=='Create Voucher'",
+			},
+			{
+				fieldname: "column_break_7",
+				fieldtype: "Column Break",
+			},
+			{
+				default: "Journal Entry Type",
+				fieldname: "journal_entry_type",
+				fieldtype: "Select",
+				label: "Journal Entry Type",
+				options:
+					"Journal Entry\nInter Company Journal Entry\nBank Entry\nCash Entry\nCredit Card Entry\nDebit Note\nCredit Note\nContra Entry\nExcise Entry\nWrite Off Entry\nOpening Entry\nDepreciation Entry\nExchange Rate Revaluation\nDeferred Revenue\nDeferred Expense",
+				depends_on:
+					"eval:doc.action=='Create Voucher' &&  doc.document_type=='Journal Entry'",
+				mandatory_depends_on:
+					"eval:doc.action=='Create Voucher' &&  doc.document_type=='Journal Entry'",
+			},
+			{
+				fieldname: "second_account",
+				fieldtype: "Link",
+				label: "Account",
+				options: "Account",
+				depends_on:
+					"eval:doc.action=='Create Voucher' &&  doc.document_type=='Journal Entry'",
+				mandatory_depends_on:
+					"eval:doc.action=='Create Voucher' &&  doc.document_type=='Journal Entry'",
+				get_query: () => {
+					return {
+						filters: {
+							is_group: 0,
+							company: this.company,
+						},
+					};
+				},
+			},
+			{
+				fieldname: "party_type",
+				fieldtype: "Link",
+				label: "Party Type",
+				options: "DocType",
+				mandatory_depends_on:
+				"eval:doc.action=='Create Voucher' &&  doc.document_type=='Payment Entry'",
+				get_query: function () {
+					return {
+						filters: {
+							name: [
+								"in",
+								Object.keys(frappe.boot.party_account_types),
+							],
+						},
+					};
+				},
+			},
+			{
+				fieldname: "party",
+				fieldtype: "Dynamic Link",
+				label: "Party",
+				options: "party_type",
+				mandatory_depends_on:
+					"eval:doc.action=='Create Voucher' && doc.document_type=='Payment Entry'",
+			},
+			{
+				fieldname: "project",
+				fieldtype: "Link",
+				label: "Project",
+				options: "Project",
+				depends_on:
+					"eval:doc.action=='Create Voucher' && doc.document_type=='Payment Entry'",
+			},
+			{
+				fieldname: "cost_center",
+				fieldtype: "Link",
+				label: "Cost Center",
+				options: "Cost Center",
+				depends_on:
+					"eval:doc.action=='Create Voucher' && doc.document_type=='Payment Entry'",
+			},
+			{
+				fieldtype: "Section Break",
+				fieldname: "details_section",
+				label: "Transaction Details",
+				collapsible: 1,
+			},
+			{
+				fieldname: "deposit",
+				fieldtype: "Currency",
+				label: "Deposit",
+				read_only: 1,
+			},
+			{
+				fieldname: "withdrawal",
+				fieldtype: "Currency",
+				label: "Withdrawal",
+				read_only: 1,
+			},
+			{
+				fieldname: "description",
+				fieldtype: "Small Text",
+				label: "Description",
+				read_only: 1,
+			},
+			{
+				fieldname: "column_break_17",
+				fieldtype: "Column Break",
+				read_only: 1,
+			},
+			{
+				fieldname: "allocated_amount",
+				fieldtype: "Currency",
+				label: "Allocated Amount",
+				read_only: 1,
+			},
+
+			{
+				fieldname: "unallocated_amount",
+				fieldtype: "Currency",
+				label: "Unallocated Amount",
+				read_only: 1,
+			},
+		];
+
+		me.dialog = new frappe.ui.Dialog({
+			title: __("Reconcile the Bank Transaction"),
+			fields: fields,
+			size: "large",
+			primary_action: (values) =>
+				this.reconciliation_dialog_primary_action(values),
+		});
+	}
+
+	get_selected_attributes() {
+		let selected_attributes = [];
+		this.dialog.$wrapper.find(".checkbox input").each((i, col) => {
+			if ($(col).is(":checked")) {
+				selected_attributes.push($(col).attr("data-fieldname"));
+			}
+		});
+
+		return selected_attributes;
+	}
+
+	update_options() {
+		let selected_attributes = this.get_selected_attributes();
+		this.get_linked_vouchers(selected_attributes);
+	}
+
+	reconciliation_dialog_primary_action(values) {
+		if (values.action == "Match Against Voucher") this.match(values);
+		if (
+			values.action == "Create Voucher" &&
+			values.document_type == "Payment Entry"
+		)
+			this.add_payment_entry(values);
+		if (
+			values.action == "Create Voucher" &&
+			values.document_type == "Journal Entry"
+		)
+			this.add_journal_entry(values);
+		else if (values.action == "Update Bank Transaction")
+			this.update_transaction(values);
+	}
+
+	match() {
+		var selected_map = this.datatable.rowmanager.checkMap;
+		let rows = [];
+		selected_map.forEach((val, index) => {
+			if (val == 1) rows.push(this.datatable.datamanager.rows[index]);
+		});
+		let vouchers = [];
+		rows.forEach((x) => {
+			vouchers.push({
+				payment_doctype: x[2].content,
+				payment_name: x[3].content,
+				amount: x[5].content,
+			});
+		});
+		frappe.call({
+			method:
+				"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.reconcile_vouchers",
+			args: {
+				bank_transaction_name: this.bank_transaction.name,
+				vouchers: vouchers,
+			},
+			callback: (response) => {
+				const alert_string =
+					"Bank Transaction " +
+					this.bank_transaction.name +
+					" Matched";
+				frappe.show_alert(alert_string);
+				this.update_dt_cards(response.message);
+				this.dialog.hide();
+			},
+		});
+	}
+
+	add_payment_entry(values) {
+		frappe.call({
+			method:
+				"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.create_payment_entry_bts",
+			args: {
+				bank_transaction_name: this.bank_transaction.name,
+				reference_number: values.reference_number,
+				reference_date: values.reference_date,
+				party_type: values.party_type,
+				party: values.party,
+				posting_date: values.posting_date,
+				mode_of_payment: values.mode_of_payment,
+				project: values.project,
+				cost_center: values.cost_center,
+			},
+			callback: (response) => {
+				const alert_string =
+					"Bank Transaction " +
+					this.bank_transaction.name +
+					" added as Payment Entry";
+				frappe.show_alert(alert_string);
+				this.update_dt_cards(response.message);
+				this.dialog.hide();
+			},
+		});
+	}
+
+	add_journal_entry(values) {
+		frappe.call({
+			method:
+				"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.create_journal_entry_bts",
+			args: {
+				bank_transaction_name: this.bank_transaction.name,
+				reference_number: values.reference_number,
+				reference_date: values.reference_date,
+				party_type: values.party_type,
+				party: values.party,
+				posting_date: values.posting_date,
+				mode_of_payment: values.mode_of_payment,
+				entry_type: values.journal_entry_type,
+				second_account: values.second_account,
+			},
+			callback: (response) => {
+				const alert_string =
+					"Bank Transaction " +
+					this.bank_transaction.name +
+					" added as Journal Entry";
+				frappe.show_alert(alert_string);
+				this.update_dt_cards(response.message);
+				this.dialog.hide();
+			},
+		});
+	}
+
+	update_transaction(values) {
+		frappe.call({
+			method:
+				"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.update_bank_transaction",
+			args: {
+				bank_transaction_name: this.bank_transaction.name,
+				reference_number: values.reference_number,
+				party_type: values.party_type,
+				party: values.party,
+			},
+			callback: (response) => {
+				const alert_string =
+					"Bank Transaction " +
+					this.bank_transaction.name +
+					" updated";
+				frappe.show_alert(alert_string);
+				this.update_dt_cards(response.message);
+				this.dialog.hide();
+			},
+		});
+	}
+
+	edit_in_full_page() {
+		const values = this.dialog.get_values(true);
+		if (values.document_type == "Payment Entry") {
+			frappe.call({
+				method:
+					"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.create_payment_entry_bts",
+				args: {
+					bank_transaction_name: this.bank_transaction.name,
+					reference_number: values.reference_number,
+					reference_date: values.reference_date,
+					party_type: values.party_type,
+					party: values.party,
+					posting_date: values.posting_date,
+					mode_of_payment: values.mode_of_payment,
+					project: values.project,
+					cost_center: values.cost_center,
+					allow_edit: true
+				},
+				callback: (r) => {
+					const doc = frappe.model.sync(r.message);
+					frappe.set_route("Form", doc[0].doctype, doc[0].name);
+				},
+			});
+		} else {
+			frappe.call({
+				method:
+					"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.create_journal_entry_bts",
+				args: {
+					bank_transaction_name: this.bank_transaction.name,
+					reference_number: values.reference_number,
+					reference_date: values.reference_date,
+					party_type: values.party_type,
+					party: values.party,
+					posting_date: values.posting_date,
+					mode_of_payment: values.mode_of_payment,
+					entry_type: values.journal_entry_type,
+					second_account: values.second_account,
+					allow_edit: true
+				},
+				callback: (r) => {
+					var doc = frappe.model.sync(r.message);
+					frappe.set_route("Form", doc[0].doctype, doc[0].name);
+				},
+			});
+		}
+	}
+
+};
diff --git a/erpnext/public/js/bank_reconciliation_tool/number_card.js b/erpnext/public/js/bank_reconciliation_tool/number_card.js
new file mode 100644
index 0000000..e10d109
--- /dev/null
+++ b/erpnext/public/js/bank_reconciliation_tool/number_card.js
@@ -0,0 +1,75 @@
+frappe.provide("erpnext.accounts.bank_reconciliation");
+
+erpnext.accounts.bank_reconciliation.NumberCardManager = class NumberCardManager {
+	constructor(opts) {
+		Object.assign(this, opts);
+		this.make_cards();
+	}
+
+	make_cards() {
+		this.$reconciliation_tool_cards.empty();
+		this.$cards = [];
+		this.$summary = $(`<div class="report-summary"></div>`)
+			.hide()
+			.appendTo(this.$reconciliation_tool_cards);
+		var chart_data = [
+			{
+				value: this.bank_statement_closing_balance,
+				label: "Closing Balance as per Bank Statement",
+				datatype: "Currency",
+				currency: this.currency,
+			},
+			{
+				value: this.cleared_balance,
+				label: "Closing Balance as per ERP",
+				datatype: "Currency",
+				currency: this.currency,
+			},
+			{
+				value:
+					this.bank_statement_closing_balance - this.cleared_balance,
+				label: "Difference",
+				datatype: "Currency",
+				currency: this.currency,
+			},
+		];
+
+		chart_data.forEach((summary) => {
+			let number_card = new erpnext.accounts.NumberCard(summary);
+			this.$cards.push(number_card);
+
+			number_card.$card.appendTo(this.$summary);
+		});
+		this.$cards[2].set_value_color(
+			this.bank_statement_closing_balance - this.cleared_balance == 0
+				? "text-success"
+				: "text-danger"
+		);
+		this.$summary.css({"border-bottom": "0px", "margin-left": "0px", "margin-right": "0px"});
+		this.$summary.show();
+	}
+};
+
+erpnext.accounts.NumberCard = class NumberCard {
+	constructor(options) {
+		this.$card = frappe.utils.build_summary_item(options);
+	}
+
+	set_value(value) {
+		this.$card.find("div").text(value);
+	}
+
+	set_value_color(color) {
+		this.$card
+			.find("div")
+			.removeClass("text-danger text-success")
+			.addClass(`${color}`);
+	}
+
+	set_indicator(color) {
+		this.$card
+			.find("span")
+			.removeClass("indicator red green")
+			.addClass(`indicator ${color}`);
+	}
+};
diff --git a/erpnext/public/js/call_popup/call_popup.js b/erpnext/public/js/call_popup/call_popup.js
index be1745e..c954f12 100644
--- a/erpnext/public/js/call_popup/call_popup.js
+++ b/erpnext/public/js/call_popup/call_popup.js
@@ -7,10 +7,103 @@
 	}
 
 	make() {
+		frappe.utils.play_sound('incoming-call');
 		this.dialog = new frappe.ui.Dialog({
 			'static': true,
-			'minimizable': true,
-			'fields': [{
+			'minimizable': true
+		});
+		this.dialog.get_close_btn().show();
+		this.setup_dialog();
+		this.set_call_status();
+		frappe.utils.bind_actions_with_object(this.dialog.$body, this);
+		this.dialog.$wrapper.addClass('call-popup');
+		this.dialog.get_close_btn().unbind('click').click(this.close_modal.bind(this));
+		this.dialog.show();
+	}
+
+	setup_dialog() {
+		this.setup_call_details();
+		this.dialog.$body.empty().append(this.caller_info);
+	}
+
+	set_indicator(color, blink=false) {
+		let classes = `indicator ${color} ${blink ? 'blink': ''}`;
+		this.dialog.header.find('.indicator').attr('class', classes);
+	}
+
+	set_call_status(call_status) {
+		let title = '';
+		call_status = call_status || this.call_log.status;
+		if (['Ringing'].includes(call_status) || !call_status) {
+			title = __('Incoming call from {0}', [this.get_caller_name() || this.caller_number]);
+			this.set_indicator('blue', true);
+		} else if (call_status === 'In Progress') {
+			title = __('Call Connected');
+			this.set_indicator('green');
+		} else if (['No Answer', 'Missed'].includes(call_status)) {
+			this.set_indicator('yellow');
+			title = __('Call Missed');
+		} else if (['Completed', 'Busy', 'Failed'].includes(call_status)) {
+			this.set_indicator('red');
+			title = __('Call Ended');
+		} else {
+			this.set_indicator('blue');
+			title = call_status;
+		}
+		this.dialog.set_title(title);
+	}
+
+	update_call_log(call_log, missed) {
+		this.call_log = call_log;
+		this.set_call_status(missed ? 'Missed': null);
+	}
+
+	close_modal() {
+		this.dialog.hide();
+		delete erpnext.call_popup;
+	}
+
+	call_ended(call_log, missed) {
+		frappe.utils.play_sound('call-disconnect');
+		this.update_call_log(call_log, missed);
+		setTimeout(() => {
+			if (!this.dialog.get_value('call_summary')) {
+				this.close_modal();
+			}
+		}, 60000);
+		this.clear_listeners();
+	}
+
+	get_caller_name() {
+		const contact_link = this.get_contact_link();
+		return contact_link.link_title || contact_link.link_name;
+	}
+
+	get_contact_link() {
+		let log = this.call_log;
+		let contact_link = log.links.find(d => d.link_doctype === 'Contact');
+		return contact_link || {};
+	}
+
+	setup_listener() {
+		frappe.realtime.on(`call_${this.call_log.id}_ended`, call_log => {
+			this.call_ended(call_log);
+		});
+
+		frappe.realtime.on(`call_${this.call_log.id}_missed`, call_log => {
+			this.call_ended(call_log, true);
+		});
+	}
+
+	clear_listeners() {
+		frappe.realtime.off(`call_${this.call_log.id}_ended`);
+		frappe.realtime.off(`call_${this.call_log.id}_missed`);
+	}
+
+	setup_call_details() {
+		this.caller_info = $(`<div></div>`);
+		this.call_details = new frappe.ui.FieldGroup({
+			fields: [{
 				'fieldname': 'name',
 				'label': 'Name',
 				'default': this.get_caller_name() || __('Unknown Caller'),
@@ -19,17 +112,17 @@
 			}, {
 				'fieldtype': 'Button',
 				'label': __('Open Contact'),
-				'click': () => frappe.set_route('Form', 'Contact', this.call_log.contact),
-				'depends_on': () => this.call_log.contact
-			}, {
-				'fieldtype': 'Button',
-				'label': __('Open Lead'),
-				'click': () => frappe.set_route('Form', 'Lead', this.call_log.lead),
-				'depends_on': () => this.call_log.lead
+				'click': () => frappe.set_route('Form', 'Contact', this.get_contact_link().link_name),
+				'depends_on': () => this.get_caller_name()
 			}, {
 				'fieldtype': 'Button',
 				'label': __('Create New Contact'),
-				'click': () => frappe.new_doc('Contact', { 'mobile_no': this.caller_number }),
+				'click': this.create_new_contact.bind(this),
+				'depends_on': () => !this.get_caller_name()
+			}, {
+				'fieldtype': 'Button',
+				'label': __('Create New Customer'),
+				'click': this.create_new_customer.bind(this),
 				'depends_on': () => !this.get_caller_name()
 			}, {
 				'fieldtype': 'Button',
@@ -45,25 +138,8 @@
 				'default': this.caller_number,
 				'read_only': 1
 			}, {
-				'fielname': 'last_interaction',
 				'fieldtype': 'Section Break',
-				'label': __('Activity'),
-				'depends_on': () => this.get_caller_name()
-			}, {
-				'fieldtype': 'Small Text',
-				'label': __('Last Issue'),
-				'fieldname': 'last_issue',
-				'read_only': true,
-				'depends_on': () => this.call_log.contact,
-				'default': `<i class="text-muted">${__('No issue has been raised by the caller.')}<i>`
-			}, {
-				'fieldtype': 'Small Text',
-				'label': __('Last Communication'),
-				'fieldname': 'last_communication',
-				'read_only': true,
-				'default': `<i class="text-muted">${__('No communication found.')}<i>`
-			}, {
-				'fieldtype': 'Section Break',
+				'hide_border': 1,
 			}, {
 				'fieldtype': 'Small Text',
 				'label': __('Call Summary'),
@@ -72,7 +148,7 @@
 				'fieldtype': 'Button',
 				'label': __('Save'),
 				'click': () => {
-					const call_summary = this.dialog.get_value('call_summary');
+					const call_summary = this.call_details.get_value('call_summary');
 					if (!call_summary) return;
 					frappe.xcall('erpnext.telephony.doctype.call_log.call_log.add_call_summary', {
 						'call_log': this.call_log.name,
@@ -94,108 +170,42 @@
 					});
 				}
 			}],
+			body: this.caller_info
 		});
-		this.set_call_status();
-		this.dialog.get_close_btn().show();
-		this.make_last_interaction_section();
-		this.dialog.$body.addClass('call-popup');
-		this.dialog.set_secondary_action(this.close_modal.bind(this));
-		frappe.utils.play_sound('incoming-call');
-		this.dialog.show();
+		this.call_details.make();
 	}
 
-	set_indicator(color, blink=false) {
-		let classes = `indicator ${color} ${blink ? 'blink': ''}`;
-		this.dialog.header.find('.indicator').attr('class', classes);
+	is_known_caller() {
+		return Boolean(this.get_caller_name());
 	}
 
-	set_call_status(call_status) {
-		let title = '';
-		call_status = call_status || this.call_log.status;
-		if (['Ringing'].includes(call_status) || !call_status) {
-			title = __('Incoming call from {0}', [this.get_caller_name() || this.caller_number]);
-			this.set_indicator('blue', true);
-		} else if (call_status === 'In Progress') {
-			title = __('Call Connected');
-			this.set_indicator('yellow');
-		} else if (call_status === 'Missed') {
-			this.set_indicator('red');
-			title = __('Call Missed');
-		} else if (['Completed', 'Disconnected'].includes(call_status)) {
-			this.set_indicator('red');
-			title = __('Call Disconnected');
-		} else {
-			this.set_indicator('blue');
-			title = call_status;
-		}
-		this.dialog.set_title(title);
+	create_new_customer() {
+		// to avoid quick entry form
+		const new_customer = frappe.model.get_new_doc('Customer');
+		new_customer.mobile_no = this.caller_number;
+		frappe.set_route('Form', new_customer.doctype, new_customer.name);
 	}
 
-	update_call_log(call_log) {
-		this.call_log = call_log;
-		this.set_call_status();
-	}
-
-	close_modal() {
-		this.dialog.hide();
-		delete erpnext.call_popup;
-	}
-
-	call_disconnected(call_log) {
-		frappe.utils.play_sound('call-disconnect');
-		this.update_call_log(call_log);
-		setTimeout(() => {
-			if (!this.dialog.get_value('call_summary')) {
-				this.close_modal();
-			}
-		}, 30000);
-	}
-
-	make_last_interaction_section() {
-		frappe.xcall('erpnext.crm.doctype.utils.get_last_interaction', {
-			'contact': this.call_log.contact,
-			'lead': this.call_log.lead
-		}).then(data => {
-			const comm_field = this.dialog.get_field('last_communication');
-			if (data.last_communication) {
-				const comm = data.last_communication;
-				comm_field.set_value(comm.content);
-			}
-
-			if (data.last_issue) {
-				const issue = data.last_issue;
-				const issue_field = this.dialog.get_field("last_issue");
-				issue_field.set_value(issue.subject);
-				issue_field.$wrapper.append(`
-					<a class="text-medium" href="/app/issue?customer=${issue.customer}">
-						${__('View all issues from {0}', [issue.customer])}
-					</a>
-				`);
-			}
-		});
-	}
-
-	get_caller_name() {
-		let log = this.call_log;
-		return log.contact_name || log.lead_name;
-	}
-
-	setup_listener() {
-		frappe.realtime.on(`call_${this.call_log.id}_disconnected`, call_log => {
-			this.call_disconnected(call_log);
-			// Remove call disconnect listener after the call is disconnected
-			frappe.realtime.off(`call_${this.call_log.id}_disconnected`);
-		});
+	create_new_contact() {
+		// TODO: fix new_doc, it should accept child table values
+		const new_contact = frappe.model.get_new_doc('Contact');
+		const phone_no = frappe.model.add_child(new_contact, 'Contact Phone', 'phone_nos');
+		phone_no.phone = this.caller_number;
+		phone_no.is_primary_mobile_no = 1;
+		frappe.set_route('Form', new_contact.doctype, new_contact.name);
 	}
 }
 
 $(document).on('app_ready', function () {
 	frappe.realtime.on('show_call_popup', call_log => {
-		if (!erpnext.call_popup) {
-			erpnext.call_popup = new CallPopup(call_log);
+		let call_popup = erpnext.call_popup;
+		if (call_popup && call_log.name === call_popup.call_log.name) {
+			call_popup.update_call_log(call_log);
+			call_popup.dialog.show();
 		} else {
-			erpnext.call_popup.update_call_log(call_log);
-			erpnext.call_popup.dialog.show();
+			erpnext.call_popup = new CallPopup(call_log);
 		}
 	});
 });
+
+window.CallPopup = CallPopup;
diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js
index a2a723d..c963866 100644
--- a/erpnext/public/js/controllers/buying.js
+++ b/erpnext/public/js/controllers/buying.js
@@ -191,7 +191,6 @@
 			item.rejected_qty = flt(item.received_qty - item.qty, precision("rejected_qty", item));
 			item.received_stock_qty = flt(item.conversion_factor, precision("conversion_factor", item)) * flt(item.received_qty);
 		}
-
 		this._super(doc, cdt, cdn);
 	},
 
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 22e7578..d81321b 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -2,9 +2,11 @@
 // License: GNU General Public License v3. See license.txt
 
 erpnext.taxes_and_totals = erpnext.payments.extend({
-	setup: function() {},
+	setup: function() {
+		this.fetch_round_off_accounts();
+	},
 
-	apply_pricing_rule_on_item: function(item){
+	apply_pricing_rule_on_item: function(item) {
 		let effective_item_rate = item.price_list_rate;
 		let item_rate = item.rate;
 		if (in_list(["Sales Order", "Quotation"], item.parenttype) && item.blanket_order_rate) {
@@ -26,6 +28,7 @@
 
 		if (item.discount_amount) {
 			item_rate = flt((item.rate_with_margin) - (item.discount_amount), precision('rate', item));
+			item.discount_percentage = 100 * flt(item.discount_amount) / flt(item.rate_with_margin);
 		}
 
 		frappe.model.set_value(item.doctype, item.name, "rate", item_rate);
@@ -151,6 +154,22 @@
 		});
 	},
 
+	fetch_round_off_accounts: function() {
+		let me = this;
+		frappe.flags.round_off_applicable_accounts = [];
+
+		return frappe.call({
+			"method": "erpnext.controllers.taxes_and_totals.get_round_off_applicable_accounts",
+			"args": {
+				"company": me.frm.doc.company,
+				"account_list": frappe.flags.round_off_applicable_accounts
+			},
+			callback: function(r) {
+				frappe.flags.round_off_applicable_accounts.push(...r.message);
+			}
+		});
+	},
+
 	determine_exclusive_rate: function() {
 		var me = this;
 
@@ -371,11 +390,21 @@
 		} else if (tax.charge_type == "On Item Quantity") {
 			current_tax_amount = tax_rate * item.qty;
 		}
+
+		current_tax_amount = this.get_final_tax_amount(tax, current_tax_amount);
 		this.set_item_wise_tax(item, tax, tax_rate, current_tax_amount);
 
 		return current_tax_amount;
 	},
 
+	get_final_tax_amount: function(tax, current_tax_amount) {
+		if (frappe.flags.round_off_applicable_accounts.includes(tax.account_head)) {
+			current_tax_amount = Math.round(current_tax_amount);
+		}
+
+		return current_tax_amount;
+	},
+
 	set_item_wise_tax: function(item, tax, tax_rate, current_tax_amount) {
 		// store tax breakup for each item
 		let tax_detail = tax.item_wise_tax_detail;
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 1db0f5f..e5f9049 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -40,7 +40,7 @@
 
 			cur_frm.cscript.set_gross_profit(item);
 			cur_frm.cscript.calculate_taxes_and_totals();
-
+			cur_frm.cscript.calculate_stock_uom_rate(frm, cdt, cdn);
 		});
 
 
@@ -1122,6 +1122,7 @@
 				}
 			});
 		}
+		me.calculate_stock_uom_rate(doc, cdt, cdn);
 	},
 
 	conversion_factor: function(doc, cdt, cdn, dont_fetch_price_list_rate) {
@@ -1142,6 +1143,7 @@
 				frappe.meta.has_field(doc.doctype, "price_list_currency")) {
 				this.apply_price_list(item, true);
 			}
+			this.calculate_stock_uom_rate(doc, cdt, cdn);
 		}
 	},
 
@@ -1162,9 +1164,15 @@
 	qty: function(doc, cdt, cdn) {
 		let item = frappe.get_doc(cdt, cdn);
 		this.conversion_factor(doc, cdt, cdn, true);
+		this.calculate_stock_uom_rate(doc, cdt, cdn);
 		this.apply_pricing_rule(item, true);
 	},
 
+	calculate_stock_uom_rate: function(doc, cdt, cdn) {
+		let item = frappe.get_doc(cdt, cdn);
+		item.stock_uom_rate = flt(item.rate)/flt(item.conversion_factor);	
+		refresh_field("stock_uom_rate", item.name, item.parentfield);
+	},
 	service_stop_date: function(frm, cdt, cdn) {
 		var child = locals[cdt][cdn];
 
@@ -1275,7 +1283,7 @@
 		this.frm.set_currency_labels(["base_rate", "base_net_rate", "base_price_list_rate", "base_amount", "base_net_amount"],
 			company_currency, "items");
 
-		this.frm.set_currency_labels(["rate", "net_rate", "price_list_rate", "amount", "net_amount"],
+		this.frm.set_currency_labels(["rate", "net_rate", "price_list_rate", "amount", "net_amount", "stock_uom_rate"],
 			this.frm.doc.currency, "items");
 
 		if(this.frm.fields_dict["operations"]) {
diff --git a/erpnext/public/js/telephony.js b/erpnext/public/js/telephony.js
index 6cb1207..b66126c 100644
--- a/erpnext/public/js/telephony.js
+++ b/erpnext/public/js/telephony.js
@@ -1,13 +1,16 @@
 frappe.ui.form.ControlData = frappe.ui.form.ControlData.extend( {
 	make_input() {
-		this._super();
+		if (!this.df.read_only) {
+			this._super();
+		}
 		if (this.df.options == 'Phone') {
 			this.setup_phone();
 		}
 	},
 	setup_phone() {
 		if (frappe.phone_call.handler) {
-			this.$wrapper.find('.control-input')
+			let control = this.df.read_only ? '.control-value' : '.control-input';
+			this.$wrapper.find(control)
 				.append(`
 					<span class="phone-btn">
 						<a class="btn-open no-decoration" title="${__('Make a call')}">
diff --git a/erpnext/public/js/templates/call_link.html b/erpnext/public/js/templates/call_link.html
index 08bdf14..071078c 100644
--- a/erpnext/public/js/templates/call_link.html
+++ b/erpnext/public/js/templates/call_link.html
@@ -1,32 +1,31 @@
 <div class="call-detail-wrapper">
-	<div class="left-arrow"></div>
-	<div class="head text-muted">
+	<div class="head flex justify-between">
+		<div>
+			<span class="bold"> {{ type }} Call</span>
+			{% if (duration) %}
+			<span class="text-muted"> • {{ frappe.format(duration, { fieldtype: "Duration" }) }}</span>
+			{% endif %}
+			<span class="text-muted"> • {{ comment_when(creation) }}</span>
+		</div>
 		<span>
-			<i class="fa fa-phone"> </i>
-		<span>
-		<span> {{ type }} Call</span>
-		-
-		<span> {{ frappe.format(duration, { fieldtype: "Duration" }) }}</span>
-		-
-		<span> {{ comment_when(creation) }}</span>
-		-
-		<!-- <span> {{ status }}</span>
-		- -->
-		<a class="text-muted" href="#Form/Call Log/{{name}}">Details</a>
-		{% if (show_call_button) { %}
-			<a class="pull-right">Callback</a>
-		{% } %}
+			<a class="action-btn" href="/app/call-log/{{ name }}" title="{{ __("Open Call Log") }}">
+				<svg class="icon icon-sm">
+					<use href="#icon-link-url" class="like-icon"></use>
+				</svg>
+			</a>
+		</span>
 	</div>
-	<div class="body padding">
+
+
+	<div class="body pt-3">
 		{% if (type === "Incoming") { %}
 			<span> Incoming call from {{ from }}, received by {{ to }}</span>
 		{% } else { %}
 			<span> Outgoing Call made by {{ from }} to {{ to }}</span>
 		{% } %}
-		<hr>
-		<div class="summary">
+		<div class="summary pt-3">
 		{% if (summary) { %}
-			<span>{{ summary }}</span>
+			<i>{{ summary }}</i>
 		{% } else { %}
 			<i class="text-muted">{{ __("No Summary") }}</i>
 		{% } %}
diff --git a/erpnext/public/js/utils/serial_no_batch_selector.js b/erpnext/public/js/utils/serial_no_batch_selector.js
index 2623c3c..d49a813 100644
--- a/erpnext/public/js/utils/serial_no_batch_selector.js
+++ b/erpnext/public/js/utils/serial_no_batch_selector.js
@@ -140,6 +140,7 @@
 					() => me.update_batch_serial_no_items(),
 					() => {
 						refresh_field("items");
+						refresh_field("packed_items");
 						if (me.callback) {
 							return me.callback(me.item);
 						}
@@ -154,7 +155,7 @@
 			if (this.item.serial_no) {
 				this.dialog.fields_dict.serial_no.set_value(this.item.serial_no);
 			}
-			
+
 			if (this.has_batch && !this.has_serial_no && d.batch_no) {
 				this.frm.doc.items.forEach(data => {
 					if(data.item_code == d.item_code) {
@@ -231,7 +232,7 @@
 				this.map_row_values(row, batch, 'batch_no',
 					'selected_qty', this.values.warehouse);
 			});
-		} 
+		}
 	},
 
 	update_serial_no_item() {
@@ -250,7 +251,7 @@
 				filters: { 'name': ["in", selected_serial_nos]},
 				fields: ["batch_no", "name"]
 			}).then((data) => {
-				// data = [{batch_no: 'batch-1', name: "SR-001"}, 
+				// data = [{batch_no: 'batch-1', name: "SR-001"},
 				// 	{batch_no: 'batch-2', name: "SR-003"}, {batch_no: 'batch-2', name: "SR-004"}]
 				const batch_serial_map = data.reduce((acc, d) => {
 					if (!acc[d['batch_no']]) acc[d['batch_no']] = [];
@@ -298,6 +299,8 @@
 		} else {
 			row.warehouse = values.warehouse || warehouse;
 		}
+
+		this.frm.dirty();
 	},
 
 	update_total_qty: function() {
diff --git a/erpnext/public/less/call_popup.less b/erpnext/public/less/call_popup.less
deleted file mode 100644
index 32e85ce..0000000
--- a/erpnext/public/less/call_popup.less
+++ /dev/null
@@ -1,9 +0,0 @@
-.call-popup {
-	a:hover {
-		text-decoration: underline;
-	}
-	.for-description {
-		max-height: 250px;
-		overflow: scroll;
-	}
-}
\ No newline at end of file
diff --git a/erpnext/public/less/hub.less b/erpnext/public/less/hub.less
index 8cb7a9c..29deada 100644
--- a/erpnext/public/less/hub.less
+++ b/erpnext/public/less/hub.less
@@ -32,7 +32,12 @@
 	}
 
 	.hub-image-loading, .hub-image-broken {
-		.img-background();
+		content: " ";
+		position: absolute;
+		left: 0;
+		height: 100%;
+		width: 100%;
+		background-color: var(--bg-light-gray);
 		display: flex;
 		align-items: center;
 		justify-content: center;
diff --git a/erpnext/public/scss/call_popup.scss b/erpnext/public/scss/call_popup.scss
new file mode 100644
index 0000000..95e3182
--- /dev/null
+++ b/erpnext/public/scss/call_popup.scss
@@ -0,0 +1,21 @@
+.call-popup {
+	a:hover {
+		text-decoration: underline;
+	}
+	.for-description {
+		max-height: 250px;
+		overflow: scroll;
+	}
+}
+
+audio {
+	height: 40px;
+	width: 100%;
+	max-width: 500px;
+	background-color: var(--control-bg);
+	border-radius: var(--border-radius-sm);
+	&-webkit-media-controls-panel {
+		background: var(--control-bg);
+	}
+	outline: none;
+}
diff --git a/erpnext/regional/doctype/gst_settings/gst_settings.json b/erpnext/regional/doctype/gst_settings/gst_settings.json
index 98c33ad..95b930c 100644
--- a/erpnext/regional/doctype/gst_settings/gst_settings.json
+++ b/erpnext/regional/doctype/gst_settings/gst_settings.json
@@ -1,222 +1,86 @@
 {
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "beta": 0, 
- "creation": "2017-06-27 15:09:01.318003", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 1, 
- "engine": "InnoDB", 
+ "actions": [],
+ "creation": "2017-06-27 15:09:01.318003",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "gst_summary",
+  "column_break_2",
+  "round_off_gst_values",
+  "gstin_email_sent_on",
+  "section_break_4",
+  "gst_accounts",
+  "b2c_limit"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "gst_summary", 
-   "fieldtype": "HTML", 
-   "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": "GST Summary", 
-   "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
-  }, 
+   "fieldname": "gst_summary",
+   "fieldtype": "HTML",
+   "label": "GST Summary",
+   "show_days": 1,
+   "show_seconds": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break_2", 
-   "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
-  }, 
+   "fieldname": "column_break_2",
+   "fieldtype": "Column Break",
+   "show_days": 1,
+   "show_seconds": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "gstin_email_sent_on", 
-   "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": "GSTIN Email Sent On", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "gstin_email_sent_on",
+   "fieldtype": "Date",
+   "label": "GSTIN Email Sent On",
+   "read_only": 1,
+   "show_days": 1,
+   "show_seconds": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "section_break_4", 
-   "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
-  }, 
+   "fieldname": "section_break_4",
+   "fieldtype": "Section Break",
+   "show_days": 1,
+   "show_seconds": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "gst_accounts", 
-   "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": "GST Accounts", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "GST Account", 
-   "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
-  }, 
+   "fieldname": "gst_accounts",
+   "fieldtype": "Table",
+   "label": "GST Accounts",
+   "options": "GST Account",
+   "show_days": 1,
+   "show_seconds": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "default": "250000", 
-   "description": "Set Invoice Value for B2C. B2CL and B2CS calculated based on this invoice value.", 
-   "fieldname": "b2c_limit", 
-   "fieldtype": "Data", 
-   "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": "B2C Limit", 
-   "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": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
+   "default": "250000",
+   "description": "Set Invoice Value for B2C. B2CL and B2CS calculated based on this invoice value.",
+   "fieldname": "b2c_limit",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "B2C Limit",
+   "reqd": 1,
+   "show_days": 1,
+   "show_seconds": 1
+  },
+  {
+   "default": "0",
+   "description": "Enabling this option will round off individual GST components in all the Invoices",
+   "fieldname": "round_off_gst_values",
+   "fieldtype": "Check",
+   "label": "Round Off GST Values",
+   "show_days": 1,
+   "show_seconds": 1
   }
- ], 
- "has_web_view": 0, 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "idx": 0, 
- "image_view": 0, 
- "in_create": 0, 
- "is_submittable": 0, 
- "issingle": 1, 
- "istable": 0, 
- "max_attachments": 0, 
- "modified": "2018-02-14 08:14:15.375181", 
- "modified_by": "Administrator", 
- "module": "Regional", 
- "name": "GST Settings", 
- "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
+ ],
+ "index_web_pages_for_search": 1,
+ "issingle": 1,
+ "links": [],
+ "modified": "2021-01-28 17:19:47.969260",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "GST Settings",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+   }
\ No newline at end of file
diff --git a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py
index 8174da2..023b4ed 100644
--- a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py
+++ b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py
@@ -14,8 +14,20 @@
 test_dependencies = ["Territory", "Customer Group", "Supplier Group", "Item"]
 
 class TestGSTR3BReport(unittest.TestCase):
-	def test_gstr_3b_report(self):
+	def setUp(self):
+		frappe.set_user("Administrator")
 
+		frappe.db.sql("delete from `tabSales Invoice` where company='_Test Company GST'")
+		frappe.db.sql("delete from `tabPurchase Invoice` where company='_Test Company GST'")
+		frappe.db.sql("delete from `tabGSTR 3B Report` where company='_Test Company GST'")
+
+		make_company()
+		make_item("Milk", properties = {"is_nil_exempt": 1, "standard_rate": 0.000000})
+		set_account_heads()
+		make_customers()
+		make_suppliers()
+
+	def test_gstr_3b_report(self):
 		month_number_mapping = {
 			1: "January",
 			2: "February",
@@ -31,17 +43,6 @@
 			12: "December"
 		}
 
-		frappe.set_user("Administrator")
-
-		frappe.db.sql("delete from `tabSales Invoice` where company='_Test Company GST'")
-		frappe.db.sql("delete from `tabPurchase Invoice` where company='_Test Company GST'")
-		frappe.db.sql("delete from `tabGSTR 3B Report` where company='_Test Company GST'")
-
-		make_company()
-		make_item("Milk", properties = {"is_nil_exempt": 1, "standard_rate": 0.000000})
-		set_account_heads()
-		make_customers()
-		make_suppliers()
 		make_sales_invoice()
 		create_purchase_invoices()
 
@@ -67,6 +68,42 @@
 		self.assertEqual(output["itc_elg"]["itc_avl"][4]["samt"], 22.50)
 		self.assertEqual(output["itc_elg"]["itc_avl"][4]["camt"], 22.50)
 
+	def test_gst_rounding(self):
+		gst_settings = frappe.get_doc('GST Settings')
+		gst_settings.round_off_gst_values = 1
+		gst_settings.save()
+
+		current_country = frappe.flags.country
+		frappe.flags.country = 'India'
+
+		si = create_sales_invoice(company="_Test Company GST",
+			customer = '_Test GST Customer',
+			currency = 'INR',
+			warehouse = 'Finished Goods - _GST',
+			debit_to = 'Debtors - _GST',
+			income_account = 'Sales - _GST',
+			expense_account = 'Cost of Goods Sold - _GST',
+			cost_center = 'Main - _GST',
+			rate=216,
+			do_not_save=1
+		)
+
+		si.append("taxes", {
+			"charge_type": "On Net Total",
+			"account_head": "IGST - _GST",
+			"cost_center": "Main - _GST",
+			"description": "IGST @ 18.0",
+			"rate": 18
+		})
+
+		si.save()
+		# Check for 39 instead of 38.88
+		self.assertEqual(si.taxes[0].base_tax_amount_after_discount_amount, 39)
+
+		frappe.flags.country = current_country
+		gst_settings.round_off_gst_values = 1
+		gst_settings.save()
+
 def make_sales_invoice():
 	si = create_sales_invoice(company="_Test Company GST",
 			customer = '_Test GST Customer',
@@ -145,7 +182,6 @@
 	si3.submit()
 
 def create_purchase_invoices():
-
 	pi = make_purchase_invoice(
 			company="_Test Company GST",
 			supplier = '_Test Registered Supplier',
@@ -193,7 +229,6 @@
 	pi1.submit()
 
 def make_suppliers():
-
 	if not frappe.db.exists("Supplier", "_Test Registered Supplier"):
 		frappe.get_doc({
 			"supplier_group": "_Test Supplier Group",
@@ -257,7 +292,6 @@
 		address.save()
 
 def make_customers():
-
 	if not frappe.db.exists("Customer", "_Test GST Customer"):
 		frappe.get_doc({
 			"customer_group": "_Test Customer Group",
@@ -354,9 +388,9 @@
 		address.save()
 
 def make_company():
-
 	if frappe.db.exists("Company", "_Test Company GST"):
 		return
+
 	company = frappe.new_doc("Company")
 	company.company_name = "_Test Company GST"
 	company.abbr = "_GST"
@@ -388,7 +422,6 @@
 		address.save()
 
 def set_account_heads():
-
 	gst_settings = frappe.get_doc("GST Settings")
 
 	gst_account = frappe.get_all(
diff --git a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
index e8a8ed8..ad60db0 100644
--- a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
+++ b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
@@ -5,12 +5,16 @@
 from __future__ import unicode_literals
 import frappe
 from frappe import _
-from frappe.utils import getdate
+from frappe.utils import getdate, get_link_to_form
 from frappe.model.document import Document
 from erpnext.accounts.utils import get_fiscal_year
 
 class LowerDeductionCertificate(Document):
 	def validate(self):
+		self.validate_dates()
+		self.validate_supplier_against_section_code()
+		
+	def validate_dates(self):
 		if getdate(self.valid_upto) < getdate(self.valid_from):
 			frappe.throw(_("Valid Upto date cannot be before Valid From date"))
 
@@ -24,3 +28,20 @@
 			<= fiscal_year.year_end_date):
 			frappe.throw(_("Valid Upto date not in Fiscal Year {0}").format(frappe.bold(self.fiscal_year)))
 
+	def validate_supplier_against_section_code(self):
+		duplicate_certificate = frappe.db.get_value('Lower Deduction Certificate', {'supplier': self.supplier, 'section_code': self.section_code}, ['name', 'valid_from', 'valid_upto'], as_dict=True)
+		if duplicate_certificate and self.are_dates_overlapping(duplicate_certificate):
+			certificate_link = get_link_to_form('Lower Deduction Certificate', duplicate_certificate.name)
+			frappe.throw(_("There is already a valid Lower Deduction Certificate {0} for Supplier {1} against Section Code {2} for this time period.")
+				.format(certificate_link, frappe.bold(self.supplier), frappe.bold(self.section_code)))
+
+	def are_dates_overlapping(self,duplicate_certificate):
+		valid_from = duplicate_certificate.valid_from
+		valid_upto = duplicate_certificate.valid_upto
+		if valid_from <= getdate(self.valid_from) <= valid_upto:
+			return True
+		elif valid_from <= getdate(self.valid_upto) <= valid_upto:
+			return True
+		elif getdate(self.valid_from) <= valid_from and valid_upto <= getdate(self.valid_upto):
+			return True
+		return False
\ No newline at end of file
diff --git a/erpnext/regional/india/__init__.py b/erpnext/regional/india/__init__.py
index d6221a8..378b735 100644
--- a/erpnext/regional/india/__init__.py
+++ b/erpnext/regional/india/__init__.py
@@ -20,6 +20,7 @@
  'Jharkhand',
  'Karnataka',
  'Kerala',
+ 'Ladakh',
  'Lakshadweep Islands',
  'Madhya Pradesh',
  'Maharashtra',
@@ -59,6 +60,7 @@
  "Jharkhand": "20",
  "Karnataka": "29",
  "Kerala": "32",
+ "Ladakh": "38",
  "Lakshadweep Islands": "31",
  "Madhya Pradesh": "23",
  "Maharashtra": "27",
@@ -80,4 +82,4 @@
  "West Bengal": "19",
 }
 
-number_state_mapping = {v: k for k, v in iteritems(state_numbers)}
\ No newline at end of file
+number_state_mapping = {v: k for k, v in iteritems(state_numbers)}
diff --git a/erpnext/regional/india/e_invoice/einvoice.js b/erpnext/regional/india/e_invoice/einvoice.js
index 9fa94c4..a756b57 100644
--- a/erpnext/regional/india/e_invoice/einvoice.js
+++ b/erpnext/regional/india/e_invoice/einvoice.js
@@ -188,7 +188,6 @@
 			'fieldname': 'vehicle_no',
 			'label': 'Vehicle No',
 			'fieldtype': 'Data',
-			'depends_on': 'eval:(doc.mode_of_transport === "Road")',
 			'default': frm.doc.vehicle_no
 		},
 		{
diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
index c8e7e14..322fa18 100644
--- a/erpnext/regional/india/e_invoice/utils.py
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -20,11 +20,13 @@
 
 def validate_einvoice_fields(doc):
 	einvoicing_enabled = cint(frappe.db.get_value('E Invoice Settings', 'E Invoice Settings', 'enable'))
-	invalid_doctype = doc.doctype not in ['Sales Invoice']
+	invalid_doctype = doc.doctype != 'Sales Invoice'
 	invalid_supply_type = doc.get('gst_category') not in ['Registered Regular', 'SEZ', 'Overseas', 'Deemed Export']
 	company_transaction = doc.get('billing_address_gstin') == doc.get('company_gstin')
+	no_taxes_applied = not doc.get('taxes')
 
-	if not einvoicing_enabled or invalid_doctype or invalid_supply_type or company_transaction: return
+	if not einvoicing_enabled or invalid_doctype or invalid_supply_type or company_transaction or no_taxes_applied:
+		return
 
 	if doc.docstatus == 0 and doc._action == 'save':
 		if doc.irn:
@@ -35,7 +37,7 @@
 	elif doc.docstatus == 1 and doc._action == 'submit' and not doc.irn:
 		frappe.throw(_('You must generate IRN before submitting the document.'), title=_('Missing IRN'))
 
-	elif doc.docstatus == 2 and doc._action == 'cancel' and not doc.irn_cancelled:
+	elif doc.irn and doc.docstatus == 2 and doc._action == 'cancel' and not doc.irn_cancelled:
 		frappe.throw(_('You must cancel IRN before cancelling the document.'), title=_('Cancel Not Allowed'))
 
 def raise_document_name_too_long_error():
@@ -61,7 +63,7 @@
 	elif invoice.gst_category == 'Overseas': supply_type = 'EXPWOP'
 	elif invoice.gst_category == 'Deemed Export': supply_type = 'DEXP'
 
-	if not supply_type: 
+	if not supply_type:
 		rr, sez, overseas, export = bold('Registered Regular'), bold('SEZ'), bold('Overseas'), bold('Deemed Export')
 		frappe.throw(_('GST category should be one of {}, {}, {}, {}').format(rr, sez, overseas, export),
 			title=_('Invalid Supply Type'))
@@ -126,7 +128,7 @@
 	if details:
 		frappe.local.gstin_cache[key] = details
 		return details
-	
+
 	if not details:
 		return GSPConnector.get_gstin_details(gstin)
 
@@ -158,7 +160,7 @@
 		item.update(d.as_dict())
 
 		item.sr_no = d.idx
-		item.description = d.item_name.replace('"', '\\"')
+		item.description = json.dumps(d.item_name)[1:-1]
 
 		item.qty = abs(item.qty)
 		item.discount_amount = 0
@@ -172,7 +174,7 @@
 		item.serial_no = ""
 
 		item = update_item_taxes(invoice, item)
-		
+
 		item.total_value = abs(
 			item.taxable_value + item.igst_amount + item.sgst_amount +
 			item.cgst_amount + item.cess_amount + item.cess_nadv_amount + item.other_charges
@@ -230,9 +232,9 @@
 	invoice_value_details.round_off = invoice.base_rounding_adjustment
 	invoice_value_details.base_grand_total = abs(invoice.base_rounded_total) or abs(invoice.base_grand_total)
 	invoice_value_details.grand_total = abs(invoice.rounded_total) or abs(invoice.grand_total)
-	
+
 	invoice_value_details = update_invoice_taxes(invoice, invoice_value_details)
-	
+
 	return invoice_value_details
 
 def update_invoice_taxes(invoice, invoice_value_details):
@@ -249,13 +251,13 @@
 			if t.account_head in gst_accounts.cess_account:
 				# using after discount amt since item also uses after discount amt for cess calc
 				invoice_value_details.total_cess_amt += abs(t.base_tax_amount_after_discount_amount)
-			
+
 			for tax_type in ['igst', 'cgst', 'sgst']:
 				if t.account_head in gst_accounts[f'{tax_type}_account']:
 					invoice_value_details[f'total_{tax_type}_amt'] += abs(t.base_tax_amount_after_discount_amount)
 		else:
 			invoice_value_details.total_other_charges += abs(t.base_tax_amount_after_discount_amount)
-	
+
 	return invoice_value_details
 
 def get_payment_details(invoice):
@@ -303,7 +305,7 @@
 			_('GSTIN is mandatory to fetch company GSTIN details. Please enter GSTIN in selected company address.'),
 			title=_('Missing Fields')
 		)
-	if not frappe.db.get_value('Address', invoice.customer_address, 'gstin'):
+	if invoice.gst_category != 'Overseas' and not frappe.db.get_value('Address', invoice.customer_address, 'gstin'):
 		frappe.throw(
 			_('GSTIN is mandatory to fetch customer GSTIN details. Please enter GSTIN in selected customer address.'),
 			title=_('Missing Fields')
@@ -327,23 +329,23 @@
 		place_of_supply = get_place_of_supply(invoice, invoice.doctype) or invoice.billing_address_gstin
 		place_of_supply = place_of_supply[:2]
 		buyer_details.update(dict(place_of_supply=place_of_supply))
-	
+
 	shipping_details = payment_details = prev_doc_details = eway_bill_details = frappe._dict({})
 	if invoice.shipping_address_name and invoice.customer_address != invoice.shipping_address_name:
 		if invoice.gst_category == 'Overseas':
 			shipping_details = get_overseas_address_details(invoice.shipping_address_name)
 		else:
 			shipping_details = get_party_details(invoice.shipping_address_name)
-	
+
 	if invoice.is_pos and invoice.base_paid_amount:
 		payment_details = get_payment_details(invoice)
-	
+
 	if invoice.is_return and invoice.return_against:
 		prev_doc_details = get_return_doc_reference(invoice)
-	
+
 	if invoice.transporter:
 		eway_bill_details = get_eway_bill_details(invoice)
-	
+
 	# not yet implemented
 	dispatch_details = period_details = export_details = frappe._dict({})
 
@@ -355,7 +357,7 @@
 		export_details=export_details, eway_bill_details=eway_bill_details
 	)
 	einvoice = json.loads(einvoice)
-	
+
 	validations = json.loads(read_json('einv_validation'))
 	errors = validate_einvoice(validations, einvoice)
 	if errors:
@@ -417,7 +419,7 @@
 			errors.append(_('{} {} should be between {} and {}').format(label, value, minimum, maximum))
 		if pattern_str and not pattern.match(value):
 			errors.append(field_validation.get('validationMsg'))
-	
+
 	return errors
 
 class RequestFailed(Exception): pass
@@ -444,23 +446,25 @@
 	def get_credentials(self):
 		if self.invoice:
 			gstin = self.get_seller_gstin()
+			if not self.e_invoice_settings.enable:
+				frappe.throw(_("E-Invoicing is disabled. Please enable it from {} to generate e-invoices.").format(get_link_to_form("E Invoice Settings", "E Invoice Settings")))
 			credentials = next(d for d in self.e_invoice_settings.credentials if d.gstin == gstin)
 		else:
 			credentials = self.e_invoice_settings.credentials[0] if self.e_invoice_settings.credentials else None
 		return credentials
-	
+
 	def get_seller_gstin(self):
 		gstin = self.invoice.company_gstin or frappe.db.get_value('Address', self.invoice.company_address, 'gstin')
 		if not gstin:
 			frappe.throw(_('Cannot retrieve Company GSTIN. Please select company address with valid GSTIN.'))
 		return gstin
-	
+
 	def get_auth_token(self):
 		if time_diff_in_seconds(self.e_invoice_settings.token_expiry, now_datetime()) < 150.0:
 			self.fetch_auth_token()
-		
+
 		return self.e_invoice_settings.auth_token
-	
+
 	def make_request(self, request_type, url, headers=None, data=None):
 		if request_type == 'post':
 			res = make_post_request(url, headers=headers, data=data)
@@ -469,7 +473,7 @@
 
 		self.log_request(url, headers, data, res)
 		return res
-	
+
 	def log_request(self, url, headers, data, res):
 		headers.update({ 'password': self.credentials.password })
 		request_log = frappe.get_doc({
@@ -500,7 +504,7 @@
 		except Exception:
 			self.log_error(res)
 			self.raise_error(True)
-	
+
 	def get_headers(self):
 		return {
 			'content-type': 'application/json',
@@ -522,7 +526,7 @@
 			else:
 				self.log_error(res)
 				raise RequestFailed
-		
+
 		except RequestFailed:
 			self.raise_error()
 
@@ -567,7 +571,7 @@
 
 			else:
 				raise RequestFailed
-		
+
 		except RequestFailed:
 			errors = self.sanitize_error_message(res.get('message'))
 			self.raise_error(errors=errors)
@@ -575,7 +579,7 @@
 		except Exception:
 			self.log_error(data)
 			self.raise_error(True)
-	
+
 	def get_irn_details(self, irn):
 		headers = self.get_headers()
 
@@ -586,7 +590,7 @@
 				return res.get('result')
 			else:
 				raise RequestFailed
-		
+
 		except RequestFailed:
 			errors = self.sanitize_error_message(res.get('message'))
 			self.raise_error(errors=errors)
@@ -594,7 +598,7 @@
 		except Exception:
 			self.log_error()
 			self.raise_error(True)
-	
+
 	def cancel_irn(self, irn, reason, remark):
 		headers = self.get_headers()
 		data = json.dumps({
@@ -616,7 +620,7 @@
 
 			else:
 				raise RequestFailed
-		
+
 		except RequestFailed:
 			errors = self.sanitize_error_message(res.get('message'))
 			self.raise_error(errors=errors)
@@ -665,7 +669,7 @@
 		except Exception:
 			self.log_error(data)
 			self.raise_error(True)
-	
+
 	def cancel_eway_bill(self, eway_bill, reason, remark):
 		headers = self.get_headers()
 		data = json.dumps({
@@ -697,7 +701,7 @@
 		except Exception:
 			self.log_error(data)
 			self.raise_error(True)
-	
+
 	def sanitize_error_message(self, message):
 		'''
 			On validation errors, response message looks something like this:
@@ -736,7 +740,7 @@
 			"Exception:", err_tb
 		])
 		frappe.log_error(title=_('E Invoice Request Failed'), message=message)
-	
+
 	def raise_error(self, raise_exception=False, errors=[]):
 		title = _('E Invoice Request Failed')
 		if errors:
@@ -749,7 +753,7 @@
 				raise_exception=raise_exception,
 				indicator='red'
 			)
-	
+
 	def set_einvoice_data(self, res):
 		enc_signed_invoice = res.get('SignedInvoice')
 		dec_signed_invoice = jwt.decode(enc_signed_invoice, verify=False)['data']
@@ -788,7 +792,7 @@
 		_file.save()
 		frappe.db.commit()
 		self.invoice.qrcode_image = _file.file_url
-	
+
 	def update_invoice(self):
 		self.invoice.flags.ignore_validate_update_after_submit = True
 		self.invoice.flags.ignore_validate = True
@@ -817,4 +821,4 @@
 @frappe.whitelist()
 def cancel_eway_bill(doctype, docname, eway_bill, reason, remark):
 	gsp_connector = GSPConnector(doctype, docname)
-	gsp_connector.cancel_eway_bill(eway_bill, reason, remark)
\ No newline at end of file
+	gsp_connector.cancel_eway_bill(eway_bill, reason, remark)
diff --git a/erpnext/regional/india/gst_state_code_data.json b/erpnext/regional/india/gst_state_code_data.json
index ff88e0f..8481c27 100644
--- a/erpnext/regional/india/gst_state_code_data.json
+++ b/erpnext/regional/india/gst_state_code_data.json
@@ -168,5 +168,10 @@
   "state_number": "37",
   "state_code": "AD",
   "state_name": "Andhra Pradesh (New)"
+ },
+ {
+  "state_number": "38",
+  "state_code": "LA",
+  "state_name": "Ladakh"
  }
 ]
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index e89885f..cb30605 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -55,6 +55,14 @@
 			frappe.throw(_("Invalid GSTIN! First 2 digits of GSTIN should match with State number {0}.")
 				.format(doc.gst_state_number))
 
+def validate_pan_for_india(doc, method):
+	if doc.get('country') != 'India' or not doc.pan:
+		return
+
+	p = re.compile("[A-Z]{5}[0-9]{4}[A-Z]{1}")
+	if not p.match(doc.pan):
+		frappe.throw(_("Invalid PAN No. The input you've entered doesn't match the format of PAN."))
+
 def validate_tax_category(doc, method):
 	if doc.get('gst_state') and frappe.db.get_value('Tax Category', {'gst_state': doc.gst_state, 'is_inter_state': doc.is_inter_state}):
 		if doc.is_inter_state:
@@ -772,3 +780,24 @@
 				)
 
 	return gl_entries
+
+@frappe.whitelist()
+def get_regional_round_off_accounts(company, account_list):
+	country = frappe.get_cached_value('Company', company, 'country')
+
+	if country != 'India':
+		return
+
+	if isinstance(account_list, string_types):
+		account_list = json.loads(account_list)
+
+	if not frappe.db.get_single_value('GST Settings', 'round_off_gst_values'):
+		return
+
+	gst_accounts = get_gst_accounts(company)
+	gst_account_list = gst_accounts.get('cgst_account') + gst_accounts.get('sgst_account') \
+		+ gst_accounts.get('igst_account')
+
+	account_list.extend(gst_account_list)
+
+	return account_list
\ No newline at end of file
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
index 96dc3f7..09b04ff 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.py
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -236,6 +236,7 @@
 		self.cgst_sgst_invoices = []
 
 		unidentified_gst_accounts = []
+		unidentified_gst_accounts_invoice = []
 		for parent, account, item_wise_tax_detail, tax_amount in self.tax_details:
 			if account in self.gst_accounts.cess_account:
 				self.invoice_cess.setdefault(parent, tax_amount)
@@ -251,6 +252,7 @@
 						if not (cgst_or_sgst or account in self.gst_accounts.igst_account):
 							if "gst" in account.lower() and account not in unidentified_gst_accounts:
 								unidentified_gst_accounts.append(account)
+								unidentified_gst_accounts_invoice.append(parent)
 							continue
 
 						for item_code, tax_amounts in item_wise_tax_detail.items():
@@ -273,7 +275,7 @@
 
 		# Build itemised tax for export invoices where tax table is blank
 		for invoice, items in iteritems(self.invoice_items):
-			if invoice not in self.items_based_on_tax_rate \
+			if invoice not in self.items_based_on_tax_rate and invoice not in unidentified_gst_accounts_invoice \
 				and frappe.db.get_value(self.doctype, invoice, "export_type") == "Without Payment of Tax":
 					self.items_based_on_tax_rate.setdefault(invoice, {}).setdefault(0, items.keys())
 
diff --git a/erpnext/regional/report/irs_1099/irs_1099.py b/erpnext/regional/report/irs_1099/irs_1099.py
index c1c8aed..4e57ff7 100644
--- a/erpnext/regional/report/irs_1099/irs_1099.py
+++ b/erpnext/regional/report/irs_1099/irs_1099.py
@@ -32,6 +32,10 @@
 
 	data = []
 	columns = get_columns()
+	conditions = ""
+	if filters.supplier_group:
+		conditions += "AND s.supplier_group = %s" %frappe.db.escape(filters.get("supplier_group"))
+
 	data = frappe.db.sql("""
 		SELECT
 			s.supplier_group as "supplier_group",
@@ -46,15 +50,17 @@
 				AND s.irs_1099 = 1
 				AND gl.fiscal_year = %(fiscal_year)s
 				AND gl.party_type = "Supplier"
+				AND gl.company = %(company)s
+				{conditions}
+			
 		GROUP BY
 			gl.party
+
 		ORDER BY
-			gl.party DESC
-	""", {
-		"fiscal_year": filters.fiscal_year,
-		"supplier_group": filters.supplier_group,
-		"company": filters.company
-	}, as_dict=True)
+			gl.party DESC""".format(conditions=conditions), {
+				"fiscal_year": filters.fiscal_year,
+				"company": filters.company
+			}, as_dict=True)
 
 	return columns, data
 
@@ -79,13 +85,13 @@
 			"fieldname": "tax_id",
 			"label": _("Tax ID"),
 			"fieldtype": "Data",
-			"width": 120
+			"width": 200
 		},
 		{
 			"fieldname": "payments",
 			"label": _("Total Payments"),
 			"fieldtype": "Currency",
-			"width": 120
+			"width": 200
 		}
 	]
 
diff --git a/erpnext/selling/doctype/customer/customer.json b/erpnext/selling/doctype/customer/customer.json
index 557c715..3c0652eb 100644
--- a/erpnext/selling/doctype/customer/customer.json
+++ b/erpnext/selling/doctype/customer/customer.json
@@ -34,9 +34,8 @@
   "companies",
   "currency_and_price_list",
   "default_currency",
-  "default_price_list",
   "column_break_14",
-  "language",
+  "default_price_list",
   "address_contacts",
   "address_html",
   "website",
@@ -59,6 +58,7 @@
   "column_break_45",
   "market_segment",
   "industry",
+  "language",
   "is_frozen",
   "column_break_38",
   "loyalty_program",
@@ -485,7 +485,7 @@
  "idx": 363,
  "image_field": "image",
  "links": [],
- "modified": "2020-03-17 11:03:42.706907",
+ "modified": "2021-01-06 19:35:25.418017",
  "modified_by": "Administrator",
  "module": "Selling",
  "name": "Customer",
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index bf8b7fc..c452594 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -126,7 +126,9 @@
 		'''If Customer created from Lead, update lead status to "Converted"
 		update Customer link in Quotation, Opportunity'''
 		if self.lead_name:
-			frappe.db.set_value('Lead', self.lead_name, 'status', 'Converted', update_modified=False)
+			lead = frappe.get_doc('Lead', self.lead_name)
+			lead.status = 'Converted'
+			lead.save()
 
 	def create_lead_address_contact(self):
 		if self.lead_name:
diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.json b/erpnext/selling/doctype/quotation_item/quotation_item.json
index 59ae7b2..a6785f7 100644
--- a/erpnext/selling/doctype/quotation_item/quotation_item.json
+++ b/erpnext/selling/doctype/quotation_item/quotation_item.json
@@ -47,6 +47,7 @@
   "base_amount",
   "base_net_amount",
   "pricing_rules",
+  "stock_uom_rate",
   "is_free_item",
   "section_break_43",
   "valuation_rate",
@@ -634,12 +635,20 @@
    "print_hide": 1,
    "read_only": 1,
    "report_hide": 1
+  },
+  {
+   "depends_on": "eval: doc.uom != doc.stock_uom",
+   "fieldname": "stock_uom_rate",
+   "fieldtype": "Currency",
+   "label": "Rate of Stock UOM",
+   "options": "currency",
+   "read_only": 1
   }
  ],
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-05-19 20:48:43.222229",
+ "modified": "2021-01-30 21:39:40.174551",
  "modified_by": "Administrator",
  "module": "Selling",
  "name": "Quotation Item",
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index e492377..e3b41e6 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -514,7 +514,7 @@
 	make_delivery_note: function() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.selling.doctype.sales_order.sales_order.make_delivery_note",
-			frm: me.frm
+			frm: this.frm
 		})
 	},
 
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 1516dd6..e561291 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -180,6 +180,7 @@
 			update_coupon_code_count(self.coupon_code,'used')
 
 	def on_cancel(self):
+		self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
 		super(SalesOrder, self).on_cancel()
 
 		# Cannot cancel closed SO
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index e259367..52a0174 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -17,6 +17,18 @@
 from erpnext.stock.doctype.item.test_item import make_item
 
 class TestSalesOrder(unittest.TestCase):
+
+	@classmethod
+	def setUpClass(cls):
+		cls.unlink_setting = int(frappe.db.get_value("Accounts Settings", "Accounts Settings",
+			"unlink_advance_payment_on_cancelation_of_order"))
+
+	@classmethod
+	def tearDownClass(cls) -> None:
+		# reset config to previous state
+		frappe.db.set_value("Accounts Settings", "Accounts Settings",
+			"unlink_advance_payment_on_cancelation_of_order", cls.unlink_setting)
+
 	def tearDown(self):
 		frappe.set_user("Administrator")
 
@@ -325,6 +337,9 @@
 		create_dn_against_so(so.name, 4)
 		make_sales_invoice(so.name)
 
+		prev_total = so.get("base_total")
+		prev_total_in_words = so.get("base_in_words")
+
 		first_item_of_so = so.get("items")[0]
 		trans_item = json.dumps([
 			{'item_code' : first_item_of_so.item_code, 'rate' : first_item_of_so.rate, \
@@ -340,6 +355,12 @@
 		self.assertEqual(so.get("items")[-1].amount, 1400)
 		self.assertEqual(so.status, 'To Deliver and Bill')
 
+		updated_total = so.get("base_total")
+		updated_total_in_words = so.get("base_in_words")
+
+		self.assertEqual(updated_total, prev_total+1400)
+		self.assertNotEqual(updated_total_in_words, prev_total_in_words)
+
 	def test_update_child_removing_item(self):
 		so = make_sales_order(**{
 			"item_list": [{
@@ -1040,6 +1061,38 @@
 
 		self.assertRaises(frappe.LinkExistsError, so_doc.cancel)
 
+	def test_cancel_sales_order_after_cancel_payment_entry(self):
+		from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
+		# make a sales order
+		so = make_sales_order()
+
+		# disable unlinking of payment entry
+		frappe.db.set_value("Accounts Settings", "Accounts Settings",
+			"unlink_advance_payment_on_cancelation_of_order", 0)
+
+		# create a payment entry against sales order
+		pe = get_payment_entry("Sales Order", so.name, bank_account="_Test Bank - _TC")
+		pe.reference_no = "1"
+		pe.reference_date = nowdate()
+		pe.paid_from_account_currency = so.currency
+		pe.paid_to_account_currency = so.currency
+		pe.source_exchange_rate = 1
+		pe.target_exchange_rate = 1
+		pe.paid_amount = so.grand_total
+		pe.save(ignore_permissions=True)
+		pe.submit()
+
+		# Cancel payment entry
+		po_doc = frappe.get_doc("Payment Entry", pe.name)
+		po_doc.cancel()
+
+		# Cancel sales order
+		try:
+			so_doc = frappe.get_doc('Sales Order', so.name)
+			so_doc.cancel()
+		except Exception:
+			self.fail("Can not cancel sales order with linked cancelled payment entry")
+
 	def test_request_for_raw_materials(self):
 		item = make_item("_Test Finished Item", {"is_stock_item": 1,
 			"maintain_stock": 1,
@@ -1198,4 +1251,4 @@
 	))
 	workflow.insert(ignore_permissions=True)
 
-	return workflow
\ No newline at end of file
+	return workflow
diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
index 159655b..37e47a9 100644
--- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json
+++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
@@ -46,6 +46,7 @@
   "base_rate",
   "base_amount",
   "pricing_rules",
+  "stock_uom_rate",
   "is_free_item",
   "section_break_24",
   "net_rate",
@@ -214,7 +215,6 @@
    "fieldtype": "Link",
    "label": "UOM",
    "options": "UOM",
-   "print_hide": 0,
    "reqd": 1
   },
   {
@@ -780,12 +780,20 @@
    "fieldname": "manufacturing_section_section",
    "fieldtype": "Section Break",
    "label": "Manufacturing Section"
+  },
+  {
+   "depends_on": "eval: doc.uom != doc.stock_uom",
+   "fieldname": "stock_uom_rate",
+   "fieldtype": "Currency",
+   "label": "Rate of Stock UOM",
+   "options": "currency",
+   "read_only": 1
   }
  ],
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-012-07 20:54:32.309460",
+ "modified": "2021-01-30 21:35:07.617320",
  "modified_by": "Administrator",
  "module": "Selling",
  "name": "Sales Order Item",
diff --git a/erpnext/selling/page/point_of_sale/pos_item_cart.js b/erpnext/selling/page/point_of_sale/pos_item_cart.js
index f753b6d..044e803 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_cart.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_cart.js
@@ -477,7 +477,7 @@
 		const taxes = frm.doc.taxes.map(t => {
 			return {
 				description: t.description, rate: t.rate
-			}
+			};
 		});
 		this.render_taxes(frm.doc.total_taxes_and_charges, taxes);
 	}
diff --git a/erpnext/selling/page/point_of_sale/pos_payment.js b/erpnext/selling/page/point_of_sale/pos_payment.js
index c9b8ad9..bcbac3b 100644
--- a/erpnext/selling/page/point_of_sale/pos_payment.js
+++ b/erpnext/selling/page/point_of_sale/pos_payment.js
@@ -153,32 +153,23 @@
 				me.$payment_modes.find(`.${mode}-amount`).css('display', 'none');
 				me.$payment_modes.find(`.${mode}-name`).css('display', 'inline');
 
-				const doc = me.events.get_frm().doc;
 				me.selected_mode = me[`${mode}_control`];
 				me.selected_mode && me.selected_mode.$input.get(0).focus();
-				const current_value = me.selected_mode ? me.selected_mode.get_value() : undefined;
-				!current_value && doc.grand_total > doc.paid_amount && me.selected_mode ?
-					me.selected_mode.set_value(doc.grand_total - doc.paid_amount) : '';
+				me.auto_set_remaining_amount();
 			}
 		});
 
-		frappe.realtime.on("process_phone_payment", function(data) {
-			frappe.dom.unfreeze();
-			cur_frm.reload_doc();
-			let message = data["ResultDesc"];
-			let title = __("Payment Failed");
+		frappe.ui.form.on('POS Invoice', 'contact_mobile', (frm) => {
+			const contact = frm.doc.contact_mobile;
+			const request_button = $(this.request_for_payment_field.$input[0]);
+			if (contact) {
+				request_button.removeClass('btn-default').addClass('btn-primary');
+			} else {
+				request_button.removeClass('btn-primary').addClass('btn-default');
+      }
+    });
 
-			if (data["ResultCode"] == 0) {
-				title = __("Payment Received");
-				$('.btn.btn-xs.btn-default[data-fieldname=request_for_payment]').html(`Payment Received`);
-				me.events.submit_invoice();
-			}
-
-			frappe.msgprint({
-				"message": message,
-				"title": title
-			});
-		});
+		this.setup_listener_for_payments();
 
 		this.$payment_modes.on('click', '.shortcut', () => {
 			const value = $(this).attr('data-value');
@@ -224,6 +215,41 @@
 		});
 	}
 
+	setup_listener_for_payments() {
+		frappe.realtime.on("process_phone_payment", (data) => {
+			const doc = this.events.get_frm().doc;
+			const { response, amount, success, failure_message } = data;
+			let message, title;
+
+			if (success) {
+				title = __("Payment Received");
+				if (amount >= doc.grand_total) {
+					frappe.dom.unfreeze();
+					message = __("Payment of {0} received successfully.", [format_currency(amount, doc.currency, 0)]);
+					this.events.submit_invoice();
+					cur_frm.reload_doc();
+
+				} else {
+					message = __("Payment of {0} received successfully. Waiting for other requests to complete...", [format_currency(amount, doc.currency, 0)]);
+				}
+			} else if (failure_message) {
+				message = failure_message;
+				title = __("Payment Failed");
+			}
+
+			frappe.msgprint({ "message": message, "title": title });
+		});
+	}
+
+	auto_set_remaining_amount() {
+		const doc = this.events.get_frm().doc;
+		const remaining_amount = doc.grand_total - doc.paid_amount;
+		const current_value = this.selected_mode ? this.selected_mode.get_value() : undefined;
+		if (!current_value && remaining_amount > 0 && this.selected_mode) {
+			this.selected_mode.set_value(remaining_amount);
+		}
+	}
+
 	attach_shortcuts() {
 		const ctrl_label = frappe.utils.is_mac() ? '⌘' : 'Ctrl';
 		this.$component.find('.submit-order-btn').attr("title", `${ctrl_label}+Enter`);
@@ -333,9 +359,11 @@
 					fieldtype: 'Currency',
 					placeholder: __('Enter {0} amount.', [p.mode_of_payment]),
 					onchange: function() {
-						if (this.value || this.value == 0) {
-							frappe.model.set_value(p.doctype, p.name, 'amount', flt(this.value))
-								.then(() => me.update_totals_section());
+						const current_value = frappe.model.get_value(p.doctype, p.name, 'amount');
+						if (current_value != this.value) {
+							frappe.model
+								.set_value(p.doctype, p.name, 'amount', flt(this.value))
+								.then(() => me.update_totals_section())
 
 							const formatted_currency = format_currency(this.value, currency);
 							me.$payment_modes.find(`.${mode}-amount`).html(formatted_currency);
diff --git a/erpnext/setup/doctype/company/delete_company_transactions.py b/erpnext/setup/doctype/company/delete_company_transactions.py
index 7a72fe3..0df4c87 100644
--- a/erpnext/setup/doctype/company/delete_company_transactions.py
+++ b/erpnext/setup/doctype/company/delete_company_transactions.py
@@ -28,7 +28,7 @@
 			"Party Account", "Employee", "Sales Taxes and Charges Template",
 			"Purchase Taxes and Charges Template", "POS Profile", "BOM",
 			"Company", "Bank Account", "Item Tax Template", "Mode Of Payment",
-			"Item Default", "Customer", "Supplier"):
+			"Item Default", "Customer", "Supplier", "GST Account"):
 				delete_for_doctype(doctype, company_name)
 
 	# reset company values
diff --git a/erpnext/setup/doctype/customer_group/customer_group.json b/erpnext/setup/doctype/customer_group/customer_group.json
index 10f9bd0..0e2ed9e 100644
--- a/erpnext/setup/doctype/customer_group/customer_group.json
+++ b/erpnext/setup/doctype/customer_group/customer_group.json
@@ -139,7 +139,7 @@
  "idx": 1,
  "is_tree": 1,
  "links": [],
- "modified": "2020-03-18 18:10:13.048492",
+ "modified": "2021-02-08 17:01:52.162202",
  "modified_by": "Administrator",
  "module": "Setup",
  "name": "Customer Group",
@@ -189,6 +189,15 @@
    "permlevel": 1,
    "read": 1,
    "role": "Sales Manager"
+  },
+  {
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "report": 1,
+   "role": "Customer",
+   "select": 1,
+   "share": 1
   }
  ],
  "search_fields": "parent_customer_group",
diff --git a/erpnext/setup/doctype/item_group/item_group.json b/erpnext/setup/doctype/item_group/item_group.json
index 31624ed..e835214 100644
--- a/erpnext/setup/doctype/item_group/item_group.json
+++ b/erpnext/setup/doctype/item_group/item_group.json
@@ -214,7 +214,7 @@
  "is_tree": 1,
  "links": [],
  "max_attachments": 3,
- "modified": "2020-12-30 12:57:38.876956",
+ "modified": "2021-02-08 17:02:44.951572",
  "modified_by": "Administrator",
  "module": "Setup",
  "name": "Item Group",
@@ -271,6 +271,15 @@
    "read": 1,
    "report": 1,
    "role": "Accounts User"
+  },
+  {
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "report": 1,
+   "role": "Customer",
+   "select": 1,
+   "share": 1
   }
  ],
  "search_fields": "parent_item_group",
diff --git a/erpnext/setup/doctype/territory/territory.json b/erpnext/setup/doctype/territory/territory.json
index aa8e048..a25bda0 100644
--- a/erpnext/setup/doctype/territory/territory.json
+++ b/erpnext/setup/doctype/territory/territory.json
@@ -123,7 +123,7 @@
  "idx": 1,
  "is_tree": 1,
  "links": [],
- "modified": "2020-03-18 18:11:36.623555",
+ "modified": "2021-02-08 17:10:03.767426",
  "modified_by": "Administrator",
  "module": "Setup",
  "name": "Territory",
@@ -166,6 +166,15 @@
   {
    "read": 1,
    "role": "Maintenance User"
+  },
+  {
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "report": 1,
+   "role": "Customer",
+   "select": 1,
+   "share": 1
   }
  ],
  "search_fields": "parent_territory,territory_manager",
diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py
index 3c9f849..681d161 100644
--- a/erpnext/shopping_cart/cart.py
+++ b/erpnext/shopping_cart/cart.py
@@ -462,6 +462,9 @@
 		return customer
 
 def get_debtors_account(cart_settings):
+	if not cart_settings.payment_gateway_account:
+		frappe.throw(_("Payment Gateway Account not set"), _("Mandatory"))
+
 	payment_gateway_account_currency = \
 		frappe.get_doc("Payment Gateway Account", cart_settings.payment_gateway_account).currency
 
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json
index 702583a..3691721 100644
--- a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json
+++ b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json
@@ -26,10 +26,10 @@
   "quotation_series",
   "section_break_8",
   "enable_checkout",
-  "payment_success_url",
-  "column_break_11",
   "save_quotations_as_draft",
-  "payment_gateway_account"
+  "column_break_11",
+  "payment_gateway_account",
+  "payment_success_url"
  ],
  "fields": [
   {
@@ -143,10 +143,12 @@
   },
   {
    "default": "Orders",
+   "depends_on": "enable_checkout",
    "description": "After payment completion redirect user to selected page.",
    "fieldname": "payment_success_url",
    "fieldtype": "Select",
    "label": "Payment Success Url",
+   "mandatory_depends_on": "enable_checkout",
    "options": "\nOrders\nInvoices\nMy Account"
   },
   {
@@ -154,9 +156,11 @@
    "fieldtype": "Column Break"
   },
   {
+   "depends_on": "enable_checkout",
    "fieldname": "payment_gateway_account",
    "fieldtype": "Link",
    "label": "Payment Gateway Account",
+   "mandatory_depends_on": "enable_checkout",
    "options": "Payment Gateway Account"
   },
   {
@@ -186,7 +190,7 @@
  "idx": 1,
  "issingle": 1,
  "links": [],
- "modified": "2021-02-01 18:18:54.606535",
+ "modified": "2021-02-11 18:48:30.433058",
  "modified_by": "Administrator",
  "module": "Shopping Cart",
  "name": "Shopping Cart Settings",
diff --git a/erpnext/shopping_cart/product_query.py b/erpnext/shopping_cart/product_query.py
index da9e798..36d446e 100644
--- a/erpnext/shopping_cart/product_query.py
+++ b/erpnext/shopping_cart/product_query.py
@@ -23,8 +23,10 @@
 		self.cart_settings = frappe.get_doc("Shopping Cart Settings")
 		self.page_length = self.settings.products_per_page or 20
 		self.fields = ['name', 'item_name', 'item_code', 'website_image', 'variant_of', 'has_variants', 'item_group', 'image', 'web_long_description', 'description', 'route']
-		self.filters = [['show_in_website', '=', 1]]
-		self.or_filters = []
+		self.filters = []
+		self.or_filters = [['show_in_website', '=', 1]]
+		if not self.settings.get('hide_variants'):
+			self.or_filters.append(['show_variant_in_website', '=', 1])
 
 	def query(self, attributes=None, fields=None, search_term=None, start=0):
 		"""Summary
@@ -73,7 +75,8 @@
 
 		for item in result:
 			product_info = get_product_info_for_website(item.item_code, skip_quotation_creation=True).get('product_info')
-			item.formatted_price = product_info['price'].get('formatted_price') if product_info['price'] else None
+			if product_info:
+				item.formatted_price = product_info['price'].get('formatted_price') if product_info['price'] else None
 
 		return result
 
diff --git a/erpnext/stock/__init__.py b/erpnext/stock/__init__.py
index 8d64efe..9e240cc 100644
--- a/erpnext/stock/__init__.py
+++ b/erpnext/stock/__init__.py
@@ -64,10 +64,10 @@
 	if not account and warehouse.company:
 		account = get_company_default_inventory_account(warehouse.company)
 
-	if not account and warehouse.company:
+	if not account and warehouse.company and not warehouse.is_group:
 		frappe.throw(_("Please set Account in Warehouse {0} or Default Inventory Account in Company {1}")
 			.format(warehouse.name, warehouse.company))
 	return account
 
 def get_company_default_inventory_account(company):
-	return frappe.get_cached_value('Company',  company,  'default_inventory_account')
+	return frappe.get_cached_value('Company',  company, 'default_inventory_account')
diff --git a/erpnext/stock/dashboard/item_dashboard.js b/erpnext/stock/dashboard/item_dashboard.js
index 9dbb64c..95cb92b 100644
--- a/erpnext/stock/dashboard/item_dashboard.js
+++ b/erpnext/stock/dashboard/item_dashboard.js
@@ -132,7 +132,7 @@
 			var message = __("No Stock Available Currently");
 			this.content.find('.result').css('text-align', 'center');
 
-			$(`<div class='text-muted' style='margin: 20px 5px; font-weight: lighter;'>
+			$(`<div class='text-muted' style='margin: 20px 5px;'>
 				${message} </div>`).appendTo(this.result);
 		}
 	},
diff --git a/erpnext/stock/doctype/batch/test_batch.py b/erpnext/stock/doctype/batch/test_batch.py
index 97f85ba..cbd272d 100644
--- a/erpnext/stock/doctype/batch/test_batch.py
+++ b/erpnext/stock/doctype/batch/test_batch.py
@@ -298,9 +298,9 @@
 		self.assertEqual(details.get('price_list_rate'), 400)
 
 def create_batch(item_code, rate, create_item_price_for_batch):
-	pi = make_purchase_invoice(company="_Test Company with perpetual inventory",
-		warehouse= "Stores - TCP1", cost_center = "Main - TCP1", update_stock=1,
-		expense_account ="_Test Account Cost for Goods Sold - TCP1", item_code=item_code)
+	pi = make_purchase_invoice(company="_Test Company",
+		warehouse= "Stores - _TC", cost_center = "Main - _TC", update_stock=1,
+		expense_account ="_Test Account Cost for Goods Sold - _TC", item_code=item_code)
 
 	batch = frappe.db.get_value('Batch', {'item': item_code, 'reference_name': pi.name})
 
diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py
index 1088b41..0514bd2 100644
--- a/erpnext/stock/doctype/bin/bin.py
+++ b/erpnext/stock/doctype/bin/bin.py
@@ -16,8 +16,9 @@
 	def update_stock(self, args, allow_negative_stock=False, via_landed_cost_voucher=False):
 		'''Called from erpnext.stock.utils.update_bin'''
 		self.update_qty(args)
+
 		if args.get("actual_qty") or args.get("voucher_type") == "Stock Reconciliation":
-			from erpnext.stock.stock_ledger import update_entries_after, validate_negative_qty_in_future_sle
+			from erpnext.stock.stock_ledger import update_entries_after, update_qty_in_future_sle
 
 			if not args.get("posting_date"):
 				args["posting_date"] = nowdate()
@@ -34,11 +35,13 @@
 				"posting_time": args.get("posting_time"),
 				"voucher_type": args.get("voucher_type"),
 				"voucher_no": args.get("voucher_no"),
-				"sle_id": args.name
+				"sle_id": args.name,
+				"creation": args.creation
 			}, allow_negative_stock=allow_negative_stock, via_landed_cost_voucher=via_landed_cost_voucher)
 
-			# Validate negative qty in future transactions
-			validate_negative_qty_in_future_sle(args)
+			# update qty in future ale and Validate negative qty
+			update_qty_in_future_sle(args, allow_negative_stock)
+
 
 	def update_qty(self, args):
 		# update the stock values (for current quantities)
@@ -51,7 +54,7 @@
 		self.reserved_qty = flt(self.reserved_qty) + flt(args.get("reserved_qty"))
 		self.indented_qty = flt(self.indented_qty) + flt(args.get("indented_qty"))
 		self.planned_qty = flt(self.planned_qty) + flt(args.get("planned_qty"))
-
+		
 		self.set_projected_qty()
 		self.db_update()
 
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index 559f8be..d39b229 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -489,7 +489,10 @@
 	def test_closed_delivery_note(self):
 		from erpnext.stock.doctype.delivery_note.delivery_note import update_delivery_note_status
 
-		dn = create_delivery_note(company='_Test Company with perpetual inventory', warehouse='Stores - TCP1', cost_center = 'Main - TCP1', expense_account = "Cost of Goods Sold - TCP1", do_not_submit=True)
+		make_stock_entry(target="Stores - TCP1", qty=5, basic_rate=100)
+
+		dn = create_delivery_note(company='_Test Company with perpetual inventory', warehouse='Stores - TCP1',
+			cost_center = 'Main - TCP1', expense_account = "Cost of Goods Sold - TCP1", do_not_submit=True)
 
 		dn.submit()
 
diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
index 9de088d..1799624 100644
--- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
+++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
@@ -47,6 +47,7 @@
   "base_rate",
   "base_amount",
   "pricing_rules",
+  "stock_uom_rate",
   "is_free_item",
   "section_break_25",
   "net_rate",
@@ -743,13 +744,21 @@
    "no_copy": 1,
    "print_hide": 1,
    "read_only": 1
+  },
+  {
+   "depends_on": "eval: doc.uom != doc.stock_uom",
+   "fieldname": "stock_uom_rate",
+   "fieldtype": "Currency",
+   "label": "Rate of Stock UOM",
+   "options": "currency",
+   "read_only": 1
   }
  ],
  "idx": 1,
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-12-26 17:31:27.029803",
+ "modified": "2021-01-30 21:42:03.767968",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Delivery Note Item",
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index b661570..7b7d2da 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -177,7 +177,7 @@
 		if not self.valuation_rate and self.standard_rate:
 			self.valuation_rate = self.standard_rate
 
-		if not self.valuation_rate:
+		if not self.valuation_rate and not self.is_customer_provided_item:
 			frappe.throw(_("Valuation Rate is mandatory if Opening Stock entered"))
 
 		from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
diff --git a/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.json b/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.json
index 471e685..9b1a47e 100644
--- a/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.json
+++ b/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.json
@@ -7,6 +7,7 @@
  "engine": "InnoDB",
  "field_order": [
   "specification",
+  "parameter_group",
   "value",
   "numeric",
   "column_break_3",
@@ -75,12 +76,20 @@
    "in_list_view": 1,
    "label": "Numeric",
    "width": "80px"
+  },
+  {
+   "fetch_from": "specification.parameter_group",
+   "fieldname": "parameter_group",
+   "fieldtype": "Link",
+   "label": "Parameter Group",
+   "options": "Quality Inspection Parameter Group",
+   "read_only": 1
   }
  ],
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2021-02-01 19:18:46.924399",
+ "modified": "2021-02-04 18:50:02.056173",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Item Quality Inspection Parameter",
diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
index 144101c..984ae46 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
@@ -148,7 +148,6 @@
 
 
 	def test_landed_cost_voucher_for_odd_numbers (self):
-
 		pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1", do_not_save=True)
 		pr.items[0].cost_center = "Main - TCP1"
 		for x in range(2):
@@ -208,6 +207,10 @@
 		self.assertEqual(pr.items[1].landed_cost_voucher_amount, 100)
 
 	def test_multi_currency_lcv(self):
+		from erpnext.setup.doctype.currency_exchange.test_currency_exchange import test_records, save_new_records
+
+		save_new_records(test_records)
+
 		## Create USD Shipping charges_account
 		usd_shipping = create_account(account_name="Shipping Charges USD",
 			parent_account="Duties and Taxes - TCP1", company="_Test Company with perpetual inventory",
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index ca58ab2..7741ee7 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -94,10 +94,15 @@
 		frappe.get_doc('Payment Terms Template', '_Test Payment Terms Template For Purchase Invoice').delete()
 
 	def test_purchase_receipt_no_gl_entry(self):
+		from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
+
 		company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
 
-		existing_bin_stock_value = frappe.db.get_value("Bin", {"item_code": "_Test Item",
-			"warehouse": "_Test Warehouse - _TC"}, "stock_value")
+		existing_bin_qty, existing_bin_stock_value = frappe.db.get_value("Bin", {"item_code": "_Test Item",
+			"warehouse": "_Test Warehouse - _TC"}, ["actual_qty", "stock_value"])
+
+		if existing_bin_qty < 0:
+			make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=abs(existing_bin_qty))
 
 		pr = make_purchase_receipt()
 
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
index e991192..8974ad9 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
@@ -48,6 +48,7 @@
   "base_rate",
   "base_amount",
   "pricing_rules",
+  "stock_uom_rate",
   "is_free_item",
   "section_break_29",
   "net_rate",
@@ -875,6 +876,14 @@
    "print_hide": 1
   },
   {
+   "depends_on": "eval: doc.uom != doc.stock_uom",
+   "fieldname": "stock_uom_rate",
+   "fieldtype": "Currency",
+   "label": "Rate of Stock UOM",
+   "options": "currency",
+   "read_only": 1
+  },
+  {
    "fieldname": "delivery_note_item",
    "fieldtype": "Data",
    "label": "Delivery Note Item",
@@ -886,7 +895,7 @@
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-12-26 16:50:56.479347",
+ "modified": "2021-01-30 21:44:06.918515",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Purchase Receipt Item",
diff --git a/erpnext/stock/doctype/quality_inspection_parameter/quality_inspection_parameter.json b/erpnext/stock/doctype/quality_inspection_parameter/quality_inspection_parameter.json
index 0b5a9b5..418b482 100644
--- a/erpnext/stock/doctype/quality_inspection_parameter/quality_inspection_parameter.json
+++ b/erpnext/stock/doctype/quality_inspection_parameter/quality_inspection_parameter.json
@@ -7,24 +7,34 @@
  "engine": "InnoDB",
  "field_order": [
   "parameter",
+  "parameter_group",
   "description"
  ],
  "fields": [
   {
    "fieldname": "parameter",
    "fieldtype": "Data",
+   "in_list_view": 1,
    "label": "Parameter",
+   "reqd": 1,
    "unique": 1
   },
   {
    "fieldname": "description",
    "fieldtype": "Text Editor",
    "label": "Description"
+  },
+  {
+   "fieldname": "parameter_group",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Parameter Group",
+   "options": "Quality Inspection Parameter Group"
   }
  ],
  "index_web_pages_for_search": 1,
  "links": [],
- "modified": "2020-12-28 18:06:54.897317",
+ "modified": "2021-02-19 20:33:30.657406",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Quality Inspection Parameter",
diff --git a/erpnext/accounts/doctype/bank_statement_settings/__init__.py b/erpnext/stock/doctype/quality_inspection_parameter_group/__init__.py
similarity index 100%
copy from erpnext/accounts/doctype/bank_statement_settings/__init__.py
copy to erpnext/stock/doctype/quality_inspection_parameter_group/__init__.py
diff --git a/erpnext/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.js b/erpnext/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.js
new file mode 100644
index 0000000..8716a29
--- /dev/null
+++ b/erpnext/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Quality Inspection Parameter Group', {
+	// refresh: function(frm) {
+
+	// }
+});
diff --git a/erpnext/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.json b/erpnext/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.json
new file mode 100644
index 0000000..5726474
--- /dev/null
+++ b/erpnext/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.json
@@ -0,0 +1,82 @@
+{
+ "actions": [],
+ "autoname": "field:group_name",
+ "creation": "2021-02-04 18:44:12.223295",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "group_name"
+ ],
+ "fields": [
+  {
+   "fieldname": "group_name",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Parameter Group Name",
+   "reqd": 1,
+   "unique": 1
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2021-02-04 18:44:12.223295",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Quality Inspection Parameter Group",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Stock User",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Quality Manager",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Manufacturing User",
+   "share": 1,
+   "write": 1
+  }
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.py b/erpnext/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.py
new file mode 100644
index 0000000..1a3b1a0
--- /dev/null
+++ b/erpnext/stock/doctype/quality_inspection_parameter_group/quality_inspection_parameter_group.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class QualityInspectionParameterGroup(Document):
+	pass
diff --git a/erpnext/stock/doctype/quality_inspection_parameter_group/test_quality_inspection_parameter_group.py b/erpnext/stock/doctype/quality_inspection_parameter_group/test_quality_inspection_parameter_group.py
new file mode 100644
index 0000000..212d4b8
--- /dev/null
+++ b/erpnext/stock/doctype/quality_inspection_parameter_group/test_quality_inspection_parameter_group.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+# import frappe
+import unittest
+
+class TestQualityInspectionParameterGroup(unittest.TestCase):
+	pass
diff --git a/erpnext/stock/doctype/quality_inspection_reading/quality_inspection_reading.json b/erpnext/stock/doctype/quality_inspection_reading/quality_inspection_reading.json
index 35d58ef..0eff5a8 100644
--- a/erpnext/stock/doctype/quality_inspection_reading/quality_inspection_reading.json
+++ b/erpnext/stock/doctype/quality_inspection_reading/quality_inspection_reading.json
@@ -7,6 +7,7 @@
  "engine": "InnoDB",
  "field_order": [
   "specification",
+  "parameter_group",
   "status",
   "value",
   "numeric",
@@ -210,12 +211,20 @@
    "fieldtype": "Check",
    "in_list_view": 1,
    "label": "Numeric"
+  },
+  {
+   "fetch_from": "specification.parameter_group",
+   "fieldname": "parameter_group",
+   "fieldtype": "Link",
+   "label": "Parameter Group",
+   "options": "Quality Inspection Parameter Group",
+   "read_only": 1
   }
  ],
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2021-02-01 19:46:22.138018",
+ "modified": "2021-02-04 19:15:37.991221",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Quality Inspection Reading",
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
index ba2c2c6..8436acb 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
@@ -46,6 +46,9 @@
 
 def repost(doc):
 	try:
+		if not frappe.db.exists("Repost Item Valuation", doc.name):
+			return
+
 		doc.set_status('In Progress')
 		frappe.db.commit()
 
@@ -64,7 +67,7 @@
 			message += "<br>" + "Traceback: <br>" + traceback
 		frappe.db.set_value(doc.doctype, doc.name, 'error_log', message)
 
-		notify_error_to_stock_managers(doc)
+		notify_error_to_stock_managers(doc, message)
 		doc.set_status('Failed')
 		raise
 	finally:
diff --git a/erpnext/stock/doctype/shipment/test_shipment.py b/erpnext/stock/doctype/shipment/test_shipment.py
index e1fa207..9c3e22f 100644
--- a/erpnext/stock/doctype/shipment/test_shipment.py
+++ b/erpnext/stock/doctype/shipment/test_shipment.py
@@ -190,6 +190,7 @@
 	company.abbr = abbr
 	company.default_currency = 'EUR'
 	company.country = 'Germany'
+	company.enable_perpetual_inventory = 0
 	company.insert()
 	return company
 
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index d77b70f..9cdc3cf 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -163,7 +163,7 @@
 		if self.purpose not in valid_purposes:
 			frappe.throw(_("Purpose must be one of {0}").format(comma_or(valid_purposes)))
 
-		if self.job_card and self.purpose != 'Material Transfer for Manufacture':
+		if self.job_card and self.purpose not in ['Material Transfer for Manufacture', 'Repack']:
 			frappe.throw(_("For job card {0}, you can only make the 'Material Transfer for Manufacture' type stock entry")
 				.format(self.job_card))
 
@@ -823,6 +823,7 @@
 		if self.job_card:
 			job_doc = frappe.get_doc('Job Card', self.job_card)
 			job_doc.set_transferred_qty(update_status=True)
+			job_doc.set_transferred_qty_in_job_card(self)
 
 		if self.work_order:
 			pro_doc = frappe.get_doc("Work Order", self.work_order)
diff --git a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json
index 988ae92..864ff48 100644
--- a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json
+++ b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json
@@ -69,7 +69,8 @@
   "putaway_rule",
   "column_break_51",
   "reference_purchase_receipt",
-  "quality_inspection"
+  "quality_inspection",
+  "job_card_item"
  ],
  "fields": [
   {
@@ -532,13 +533,22 @@
    "fieldname": "is_finished_item",
    "fieldtype": "Check",
    "label": "Is Finished Item"
+  },
+  {
+   "fieldname": "job_card_item",
+   "fieldtype": "Data",
+   "hidden": 1,
+   "label": "Job Card Item",
+   "no_copy": 1,
+   "print_hide": 1,
+   "read_only": 1
   }
  ],
  "idx": 1,
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-12-30 15:00:44.489442",
+ "modified": "2021-02-11 13:47:50.158754",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Stock Entry Detail",
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
index a5c303c..b0e7440 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
@@ -27,16 +27,18 @@
 
 	def validate(self):
 		self.flags.ignore_submit_comment = True
-		from erpnext.stock.utils import validate_warehouse_company
+		from erpnext.stock.utils import validate_warehouse_company, validate_disabled_warehouse
 		self.validate_mandatory()
 		self.validate_item()
 		self.validate_batch()
+		validate_disabled_warehouse(self.warehouse)
 		validate_warehouse_company(self.warehouse, self.company)
 		self.scrub_posting_time()
 		self.validate_and_set_fiscal_year()
 		self.block_transactions_against_group_warehouse()
 		self.validate_with_last_transaction_posting_time()
 
+
 	def on_submit(self):
 		self.check_stock_frozen_date()
 		self.actual_amt_check()
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 46919c8..f54b3c1 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -23,6 +23,7 @@
 
 		cancel = sl_entries[0].get("is_cancelled")
 		if cancel:
+			validate_cancellation(sl_entries)
 			set_as_cancel(sl_entries[0].get('voucher_type'), sl_entries[0].get('voucher_no'))
 
 		for sle in sl_entries:
@@ -45,6 +46,21 @@
 			args = sle_doc.as_dict()
 			update_bin(args, allow_negative_stock, via_landed_cost_voucher)
 
+def validate_cancellation(args):
+	if args[0].get("is_cancelled"):
+		repost_entry = frappe.db.get_value("Repost Item Valuation", {
+			'voucher_type': args[0].voucher_type,
+			'voucher_no': args[0].voucher_no,
+			'docstatus': 1
+		}, ['name', 'status'], as_dict=1)
+
+		if repost_entry:
+			if repost_entry.status == 'In Progress':
+				frappe.throw(_("Cannot cancel the transaction. Reposting of item valuation on submission is not completed yet."))
+			if repost_entry.status == 'Queued':
+				doc = frappe.get_doc("Repost Item Valuation", repost_entry.name)
+				doc.cancel()
+				doc.delete()
 
 def set_as_cancel(voucher_type, voucher_no):
 	frappe.db.sql("""update `tabStock Ledger Entry` set is_cancelled=1,
@@ -74,7 +90,8 @@
 			"item_code": args[i].item_code,
 			"warehouse": args[i].warehouse,
 			"posting_date": args[i].posting_date,
-			"posting_time": args[i].posting_time
+			"posting_time": args[i].posting_time,
+			"creation": args[i].get("creation")
 		}, allow_negative_stock=allow_negative_stock, via_landed_cost_voucher=via_landed_cost_voucher)
 
 		for item_wh, new_sle in iteritems(obj.new_items):
@@ -86,7 +103,7 @@
 def get_args_for_voucher(voucher_type, voucher_no):
 	return frappe.db.get_all("Stock Ledger Entry",
 		filters={"voucher_type": voucher_type, "voucher_no": voucher_no},
-		fields=["item_code", "warehouse", "posting_date", "posting_time"],
+		fields=["item_code", "warehouse", "posting_date", "posting_time", "creation"],
 		order_by="creation asc",
 		group_by="item_code, warehouse"
 	)
@@ -155,7 +172,7 @@
 		"""
 		self.data.setdefault(args.warehouse, frappe._dict())
 		warehouse_dict = self.data[args.warehouse]
-		previous_sle = self.get_sle_before_datetime(args)
+		previous_sle = self.get_previous_sle_of_current_voucher(args)
 		warehouse_dict.previous_sle = previous_sle
 
 		for key in ("qty_after_transaction", "valuation_rate", "stock_value"):
@@ -167,9 +184,35 @@
 			"stock_value_difference": 0.0
 		})
 
+	def get_previous_sle_of_current_voucher(self, args):
+		"""get stock ledger entries filtered by specific posting datetime conditions"""
+
+		args['time_format'] = '%H:%i:%s'
+		if not args.get("posting_date"):
+			args["posting_date"] = "1900-01-01"
+		if not args.get("posting_time"):
+			args["posting_time"] = "00:00"
+
+		sle = frappe.db.sql("""
+			select *, timestamp(posting_date, posting_time) as "timestamp"
+			from `tabStock Ledger Entry`
+			where item_code = %(item_code)s
+				and warehouse = %(warehouse)s
+				and is_cancelled = 0
+				and timestamp(posting_date, time_format(posting_time, %(time_format)s)) < timestamp(%(posting_date)s, time_format(%(posting_time)s, %(time_format)s))
+			order by timestamp(posting_date, posting_time) desc, creation desc
+			limit 1""", args, as_dict=1)
+
+		return sle[0] if sle else frappe._dict()
+
+
 	def build(self):
+		from erpnext.controllers.stock_controller import check_if_future_sle_exists
+
 		if self.args.get("sle_id"):
-			self.process_sle_against_current_voucher()
+			self.process_sle_against_current_timestamp()
+			if not check_if_future_sle_exists(self.args):
+				self.update_bin()
 		else:
 			entries_to_fix = self.get_future_entries_to_fix()
 
@@ -183,17 +226,19 @@
 				if sle.dependant_sle_voucher_detail_no:
 					entries_to_fix = self.get_dependent_entries_to_fix(entries_to_fix, sle)
 
+			self.update_bin()
+
 		if self.exceptions:
 			self.raise_exceptions()
 
-		self.update_bin()
-
-	def process_sle_against_current_voucher(self):
+	def process_sle_against_current_timestamp(self):
 		sl_entries = self.get_sle_against_current_voucher()
 		for sle in sl_entries:
 			self.process_sle(sle)
 
 	def get_sle_against_current_voucher(self):
+		self.args['time_format'] = '%H:%i:%s'
+
 		return frappe.db.sql("""
 			select
 				*, timestamp(posting_date, posting_time) as "timestamp"
@@ -202,8 +247,8 @@
 			where
 				item_code = %(item_code)s
 				and warehouse = %(warehouse)s
-				and voucher_type = %(voucher_type)s
-				and voucher_no = %(voucher_no)s
+				and timestamp(posting_date, time_format(posting_time, %(time_format)s)) = timestamp(%(posting_date)s, time_format(%(posting_time)s, %(time_format)s))
+
 			order by
 				creation ASC
 			for update
@@ -230,7 +275,6 @@
 			return entries_to_fix
 		elif dependant_sle.item_code == self.item_code and dependant_sle.warehouse in self.data:
 			return entries_to_fix
-
 		self.initialize_previous_data(dependant_sle)
 
 		args = self.data[dependant_sle.warehouse].previous_sle \
@@ -396,7 +440,7 @@
 
 		# Recalculate subcontracted item's rate in case of subcontracted purchase receipt/invoice
 		if frappe.db.get_value(sle.voucher_type, sle.voucher_no, "is_subcontracted"):
-			doc = frappe.get_cached_doc(sle.voucher_type, sle.voucher_no)
+			doc = frappe.get_doc(sle.voucher_type, sle.voucher_no)
 			doc.update_valuation_rate(reset_outgoing_rate=False)
 			for d in (doc.items + doc.supplied_items):
 				d.db_update()
@@ -637,7 +681,6 @@
 		# update bin for each warehouse
 		for warehouse, data in iteritems(self.data):
 			bin_doc = get_bin(self.item_code, warehouse)
-
 			bin_doc.update({
 				"valuation_rate": data.valuation_rate,
 				"actual_qty": data.qty_after_transaction,
@@ -763,6 +806,25 @@
 
 	return valuation_rate
 
+def update_qty_in_future_sle(args, allow_negative_stock=None):
+	frappe.db.sql("""
+		update `tabStock Ledger Entry`
+		set qty_after_transaction = qty_after_transaction + {qty}
+		where
+			item_code = %(item_code)s
+			and warehouse = %(warehouse)s
+			and voucher_no != %(voucher_no)s
+			and is_cancelled = 0
+			and (timestamp(posting_date, posting_time) > timestamp(%(posting_date)s, %(posting_time)s)
+				or (
+					timestamp(posting_date, posting_time) = timestamp(%(posting_date)s, %(posting_time)s)
+					and creation > %(creation)s
+				)
+			)
+	""".format(qty=args.actual_qty), args)
+
+	validate_negative_qty_in_future_sle(args, allow_negative_stock)
+
 def validate_negative_qty_in_future_sle(args, allow_negative_stock=None):
 	allow_negative_stock = allow_negative_stock \
 		or cint(frappe.db.get_single_value("Stock Settings", "allow_negative_stock"))
@@ -791,7 +853,7 @@
 			and voucher_no != %(voucher_no)s
 			and timestamp(posting_date, posting_time) >= timestamp(%(posting_date)s, %(posting_time)s)
 			and is_cancelled = 0
-			and qty_after_transaction + {0} < 0
+			and qty_after_transaction < 0
 		order by timestamp(posting_date, posting_time) asc
 		limit 1
-	""".format(args.actual_qty), args, as_dict=1)
\ No newline at end of file
+	""", args, as_dict=1)
\ No newline at end of file
diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py
index 4ea7e4f..0af3d90 100644
--- a/erpnext/stock/utils.py
+++ b/erpnext/stock/utils.py
@@ -5,7 +5,7 @@
 import frappe, erpnext
 from frappe import _
 import json
-from frappe.utils import flt, cstr, nowdate, nowtime
+from frappe.utils import flt, cstr, nowdate, nowtime, get_link_to_form
 
 from six import string_types
 
@@ -284,6 +284,10 @@
 	if frappe.db.get_value("Warehouse", warehouse, "is_group"):
 		frappe.throw(_("Group node warehouse is not allowed to select for transactions"))
 
+def validate_disabled_warehouse(warehouse):
+	if frappe.db.get_value("Warehouse", warehouse, "disabled"):
+		frappe.throw(_("Disabled Warehouse {0} cannot be used for this transaction.").format(get_link_to_form('Warehouse', warehouse)))
+
 def update_included_uom_in_report(columns, result, include_uom, conversion_factors):
 	if not include_uom or not conversion_factors:
 		return
diff --git a/erpnext/telephony/doctype/call_log/call_log.js b/erpnext/telephony/doctype/call_log/call_log.js
index 977f86d..e7afa0b 100644
--- a/erpnext/telephony/doctype/call_log/call_log.js
+++ b/erpnext/telephony/doctype/call_log/call_log.js
@@ -2,7 +2,26 @@
 // For license information, please see license.txt
 
 frappe.ui.form.on('Call Log', {
-	// refresh: function(frm) {
-
-	// }
+	refresh: function(frm) {
+		frm.events.setup_recording_audio_control(frm);
+		const incoming_call = frm.doc.type == 'Incoming';
+		frm.add_custom_button(incoming_call ? __('Callback'): __('Call Again'), () => {
+			const number = incoming_call ? frm.doc.from : frm.doc.to;
+			frappe.phone_call.handler(number, frm);
+		});
+	},
+	setup_recording_audio_control(frm) {
+		const recording_wrapper = frm.get_field('recording_html').$wrapper;
+		if (!frm.doc.recording_url || frm.doc.recording_url == 'null') {
+			recording_wrapper.empty();
+		} else {
+			recording_wrapper.addClass('input-max-width');
+			recording_wrapper.html(`
+				<audio
+					controls
+					src="${frm.doc.recording_url}">
+				</audio>
+			`);
+		}
+	}
 });
diff --git a/erpnext/telephony/doctype/call_log/call_log.json b/erpnext/telephony/doctype/call_log/call_log.json
index 1ecd884..1d6c39e 100644
--- a/erpnext/telephony/doctype/call_log/call_log.json
+++ b/erpnext/telephony/doctype/call_log/call_log.json
@@ -5,6 +5,7 @@
  "doctype": "DocType",
  "engine": "InnoDB",
  "field_order": [
+  "call_details_section",
   "id",
   "from",
   "to",
@@ -21,21 +22,10 @@
   "section_break_11",
   "summary",
   "section_break_19",
-  "links",
-  "column_break_3",
-  "section_break_5"
+  "links"
  ],
  "fields": [
   {
-   "fieldname": "column_break_3",
-   "fieldtype": "Column Break"
-  },
-  {
-   "fieldname": "section_break_5",
-   "fieldtype": "Section Break",
-   "label": "Call Details"
-  },
-  {
    "fieldname": "id",
    "fieldtype": "Data",
    "label": "ID",
@@ -75,6 +65,7 @@
   {
    "fieldname": "recording_url",
    "fieldtype": "Data",
+   "hidden": 1,
    "label": "Recording URL"
   },
   {
@@ -112,13 +103,13 @@
   },
   {
    "fieldname": "summary",
-   "fieldtype": "Small Text",
-   "label": "Call Summary"
+   "fieldtype": "Small Text"
   },
   {
    "fieldname": "section_break_11",
    "fieldtype": "Section Break",
-   "hide_border": 1
+   "hide_border": 1,
+   "label": "Call Summary"
   },
   {
    "fieldname": "start_time",
@@ -138,12 +129,17 @@
    "label": "Customer",
    "options": "Customer",
    "read_only": 1
+  },
+  {
+   "fieldname": "call_details_section",
+   "fieldtype": "Section Break",
+   "label": "Call Details"
   }
  ],
  "in_create": 1,
  "index_web_pages_for_search": 1,
  "links": [],
- "modified": "2021-01-13 12:28:20.288985",
+ "modified": "2021-02-08 14:23:28.744844",
  "modified_by": "Administrator",
  "module": "Telephony",
  "name": "Call Log",
diff --git a/erpnext/telephony/doctype/call_log/call_log.py b/erpnext/telephony/doctype/call_log/call_log.py
index a277a5f..4d553df 100644
--- a/erpnext/telephony/doctype/call_log/call_log.py
+++ b/erpnext/telephony/doctype/call_log/call_log.py
@@ -165,6 +165,8 @@
 	for log in logs:
 		log.show_call_button = 0
 		timeline_contents.append({
+			'icon': 'call',
+			'is_card': True,
 			'creation': log.creation,
 			'template': 'call_link',
 			'template_data': log
diff --git a/erpnext/templates/pages/cart.html b/erpnext/templates/pages/cart.html
index 2cabf5a..ea34371 100644
--- a/erpnext/templates/pages/cart.html
+++ b/erpnext/templates/pages/cart.html
@@ -62,6 +62,9 @@
 				<div class="col-8">
 					{% if doc.items %}
 					<div class="place-order-container">
+						<a class="btn btn-primary-light mr-2" href="/all-products">
+							{{ _("Continue Shopping") }}
+						</a>
 						{% if cart_settings.enable_checkout %}
 							<button class="btn btn-primary btn-place-order" type="button">
 								{{ _("Place Order") }}
diff --git a/requirements.txt b/requirements.txt
index 4511aa5..5a35236 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,7 +3,7 @@
 gocardless-pro==1.11.0
 googlemaps==3.1.1
 pandas>=1.0.5
-plaid-python==6.0.0
+plaid-python>=7.0.0
 pycountry==19.8.18
 PyGithub==1.44.1
 python-stdnum==1.12
@@ -12,4 +12,4 @@
 tweepy==3.8.0
 Unidecode==1.1.1
 WooCommerce==2.1.1
-pycryptodome==3.9.8
\ No newline at end of file
+pycryptodome==3.9.8