Merge pull request #23370 from prssanna/account-user-permission

fix: apply user permissions in tax accounts query
diff --git a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js b/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js
index efc76f9..9703527 100644
--- a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js
+++ b/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js
@@ -72,7 +72,7 @@
 	check_plaid_status() {
 		const me = this;
 		frappe.db.get_value("Plaid Settings", "Plaid Settings", "enabled", (r) => {
-			if (r && r.enabled == "1") {
+			if (r && r.enabled === "1") {
 				me.plaid_status = "active"
 			} else {
 				me.plaid_status = "inactive"
@@ -139,7 +139,7 @@
 	}
 
 	make() {
-		const me = this;	
+		const me = this;
 		new frappe.ui.FileUploader({
 			method: 'erpnext.accounts.doctype.bank_transaction.bank_transaction_upload.upload_bank_statement',
 			allow_multiple: 0,
@@ -214,31 +214,35 @@
 
 	init_config() {
 		const me = this;
-		frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.plaid_configuration')
-		.then(result => {
-			me.plaid_env = result.plaid_env;
-			me.plaid_public_key = result.plaid_public_key;
-			me.client_name = result.client_name;
-			me.sync_transactions()
-		})
+		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", (v) => {
+		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: v['bank'],
+				bank: r.bank,
 				bank_account: me.parent.bank_account,
 				freeze: true
 			})
 			.then((result) => {
-				let result_title = (result.length > 0) ? __("{0} bank transaction(s) created", [result.length]) : __("This bank account is already synchronized")
+				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>`
+				<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'});
+				frappe.show_alert({ message: __("Bank account '{0}' has been synchronized", [me.parent.bank_account]), indicator: 'green' });
 			})
 		})
 	}
@@ -384,7 +388,7 @@
 		})
 
 		frappe.xcall('erpnext.accounts.page.bank_reconciliation.bank_reconciliation.get_linked_payments',
-			{bank_transaction: data, freeze:true, freeze_message:__("Finding linked payments")}
+			{ bank_transaction: data, freeze: true, freeze_message: __("Finding linked payments") }
 		).then((result) => {
 			me.make_dialog(result)
 		})
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
index 532e19c..a033a2a 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
@@ -2,81 +2,90 @@
 # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
 # For license information, please see license.txt
 
-from __future__ import unicode_literals
-from frappe import _
-from frappe.utils.password import get_decrypted_password
-from plaid import Client
-from plaid.errors import APIError, ItemError
+import plaid
+import requests
+from plaid.errors import APIError, ItemError, InvalidRequestError
 
 import frappe
-import requests
+from frappe import _
+
 
 class PlaidConnector():
 	def __init__(self, access_token=None):
-
-		plaid_settings = frappe.get_single("Plaid Settings")
-
-		self.config = {
-			"plaid_client_id": plaid_settings.plaid_client_id,
-			"plaid_secret": get_decrypted_password("Plaid Settings", "Plaid Settings", 'plaid_secret'),
-			"plaid_public_key": plaid_settings.plaid_public_key,
-			"plaid_env": plaid_settings.plaid_env
-		}
-
-		self.client = Client(client_id=self.config.get("plaid_client_id"),
-			secret=self.config.get("plaid_secret"),
-			public_key=self.config.get("plaid_public_key"),
-			environment=self.config.get("plaid_env")
-			)
-
 		self.access_token = access_token
+		self.settings = frappe.get_single("Plaid Settings")
+		self.products = ["auth", "transactions"]
+		self.client_name = frappe.local.site
+		self.client = plaid.Client(
+			client_id=self.settings.plaid_client_id,
+			secret=self.settings.get_password("plaid_secret"),
+			environment=self.settings.plaid_env,
+			api_version="2019-05-29"
+		)
 
 	def get_access_token(self, public_token):
 		if public_token is None:
 			frappe.log_error(_("Public token is missing for this bank"), _("Plaid public token error"))
-
 		response = self.client.Item.public_token.exchange(public_token)
-		access_token = response['access_token']
-
+		access_token = response["access_token"]
 		return access_token
 
+	def get_link_token(self):
+		token_request = {
+			"client_name": self.client_name,
+			"client_id": self.settings.plaid_client_id,
+			"secret": self.settings.plaid_secret,
+			"products": self.products,
+			# only allow Plaid-supported languages and countries (LAST: Sep-19-2020)
+			"language": frappe.local.lang if frappe.local.lang in ["en", "fr", "es", "nl"] else "en",
+			"country_codes": ["US", "CA", "FR", "IE", "NL", "ES", "GB"],
+			"user": {
+				"client_user_id": frappe.generate_hash(frappe.session.user, length=32)
+			}
+		}
+
+		try:
+			response = self.client.LinkToken.create(token_request)
+		except InvalidRequestError:
+			frappe.log_error(frappe.get_traceback(), _("Plaid invalid request error"))
+			frappe.msgprint(_("Please check your Plaid client ID and secret values"))
+		except APIError as e:
+			frappe.log_error(frappe.get_traceback(), _("Plaid authentication error"))
+			frappe.throw(_(str(e)), title=_("Authentication Failed"))
+		else:
+			return response["link_token"]
+
 	def auth(self):
 		try:
 			self.client.Auth.get(self.access_token)
-			print("Authentication successful.....")
 		except ItemError as e:
-			if e.code == 'ITEM_LOGIN_REQUIRED':
-				pass
-			else:
+			if e.code == "ITEM_LOGIN_REQUIRED":
 				pass
 		except APIError as e:
-			if e.code == 'PLANNED_MAINTENANCE':
-				pass
-			else:
+			if e.code == "PLANNED_MAINTENANCE":
 				pass
 		except requests.Timeout:
 			pass
 		except Exception as e:
-			print(e)
 			frappe.log_error(frappe.get_traceback(), _("Plaid authentication error"))
-			frappe.msgprint({"title": _("Authentication Failed"), "message":e, "raise_exception":1, "indicator":'red'})
+			frappe.throw(_(str(e)), title=_("Authentication Failed"))
 
 	def get_transactions(self, start_date, end_date, account_id=None):
+		self.auth()
+		kwargs = dict(
+			access_token=self.access_token,
+			start_date=start_date,
+			end_date=end_date
+		)
+		if account_id:
+			kwargs.update(dict(account_ids=[account_id]))
+
 		try:
-			self.auth()
-			if account_id:
-				account_ids = [account_id]
-
-				response = self.client.Transactions.get(self.access_token, start_date=start_date, end_date=end_date, account_ids=account_ids)
-
-			else:
-				response = self.client.Transactions.get(self.access_token, start_date=start_date, end_date=end_date)
-
-			transactions = response['transactions']
-
-			while len(transactions) < response['total_transactions']:
+			response = self.client.Transactions.get(**kwargs)
+			transactions = response["transactions"]
+			while len(transactions) < response["total_transactions"]:
 				response = self.client.Transactions.get(self.access_token, start_date=start_date, end_date=end_date, offset=len(transactions))
-				transactions.extend(response['transactions'])
+				transactions.extend(response["transactions"])
 			return transactions
 		except Exception:
 			frappe.log_error(frappe.get_traceback(), _("Plaid transactions sync error"))
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js
index 0ffbb87..22a4004 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js
@@ -4,14 +4,14 @@
 frappe.provide("erpnext.integrations");
 
 frappe.ui.form.on('Plaid Settings', {
-	enabled: function(frm) {
+	enabled: function (frm) {
 		frm.toggle_reqd('plaid_client_id', frm.doc.enabled);
 		frm.toggle_reqd('plaid_secret', frm.doc.enabled);
-		frm.toggle_reqd('plaid_public_key', frm.doc.enabled);
 		frm.toggle_reqd('plaid_env', frm.doc.enabled);
 	},
-	refresh: function(frm) {
-		if(frm.doc.enabled) {
+
+	refresh: function (frm) {
+		if (frm.doc.enabled) {
 			frm.add_custom_button('Link a new bank account', () => {
 				new erpnext.integrations.plaidLink(frm);
 			});
@@ -22,17 +22,16 @@
 erpnext.integrations.plaidLink = class plaidLink {
 	constructor(parent) {
 		this.frm = parent;
-		this.product = ["transactions", "auth"];
 		this.plaidUrl = 'https://cdn.plaid.com/link/v2/stable/link-initialize.js';
 		this.init_config();
 	}
 
-	init_config() {
-		const me = this;
-		me.plaid_env = me.frm.doc.plaid_env;
-		me.plaid_public_key = me.frm.doc.plaid_public_key;
-		me.client_name = frappe.boot.sitename;
-		me.init_plaid();
+	async init_config() {
+		this.product = ["auth", "transactions"];
+		this.plaid_env = this.frm.doc.plaid_env;
+		this.client_name = frappe.boot.sitename;
+		this.token = await this.frm.call("get_link_token").then(resp => resp.message);
+		this.init_plaid();
 	}
 
 	init_plaid() {
@@ -69,17 +68,17 @@
 	}
 
 	onScriptLoaded(me) {
-		me.linkHandler = window.Plaid.create({
+		me.linkHandler = Plaid.create({
 			clientName: me.client_name,
+			product: me.product,
 			env: me.plaid_env,
-			key: me.plaid_public_key,
-			onSuccess: me.plaid_success,
-			product: me.product
+			token: me.token,
+			onSuccess: me.plaid_success
 		});
 	}
 
 	onScriptError(error) {
-		frappe.msgprint('There was an issue loading the link-initialize.js script');
+		frappe.msgprint("There was an issue connecting to Plaid's authentication server");
 		frappe.msgprint(error);
 	}
 
@@ -87,21 +86,25 @@
 		const me = this;
 
 		frappe.prompt({
-			fieldtype:"Link",
+			fieldtype: "Link",
 			options: "Company",
-			label:__("Company"),
-			fieldname:"company",
-			reqd:1
+			label: __("Company"),
+			fieldname: "company",
+			reqd: 1
 		}, (data) => {
 			me.company = data.company;
-			frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.add_institution', {token: token, response: response})
-				.then((result) => {
-					frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.add_bank_accounts', {response: response,
-						bank: result, company: me.company});
-				})
-				.then(() => {
-					frappe.show_alert({message:__("Bank accounts added"), indicator:'green'});
+			frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.add_institution', {
+				token: token,
+				response: response
+			}).then((result) => {
+				frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.add_bank_accounts', {
+					response: response,
+					bank: result,
+					company: me.company
 				});
+			}).then(() => {
+				frappe.show_alert({ message: __("Bank accounts added"), indicator: 'green' });
+			});
 		}, __("Select a company"), __("Continue"));
 	}
 };
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.json b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.json
index d8203d7..2706217 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.json
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.json
@@ -1,5 +1,4 @@
 {
- "actions": [],
  "creation": "2018-10-25 10:02:48.656165",
  "doctype": "DocType",
  "editable_grid": 1,
@@ -12,7 +11,6 @@
   "plaid_client_id",
   "plaid_secret",
   "column_break_7",
-  "plaid_public_key",
   "plaid_env"
  ],
  "fields": [
@@ -42,12 +40,6 @@
    "label": "Plaid Secret"
   },
   {
-   "fieldname": "plaid_public_key",
-   "fieldtype": "Data",
-   "in_list_view": 1,
-   "label": "Plaid Public Key"
-  },
-  {
    "fieldname": "plaid_env",
    "fieldtype": "Select",
    "in_list_view": 1,
@@ -69,8 +61,7 @@
   }
  ],
  "issingle": 1,
- "links": [],
- "modified": "2020-02-07 15:21:11.616231",
+ "modified": "2020-09-12 02:31:44.542385",
  "modified_by": "Administrator",
  "module": "ERPNext Integrations",
  "name": "Plaid Settings",
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
index c3371ed..e535e81 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
@@ -2,30 +2,36 @@
 # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
 # For license information, please see license.txt
 
-from __future__ import unicode_literals
-import frappe
 import json
-from frappe import _
-from frappe.model.document import Document
+
+import frappe
 from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
 from erpnext.erpnext_integrations.doctype.plaid_settings.plaid_connector import PlaidConnector
-from frappe.utils import getdate, formatdate, today, add_months
+from frappe import _
 from frappe.desk.doctype.tag.tag import add_tag
+from frappe.model.document import Document
+from frappe.utils import add_months, formatdate, getdate, today
+
 
 class PlaidSettings(Document):
-	pass
+	@staticmethod
+	def get_link_token():
+		plaid = PlaidConnector()
+		return plaid.get_link_token()
+
 
 @frappe.whitelist()
-def plaid_configuration():
+def get_plaid_configuration():
 	if frappe.db.get_single_value("Plaid Settings", "enabled"):
 		plaid_settings = frappe.get_single("Plaid Settings")
 		return {
-			"plaid_public_key": plaid_settings.plaid_public_key,
 			"plaid_env": plaid_settings.plaid_env,
+			"link_token": plaid_settings.get_link_token(),
 			"client_name": frappe.local.site
 		}
-	else:
-		return "disabled"
+
+	return "disabled"
+
 
 @frappe.whitelist()
 def add_institution(token, response):
@@ -33,6 +39,7 @@
 
 	plaid = PlaidConnector()
 	access_token = plaid.get_access_token(token)
+	bank = None
 
 	if not frappe.db.exists("Bank", response["institution"]["name"]):
 		try:
@@ -44,7 +51,6 @@
 			bank.insert()
 		except Exception:
 			frappe.throw(frappe.get_traceback())
-
 	else:
 		bank = frappe.get_doc("Bank", response["institution"]["name"])
 		bank.plaid_access_token = access_token
@@ -52,6 +58,7 @@
 
 	return bank
 
+
 @frappe.whitelist()
 def add_bank_accounts(response, bank, company):
 	try:
@@ -92,9 +99,8 @@
 				new_account.insert()
 
 				result.append(new_account.name)
-
 			except frappe.UniqueValidationError:
-				frappe.msgprint(_("Bank account {0} already exists and could not be created again").format(new_account.account_name))
+				frappe.msgprint(_("Bank account {0} already exists and could not be created again").format(account["name"]))
 			except Exception:
 				frappe.throw(frappe.get_traceback())
 
@@ -103,6 +109,7 @@
 
 	return result
 
+
 def add_account_type(account_type):
 	try:
 		frappe.get_doc({
@@ -122,10 +129,11 @@
 	except Exception:
 		frappe.throw(frappe.get_traceback())
 
+
 @frappe.whitelist()
 def sync_transactions(bank, bank_account):
-	'''Sync transactions based on the last integration date as the start date, after the sync is completed
-		add the transaction date of the oldest transaction as the last integration date'''
+	"""Sync transactions based on the last integration date as the start date, after sync is completed
+	add the transaction date of the oldest transaction as the last integration date."""
 	last_transaction_date = frappe.db.get_value("Bank Account", bank_account, "last_integration_date")
 	if last_transaction_date:
 		start_date = formatdate(last_transaction_date, "YYYY-MM-dd")
@@ -147,10 +155,10 @@
 				len(result), bank_account, start_date, end_date))
 
 			frappe.db.set_value("Bank Account", bank_account, "last_integration_date", last_transaction_date)
-
 	except Exception:
 		frappe.log_error(frappe.get_traceback(), _("Plaid transactions sync error"))
 
+
 def get_transactions(bank, bank_account=None, start_date=None, end_date=None):
 	access_token = None
 
@@ -168,6 +176,7 @@
 
 	return transactions
 
+
 def new_bank_transaction(transaction):
 	result = []
 
@@ -182,8 +191,8 @@
 
 	status = "Pending" if transaction["pending"] == "True" else "Settled"
 
+	tags = []
 	try:
-		tags  = []
 		tags += transaction["category"]
 		tags += ["Plaid Cat. {}".format(transaction["category_id"])]
 	except KeyError:
@@ -216,6 +225,7 @@
 
 	return result
 
+
 def automatic_synchronization():
 	settings = frappe.get_doc("Plaid Settings", "Plaid Settings")
 
@@ -223,4 +233,8 @@
 		plaid_accounts = frappe.get_all("Bank Account", filters={"integration_id": ["!=", ""]}, fields=["name", "bank"])
 
 		for plaid_account in plaid_accounts:
-			frappe.enqueue("erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.sync_transactions", bank=plaid_account.bank, bank_account=plaid_account.name)
+			frappe.enqueue(
+				"erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.sync_transactions",
+				bank=plaid_account.bank,
+				bank_account=plaid_account.name
+			)
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py
index 1a063d6..3c90637 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py
@@ -1,14 +1,17 @@
 # -*- coding: utf-8 -*-
 # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
 # See license.txt
-from __future__ import unicode_literals
 
-import unittest
-import frappe
-from erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings import plaid_configuration, add_account_type, add_account_subtype, new_bank_transaction, add_bank_accounts
 import json
-from frappe.utils.response import json_handler
+import unittest
+
+import frappe
 from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
+from erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings import (
+	add_account_subtype, add_account_type, add_bank_accounts,
+	new_bank_transaction, get_plaid_configuration)
+from frappe.utils.response import json_handler
+
 
 class TestPlaidSettings(unittest.TestCase):
 	def setUp(self):
@@ -31,7 +34,7 @@
 
 	def test_plaid_disabled(self):
 		frappe.db.set_value("Plaid Settings", None, "enabled", 0)
-		self.assertTrue(plaid_configuration() == "disabled")
+		self.assertTrue(get_plaid_configuration() == "disabled")
 
 	def test_add_account_type(self):
 		add_account_type("brokerage")
@@ -64,7 +67,7 @@
 				'mask': '0000',
 				'id': '6GbM6RRQgdfy3lAqGz4JUnpmR948WZFg8DjQK',
 				'name': 'Plaid Checking'
-				}],
+			}],
 			'institution': {
 				'institution_id': 'ins_6',
 				'name': 'Citi'
@@ -100,7 +103,7 @@
 				'mask': '0000',
 				'id': '6GbM6RRQgdfy3lAqGz4JUnpmR948WZFg8DjQK',
 				'name': 'Plaid Checking'
-				}],
+			}],
 			'institution': {
 				'institution_id': 'ins_6',
 				'name': 'Citi'
@@ -152,4 +155,4 @@
 
 		new_bank_transaction(transactions)
 
-		self.assertTrue(len(frappe.get_all("Bank Transaction")) == 1)
\ No newline at end of file
+		self.assertTrue(len(frappe.get_all("Bank Transaction")) == 1)
diff --git a/erpnext/patches/v12_0/move_plaid_settings_to_doctype.py b/erpnext/patches/v12_0/move_plaid_settings_to_doctype.py
index 8e60d33..d2bcb12 100644
--- a/erpnext/patches/v12_0/move_plaid_settings_to_doctype.py
+++ b/erpnext/patches/v12_0/move_plaid_settings_to_doctype.py
@@ -4,17 +4,16 @@
 from __future__ import unicode_literals
 import frappe
 
+
 def execute():
 	frappe.reload_doc("erpnext_integrations", "doctype", "plaid_settings")
 	plaid_settings = frappe.get_single("Plaid Settings")
 	if plaid_settings.enabled:
-		if not (frappe.conf.plaid_client_id and frappe.conf.plaid_env \
-			and frappe.conf.plaid_public_key and frappe.conf.plaid_secret):
+		if not (frappe.conf.plaid_client_id and frappe.conf.plaid_env and frappe.conf.plaid_secret):
 			plaid_settings.enabled = 0
 		else:
 			plaid_settings.update({
 				"plaid_client_id": frappe.conf.plaid_client_id,
-				"plaid_public_key": frappe.conf.plaid_public_key,
 				"plaid_env": frappe.conf.plaid_env,
 				"plaid_secret": frappe.conf.plaid_secret
 			})
diff --git a/erpnext/public/js/conf.js b/erpnext/public/js/conf.js
index 2af9140..eb709e5 100644
--- a/erpnext/public/js/conf.js
+++ b/erpnext/public/js/conf.js
@@ -11,7 +11,9 @@
 	"Territory": "Selling",
 	"Sales Person": "Selling",
 	"Sales Partner": "Selling",
-	"Brand": "Stock"
+	"Brand": "Stock",
+	"Maintenance Schedule": "Support",
+	"Maintenance Visit": "Support"
 });
 
 $.extend(frappe.breadcrumbs.module_map, {
diff --git a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.js b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.js
index 23700c9..2499c80 100644
--- a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.js
+++ b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.js
@@ -9,13 +9,15 @@
 			"fieldtype": "Date",
 			"width": "80",
 			"default": frappe.sys_defaults.year_start_date,
+			"reqd": 1
 		},
 		{
 			"fieldname":"to_date",
 			"label": __("To Date"),
 			"fieldtype": "Date",
 			"width": "80",
-			"default": frappe.datetime.get_today()
+			"default": frappe.datetime.get_today(),
+			"reqd": 1
 		},
 		{
 			"fieldname": "item",
diff --git a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
index 2c95084..8f3e246 100644
--- a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
+++ b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
@@ -11,6 +11,9 @@
 def execute(filters=None):
 	if not filters: filters = {}
 
+	if filters.from_date > filters.to_date:
+		frappe.throw(_("From Date must be before To Date"))
+
 	float_precision = cint(frappe.db.get_default("float_precision")) or 3
 
 	columns = get_columns(filters)
diff --git a/erpnext/utilities/activation.py b/erpnext/utilities/activation.py
index 63c36b3..7b17c8c 100644
--- a/erpnext/utilities/activation.py
+++ b/erpnext/utilities/activation.py
@@ -11,8 +11,39 @@
 	activation_level = 0
 	sales_data = []
 	min_count = 0
-	doctypes = {"Item": 5, "Customer": 5, "Sales Order": 2, "Sales Invoice": 2, "Purchase Order": 2, "Employee": 3, "Lead": 3, "Quotation": 3,
-					"Payment Entry": 2, "User": 5, "Student": 5, "Instructor": 5, "BOM": 3, "Journal Entry": 3, "Stock Entry": 3}
+	doctypes = {
+		"Asset": 5,
+		"BOM": 3, 
+		"Customer": 5, 
+		"Delivery Note": 5,
+		"Employee": 3, 
+		"Instructor": 5, 
+		"Instructor": 5, 
+		"Issue": 5,
+		"Item": 5, 
+		"Journal Entry": 3, 
+		"Lead": 3,
+		"Leave Application": 5,
+		"Material Request": 5,
+		"Opportunity": 5, 
+		"Payment Entry": 2, 
+		"Project": 5,
+		"Purchase Order": 2, 
+		"Purchase Invoice": 5,
+		"Purchase Receipt": 5,
+		"Quotation": 3,
+		"Salary Slip": 5,
+		"Salary Structure": 5,
+		"Sales Order": 2, 
+		"Sales Invoice": 2, 
+		"Stock Entry": 3,
+		"Student": 5, 
+		"Supplier": 5,
+		"Task": 5,
+		"User": 5, 
+		"Work Order": 5
+	}
+
 	for doctype, min_count in iteritems(doctypes):
 		count = frappe.db.count(doctype)
 		if count > min_count:
diff --git a/requirements.txt b/requirements.txt
index 912d61f..b7ba412 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==3.4.0
+plaid-python==6.0.0
 pycountry==19.8.18
 PyGithub==1.44.1
 python-stdnum==1.12