Merge pull request #25850 from gavindsouza/rm-py2

fix: Add future in requirements.txt
diff --git a/.flake8 b/.flake8
index 399b176..56c9b9a 100644
--- a/.flake8
+++ b/.flake8
@@ -29,4 +29,5 @@
     B950,
     W191,
 
-max-line-length = 200
\ No newline at end of file
+max-line-length = 200
+exclude=.github/helper/semgrep_rules
diff --git a/.github/helper/semgrep_rules/frappe_correctness.py b/.github/helper/semgrep_rules/frappe_correctness.py
index 4798b92..745e646 100644
--- a/.github/helper/semgrep_rules/frappe_correctness.py
+++ b/.github/helper/semgrep_rules/frappe_correctness.py
@@ -4,25 +4,61 @@
 from frappe.model.document import Document
 
 
+# ruleid: frappe-modifying-but-not-comitting
 def on_submit(self):
 	if self.value_of_goods == 0:
 		frappe.throw(_('Value of goods cannot be 0'))
-	# ruleid: frappe-modifying-after-submit
 	self.status = 'Submitted'
 
+
+# ok: frappe-modifying-but-not-comitting
 def on_submit(self):
-	if flt(self.per_billed) < 100:
-		self.update_billing_status()
-	else:
-		# todook: frappe-modifying-after-submit
-		self.status = "Completed"
-		self.db_set("status", "Completed")
+	if self.value_of_goods == 0:
+		frappe.throw(_('Value of goods cannot be 0'))
+	self.status = 'Submitted'
+	self.db_set('status', 'Submitted')
 
-class TestDoc(Document):
-	pass
+# ok: frappe-modifying-but-not-comitting
+def on_submit(self):
+	if self.value_of_goods == 0:
+		frappe.throw(_('Value of goods cannot be 0'))
+	x = "y"
+	self.status = x
+	self.db_set('status', x)
 
-	def validate(self):
-		#ruleid: frappe-modifying-child-tables-while-iterating
-		for item in self.child_table:
-			if item.value < 0:
-				self.remove(item)
+
+# ok: frappe-modifying-but-not-comitting
+def on_submit(self):
+	x = "y"
+	self.status = x
+	self.save()
+
+# ruleid: frappe-modifying-but-not-comitting-other-method
+class DoctypeClass(Document):
+	def on_submit(self):
+		self.good_method()
+		self.tainted_method()
+
+	def tainted_method(self):
+		self.status = "uptate"
+
+
+# ok: frappe-modifying-but-not-comitting-other-method
+class DoctypeClass(Document):
+	def on_submit(self):
+		self.good_method()
+		self.tainted_method()
+
+	def tainted_method(self):
+		self.status = "update"
+		self.db_set("status", "update")
+
+# ok: frappe-modifying-but-not-comitting-other-method
+class DoctypeClass(Document):
+	def on_submit(self):
+		self.good_method()
+		self.tainted_method()
+		self.save()
+
+	def tainted_method(self):
+		self.status = "uptate"
diff --git a/.github/helper/semgrep_rules/frappe_correctness.yml b/.github/helper/semgrep_rules/frappe_correctness.yml
index 54df062..faab334 100644
--- a/.github/helper/semgrep_rules/frappe_correctness.yml
+++ b/.github/helper/semgrep_rules/frappe_correctness.yml
@@ -1,32 +1,93 @@
 # This file specifies rules for correctness according to how frappe doctype data model works.
 
 rules:
-- id: frappe-modifying-after-submit
+- id: frappe-modifying-but-not-comitting
   patterns:
-    - pattern: self.$ATTR = ...
-    - pattern-inside: |
-        def on_submit(self, ...):
+    - pattern: |
+        def $METHOD(self, ...):
           ...
+          self.$ATTR = ...
+    - pattern-not: |
+        def $METHOD(self, ...):
+          ...
+          self.$ATTR = ...
+          ...
+          self.db_set(..., self.$ATTR, ...)
+    - pattern-not: |
+        def $METHOD(self, ...):
+          ...
+          self.$ATTR = $SOME_VAR
+          ...
+          self.db_set(..., $SOME_VAR, ...)
+    - pattern-not: |
+        def $METHOD(self, ...):
+          ...
+          self.$ATTR = $SOME_VAR
+          ...
+          self.save()
     - metavariable-regex:
         metavariable: '$ATTR'
         # this is negative look-ahead, add more attrs to ignore like (ignore|ignore_this_too|ignore_me)
-        regex: '^(?!status_updater)(.*)$'
+        regex: '^(?!ignore_linked_doctypes|status_updater)(.*)$'
+    - metavariable-regex:
+        metavariable: "$METHOD"
+        regex: "(on_submit|on_cancel)"
   message: |
-    Doctype modified after submission. Please check if modification of self.$ATTR is commited to database.
+    DocType modified in self.$METHOD. Please check if modification of self.$ATTR is commited to database.
   languages: [python]
   severity: ERROR
 
-- id: frappe-modifying-after-cancel
+- id: frappe-modifying-but-not-comitting-other-method
   patterns:
-    - pattern: self.$ATTR = ...
-    - pattern-inside: |
-        def on_cancel(self, ...):
+  - pattern: |
+      class $DOCTYPE(...):
+        def $METHOD(self, ...):
           ...
-    - metavariable-regex:
-        metavariable: '$ATTR'
-        regex: '^(?!ignore_linked_doctypes|status_updater)(.*)$'
+          self.$ANOTHER_METHOD()
+          ...
+
+        def $ANOTHER_METHOD(self, ...):
+          ...
+          self.$ATTR = ...
+  - pattern-not: |
+      class $DOCTYPE(...):
+        def $METHOD(self, ...):
+          ...
+          self.$ANOTHER_METHOD()
+          ...
+
+        def $ANOTHER_METHOD(self, ...):
+          ...
+          self.$ATTR = ...
+          ...
+          self.db_set(..., self.$ATTR, ...)
+  - pattern-not: |
+      class $DOCTYPE(...):
+        def $METHOD(self, ...):
+          ...
+          self.$ANOTHER_METHOD()
+          ...
+
+        def $ANOTHER_METHOD(self, ...):
+          ...
+          self.$ATTR = $SOME_VAR
+          ...
+          self.db_set(..., $SOME_VAR, ...)
+  - pattern-not: |
+      class $DOCTYPE(...):
+        def $METHOD(self, ...):
+          ...
+          self.$ANOTHER_METHOD()
+          ...
+          self.save()
+        def $ANOTHER_METHOD(self, ...):
+          ...
+          self.$ATTR = ...
+  - metavariable-regex:
+      metavariable: "$METHOD"
+      regex: "(on_submit|on_cancel)"
   message: |
-    Doctype modified after cancellation. Please check if modification of self.$ATTR is commited to database.
+    self.$ANOTHER_METHOD is called from self.$METHOD, check if changes to self.$ATTR are commited to database.
   languages: [python]
   severity: ERROR
 
diff --git a/.github/helper/semgrep_rules/translate.js b/.github/helper/semgrep_rules/translate.js
index 7b92fe2..9cdfb75 100644
--- a/.github/helper/semgrep_rules/translate.js
+++ b/.github/helper/semgrep_rules/translate.js
@@ -35,3 +35,10 @@
 // ruleid: frappe-translation-js-splitting
 __('You have {0} subscribers' +
     'in your mailing list', [subscribers.length])
+
+// ok: frappe-translation-js-splitting
+__("Ctrl+Enter to add comment")
+
+// ruleid: frappe-translation-js-splitting
+__('You have {0} subscribers \
+    in your mailing list', [subscribers.length])
diff --git a/.github/helper/semgrep_rules/translate.py b/.github/helper/semgrep_rules/translate.py
index bd6cd91..9de6aa9 100644
--- a/.github/helper/semgrep_rules/translate.py
+++ b/.github/helper/semgrep_rules/translate.py
@@ -51,3 +51,11 @@
 _("")
 # ruleid: frappe-translation-empty-string
 _('')
+
+
+class Test:
+	# ok: frappe-translation-python-splitting
+	def __init__(
+			args
+			):
+		pass
diff --git a/.github/helper/semgrep_rules/translate.yml b/.github/helper/semgrep_rules/translate.yml
index 3737da5..5f03fb9 100644
--- a/.github/helper/semgrep_rules/translate.yml
+++ b/.github/helper/semgrep_rules/translate.yml
@@ -42,9 +42,10 @@
 
 - id: frappe-translation-python-splitting
   pattern-either:
-  - pattern: _(...) + ... + _(...)
+  - pattern: _(...) + _(...)
   - pattern: _("..." + "...")
-  - pattern-regex: '_\([^\)]*\\\s*'
+  - pattern-regex: '[\s\.]_\([^\)]*\\\s*'    # lines broken by `\`
+  - pattern-regex: '[\s\.]_\(\s*\n'          # line breaks allowed by python for using ( )
   message: |
     Do not split strings inside translate function. Do not concatenate using translate functions.
     Please refer: https://frappeframework.com/docs/user/en/translations
@@ -53,8 +54,8 @@
 
 - id: frappe-translation-js-splitting
   pattern-either:
-  - pattern-regex: '__\([^\)]*[\+\\]\s*'
-  - pattern: __('...' + '...')
+  - pattern-regex: '__\([^\)]*[\\]\s+'
+  - pattern: __('...' + '...', ...)
   - pattern: __('...') + __('...')
   message: |
     Do not split strings inside translate function. Do not concatenate using translate functions.
diff --git a/.github/helper/semgrep_rules/ux.js b/.github/helper/semgrep_rules/ux.js
new file mode 100644
index 0000000..ae73f9c
--- /dev/null
+++ b/.github/helper/semgrep_rules/ux.js
@@ -0,0 +1,9 @@
+
+// ok: frappe-missing-translate-function-js
+frappe.msgprint('{{ _("Both login and password required") }}');
+
+// ruleid: frappe-missing-translate-function-js
+frappe.msgprint('What');
+
+// ok: frappe-missing-translate-function-js
+frappe.throw('  {{ _("Both login and password required") }}.  ');
diff --git a/.github/helper/semgrep_rules/ux.py b/.github/helper/semgrep_rules/ux.py
index 4a74457..a00d3cd 100644
--- a/.github/helper/semgrep_rules/ux.py
+++ b/.github/helper/semgrep_rules/ux.py
@@ -2,30 +2,30 @@
 from frappe import msgprint, throw, _
 
 
-# ruleid: frappe-missing-translate-function
+# ruleid: frappe-missing-translate-function-python
 throw("Error Occured")
 
-# ruleid: frappe-missing-translate-function
+# ruleid: frappe-missing-translate-function-python
 frappe.throw("Error Occured")
 
-# ruleid: frappe-missing-translate-function
+# ruleid: frappe-missing-translate-function-python
 frappe.msgprint("Useful message")
 
-# ruleid: frappe-missing-translate-function
+# ruleid: frappe-missing-translate-function-python
 msgprint("Useful message")
 
 
-# ok: frappe-missing-translate-function
+# ok: frappe-missing-translate-function-python
 translatedmessage = _("Hello")
 
-# ok: frappe-missing-translate-function
+# ok: frappe-missing-translate-function-python
 throw(translatedmessage)
 
-# ok: frappe-missing-translate-function
+# ok: frappe-missing-translate-function-python
 msgprint(translatedmessage)
 
-# ok: frappe-missing-translate-function
+# ok: frappe-missing-translate-function-python
 msgprint(_("Helpful message"))
 
-# ok: frappe-missing-translate-function
+# ok: frappe-missing-translate-function-python
 frappe.throw(_("Error occured"))
diff --git a/.github/helper/semgrep_rules/ux.yml b/.github/helper/semgrep_rules/ux.yml
index ed06a6a..dd667f3 100644
--- a/.github/helper/semgrep_rules/ux.yml
+++ b/.github/helper/semgrep_rules/ux.yml
@@ -1,15 +1,30 @@
 rules:
-- id: frappe-missing-translate-function
+- id: frappe-missing-translate-function-python
   pattern-either:
   - patterns:
       - pattern: frappe.msgprint("...", ...)
       - pattern-not: frappe.msgprint(_("..."), ...)
-      - pattern-not: frappe.msgprint(__("..."), ...)
   - patterns:
       - pattern: frappe.throw("...", ...)
       - pattern-not: frappe.throw(_("..."), ...)
-      - pattern-not: frappe.throw(__("..."), ...)
   message: |
       All user facing text must be wrapped in translate function. Please refer to translation documentation. https://frappeframework.com/docs/user/en/guides/basics/translations
-  languages: [python, javascript, json]
+  languages: [python]
+  severity: ERROR
+
+- id: frappe-missing-translate-function-js
+  pattern-either:
+  - patterns:
+      - pattern: frappe.msgprint("...", ...)
+      - pattern-not: frappe.msgprint(__("..."), ...)
+      # ignore microtemplating e.g. msgprint("{{ _("server side translation") }}")
+      - pattern-not: frappe.msgprint("=~/\{\{.*\_.*\}\}/i", ...)
+  - patterns:
+      - pattern: frappe.throw("...", ...)
+      - pattern-not: frappe.throw(__("..."), ...)
+      # ignore microtemplating
+      - pattern-not: frappe.throw("=~/\{\{.*\_.*\}\}/i", ...)
+  message: |
+      All user facing text must be wrapped in translate function. Please refer to translation documentation. https://frappeframework.com/docs/user/en/guides/basics/translations
+  languages: [javascript]
   severity: ERROR
diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml
index df08263..389524e 100644
--- a/.github/workflows/semgrep.yml
+++ b/.github/workflows/semgrep.yml
@@ -4,6 +4,8 @@
   pull_request:
     branches:
       - develop
+      - version-13-hotfix
+      - version-13-pre-release
 jobs:
   semgrep:
     name: Frappe Linter
@@ -14,11 +16,19 @@
       uses: actions/setup-python@v2
       with:
         python-version: 3.8
-    - name: Run semgrep
+
+    - name: Setup semgrep
       run: |
         python -m pip install -q semgrep
         git fetch origin $GITHUB_BASE_REF:$GITHUB_BASE_REF -q
+
+    - name: Semgrep errors
+      run: |
         files=$(git diff --name-only --diff-filter=d $GITHUB_BASE_REF)
         [[ -d .github/helper/semgrep_rules ]] && semgrep --severity ERROR --config=.github/helper/semgrep_rules --quiet --error $files
         semgrep --config="r/python.lang.correctness" --quiet --error $files
+
+    - name: Semgrep warnings
+      run: |
+        files=$(git diff --name-only --diff-filter=d $GITHUB_BASE_REF)
         [[ -d .github/helper/semgrep_rules ]] && semgrep --severity WARNING --severity INFO --config=.github/helper/semgrep_rules --quiet $files
diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml
index 672d965..69afa15 100644
--- a/.github/workflows/server-tests.yml
+++ b/.github/workflows/server-tests.yml
@@ -91,6 +91,7 @@
           coveralls
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
           COVERALLS_FLAG_NAME: run-${{ matrix.container }}
           COVERALLS_SERVICE_NAME: ${{ github.event_name == 'pull_request' && 'github' || 'github-actions' }}
           COVERALLS_PARALLEL: true
diff --git a/.pylintrc b/.pylintrc
deleted file mode 100644
index 4b2ea0a..0000000
--- a/.pylintrc
+++ /dev/null
@@ -1 +0,0 @@
-disable=access-member-before-definition
\ No newline at end of file
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 8d17674..5808090 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -5,7 +5,7 @@
 from erpnext.hooks import regional_overrides
 from frappe.utils import getdate
 
-__version__ = '13.3.1'
+__version__ = '13.4.1'
 
 def get_default_company(user=None):
 	'''Get default company for user'''
diff --git a/erpnext/accounts/deferred_revenue.py b/erpnext/accounts/deferred_revenue.py
index d5ab1c1..dd346bc 100644
--- a/erpnext/accounts/deferred_revenue.py
+++ b/erpnext/accounts/deferred_revenue.py
@@ -41,7 +41,7 @@
 	if account:
 		conditions += "AND %s='%s'"%(deferred_account, account)
 	elif company:
-		conditions += "AND p.company='%s'"%(company)
+		conditions += f"AND p.company = {frappe.db.escape(company)}"
 
 	return conditions
 
@@ -360,12 +360,10 @@
 			frappe.flags.deferred_accounting_error = True
 
 def send_mail(deferred_process):
-	title = _("Error while processing deferred accounting for {0}".format(deferred_process))
-	content = _("""
-		Deferred accounting failed for some invoices:
-		Please check Process Deferred Accounting {0}
-		and submit manually after resolving errors
-	""").format(get_link_to_form('Process Deferred Accounting', deferred_process))
+	title = _("Error while processing deferred accounting for {0}").format(deferred_process)
+	link = get_link_to_form('Process Deferred Accounting', deferred_process)
+	content = _("Deferred accounting failed for some invoices:") + "\n"
+	content += _("Please check Process Deferred Accounting {0} and submit manually after resolving errors.").format(link)
 	sendmail_to_system_managers(title, content)
 
 def book_revenue_via_journal_entry(doc, credit_account, debit_account, against,
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 78febf9..948c513 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -75,8 +75,13 @@
 	def pl_must_have_cost_center(self):
 		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))
+				msg = _("{0} {1}: Cost Center is required for 'Profit and Loss' account {2}.").format(
+					self.voucher_type, self.voucher_no, self.account)
+				msg += " "
+				msg += _("Please set the cost center field in {0} or setup a default Cost Center for the Company.").format(
+					self.voucher_type)
+
+				frappe.throw(msg, title=_("Missing Cost Center"))
 
 	def validate_dimensions_for_pl_and_bs(self):
 		account_type = frappe.db.get_value("Account", self.account, "report_type")
diff --git a/erpnext/accounts/doctype/gst_account/gst_account.json b/erpnext/accounts/doctype/gst_account/gst_account.json
index 7067338..b6ec884 100644
--- a/erpnext/accounts/doctype/gst_account/gst_account.json
+++ b/erpnext/accounts/doctype/gst_account/gst_account.json
@@ -1,196 +1,82 @@
 {
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "beta": 0, 
- "creation": "2018-01-02 15:48:58.768352", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 1, 
- "engine": "InnoDB", 
+ "actions": [],
+ "creation": "2018-01-02 15:48:58.768352",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "company",
+  "cgst_account",
+  "sgst_account",
+  "igst_account",
+  "cess_account",
+  "is_reverse_charge_account"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 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": 1, 
-   "in_standard_filter": 0, 
-   "label": "Company", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Company", 
-   "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
-  }, 
+   "columns": 1,
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Company",
+   "options": "Company",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "cgst_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": "CGST 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, 
-   "unique": 0
-  }, 
+   "columns": 2,
+   "fieldname": "cgst_account",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "CGST Account",
+   "options": "Account",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "sgst_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": "SGST 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, 
-   "unique": 0
-  }, 
+   "columns": 2,
+   "fieldname": "sgst_account",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "SGST Account",
+   "options": "Account",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "igst_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": "IGST 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, 
-   "unique": 0
-  }, 
+   "columns": 2,
+   "fieldname": "igst_account",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "IGST Account",
+   "options": "Account",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "cess_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": "CESS 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
+   "columns": 2,
+   "fieldname": "cess_account",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "CESS Account",
+   "options": "Account"
+  },
+  {
+   "columns": 1,
+   "default": "0",
+   "fieldname": "is_reverse_charge_account",
+   "fieldtype": "Check",
+   "in_list_view": 1,
+   "label": "Is Reverse Charge Account"
   }
- ], 
- "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-02 15:52:22.335988", 
- "modified_by": "Administrator", 
- "module": "Accounts", 
- "name": "GST Account", 
- "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
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-04-09 12:30:25.889993",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "GST Account",
+ "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/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index fefab82..ed1bd28 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -39,7 +39,11 @@
 		self.validate_multi_currency()
 		self.set_amounts_in_company_currency()
 		self.validate_debit_credit_amount()
-		self.validate_total_debit_and_credit()
+
+		# Do not validate while importing via data import
+		if not frappe.flags.in_import:
+			self.validate_total_debit_and_credit()
+
 		self.validate_against_jv()
 		self.validate_reference_doc()
 		self.set_against_account()
diff --git a/erpnext/accounts/doctype/journal_entry/regional/india.js b/erpnext/accounts/doctype/journal_entry/regional/india.js
new file mode 100644
index 0000000..75a69ac
--- /dev/null
+++ b/erpnext/accounts/doctype/journal_entry/regional/india.js
@@ -0,0 +1,17 @@
+frappe.ui.form.on("Journal Entry", {
+	refresh: function(frm) {
+		frm.set_query('company_address', function(doc) {
+			if(!doc.company) {
+				frappe.throw(__('Please set Company'));
+			}
+
+			return {
+				query: 'frappe.contacts.doctype.address.address.address_query',
+				filters: {
+					link_doctype: 'Company',
+					link_name: doc.company
+				}
+			};
+		});
+	}
+});
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/pos_closing_entry_detail/pos_closing_entry_detail.json b/erpnext/accounts/doctype/pos_closing_entry_detail/pos_closing_entry_detail.json
index 6e7768d..bbf1ba0 100644
--- a/erpnext/accounts/doctype/pos_closing_entry_detail/pos_closing_entry_detail.json
+++ b/erpnext/accounts/doctype/pos_closing_entry_detail/pos_closing_entry_detail.json
@@ -46,6 +46,7 @@
    "reqd": 1
   },
   {
+   "default": "0",
    "fieldname": "closing_amount",
    "fieldtype": "Currency",
    "in_list_view": 1,
@@ -57,7 +58,7 @@
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-10-23 16:45:43.662034",
+ "modified": "2021-05-19 20:08:44.523861",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "POS Closing Entry Detail",
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
index 473db56..f55fdab 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
@@ -455,32 +455,26 @@
 
 @frappe.whitelist()
 def get_stock_availability(item_code, warehouse):
-	latest_sle = frappe.db.sql("""select qty_after_transaction
-		from `tabStock Ledger Entry`
+	bin_qty = frappe.db.sql("""select actual_qty from `tabBin`
 		where item_code = %s and warehouse = %s
-		order by posting_date desc, posting_time desc
 		limit 1""", (item_code, warehouse), as_dict=1)
 
 	pos_sales_qty = get_pos_reserved_qty(item_code, warehouse)
 
-	sle_qty = latest_sle[0].qty_after_transaction or 0 if latest_sle else 0
+	bin_qty = bin_qty[0].actual_qty or 0 if bin_qty else 0
 
-	if sle_qty and pos_sales_qty:
-		return sle_qty - pos_sales_qty
-	else:
-		return sle_qty
+	return bin_qty - pos_sales_qty
 
 def get_pos_reserved_qty(item_code, warehouse):
 	reserved_qty = frappe.db.sql("""select sum(p_item.qty) as qty
 		from `tabPOS Invoice` p, `tabPOS Invoice Item` p_item
 		where p.name = p_item.parent
-		and p.consolidated_invoice is NULL
-		and p.docstatus = 1
+		and ifnull(p.consolidated_invoice, '') = ''
 		and p_item.docstatus = 1
 		and p_item.item_code = %s
 		and p_item.warehouse = %s
 		""", (item_code, warehouse), as_dict=1)
-	
+
 	return reserved_qty[0].qty or 0 if reserved_qty else 0
 
 @frappe.whitelist()
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 bc78743..08e072e 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
@@ -42,8 +42,9 @@
 				if return_against_status != "Consolidated":
 					# if return entry is not getting merged in the current pos closing and if it is not consolidated
 					bold_unconsolidated = frappe.bold("not Consolidated")
-					msg = (_("Row #{}: Original Invoice {} of return invoice {} is {}. ")
+					msg = (_("Row #{}: Original Invoice {} of return invoice {} is {}.")
 								.format(d.idx, bold_return_against, bold_pos_invoice, bold_unconsolidated))
+					msg += " "
 					msg += _("Original invoice should be consolidated before or along with the return invoice.")
 					msg += "<br><br>"
 					msg += _("You can add original invoice {} manually to proceed.").format(bold_return_against)
@@ -56,12 +57,12 @@
 		sales = [d for d in pos_invoice_docs if d.get('is_return') == 0]
 
 		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)
 
+		if sales:
+			sales_invoice = self.process_merging_into_sales_invoice(sales)
+
 		self.save() # save consolidated_sales_invoice & consolidated_credit_note ref in merge log
 
 		self.update_pos_invoices(pos_invoice_docs, sales_invoice, credit_note)
@@ -274,9 +275,9 @@
 			closing_entry.db_set('error_message', '')
 			closing_entry.update_opening_entry()
 
-	except Exception:
+	except Exception as e:
 		frappe.db.rollback()
-		message_log = frappe.message_log.pop()
+		message_log = frappe.message_log.pop() if frappe.message_log else str(e)
 		error_message = safe_load_json(message_log)
 
 		if closing_entry:
@@ -300,9 +301,9 @@
 			closing_entry.db_set('error_message', '')
 			closing_entry.update_opening_entry(for_cancel=True)
 
-	except Exception:
+	except Exception as e:
 		frappe.db.rollback()
-		message_log = frappe.message_log.pop()
+		message_log = frappe.message_log.pop() if frappe.message_log else str(e)
 		error_message = safe_load_json(message_log)
 
 		if closing_entry:
@@ -348,11 +349,9 @@
 		return True
 
 def safe_load_json(message):
-	JSONDecodeError = ValueError if six.PY2 else json.JSONDecodeError
-
 	try:
 		json_message = json.loads(message).get('message')
-	except JSONDecodeError:
+	except Exception:
 		json_message = message
 
 	return json_message
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html
index db1fea1..f8d191c 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html
@@ -13,7 +13,6 @@
 		</div>
 		{% endif %}
 	</div>
-
 	<h2 class="text-center">{{ _("STATEMENTS OF ACCOUNTS") }}</h2>
 	<div>
 		<h5 style="float: left;">{{ _("Customer: ") }} <b>{{filters.party[0] }}</b></h5>
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json
index 922f636..295a3b8 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json
@@ -286,7 +286,7 @@
   }
  ],
  "links": [],
- "modified": "2021-05-13 12:44:19.574844",
+ "modified": "2021-05-21 11:14:22.426672",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Process Statement Of Accounts",
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
index cf79c03..0b0ee90 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
@@ -94,10 +94,11 @@
 			continue
 
 		html = frappe.render_template(template_path, \
-			{"filters": filters, "data": res, "ageing": ageing[0] if doc.include_ageing else None,
+			{"filters": filters, "data": res, "ageing": ageing[0] if (doc.include_ageing and ageing) else None,
 				"letter_head": letter_head if doc.letter_head else None,
 				"terms_and_conditions": frappe.db.get_value('Terms and Conditions', doc.terms_and_conditions, 'terms')
 					if doc.terms_and_conditions else None})
+
 		html = frappe.render_template(base_template_path, {"body": html, \
 			"css": get_print_style(), "title": "Statement For " + entry.customer})
 		statement_dict[entry.customer] = html
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 16e70dd..b735fde 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -582,6 +582,16 @@
 			};
 		});
 
+		frm.set_query("adjustment_against", function() {
+			return {
+				filters: {
+					company: frm.doc.company,
+					customer: frm.doc.customer,
+					docstatus: 1
+				}
+			};
+		});
+
 		frm.custom_make_buttons = {
 			'Delivery Note': 'Delivery',
 			'Sales Invoice': 'Return / Credit Note',
@@ -897,6 +907,10 @@
 			})
 		}
 
+		if (frm.doc.is_debit_note) {
+			frm.set_df_property('return_against', 'label', 'Adjustment Against');
+		}
+
 		if (frappe.boot.active_domains.includes("Healthcare")) {
 			frm.set_df_property("patient", "hidden", 0);
 			frm.set_df_property("patient_name", "hidden", 0);
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index 52bc409..e7dd6b8 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -16,6 +16,7 @@
   "is_pos",
   "is_consolidated",
   "is_return",
+  "is_debit_note",
   "update_billed_amount_in_sales_order",
   "column_break1",
   "company",
@@ -392,7 +393,7 @@
    "read_only": 1
   },
   {
-   "depends_on": "return_against",
+   "depends_on": "eval:doc.return_against || doc.is_debit_note",
    "fieldname": "return_against",
    "fieldtype": "Link",
    "hide_days": 1,
@@ -401,7 +402,7 @@
    "no_copy": 1,
    "options": "Sales Invoice",
    "print_hide": 1,
-   "read_only": 1,
+   "read_only_depends_on": "eval:doc.is_return",
    "search_index": 1
   },
   {
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index a008742..023f4b0 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -1137,7 +1137,6 @@
 		"""
 		self.set_serial_no_against_delivery_note()
 		self.validate_serial_against_delivery_note()
-		self.validate_serial_against_sales_invoice()
 
 	def set_serial_no_against_delivery_note(self):
 		for item in self.items:
@@ -1168,26 +1167,6 @@
 				frappe.throw(_("Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.").format(
 					item.idx, item.qty, item.item_code, len(si_serial_nos)))
 
-	def validate_serial_against_sales_invoice(self):
-		""" check if serial number is already used in other sales invoice """
-		for item in self.items:
-			if not item.serial_no:
-				continue
-
-			for serial_no in item.serial_no.split("\n"):
-				serial_no_details = frappe.db.get_value("Serial No", serial_no,
-					["sales_invoice", "item_code"], as_dict=1)
-
-				if not serial_no_details:
-					continue
-
-				if serial_no_details.sales_invoice and serial_no_details.item_code == item.item_code \
-					and self.name != serial_no_details.sales_invoice:
-					sales_invoice_company = frappe.db.get_value("Sales Invoice", serial_no_details.sales_invoice, "company")
-					if sales_invoice_company == self.company:
-						frappe.throw(_("Serial Number: {0} is already referenced in Sales Invoice: {1}")
-							.format(serial_no, serial_no_details.sales_invoice))
-
 	def update_project(self):
 		if self.project:
 			project = frappe.get_doc("Project", self.project)
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 9059d0b..df6d483 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -933,12 +933,6 @@
 		self.assertFalse(frappe.db.get_value("Serial No", serial_nos[0], "warehouse"))
 		self.assertEqual(frappe.db.get_value("Serial No", serial_nos[0],
 			"delivery_document_no"), si.name)
-		self.assertEqual(frappe.db.get_value("Serial No", serial_nos[0], "sales_invoice"),
-			si.name)
-
-		# check if the serial number is already linked with any other Sales Invoice
-		_si = frappe.copy_doc(si.as_dict())
-		self.assertRaises(frappe.ValidationError, _si.insert)
 
 		return si
 
diff --git a/erpnext/accounts/report/cash_flow/custom_cash_flow.py b/erpnext/accounts/report/cash_flow/custom_cash_flow.py
index fe2bc72..ff87276 100644
--- a/erpnext/accounts/report/cash_flow/custom_cash_flow.py
+++ b/erpnext/accounts/report/cash_flow/custom_cash_flow.py
@@ -165,7 +165,7 @@
 	if profit_data:
 		profit_data.update({
 			"indent": 1,
-			"parent_account": get_mapper_for(light_mappers, position=0)['section_header']
+			"parent_account": get_mapper_for(light_mappers, position=1)['section_header']
 		})
 		data.append(profit_data)
 		section_data.append(profit_data)
@@ -312,10 +312,10 @@
 def compute_data(filters, company_currency, profit_data, period_list, light_mappers, full_mapper):
 	data = []
 
-	operating_activities_mapper = get_mapper_for(light_mappers, position=0)
+	operating_activities_mapper = get_mapper_for(light_mappers, position=1)
 	other_mappers = [
-		get_mapper_for(light_mappers, position=1),
-		get_mapper_for(light_mappers, position=2)
+		get_mapper_for(light_mappers, position=2),
+		get_mapper_for(light_mappers, position=3)
 	]
 
 	if operating_activities_mapper:
diff --git a/erpnext/accounts/report/dimension_wise_accounts_balance_report/__init__.py b/erpnext/accounts/report/dimension_wise_accounts_balance_report/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/report/dimension_wise_accounts_balance_report/__init__.py
diff --git a/erpnext/accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.js b/erpnext/accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.js
new file mode 100644
index 0000000..6a03948
--- /dev/null
+++ b/erpnext/accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.js
@@ -0,0 +1,81 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.require("assets/erpnext/js/financial_statements.js", function() {
+	frappe.query_reports["Dimension-wise Accounts Balance Report"] = {
+		"filters": [
+			{
+				"fieldname": "company",
+				"label": __("Company"),
+				"fieldtype": "Link",
+				"options": "Company",
+				"default": frappe.defaults.get_user_default("Company"),
+				"reqd": 1
+			},
+			{
+				"fieldname": "fiscal_year",
+				"label": __("Fiscal Year"),
+				"fieldtype": "Link",
+				"options": "Fiscal Year",
+				"default": frappe.defaults.get_user_default("fiscal_year"),
+				"reqd": 1,
+				"on_change": function(query_report) {
+					var fiscal_year = query_report.get_values().fiscal_year;
+					if (!fiscal_year) {
+						return;
+					}
+					frappe.model.with_doc("Fiscal Year", fiscal_year, function(r) {
+						var fy = frappe.model.get_doc("Fiscal Year", fiscal_year);
+						frappe.query_report.set_filter_value({
+							from_date: fy.year_start_date,
+							to_date: fy.year_end_date
+						});
+					});
+				}
+			},
+			{
+				"fieldname": "from_date",
+				"label": __("From Date"),
+				"fieldtype": "Date",
+				"default": frappe.defaults.get_user_default("year_start_date"),
+			},
+			{
+				"fieldname": "to_date",
+				"label": __("To Date"),
+				"fieldtype": "Date",
+				"default": frappe.defaults.get_user_default("year_end_date"),
+			},
+			{
+				"fieldname": "finance_book",
+				"label": __("Finance Book"),
+				"fieldtype": "Link",
+				"options": "Finance Book",
+			},
+			{
+				"fieldname": "dimension",
+				"label": __("Select Dimension"),
+				"fieldtype": "Select",
+				"options": get_accounting_dimension_options(),
+				"reqd": 1,
+			},
+		],
+		"formatter": erpnext.financial_statements.formatter,
+		"tree": true,
+		"name_field": "account",
+		"parent_field": "parent_account",
+		"initial_depth": 3
+	}
+
+});
+
+function get_accounting_dimension_options() {
+	let options =["", "Cost Center", "Project"];
+	frappe.db.get_list('Accounting Dimension',
+		{fields:['document_type']}).then((res) => {
+			res.forEach((dimension) => {
+				options.push(dimension.document_type);
+			});
+		});
+	return options
+}
diff --git a/erpnext/accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.json b/erpnext/accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.json
new file mode 100644
index 0000000..6141944
--- /dev/null
+++ b/erpnext/accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.json
@@ -0,0 +1,22 @@
+{
+ "add_total_row": 0,
+ "columns": [],
+ "creation": "2021-04-09 16:48:59.548018",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "filters": [],
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2021-04-09 16:48:59.548018",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Dimension-wise Accounts Balance Report",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "GL Entry",
+ "report_name": "Dimension-wise Accounts Balance Report",
+ "report_type": "Script Report",
+ "roles": []
+}
\ No newline at end of file
diff --git a/erpnext/accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.py b/erpnext/accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.py
new file mode 100644
index 0000000..de7ed49
--- /dev/null
+++ b/erpnext/accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.py
@@ -0,0 +1,213 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe, erpnext
+from frappe import _
+from frappe.utils import (flt, cstr)
+
+from erpnext.accounts.report.financial_statements import filter_accounts, filter_out_zero_value_rows
+from erpnext.accounts.report.trial_balance.trial_balance import validate_filters
+
+from six import itervalues
+
+def execute(filters=None):
+	validate_filters(filters)
+	dimension_items_list = get_dimension_items_list(filters.dimension, filters.company)
+
+	if not dimension_items_list:
+		return [], []
+
+	dimension_items_list = [''.join(d) for d in dimension_items_list]
+	columns = get_columns(dimension_items_list)
+	data = get_data(filters, dimension_items_list)
+
+	return columns, data
+
+def get_data(filters, dimension_items_list):
+	company_currency = erpnext.get_company_currency(filters.company)
+	acc = frappe.db.sql("""
+		select
+			name, account_number, parent_account, lft, rgt, root_type,
+			report_type, account_name, include_in_gross, account_type, is_group
+		from
+			`tabAccount`
+		where
+			company=%s
+			order by lft""", (filters.company), as_dict=True)
+
+	if not acc:
+		return None
+
+	accounts, accounts_by_name, parent_children_map = filter_accounts(acc)
+
+	min_lft, max_rgt = frappe.db.sql("""select min(lft), max(rgt) from `tabAccount`
+		where company=%s""", (filters.company))[0]
+
+	account = frappe.db.sql_list("""select name from `tabAccount`
+		where lft >= %s and rgt <= %s and company = %s""", (min_lft, max_rgt, filters.company))
+
+	gl_entries_by_account = {}
+	set_gl_entries_by_account(dimension_items_list, filters, account, gl_entries_by_account)
+	format_gl_entries(gl_entries_by_account, accounts_by_name, dimension_items_list)
+	accumulate_values_into_parents(accounts, accounts_by_name, dimension_items_list)
+	out = prepare_data(accounts, filters, parent_children_map, company_currency, dimension_items_list)
+	out = filter_out_zero_value_rows(out, parent_children_map)
+
+	return out
+
+def set_gl_entries_by_account(dimension_items_list, filters, account, gl_entries_by_account):
+	for item in dimension_items_list:
+		condition = get_condition(filters.from_date, item, filters.dimension)
+		if account:
+			condition += " and account in ({})"\
+				.format(", ".join([frappe.db.escape(d) for d in account]))
+
+		gl_filters = {
+			"company": filters.get("company"),
+			"from_date": filters.get("from_date"),
+			"to_date": filters.get("to_date"),
+			"finance_book": cstr(filters.get("finance_book"))
+		}
+
+		gl_filters['item'] = ''.join(item)
+
+		if filters.get("include_default_book_entries"):
+			gl_filters["company_fb"] = frappe.db.get_value("Company",
+				filters.company, 'default_finance_book')
+
+		for key, value in filters.items():
+			if value:
+				gl_filters.update({
+					key: value
+				})
+
+		gl_entries = frappe.db.sql("""
+		select
+			posting_date, account, debit, credit, is_opening, fiscal_year,
+			debit_in_account_currency, credit_in_account_currency, account_currency
+		from
+			`tabGL Entry`
+		where
+			company=%(company)s
+		{condition}
+		and posting_date <= %(to_date)s
+		and is_cancelled = 0
+		order by account, posting_date""".format(
+			condition=condition),
+			gl_filters, as_dict=True) #nosec
+
+		for entry in gl_entries:
+			entry['dimension_item'] = ''.join(item)
+			gl_entries_by_account.setdefault(entry.account, []).append(entry)
+
+def format_gl_entries(gl_entries_by_account, accounts_by_name, dimension_items_list):
+
+	for entries in itervalues(gl_entries_by_account):
+		for entry in entries:
+			d = accounts_by_name.get(entry.account)
+			if not d:
+				frappe.msgprint(
+					_("Could not retrieve information for {0}.").format(entry.account), title="Error",
+					raise_exception=1
+				)
+			for item in dimension_items_list:
+				if item == entry.dimension_item:
+					d[frappe.scrub(item)] = d.get(frappe.scrub(item), 0.0) + flt(entry.debit) - flt(entry.credit)
+
+def prepare_data(accounts, filters, parent_children_map, company_currency, dimension_items_list):
+	data = []
+
+	for d in accounts:
+		has_value = False
+		total = 0
+		row = {
+			"account": d.name,
+			"parent_account": d.parent_account,
+			"indent": d.indent,
+			"from_date": filters.from_date,
+			"to_date": filters.to_date,
+			"currency": company_currency,
+			"account_name": ('{} - {}'.format(d.account_number, d.account_name)
+				if d.account_number else d.account_name)
+		}
+
+		for item in dimension_items_list:
+			row[frappe.scrub(item)] = flt(d.get(frappe.scrub(item), 0.0), 3)
+
+			if abs(row[frappe.scrub(item)]) >= 0.005:
+				# ignore zero values
+				has_value = True
+				total += flt(d.get(frappe.scrub(item), 0.0), 3)
+
+		row["has_value"] = has_value
+		row["total"] = total
+		data.append(row)
+
+	return data
+
+def accumulate_values_into_parents(accounts, accounts_by_name, dimension_items_list):
+	"""accumulate children's values in parent accounts"""
+	for d in reversed(accounts):
+		if d.parent_account:
+			for item in dimension_items_list:
+				accounts_by_name[d.parent_account][frappe.scrub(item)] = \
+					accounts_by_name[d.parent_account].get(frappe.scrub(item), 0.0) + d.get(frappe.scrub(item), 0.0)
+
+def get_condition(from_date, item, dimension):
+	conditions = []
+
+	if from_date:
+		conditions.append("posting_date >= %(from_date)s")
+	if dimension:
+		if dimension not in ['Cost Center', 'Project']:
+			if dimension in ['Customer', 'Supplier']:
+				dimension = 'Party'
+			else:
+				dimension = 'Voucher No'
+		txt = "{0} = %(item)s".format(frappe.scrub(dimension))
+		conditions.append(txt)
+
+	return " and {}".format(" and ".join(conditions)) if conditions else ""
+
+def get_dimension_items_list(dimension, company):
+	meta = frappe.get_meta(dimension, cached=False)
+	fieldnames = [d.fieldname for d in meta.get("fields")]
+	filters = {}
+	if 'company' in fieldnames:
+		filters['company'] = company
+	return frappe.get_all(dimension, filters, as_list=True)
+
+def get_columns(dimension_items_list, accumulated_values=1, company=None):
+	columns = [{
+		"fieldname": "account",
+		"label": _("Account"),
+		"fieldtype": "Link",
+		"options": "Account",
+		"width": 300
+	}]
+	if company:
+		columns.append({
+			"fieldname": "currency",
+			"label": _("Currency"),
+			"fieldtype": "Link",
+			"options": "Currency",
+			"hidden": 1
+		})
+	for item in dimension_items_list:
+		columns.append({
+			"fieldname": frappe.scrub(item),
+			"label": item,
+			"fieldtype": "Currency",
+			"options": "currency",
+			"width": 150
+		})
+	columns.append({
+			"fieldname": "total",
+			"label": "Total",
+			"fieldtype": "Currency",
+			"options": "currency",
+			"width": 150
+		})
+
+	return columns
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index fb0d359..84f7868 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -166,6 +166,11 @@
 			"fieldname": "show_cancelled_entries",
 			"label": __("Show Cancelled Entries"),
 			"fieldtype": "Check"
+		},
+		{
+			"fieldname": "show_net_values_in_party_account",
+			"label": __("Show Net Values in Party Account"),
+			"fieldtype": "Check"
 		}
 	]
 }
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index b5d7992..562df4f 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -344,6 +344,9 @@
 	consolidated_gle = OrderedDict()
 	group_by = group_by_field(filters.get('group_by'))
 
+	if filters.get('show_net_values_in_party_account'):
+		account_type_map = get_account_type_map(filters.get('company'))
+
 	def update_value_in_dict(data, key, gle):
 		data[key].debit += flt(gle.debit)
 		data[key].credit += flt(gle.credit)
@@ -351,6 +354,24 @@
 		data[key].debit_in_account_currency += flt(gle.debit_in_account_currency)
 		data[key].credit_in_account_currency += flt(gle.credit_in_account_currency)
 
+		if filters.get('show_net_values_in_party_account') and \
+			account_type_map.get(data[key].account) in ('Receivable', 'Payable'):
+			net_value = flt(data[key].debit) - flt(data[key].credit)
+			net_value_in_account_currency = flt(data[key].debit_in_account_currency) \
+				- flt(data[key].credit_in_account_currency)
+
+			if net_value < 0:
+				dr_or_cr = 'credit'
+				rev_dr_or_cr = 'debit'
+			else:
+				dr_or_cr = 'debit'
+				rev_dr_or_cr = 'credit'
+
+			data[key][dr_or_cr] = abs(net_value)
+			data[key][dr_or_cr+'_in_account_currency'] = abs(net_value_in_account_currency)
+			data[key][rev_dr_or_cr] = 0
+			data[key][rev_dr_or_cr+'_in_account_currency'] = 0
+
 		if data[key].against_voucher and gle.against_voucher:
 			data[key].against_voucher += ', ' + gle.against_voucher
 
@@ -388,6 +409,12 @@
 
 	return totals, entries
 
+def get_account_type_map(company):
+	account_type_map = frappe._dict(frappe.get_all('Account', fields=['name', 'account_type'],
+		filters={'company': company}, as_list=1))
+
+	return account_type_map
+
 def get_result_as_list(data, filters):
 	balance, balance_in_account_currency = 0, 0
 	inv_details = get_supplier_invoice_details()
diff --git a/erpnext/accounts/report/tax_detail/test_tax_detail.py b/erpnext/accounts/report/tax_detail/test_tax_detail.py
index d3b8de5..743ddba 100644
--- a/erpnext/accounts/report/tax_detail/test_tax_detail.py
+++ b/erpnext/accounts/report/tax_detail/test_tax_detail.py
@@ -71,10 +71,8 @@
 
 	def rm_testdocs(self):
 		"Remove the Company and all data"
-		from erpnext.setup.doctype.company.delete_company_transactions import delete_company_transactions
-		delete_company_transactions(self.company.name)
-		self.company.delete()
-
+		from erpnext.setup.doctype.company.company import create_transaction_deletion_request
+		create_transaction_deletion_request(self.company.name)
 
 	def test_report(self):
 		self.load_testdocs()
diff --git a/erpnext/accounts/report/utils.py b/erpnext/accounts/report/utils.py
index 9de8d19..b020d0a 100644
--- a/erpnext/accounts/report/utils.py
+++ b/erpnext/accounts/report/utils.py
@@ -81,8 +81,7 @@
 	presentation_currency = currency_info['presentation_currency']
 	company_currency = currency_info['company_currency']
 
-	pl_accounts = [d.name for d in frappe.get_list('Account',
-		filters={'report_type': 'Profit and Loss', 'company': company})]
+	account_currencies = list(set(entry['account_currency'] for entry in gl_entries))
 
 	for entry in gl_entries:
 		account = entry['account']
@@ -92,10 +91,15 @@
 		credit_in_account_currency = flt(entry['credit_in_account_currency'])
 		account_currency = entry['account_currency']
 
-		if account_currency != presentation_currency:
-			value = debit or credit
+		if len(account_currencies) == 1 and account_currency == presentation_currency:
+			if entry.get('debit'):
+				entry['debit'] = debit_in_account_currency
 
-			date = entry['posting_date'] if account in pl_accounts else currency_info['report_date']
+			if entry.get('credit'):
+				entry['credit'] = credit_in_account_currency
+		else:
+			value = debit or credit
+			date = currency_info['report_date']
 			converted_value = convert(value, presentation_currency, company_currency, date)
 
 			if entry.get('debit'):
@@ -104,13 +108,6 @@
 			if entry.get('credit'):
 				entry['credit'] = converted_value
 
-		elif account_currency == presentation_currency:
-			if entry.get('debit'):
-				entry['debit'] = debit_in_account_currency
-
-			if entry.get('credit'):
-				entry['credit'] = credit_in_account_currency
-
 		converted_gl_list.append(entry)
 
 	return converted_gl_list
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 b530d1a..180ba93 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
@@ -62,6 +62,7 @@
 		for supplier in self.suppliers:
 			supplier.email_sent = 0
 			supplier.quote_status = 'Pending'
+		self.send_to_supplier()
 
 	def on_cancel(self):
 		frappe.db.set(self, 'status', 'Cancelled')
@@ -81,7 +82,7 @@
 	def send_to_supplier(self):
 		"""Sends RFQ mail to involved suppliers."""
 		for rfq_supplier in self.suppliers:
-			if rfq_supplier.send_email:
+			if rfq_supplier.email_id is not None and rfq_supplier.send_email:
 				self.validate_email_id(rfq_supplier)
 
 				# make new user if required
diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json
index 4cc5753..38b8dfd 100644
--- a/erpnext/buying/doctype/supplier/supplier.json
+++ b/erpnext/buying/doctype/supplier/supplier.json
@@ -383,8 +383,14 @@
  "icon": "fa fa-user",
  "idx": 370,
  "image_field": "image",
- "links": [],
- "modified": "2021-01-06 19:51:40.939087",
+ "links": [
+  {
+   "group": "Item Group",
+   "link_doctype": "Supplier Item Group",
+   "link_fieldname": "supplier"
+  }
+ ],
+ "modified": "2021-05-18 15:10:11.087191",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Supplier",
diff --git a/erpnext/buying/doctype/supplier_item_group/__init__.py b/erpnext/buying/doctype/supplier_item_group/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_item_group/__init__.py
diff --git a/erpnext/buying/doctype/supplier_item_group/supplier_item_group.js b/erpnext/buying/doctype/supplier_item_group/supplier_item_group.js
new file mode 100644
index 0000000..f7da90d
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_item_group/supplier_item_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('Supplier Item Group', {
+	// refresh: function(frm) {
+
+	// }
+});
diff --git a/erpnext/buying/doctype/supplier_item_group/supplier_item_group.json b/erpnext/buying/doctype/supplier_item_group/supplier_item_group.json
new file mode 100644
index 0000000..1971458
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_item_group/supplier_item_group.json
@@ -0,0 +1,77 @@
+{
+ "actions": [],
+ "creation": "2021-05-07 18:16:40.621421",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "supplier",
+  "item_group"
+ ],
+ "fields": [
+  {
+   "fieldname": "supplier",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Supplier",
+   "options": "Supplier",
+   "reqd": 1
+  },
+  {
+   "fieldname": "item_group",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Item Group",
+   "options": "Item Group",
+   "reqd": 1
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2021-05-19 13:48:16.742303",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Supplier Item 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": "Purchase User",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Purchase Manager",
+   "share": 1,
+   "write": 1
+  }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_item_group/supplier_item_group.py b/erpnext/buying/doctype/supplier_item_group/supplier_item_group.py
new file mode 100644
index 0000000..3a2e5d6
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_item_group/supplier_item_group.py
@@ -0,0 +1,18 @@
+# -*- 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 import _
+from frappe.model.document import Document
+
+class SupplierItemGroup(Document):
+	def validate(self):
+		exists = frappe.db.exists({
+			'doctype': 'Supplier Item Group',
+			'supplier': self.supplier,
+			'item_group': self.item_group
+		})
+		if exists:
+			frappe.throw(_("Item Group has already been linked to this supplier."))
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_item_group/test_supplier_item_group.py b/erpnext/buying/doctype/supplier_item_group/test_supplier_item_group.py
new file mode 100644
index 0000000..c75044d
--- /dev/null
+++ b/erpnext/buying/doctype/supplier_item_group/test_supplier_item_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 TestSupplierItemGroup(unittest.TestCase):
+	pass
diff --git a/erpnext/change_log/v13/v13_4_0.md b/erpnext/change_log/v13/v13_4_0.md
new file mode 100644
index 0000000..eaf4f76
--- /dev/null
+++ b/erpnext/change_log/v13/v13_4_0.md
@@ -0,0 +1,54 @@
+# Version 13.4.0 Release Notes
+
+### Features & Enhancements
+
+- Multiple GST enhancement and fixes ([#25249](https://github.com/frappe/erpnext/pull/25249))
+- Linking supplier with an item group for filtering items ([#25683](https://github.com/frappe/erpnext/pull/25683))
+- Leave Policy Assignment Refactor ([#24327](https://github.com/frappe/erpnext/pull/24327))
+- Dimension-wise Accounts Balance Report ([#25260](https://github.com/frappe/erpnext/pull/25260))
+- Show net values in Party Accounts ([#25714](https://github.com/frappe/erpnext/pull/25714))
+- Add pending qty section to batch/serial selector dialog ([#25519](https://github.com/frappe/erpnext/pull/25519))
+- enhancements in Training Event ([#25782](https://github.com/frappe/erpnext/pull/25782))
+- Refactored timesheet ([#25701](https://github.com/frappe/erpnext/pull/25701))
+
+### Fixes
+
+- Process Statement of Accounts formatting ([#25777](https://github.com/frappe/erpnext/pull/25777))
+- Removed serial no validation for sales invoice ([#25817](https://github.com/frappe/erpnext/pull/25817))
+- Fetch email id from dialog box in pos past order summary ([#25808](https://github.com/frappe/erpnext/pull/25808))
+- Don't map set warehouse from delivery note to purchase receipt ([#25672](https://github.com/frappe/erpnext/pull/25672))
+- Apply permission while selecting projects ([#25765](https://github.com/frappe/erpnext/pull/25765))
+- Error on adding bank account to plaid ([#25658](https://github.com/frappe/erpnext/pull/25658))
+- Set disable rounded total if it is globally enabled ([#25789](https://github.com/frappe/erpnext/pull/25789))
+- Wrong amount on CR side in general ledger report for customer when different account currencies are involved ([#25654](https://github.com/frappe/erpnext/pull/25654))
+- Stock move dialog duplicate submit actions (V13) ([#25486](https://github.com/frappe/erpnext/pull/25486))
+- Cashflow mapper not showing data ([#25815](https://github.com/frappe/erpnext/pull/25815))
+- Ignore rounding diff while importing JV using data import ([#25816](https://github.com/frappe/erpnext/pull/25816))
+- Woocommerce order sync issue ([#25688](https://github.com/frappe/erpnext/pull/25688))
+- Expected amount in pos closing payments table ([#25737](https://github.com/frappe/erpnext/pull/25737))
+- Show only company addresses for ITC reversal entry ([#25867](https://github.com/frappe/erpnext/pull/25867))
+- Timeout error while loading warehouse tree ([#25694](https://github.com/frappe/erpnext/pull/25694))
+- Plaid Withdrawals and Deposits are recorded incorrectly ([#25784](https://github.com/frappe/erpnext/pull/25784))
+- Return case for item with available qty equal to one ([#25760](https://github.com/frappe/erpnext/pull/25760))
+- The status of repost item valuation showing In Progress since long time ([#25754](https://github.com/frappe/erpnext/pull/25754))
+- Updated applicable charges form in landed cost voucher ([#25732](https://github.com/frappe/erpnext/pull/25732))
+- Rearrange buttons for Company DocType ([#25617](https://github.com/frappe/erpnext/pull/25617))
+- Show uom for item in selector dialog ([#25697](https://github.com/frappe/erpnext/pull/25697))
+- Warehouse not found in stock entry ([#25776](https://github.com/frappe/erpnext/pull/25776))
+- Use dictionary filter instead of list (bp #25874 pre-release) ([#25875](https://github.com/frappe/erpnext/pull/25875))
+- Send emails on rfq submit ([#25695](https://github.com/frappe/erpnext/pull/25695))
+- Cannot bypass e-invoicing for non gst item invoices ([#25759](https://github.com/frappe/erpnext/pull/25759))
+- Validation message of quality inspection in purchase receipt ([#25666](https://github.com/frappe/erpnext/pull/25666))
+- Dialog variable assignment after definition in POS ([#25681](https://github.com/frappe/erpnext/pull/25681))
+- Wrong quantity after transaction for parallel stock transactions ([#25779](https://github.com/frappe/erpnext/pull/25779))
+- Item Variant Details Report ([#25797](https://github.com/frappe/erpnext/pull/25797))
+- Duplicate stock entry on multiple click ([#25742](https://github.com/frappe/erpnext/pull/25742))
+- Bank statement import via google sheet ([#25676](https://github.com/frappe/erpnext/pull/25676))
+- Change today to now to get data for reposting ([#25702](https://github.com/frappe/erpnext/pull/25702))
+- Parameter for get_filtered_list_for_consolidated_report in consolidated balance sheet ([#25698](https://github.com/frappe/erpnext/pull/25698))
+- Ageing error in PSOA ([#25857](https://github.com/frappe/erpnext/pull/25857))
+- Breaking cost center validation ([#25660](https://github.com/frappe/erpnext/pull/25660))
+- Project filter for Kanban Board ([#25744](https://github.com/frappe/erpnext/pull/25744))
+- Show allow zero valuation only when auto checked ([#25778](https://github.com/frappe/erpnext/pull/25778))
+- Missing cost center message on creating gl entries ([#25755](https://github.com/frappe/erpnext/pull/25755))
+- Address template with upper filter throws jinja error ([#25756](https://github.com/frappe/erpnext/pull/25756))
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 913458f..f88e8df 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -368,6 +368,11 @@
 					if self.doctype in ["Purchase Invoice", "Sales Invoice"] and item.meta.get_field('is_fixed_asset'):
 						item.set('is_fixed_asset', ret.get('is_fixed_asset', 0))
 
+					# Double check for cost center
+					# Items add via promotional scheme may not have cost center set
+					if hasattr(item, 'cost_center') and not item.get('cost_center'):
+						item.set('cost_center', self.get('cost_center') or erpnext.get_default_cost_center(self.company))
+
 					if ret.get("pricing_rules"):
 						self.apply_pricing_rule_on_items(item, ret)
 						self.set_pricing_rule_details(item, ret)
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index b31724f..638503e 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -216,11 +216,23 @@
 		if not field in searchfields]
 	searchfields = " or ".join([field + " like %(txt)s" for field in searchfields])
 
+	if filters and isinstance(filters, dict) and filters.get('supplier'):
+		item_group_list = frappe.get_all('Supplier Item Group',
+			filters = {'supplier': filters.get('supplier')}, fields = ['item_group'])
+
+		item_groups = []
+		for i in item_group_list:
+			item_groups.append(i.item_group)
+
+		del filters['supplier']
+
+		if item_groups:
+			filters['item_group'] = ['in', item_groups]
+
 	description_cond = ''
 	if frappe.db.count('Item', cache=True) < 50000:
 		# scan description only if items are less than 50000
 		description_cond = 'or tabItem.description LIKE %(txt)s'
-
 	return frappe.db.sql("""select tabItem.name,
 		if(length(tabItem.item_name) > 40,
 			concat(substr(tabItem.item_name, 1, 40), "..."), item_name) as item_name,
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index ed3aee5..83d4c33 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -76,12 +76,12 @@
 		["Stopped", "eval:self.status == 'Stopped'"],
 		["Cancelled", "eval:self.docstatus == 2"],
 		["Pending", "eval:self.status != 'Stopped' and self.per_ordered == 0 and self.docstatus == 1"],
-		["Partially Ordered", "eval:self.status != 'Stopped' and self.per_ordered < 100 and self.per_ordered > 0 and self.docstatus == 1"],
 		["Ordered", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Purchase'"],
 		["Transferred", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Material Transfer'"],
 		["Issued", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Material Issue'"],
 		["Received", "eval:self.status != 'Stopped' and self.per_received == 100 and self.docstatus == 1 and self.material_request_type == 'Purchase'"],
 		["Partially Received", "eval:self.status != 'Stopped' and self.per_received > 0 and self.per_received < 100 and self.docstatus == 1 and self.material_request_type == 'Purchase'"],
+		["Partially Ordered", "eval:self.status != 'Stopped' and self.per_ordered < 100 and self.per_ordered > 0 and self.docstatus == 1"],
 		["Manufactured", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Manufacture'"]
 	],
 	"Bank Transaction": [
diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_api.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_api.py
index f713684..7fd3b34 100755
--- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_api.py
+++ b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_api.py
@@ -7,6 +7,7 @@
 from __future__ import unicode_literals
 
 import urllib
+from urllib.parse import quote
 import hashlib
 import hmac
 import base64
@@ -68,8 +69,9 @@
 	"""
 	md = hashlib.md5()
 	md.update(string)
-	return base64.encodestring(md.digest()).strip('\n') if six.PY2 \
-		else base64.encodebytes(md.digest()).decode().strip()
+	return base64.encodebytes(md.digest()).decode().strip()
+
+
 
 def remove_empty(d):
 	"""
@@ -177,7 +179,6 @@
 			'SignatureMethod': 'HmacSHA256',
 		}
 		params.update(extra_data)
-		quote = urllib.quote if six.PY2 else urllib.parse.quote
 		request_description = '&'.join(['%s=%s' % (k, quote(params[k], safe='-_.~')) for k in sorted(params)])
 		signature = self.calc_signature(method, request_description)
 		url = '%s%s?%s&Signature=%s' % (self.domain, self.uri, request_description, quote(signature))
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
index 16c6573..ce15e47 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
@@ -90,9 +90,9 @@
 					"bank": bank["bank_name"],
 					"account": default_gl_account.account,
 					"account_name": account["name"],
-					"account_type": account["type"] or "",
-					"account_subtype": account["subtype"] or "",
-					"mask": account["mask"] or "",
+					"account_type": account.get("type", ""),
+					"account_subtype": account.get("subtype", ""),
+					"mask": account.get("mask", ""),
 					"integration_id": account["id"],
 					"is_company_account": 1,
 					"company": company
@@ -183,11 +183,11 @@
 	bank_account = frappe.db.get_value("Bank Account", dict(integration_id=transaction["account_id"]))
 
 	if float(transaction["amount"]) >= 0:
-		debit = float(transaction["amount"])
-		credit = 0
-	else:
 		debit = 0
-		credit = abs(float(transaction["amount"]))
+		credit = float(transaction["amount"])
+	else:
+		debit = abs(float(transaction["amount"]))
+		credit = 0
 
 	status = "Pending" if transaction["pending"] == "True" else "Settled"
 
diff --git a/erpnext/healthcare/doctype/patient/patient.py b/erpnext/healthcare/doctype/patient/patient.py
index 789d452..56a3400 100644
--- a/erpnext/healthcare/doctype/patient/patient.py
+++ b/erpnext/healthcare/doctype/patient/patient.py
@@ -33,21 +33,20 @@
 		self.reload() # self.notify_update()
 
 	def on_update(self):
-		if self.customer:
-			customer = frappe.get_doc('Customer', self.customer)
-			if self.customer_group:
-				customer.customer_group = self.customer_group
-			if self.territory:
-				customer.territory = self.territory
-
-			customer.customer_name = self.patient_name
-			customer.default_price_list = self.default_price_list
-			customer.default_currency = self.default_currency
-			customer.language = self.language
-			customer.ignore_mandatory = True
-			customer.save(ignore_permissions=True)
-		else:
-			if frappe.db.get_single_value('Healthcare Settings', 'link_customer_to_patient'):
+		if frappe.db.get_single_value('Healthcare Settings', 'link_customer_to_patient'):
+			if self.customer:
+				customer = frappe.get_doc('Customer', self.customer)
+				if self.customer_group:
+					customer.customer_group = self.customer_group
+				if self.territory:
+					customer.territory = self.territory
+				customer.customer_name = self.patient_name
+				customer.default_price_list = self.default_price_list
+				customer.default_currency = self.default_currency
+				customer.language = self.language
+				customer.ignore_mandatory = True
+				customer.save(ignore_permissions=True)
+			else:
 				create_customer(self)
 
 	def set_full_name(self):
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index a1d37e2..0cdbbde 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -269,10 +269,12 @@
 	},
 	"Purchase Invoice": {
 		"validate": [
-			"erpnext.regional.india.utils.update_grand_total_for_rcm",
+			"erpnext.regional.india.utils.validate_reverse_charge_transaction",
+			"erpnext.regional.india.utils.update_itc_availed_fields",
 			"erpnext.regional.united_arab_emirates.utils.update_grand_total_for_rcm",
-			"erpnext.regional.united_arab_emirates.utils.validate_returns"
-			]
+			"erpnext.regional.united_arab_emirates.utils.validate_returns",
+			"erpnext.regional.india.utils.update_taxable_values"
+		]
 	},
 	"Payment Entry": {
 		"on_submit": ["erpnext.regional.create_transaction_log", "erpnext.accounts.doctype.payment_request.payment_request.update_payment_req_status", "erpnext.accounts.doctype.dunning.dunning.resolve_dunning"],
@@ -366,10 +368,8 @@
 		"erpnext.setup.doctype.email_digest.email_digest.send",
 		"erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms",
 		"erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry.process_expired_allocation",
-		"erpnext.hr.doctype.leave_policy_assignment.leave_policy_assignment.automatically_allocate_leaves_based_on_leave_policy",
 		"erpnext.hr.utils.generate_leave_encashment",
 		"erpnext.hr.utils.allocate_earned_leaves",
-		"erpnext.hr.utils.grant_leaves_automatically",
 		"erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall.create_process_loan_security_shortfall",
 		"erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual.process_loan_interest_accrual_for_term_loans",
 		"erpnext.crm.doctype.lead.lead.daily_open_lead"
@@ -426,7 +426,6 @@
 		'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',
 		'erpnext.controllers.accounts_controller.validate_einvoice_fields': 'erpnext.regional.india.e_invoice.utils.validate_einvoice_fields',
 		'erpnext.assets.doctype.asset.asset.get_depreciation_amount': 'erpnext.regional.india.utils.get_depreciation_amount'
 	},
diff --git a/erpnext/hr/doctype/employee/employee_dashboard.py b/erpnext/hr/doctype/employee/employee_dashboard.py
index 0203332..285374d 100644
--- a/erpnext/hr/doctype/employee/employee_dashboard.py
+++ b/erpnext/hr/doctype/employee/employee_dashboard.py
@@ -11,8 +11,12 @@
 		},
 		'transactions': [
 			{
-				'label': _('Leave and Attendance'),
-				'items': ['Attendance', 'Attendance Request', 'Leave Application', 'Leave Allocation', 'Employee Checkin']
+				'label': _('Attendance'),
+				'items': ['Attendance', 'Attendance Request', 'Employee Checkin']
+			},
+			{
+				'label': _('Leave'),
+				'items': ['Leave Application', 'Leave Allocation', 'Leave Policy Assignment']
 			},
 			{
 				'label': _('Lifecycle'),
@@ -31,10 +35,6 @@
 				'items': ['Employee Benefit Application', 'Employee Benefit Claim']
 			},
 			{
-				'label': _('Evaluation'),
-				'items': ['Appraisal']
-			},
-			{
 				'label': _('Payroll'),
 				'items': ['Salary Structure Assignment', 'Salary Slip', 'Additional Salary', 'Timesheet','Employee Incentive', 'Retention Bonus', 'Bank Account']
 			},
@@ -42,5 +42,9 @@
 				'label': _('Training'),
 				'items': ['Training Event', 'Training Result', 'Training Feedback', 'Employee Skill Map']
 			},
+			{
+				'label': _('Evaluation'),
+				'items': ['Appraisal']
+			},
 		]
 	}
diff --git a/erpnext/hr/doctype/hr_settings/hr_settings.json b/erpnext/hr/doctype/hr_settings/hr_settings.json
index 3db6c23..2396a8e 100644
--- a/erpnext/hr/doctype/hr_settings/hr_settings.json
+++ b/erpnext/hr/doctype/hr_settings/hr_settings.json
@@ -23,7 +23,6 @@
   "show_leaves_of_all_department_members_in_calendar",
   "auto_leave_encashment",
   "restrict_backdated_leave_application",
-  "automatically_allocate_leaves_based_on_leave_policy",
   "hiring_settings",
   "check_vacancies"
  ],
@@ -134,12 +133,6 @@
    "options": "Role"
   },
   {
-   "default": "0",
-   "fieldname": "automatically_allocate_leaves_based_on_leave_policy",
-   "fieldtype": "Check",
-   "label": "Automatically Allocate Leaves Based On Leave Policy"
-  },
-  {
    "default": "1",
    "fieldname": "send_leave_notification",
    "fieldtype": "Check",
@@ -155,7 +148,7 @@
  "idx": 1,
  "issingle": 1,
  "links": [],
- "modified": "2021-04-26 10:52:56.192773",
+ "modified": "2021-05-11 10:52:56.192773",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "HR Settings",
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index a4a96b8..2832e2f 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -446,8 +446,6 @@
 
 		leave_policy_assignments = create_assignment_for_multiple_employees([employee.name], frappe._dict(data))
 
-		frappe.get_doc("Leave Policy Assignment", leave_policy_assignments[0]).grant_leave_alloc_for_employee()
-
 		from erpnext.hr.utils import allocate_earned_leaves
 		i = 0
 		while(i<14):
diff --git a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
index e0ffa5d..c1da8b4 100644
--- a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
@@ -44,10 +44,6 @@
 		salary_structure = make_salary_structure("Salary Structure for Encashment", "Monthly", self.employee,
 			other_details={"leave_encashment_amount_per_day": 50})
 
-		#grant Leaves
-		frappe.get_doc("Leave Policy Assignment", leave_policy_assignments[0]).grant_leave_alloc_for_employee()
-
-
 	def tearDown(self):
 		for dt in ["Leave Period", "Leave Allocation", "Leave Ledger Entry", "Additional Salary", "Leave Encashment", "Salary Structure", "Leave Policy"]:
 			frappe.db.sql("delete from `tab%s`" % dt)
diff --git a/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py b/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py
index e0ec4be..ff7f042 100644
--- a/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py
+++ b/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py
@@ -7,7 +7,7 @@
 		'transactions': [
 			{
 				'label': _('Leaves'),
-				'items': ['Leave Allocation']
+				'items': ['Leave Policy Assignment', 'Leave Allocation']
 			},
 		]
 	}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.js b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.js
index 7c32a0d..0aaf4cf 100644
--- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.js
+++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.js
@@ -4,35 +4,22 @@
 frappe.ui.form.on('Leave Policy Assignment', {
 	onload: function(frm) {
 		frm.ignore_doctypes_on_cancel_all = ["Leave Ledger Entry"];
-	},
 
-	refresh: function(frm) {
-		if (frm.doc.docstatus === 1 && frm.doc.leaves_allocated === 0) {
-			frm.add_custom_button(__("Grant Leave"), function() {
-
-				frappe.call({
-					doc: frm.doc,
-					method: "grant_leave_alloc_for_employee",
-					callback: function(r) {
-						let leave_allocations = r.message;
-						let msg = frm.events.get_success_message(leave_allocations);
-						frappe.msgprint(msg);
-						cur_frm.refresh();
-					}
-				});
-			});
-		}
-	},
-
-	get_success_message: function(leave_allocations) {
-		let msg = __("Leaves has been granted successfully");
-		msg += "<br><table class='table table-bordered'>";
-		msg += "<tr><th>"+__('Leave Type')+"</th><th>"+__("Leave Allocation")+"</th><th>"+__("Leaves Granted")+"</th><tr>";
-		for (let key in leave_allocations) {
-			msg += "<tr><th>"+key+"</th><td>"+leave_allocations[key]["name"]+"</td><td>"+leave_allocations[key]["leaves"]+"</td></tr>";
-		}
-		msg += "</table>";
-		return msg;
+		frm.set_query('leave_policy', function() {
+			return {
+				filters: {
+					"docstatus": 1
+				}
+			};
+		});
+		frm.set_query('leave_period', function() {
+			return {
+				filters: {
+					"is_active": 1,
+					"company": frm.doc.company
+				}
+			};
+		});
 	},
 
 	assignment_based_on: function(frm) {
diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py
index 462b81d..d7cb1c8 100644
--- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py
+++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py
@@ -17,6 +17,9 @@
 		self.validate_policy_assignment_overlap()
 		self.set_dates()
 
+	def on_submit(self):
+		self.grant_leave_alloc_for_employee()
+
 	def set_dates(self):
 		if self.assignment_based_on == "Leave Period":
 			self.effective_from, self.effective_to = frappe.db.get_value("Leave Period", self.leave_period, ["from_date", "to_date"])
@@ -75,7 +78,7 @@
 			from_date=self.effective_from,
 			to_date=self.effective_to,
 			new_leaves_allocated=new_leaves_allocated,
-			leave_period=self.leave_period or None,
+			leave_period=self.leave_period if self.assignment_based_on == "Leave Policy" else '',
 			leave_policy_assignment = self.name,
 			leave_policy = self.leave_policy,
 			carry_forward=carry_forward
@@ -132,22 +135,6 @@
 
 
 @frappe.whitelist()
-def grant_leave_for_multiple_employees(leave_policy_assignments):
-	leave_policy_assignments = json.loads(leave_policy_assignments)
-	not_granted = []
-	for assignment in leave_policy_assignments:
-		try:
-			frappe.get_doc("Leave Policy Assignment", assignment).grant_leave_alloc_for_employee()
-		except Exception:
-			not_granted.append(assignment)
-
-		if len(not_granted):
-			msg = _("Leave not Granted for Assignments:")+ bold(comma_and(not_granted)) + _(". Please Check documents")
-		else:
-			msg = _("Leave granted Successfully")
-	frappe.msgprint(msg)
-
-@frappe.whitelist()
 def create_assignment_for_multiple_employees(employees, data):
 
 	if isinstance(employees, string_types):
@@ -166,29 +153,18 @@
 		assignment.effective_to = getdate(data.effective_to) or None
 		assignment.leave_period = data.leave_period or None
 		assignment.carry_forward = data.carry_forward
-
 		assignment.save()
-		assignment.submit()
+		try:
+			assignment.submit()
+		except frappe.exceptions.ValidationError:
+			continue
+
+		frappe.db.commit()
+
 		docs_name.append(assignment.name)
+
 	return docs_name
 
-
-def automatically_allocate_leaves_based_on_leave_policy():
-	today = getdate()
-	automatically_allocate_leaves_based_on_leave_policy = frappe.db.get_single_value(
-		'HR Settings', 'automatically_allocate_leaves_based_on_leave_policy'
-	)
-
-	pending_assignments = frappe.get_list(
-		"Leave Policy Assignment",
-		filters = {"docstatus": 1, "leaves_allocated": 0, "effective_from": today}
-	)
-
-	if len(pending_assignments) and automatically_allocate_leaves_based_on_leave_policy:
-		for assignment in pending_assignments:
-			frappe.get_doc("Leave Policy Assignment", assignment.name).grant_leave_alloc_for_employee()
-
-
 def get_leave_type_details():
 	leave_type_details = frappe._dict()
 	leave_types = frappe.get_all("Leave Type",
@@ -197,4 +173,3 @@
 	for d in leave_types:
 		leave_type_details.setdefault(d.name, d)
 	return leave_type_details
-
diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_dashboard.py b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_dashboard.py
new file mode 100644
index 0000000..4bb0535
--- /dev/null
+++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_dashboard.py
@@ -0,0 +1,13 @@
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+	return {
+		'fieldname':  'leave_policy_assignment',
+		'transactions': [
+			{
+				'label': _('Leaves'),
+				'items': ['Leave Allocation']
+			},
+		]
+	}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_list.js b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_list.js
index 468f243..8fe4b8f 100644
--- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_list.js
+++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_list.js
@@ -6,6 +6,7 @@
 				doctype: "Employee",
 				target: cur_list,
 				setters: {
+					employee_name: '',
 					company: '',
 					department: '',
 				},
@@ -92,37 +93,6 @@
 				}
 			});
 		});
-
-		list_view.page.add_inner_button(__("Grant Leaves"), function () {
-			me.dialog = new frappe.ui.form.MultiSelectDialog({
-				doctype: "Leave Policy Assignment",
-				target: cur_list,
-				setters: {
-					company: '',
-					employee: '',
-				},
-				get_query() {
-					return {
-						filters: {
-							docstatus: ['=', 1],
-							leaves_allocated: ['=', 0]
-						}
-					};
-				},
-				add_filters_group: 1,
-				primary_action_label: "Grant Leaves",
-				action(leave_policy_assignments) {
-					frappe.call({
-						method: 'erpnext.hr.doctype.leave_policy_assignment.leave_policy_assignment.grant_leave_for_multiple_employees',
-						async: false,
-						args: {
-							leave_policy_assignments: leave_policy_assignments
-						}
-					});
-					me.dialog.hide();
-				}
-			});
-		});
 	},
 
 	set_effective_date: function () {
diff --git a/erpnext/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py b/erpnext/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py
index 838e794..9a14e35 100644
--- a/erpnext/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py
+++ b/erpnext/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py
@@ -35,7 +35,6 @@
 		leave_policy_assignments = create_assignment_for_multiple_employees([employee.name], frappe._dict(data))
 
 		leave_policy_assignment_doc = frappe.get_doc("Leave Policy Assignment", leave_policy_assignments[0])
-		leave_policy_assignment_doc.grant_leave_alloc_for_employee()
 		leave_policy_assignment_doc.reload()
 
 		self.assertEqual(leave_policy_assignment_doc.leaves_allocated, 1)
@@ -73,7 +72,6 @@
 		leave_policy_assignments = create_assignment_for_multiple_employees([employee.name], frappe._dict(data))
 
 		leave_policy_assignment_doc = frappe.get_doc("Leave Policy Assignment", leave_policy_assignments[0])
-		leave_policy_assignment_doc.grant_leave_alloc_for_employee()
 		leave_policy_assignment_doc.reload()
 
 
diff --git a/erpnext/hr/doctype/training_event/training_event.js b/erpnext/hr/doctype/training_event/training_event.js
index 12bc920..b7d34b1 100644
--- a/erpnext/hr/doctype/training_event/training_event.js
+++ b/erpnext/hr/doctype/training_event/training_event.js
@@ -2,23 +2,41 @@
 // For license information, please see license.txt
 
 frappe.ui.form.on('Training Event', {
-	onload_post_render: function(frm) {
+	onload_post_render: function (frm) {
 		frm.get_field("employees").grid.set_multiple_add("employee");
 	},
-	refresh: function(frm) {
-		if(!frm.doc.__islocal) {
-			frm.add_custom_button(__("Training Result"), function() {
+	refresh: function (frm) {
+		if (!frm.doc.__islocal) {
+			frm.add_custom_button(__("Training Result"), function () {
 				frappe.route_options = {
 					training_event: frm.doc.name
-				}
+				};
 				frappe.set_route("List", "Training Result");
 			});
-			frm.add_custom_button(__("Training Feedback"), function() {
+			frm.add_custom_button(__("Training Feedback"), function () {
 				frappe.route_options = {
 					training_event: frm.doc.name
-				}
+				};
 				frappe.set_route("List", "Training Feedback");
 			});
 		}
 	}
 });
+
+frappe.ui.form.on("Training Event Employee", {
+	employee: function (frm) {
+		let emp = [];
+		for (let d in frm.doc.employees) {
+			if (frm.doc.employees[d].employee) {
+				emp.push(frm.doc.employees[d].employee);
+			}
+		}
+		frm.set_query("employee", "employees", function () {
+			return {
+				filters: {
+					name: ["NOT IN", emp]
+				}
+			};
+		});
+	}
+});
diff --git a/erpnext/hr/doctype/training_event_employee/training_event_employee.json b/erpnext/hr/doctype/training_event_employee/training_event_employee.json
index e3a4064..2d313e9 100644
--- a/erpnext/hr/doctype/training_event_employee/training_event_employee.json
+++ b/erpnext/hr/doctype/training_event_employee/training_event_employee.json
@@ -1,241 +1,80 @@
 {
- "allow_copy": 0, 
- "allow_events_in_timeline": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "beta": 0, 
- "creation": "2016-08-08 05:33:39.965305", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 1, 
+ "actions": [],
+ "creation": "2016-08-08 05:33:39.965305",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "employee",
+  "employee_name",
+  "department",
+  "column_break_3",
+  "status",
+  "attendance",
+  "is_mandatory"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "employee", 
-   "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": "Employee", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Employee", 
-   "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": "employee",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Employee",
+   "options": "Employee"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_from": "employee.employee_name", 
-   "fieldname": "employee_name", 
-   "fieldtype": "Read Only", 
-   "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": "Employee Name", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fetch_from": "employee.employee_name",
+   "fieldname": "employee_name",
+   "fieldtype": "Read Only",
+   "label": "Employee Name"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_from": "employee.department", 
-   "fieldname": "department", 
-   "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": "Department", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Department", 
-   "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
-  }, 
+   "fetch_from": "employee.department",
+   "fieldname": "department",
+   "fieldtype": "Link",
+   "label": "Department",
+   "options": "Department",
+   "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_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": 1, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "default": "Open", 
-   "fieldname": "status", 
-   "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": "Status", 
-   "length": 0, 
-   "no_copy": 1, 
-   "options": "Open\nInvited\nCompleted\nFeedback Submitted", 
-   "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_on_submit": 1,
+   "default": "Open",
+   "fieldname": "status",
+   "fieldtype": "Select",
+   "in_list_view": 1,
+   "label": "Status",
+   "no_copy": 1,
+   "options": "Open\nInvited\nCompleted\nFeedback Submitted"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "attendance", 
-   "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": "Attendance", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Mandatory\nOptional", 
-   "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": "attendance",
+   "fieldtype": "Select",
+   "in_list_view": 1,
+   "label": "Attendance",
+   "options": "Present\nAbsent"
+  },
+  {
+   "columns": 2,
+   "default": "1",
+   "fieldname": "is_mandatory",
+   "fieldtype": "Check",
+   "in_list_view": 1,
+   "label": "Is Mandatory"
   }
- ], 
- "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": "2019-01-30 11:28:16.170333", 
- "modified_by": "Administrator", 
- "module": "HR", 
- "name": "Training Event Employee", 
- "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": 0, 
- "track_seen": 0, 
- "track_views": 0
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-05-21 12:41:59.336237",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Training Event Employee",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC"
 }
\ No newline at end of file
diff --git a/erpnext/hr/notification/training_scheduled/training_scheduled.json b/erpnext/hr/notification/training_scheduled/training_scheduled.json
index 966b887..e49541e 100644
--- a/erpnext/hr/notification/training_scheduled/training_scheduled.json
+++ b/erpnext/hr/notification/training_scheduled/training_scheduled.json
@@ -11,16 +11,18 @@
  "event": "Submit",
  "idx": 0,
  "is_standard": 1,
- "message": "<table class=\"panel-header\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n    <tr height=\"10\"></tr>\n    <tr>\n        <td width=\"15\"></td>\n        <td>\n            <div class=\"text-medium text-muted\">\n                <span>{{_(\"Training Event:\")}} {{ doc.event_name }}</span>\n            </div>\n        </td>\n        <td width=\"15\"></td>\n    </tr>\n    <tr height=\"10\"></tr>\n</table>\n\n<table class=\"panel-body\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n    <tr height=\"10\"></tr>\n    <tr>\n        <td width=\"15\"></td>\n        <td>\n            <div>\n                <ul class=\"list-unstyled\" style=\"line-height: 1.7\">\n                    <li>{{ doc.introduction }}</li>\n                    <li>{{_(\"Event Location\")}}: <b>{{ doc.location }}</b></li>\n                    {% set start = frappe.utils.get_datetime(doc.start_time) %}\n                    {% set end = frappe.utils.get_datetime(doc.end_time) %}\n                    {% if start.date() == end.date() %}\n                    <li>{{_(\"Date\")}}: <b>{{ start.strftime(\"%A, %d %b %Y\") }}</b></li>\n                    <li>\n                        {{_(\"Timing\")}}: <b>{{ start.strftime(\"%I:%M %p\") + ' to ' + end.strftime(\"%I:%M %p\") }}</b>\n                    </li>\n                    {% else %}\n                    <li>{{_(\"Start Time\")}}: <b>{{ start.strftime(\"%A, %d %b %Y at %I:%M %p\") }}</b>\n                    </li>\n                    <li>{{_(\"End Time\")}}: <b>{{ end.strftime(\"%A, %d %b %Y at %I:%M %p\") }}</b>\n                    </li>\n                    {% endif %}\n                </ul>\n                {{ _('Event Link') }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}\n            </div>\n        </td>\n        <td width=\"15\"></td>\n    </tr>\n    <tr height=\"10\"></tr>\n</table>",
- "modified": "2019-11-29 15:38:31.805409",
+ "message": "<table class=\"panel-header\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n    <tr height=\"10\"></tr>\n    <tr>\n        <td width=\"15\"></td>\n        <td>\n            <div class=\"text-medium text-muted\">\n                <span>{{_(\"Training Event:\")}} {{ doc.event_name }}</span>\n            </div>\n        </td>\n        <td width=\"15\"></td>\n    </tr>\n    <tr height=\"10\"></tr>\n</table>\n\n<table class=\"panel-body\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n    <tr height=\"10\"></tr>\n    <tr>\n        <td width=\"15\"></td>\n        <td>\n            <div>\n                {{ doc.introduction }}\n                <ul class=\"list-unstyled\" style=\"line-height: 1.7\">\n                    <li>{{_(\"Event Location\")}}: <b>{{ doc.location }}</b></li>\n                    {% set start = frappe.utils.get_datetime(doc.start_time) %}\n                    {% set end = frappe.utils.get_datetime(doc.end_time) %}\n                    {% if start.date() == end.date() %}\n                    <li>{{_(\"Date\")}}: <b>{{ start.strftime(\"%A, %d %b %Y\") }}</b></li>\n                    <li>\n                        {{_(\"Timing\")}}: <b>{{ start.strftime(\"%I:%M %p\") + ' to ' + end.strftime(\"%I:%M %p\") }}</b>\n                    </li>\n                    {% else %}\n                    <li>{{_(\"Start Time\")}}: <b>{{ start.strftime(\"%A, %d %b %Y at %I:%M %p\") }}</b>\n                    </li>\n                    <li>{{_(\"End Time\")}}: <b>{{ end.strftime(\"%A, %d %b %Y at %I:%M %p\") }}</b>\n                    </li>\n                    {% endif %}\n                    <li>{{ _('Event Link') }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}</li>\n                    {% if doc.is_mandatory %}\n                    <li>Note: This Training Event is mandatory</li>\n                    {% endif %}\n                </ul>\n            </div>\n        </td>\n        <td width=\"15\"></td>\n    </tr>\n    <tr height=\"10\"></tr>\n</table>",
+ "modified": "2021-05-24 16:29:13.165930",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Training Scheduled",
  "owner": "Administrator",
  "recipients": [
   {
-   "email_by_document_field": "employee_emails"
+   "receiver_by_document_field": "employee_emails"
   }
  ],
+ "send_system_notification": 0,
+ "send_to_all_assignees": 0,
  "subject": "Training Scheduled: {{ doc.name }}"
 }
\ No newline at end of file
diff --git a/erpnext/hr/notification/training_scheduled/training_scheduled.md b/erpnext/hr/notification/training_scheduled/training_scheduled.md
index 374038a..418fd49 100644
--- a/erpnext/hr/notification/training_scheduled/training_scheduled.md
+++ b/erpnext/hr/notification/training_scheduled/training_scheduled.md
@@ -35,6 +35,9 @@
                     </li>
                     {% endif %}
                     <li>{{ _('Event Link') }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}</li>
+                    {% if doc.is_mandatory %}
+                    <li>Note: This Training Event is mandatory</li>
+                    {% endif %}
                 </ul>
             </div>
         </td>
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index 2540b3d..80189e8 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -500,13 +500,6 @@
 		total_claimed_amount = sum_of_claimed_amount[0].total_amount
 	return total_claimed_amount
 
-def grant_leaves_automatically():
-	automatically_allocate_leaves_based_on_leave_policy = frappe.db.get_singles_value("HR Settings", "automatically_allocate_leaves_based_on_leave_policy")
-	if automatically_allocate_leaves_based_on_leave_policy:
-		lpa = frappe.db.get_all("Leave Policy Assignment", filters={"effective_from": getdate(), "docstatus": 1, "leaves_allocated":0})
-		for assignment in lpa:
-			frappe.get_doc("Leave Policy Assignment", assignment.name).grant_leave_alloc_for_employee()
-
 def share_doc_with_approver(doc, user):
 	# if approver does not have permissions, share
 	if not frappe.has_permission(doc=doc, ptype="submit", user=user):
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js
index a6086fb..3e5a72d 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.js
+++ b/erpnext/manufacturing/doctype/work_order/work_order.js
@@ -76,9 +76,9 @@
 		frm.set_query("production_item", function() {
 			return {
 				query: "erpnext.controllers.queries.item_query",
-				filters:[
-					['is_stock_item', '=',1]
-				]
+				filters: {
+					"is_stock_item": 1,
+				}
 			};
 		});
 
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index f94644d..1e8ce3c 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -769,6 +769,7 @@
 erpnext.patches.v12_0.create_taxable_value_field
 erpnext.patches.v12_0.add_gst_category_in_delivery_note
 erpnext.patches.v12_0.purchase_receipt_status
+erpnext.patches.v12_0.create_itc_reversal_custom_fields
 erpnext.patches.v13_0.fix_non_unique_represents_company
 erpnext.patches.v12_0.add_document_type_field_for_italy_einvoicing
 erpnext.patches.v13_0.make_non_standard_user_type #13-04-2021
@@ -779,3 +780,4 @@
 erpnext.patches.v13_0.germany_fill_debtor_creditor_number
 erpnext.patches.v13_0.set_pos_closing_as_failed
 erpnext.patches.v13_0.update_timesheet_changes
+erpnext.patches.v13_0.set_training_event_attendance
diff --git a/erpnext/patches/v12_0/create_itc_reversal_custom_fields.py b/erpnext/patches/v12_0/create_itc_reversal_custom_fields.py
new file mode 100644
index 0000000..0078a53
--- /dev/null
+++ b/erpnext/patches/v12_0/create_itc_reversal_custom_fields.py
@@ -0,0 +1,115 @@
+from __future__ import unicode_literals
+import frappe
+from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+from frappe.custom.doctype.property_setter.property_setter import make_property_setter
+from erpnext.regional.india.utils import get_gst_accounts
+
+def execute():
+	company = frappe.get_all('Company', filters = {'country': 'India'}, fields=['name'])
+	if not company:
+		return
+
+	frappe.reload_doc("regional", "doctype", "gst_settings")
+	frappe.reload_doc("accounts", "doctype", "gst_account")
+
+	journal_entry_types = frappe.get_meta("Journal Entry").get_options("voucher_type").split("\n") + ['Reversal Of ITC']
+	make_property_setter('Journal Entry', 'voucher_type', 'options', '\n'.join(journal_entry_types), '')
+
+	custom_fields = {
+		'Journal Entry': [
+			dict(fieldname='reversal_type', label='Reversal Type',
+				fieldtype='Select', insert_after='voucher_type', print_hide=1,
+				options="As per rules 42 & 43 of CGST Rules\nOthers",
+				depends_on="eval:doc.voucher_type=='Reversal Of ITC'",
+				mandatory_depends_on="eval:doc.voucher_type=='Reversal Of ITC'"),
+			dict(fieldname='company_address', label='Company Address',
+				fieldtype='Link', options='Address', insert_after='reversal_type',
+				print_hide=1, depends_on="eval:doc.voucher_type=='Reversal Of ITC'",
+				mandatory_depends_on="eval:doc.voucher_type=='Reversal Of ITC'"),
+			dict(fieldname='company_gstin', label='Company GSTIN',
+				fieldtype='Data', read_only=1, insert_after='company_address', print_hide=1,
+				fetch_from='company_address.gstin',
+				depends_on="eval:doc.voucher_type=='Reversal Of ITC'",
+				mandatory_depends_on="eval:doc.voucher_type=='Reversal Of ITC'")
+		],
+		'Purchase Invoice': [
+			dict(fieldname='eligibility_for_itc', label='Eligibility For ITC',
+				fieldtype='Select', insert_after='reason_for_issuing_document', print_hide=1,
+				options='Input Service Distributor\nImport Of Service\nImport Of Capital Goods\nITC on Reverse Charge\nIneligible As Per Section 17(5)\nIneligible Others\nAll Other ITC',
+				default="All Other ITC")
+		],
+		'Purchase Invoice Item': [
+			dict(fieldname='taxable_value', label='Taxable Value',
+				fieldtype='Currency', insert_after='base_net_amount', hidden=1, options="Company:company:default_currency",
+				print_hide=1)
+		]
+	}
+
+	create_custom_fields(custom_fields, update=True)
+
+	# Patch ITC Availed fields from Data to Currency
+	# Patch Availed ITC for current fiscal_year
+
+	gst_accounts = get_gst_accounts(only_non_reverse_charge=1)
+
+	frappe.db.sql("""
+		UPDATE `tabCustom Field` SET fieldtype='Currency', options='Company:company:default_currency'
+		WHERE dt = 'Purchase Invoice' and fieldname in ('itc_integrated_tax', 'itc_state_tax', 'itc_central_tax',
+			'itc_cess_amount')
+	""")
+
+	frappe.db.sql("""UPDATE `tabPurchase Invoice` set itc_integrated_tax = '0'
+		WHERE trim(coalesce(itc_integrated_tax, '')) = '' """)
+
+	frappe.db.sql("""UPDATE `tabPurchase Invoice` set itc_state_tax = '0'
+		WHERE trim(coalesce(itc_state_tax, '')) = '' """)
+
+	frappe.db.sql("""UPDATE `tabPurchase Invoice` set itc_central_tax = '0'
+		WHERE trim(coalesce(itc_central_tax, '')) = '' """)
+
+	frappe.db.sql("""UPDATE `tabPurchase Invoice` set itc_cess_amount = '0'
+		WHERE trim(coalesce(itc_cess_amount, '')) = '' """)
+
+	# Get purchase invoices
+	invoices = frappe.get_all('Purchase Invoice',
+		{'posting_date': ('>=', '2021-04-01'), 'eligibility_for_itc': ('!=', 'Ineligible')},
+		['name'])
+
+	amount_map = {}
+
+	if invoices:
+		invoice_list = set([d.name for d in invoices])
+
+		# Get GST applied
+		amounts = frappe.db.sql("""
+			SELECT parent, account_head, sum(base_tax_amount_after_discount_amount) as amount
+			FROM `tabPurchase Taxes and Charges`
+			where parent in %s
+			GROUP BY parent, account_head
+		""", (invoice_list), as_dict=1)
+
+		for d in amounts:
+			amount_map.setdefault(d.parent,
+			{
+				'itc_integrated_tax': 0,
+				'itc_state_tax': 0,
+				'itc_central_tax': 0,
+				'itc_cess_amount': 0
+			})
+
+			if d.account_head in gst_accounts.get('igst_account'):
+				amount_map[d.parent]['itc_integrated_tax'] += d.amount
+			if d.account_head in gst_accounts.get('cgst_account'):
+				amount_map[d.parent]['itc_central_tax'] += d.amount
+			if d.account_head in gst_accounts.get('sgst_account'):
+				amount_map[d.parent]['itc_state_tax'] += d.amount
+			if d.account_head in gst_accounts.get('cess_account'):
+				amount_map[d.parent]['itc_cess_amount'] += d.amount
+
+		for invoice, values in amount_map.items():
+			frappe.db.set_value('Purchase Invoice', invoice, {
+				'itc_integrated_tax': values.get('itc_integrated_tax'),
+				'itc_central_tax': values.get('itc_central_tax'),
+				'itc_state_tax': values['itc_state_tax'],
+				'itc_cess_amount': values['itc_cess_amount'],
+			})
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/set_training_event_attendance.py b/erpnext/patches/v13_0/set_training_event_attendance.py
new file mode 100644
index 0000000..18cad8d
--- /dev/null
+++ b/erpnext/patches/v13_0/set_training_event_attendance.py
@@ -0,0 +1,9 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+    frappe.reload_doc('hr', 'doctype', 'training_event')
+    frappe.reload_doc('hr', 'doctype', 'training_event_employee')
+
+    frappe.db.sql("update `tabTraining Event Employee` set `attendance` = 'Present'")
+    frappe.db.sql("update `tabTraining Event Employee` set `is_mandatory` = 1 where `attendance` = 'Mandatory'")
\ No newline at end of file
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py
index afdf081..3c25331 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py
@@ -621,16 +621,13 @@
 
 			component_row = self.append(component_type)
 			for attr in (
-				'depends_on_payment_days', 'salary_component',
+				'depends_on_payment_days', 'salary_component', 'abbr',
 				'do_not_include_in_total', 'is_tax_applicable',
 				'is_flexible_benefit', 'variable_based_on_taxable_salary',
 				'exempted_from_income_tax'
 			):
 				component_row.set(attr, component_data.get(attr))
 
-			abbr = component_data.get('abbr') or component_data.get('salary_component_abbr')
-			component_row.set('abbr', abbr)
-
 		if additional_salary:
 			component_row.default_amount = 0
 			component_row.additional_amount = amount
diff --git a/erpnext/projects/doctype/project/project.js b/erpnext/projects/doctype/project/project.js
index c5265e2..31460f6 100644
--- a/erpnext/projects/doctype/project/project.js
+++ b/erpnext/projects/doctype/project/project.js
@@ -87,7 +87,7 @@
 
 				frm.add_custom_button(__("Kanban Board"), () => {
 					frappe.call('erpnext.projects.doctype.project.project.create_kanban_board_if_not_exists', {
-						project: frm.doc.project_name
+						project: frm.doc.name
 					}).then(() => {
 						frappe.set_route('List', 'Task', 'Kanban', frm.doc.project_name);
 					});
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index 55c5149..c8fbe0b 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -523,8 +523,9 @@
 def create_kanban_board_if_not_exists(project):
 	from frappe.desk.doctype.kanban_board.kanban_board import quick_kanban_board
 
-	if not frappe.db.exists('Kanban Board', project):
-		quick_kanban_board('Task', project, 'status', project)
+	project = frappe.get_doc('Project', project)
+	if not frappe.db.exists('Kanban Board', project.project_name):
+		quick_kanban_board('Task', project.project_name, 'status', project.name)
 
 	return True
 
diff --git a/erpnext/projects/doctype/task/task.js b/erpnext/projects/doctype/task/task.js
index 6a9d2d1..3cd92ee 100644
--- a/erpnext/projects/doctype/task/task.js
+++ b/erpnext/projects/doctype/task/task.js
@@ -5,12 +5,6 @@
 
 frappe.ui.form.on("Task", {
 	setup: function (frm) {
-		frm.set_query("project", function () {
-			return {
-				query: "erpnext.projects.doctype.task.task.get_project"
-			}
-		});
-
 		frm.make_methods = {
 			'Timesheet': () => frappe.model.open_mapped_doc({
 				method: 'erpnext.projects.doctype.task.task.make_timesheet',
diff --git a/erpnext/projects/report/project_profitability/test_project_profitability.py b/erpnext/projects/report/project_profitability/test_project_profitability.py
index f2b9c25..ea6bdb5 100644
--- a/erpnext/projects/report/project_profitability/test_project_profitability.py
+++ b/erpnext/projects/report/project_profitability/test_project_profitability.py
@@ -8,7 +8,7 @@
 from erpnext.projects.report.project_profitability.project_profitability import execute
 
 class TestProjectProfitability(unittest.TestCase):
-	@classmethod
+
 	def setUp(self):
 		emp = make_employee('test_employee_9@salary.com', company='_Test Company')
 		if not frappe.db.exists('Salary Component', 'Timesheet Component'):
@@ -21,7 +21,7 @@
 		self.sales_invoice.due_date = nowdate()
 		self.sales_invoice.submit()
 
-		frappe.db.set_value("HR Settings", "HR Settings", "standard_working_hours", 8)
+		frappe.db.set_value('HR Settings', None, 'standard_working_hours', 8)
 
 	def test_project_profitability(self):
 		filters = {
@@ -55,4 +55,4 @@
 	def tearDown(self):
 		frappe.get_doc("Sales Invoice", self.sales_invoice.name).cancel()
 		frappe.get_doc("Salary Slip", self.salary_slip.name).cancel()
-		frappe.get_doc("Timesheet", self.timesheet.name).cancel()
\ No newline at end of file
+		frappe.get_doc("Timesheet", self.timesheet.name).cancel()
diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js
index 8b4a497..680bf04 100644
--- a/erpnext/public/js/controllers/buying.js
+++ b/erpnext/public/js/controllers/buying.js
@@ -84,13 +84,13 @@
 			if (me.frm.doc.is_subcontracted == "Yes") {
 				return{
 					query: "erpnext.controllers.queries.item_query",
-					filters:{ 'is_sub_contracted_item': 1 }
+					filters:{ 'supplier': me.frm.doc.supplier, 'is_sub_contracted_item': 1 }
 				}
 			}
 			else {
 				return{
 					query: "erpnext.controllers.queries.item_query",
-					filters: {'is_purchase_item': 1}
+					filters: { 'supplier': me.frm.doc.supplier, 'is_purchase_item': 1 }
 				}
 			}
 		});
diff --git a/erpnext/public/js/utils/serial_no_batch_selector.js b/erpnext/public/js/utils/serial_no_batch_selector.js
index 79b6220..02b5ef3 100644
--- a/erpnext/public/js/utils/serial_no_batch_selector.js
+++ b/erpnext/public/js/utils/serial_no_batch_selector.js
@@ -74,9 +74,18 @@
 				fieldname: 'qty',
 				fieldtype:'Float',
 				read_only: me.has_batch && !me.has_serial_no,
-				label: __(me.has_batch && !me.has_serial_no ? 'Total Qty' : 'Qty'),
+				label: __(me.has_batch && !me.has_serial_no ? 'Selected Qty' : 'Qty'),
 				default: flt(me.item.stock_qty),
 			},
+			...get_pending_qty_fields(me),
+			{
+				fieldname: 'uom',
+				read_only: 1,
+				fieldtype: 'Link',
+				options: 'UOM',
+				label: __('UOM'),
+				default: me.item.uom
+			},
 			{
 				fieldname: 'auto_fetch_button',
 				fieldtype:'Button',
@@ -173,6 +182,7 @@
 
 		if (this.has_batch && !this.has_serial_no) {
 			this.update_total_qty();
+			this.update_pending_qtys();
 		}
 
 		this.dialog.show();
@@ -314,7 +324,23 @@
 		qty_field.set_input(total_qty);
 	}
 
-	get_batch_fields() {
+	update_pending_qtys: function() {
+		const pending_qty_field = this.dialog.fields_dict.pending_qty;
+		const total_selected_qty_field = this.dialog.fields_dict.total_selected_qty;
+
+		if (!pending_qty_field || !total_selected_qty_field) return;
+
+		const me = this;
+		const required_qty = this.dialog.fields_dict.required_qty.value;
+		const selected_qty = this.dialog.fields_dict.qty.value;
+		const total_selected_qty = selected_qty + calc_total_selected_qty(me);
+		const pending_qty = required_qty - total_selected_qty;
+
+		pending_qty_field.set_input(pending_qty);
+		total_selected_qty_field.set_input(total_selected_qty);
+	}
+
+	get_batch_fields: function() {
 		var me = this;
 
 		return [
@@ -415,6 +441,7 @@
 							}
 
 							me.update_total_qty();
+							me.update_pending_qtys();
 						}
 					},
 				],
@@ -510,4 +537,61 @@
 			}
 		];
 	}
-};
+});
+
+function get_pending_qty_fields(me) {
+	if (!check_can_calculate_pending_qty(me)) return [];
+	const { frm: { doc: { fg_completed_qty }}, item: { item_code, stock_qty }} = me;
+	const { qty_consumed_per_unit } = erpnext.stock.bom.items[item_code];
+
+	const total_selected_qty = calc_total_selected_qty(me);
+	const required_qty = flt(fg_completed_qty) * flt(qty_consumed_per_unit);
+	const pending_qty = required_qty - (flt(stock_qty) + total_selected_qty);
+
+	const pending_qty_fields =  [
+		{ fieldtype: 'Section Break', label: __('Pending Quantity') },
+		{
+			fieldname: 'required_qty',
+			read_only: 1,
+			fieldtype: 'Float',
+			label: __('Required Qty'),
+			default: required_qty
+		},
+		{ fieldtype: 'Column Break' },
+		{
+			fieldname: 'total_selected_qty',
+			read_only: 1,
+			fieldtype: 'Float',
+			label: __('Total Selected Qty'),
+			default: total_selected_qty
+		},
+		{ fieldtype: 'Column Break' },
+		{
+			fieldname: 'pending_qty',
+			read_only: 1,
+			fieldtype: 'Float',
+			label: __('Pending Qty'),
+			default: pending_qty
+		},
+	];
+	return pending_qty_fields;
+}
+
+function calc_total_selected_qty(me) {
+	const { frm: { doc: { items }}, item: { name, item_code }} = me;
+	const totalSelectedQty = items
+		.filter( item => ( item.name !== name ) && ( item.item_code === item_code ) )
+		.map( item => flt(item.qty) )
+		.reduce( (i, j) => i + j, 0);
+	return totalSelectedQty;
+}
+
+function check_can_calculate_pending_qty(me) {
+	const { frm: { doc }, item } = me;
+	const docChecks = doc.bom_no
+		&& doc.fg_completed_qty
+		&& erpnext.stock.bom
+		&& erpnext.stock.bom.name === doc.bom_no;
+	const itemChecks = !!item;
+	return docChecks && itemChecks;
+}
diff --git a/erpnext/regional/address_template/templates/united_states.html b/erpnext/regional/address_template/templates/united_states.html
index 089315e..77fce46 100644
--- a/erpnext/regional/address_template/templates/united_states.html
+++ b/erpnext/regional/address_template/templates/united_states.html
@@ -1,4 +1,4 @@
 {{ address_line1 }}<br>
 {% if address_line2 %}{{ address_line2 }}<br>{% endif -%}
 {{ city }}, {% if state %}{{ state }}{% endif -%}{% if pincode %} {{ pincode }}<br>{% endif -%}
-{% if country != "United States" %}{{ country|upper }}{% endif -%}
+{% if country != "United States" %}{{ country }}{% endif -%}
diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.html b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.html
index 369a400..3b6a45a 100644
--- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.html
+++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.html
@@ -172,7 +172,7 @@
 		</thead>
 		<tbody>
 			<tr>
-				<td><b>(A) {{__("ITC Available (whether in full op part)")}}</b></td>
+				<td><b>(A) {{__("ITC Available (whether in full or part)")}}</b></td>
 				<td></td>
 				<td></td>
 				<td></td>
diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
index a5dd5a2..6415204 100644
--- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
+++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
@@ -3,148 +3,21 @@
 # For license information, please see license.txt
 
 from __future__ import unicode_literals
+import os
+import json
 import frappe
+from six import iteritems
 from frappe import _
 from frappe.model.document import Document
-import json
-from six import iteritems
-from frappe.utils import flt, getdate
+from frappe.utils import flt, cstr
 from erpnext.regional.india import state_numbers
 
 class GSTR3BReport(Document):
-	def before_save(self):
-
+	def validate(self):
 		self.get_data()
 
 	def get_data(self):
-
-		self.report_dict = {
-			"gstin": "",
-			"ret_period": "",
-			"inward_sup": {
-				"isup_details": [
-					{
-						"ty": "GST",
-						"intra": 0,
-						"inter": 0
-					},
-					{
-						"ty": "NONGST",
-						"inter": 0,
-						"intra": 0
-					}
-				]
-			},
-			"sup_details": {
-				"osup_zero": {
-					"csamt": 0,
-					"txval": 0,
-					"iamt": 0
-				},
-				"osup_nil_exmp": {
-					"txval": 0
-				},
-				"osup_det": {
-					"samt": 0,
-					"csamt": 0,
-					"txval": 0,
-					"camt": 0,
-					"iamt": 0
-				},
-				"isup_rev": {
-					"samt": 0,
-					"csamt": 0,
-					"txval": 0,
-					"camt": 0,
-					"iamt": 0
-				},
-				"osup_nongst": {
-					"txval": 0,
-				}
-			},
-			"inter_sup": {
-				"unreg_details": [],
-				"comp_details": [],
-				"uin_details": []
-			},
-			"itc_elg": {
-				"itc_avl": [
-					{
-						"csamt": 0,
-						"samt": 0,
-						"ty": "IMPG",
-						"camt": 0,
-						"iamt": 0
-					},
-					{
-						"csamt": 0,
-						"samt": 0,
-						"ty": "IMPS",
-						"camt": 0,
-						"iamt": 0
-					},
-					{
-						"samt": 0,
-						"csamt": 0,
-						"ty": "ISRC",
-						"camt": 0,
-						"iamt": 0
-					},
-					{
-						"ty": "ISD",
-						"iamt": 0,
-						"camt": 0,
-						"samt": 0,
-						"csamt": 0
-					},
-					{
-						"samt": 0,
-						"csamt": 0,
-						"ty": "OTH",
-						"camt": 0,
-						"iamt": 0
-					}
-				],
-				"itc_rev": [
-					{
-						"ty": "RUL",
-						"iamt": 0,
-						"camt": 0,
-						"samt": 0,
-						"csamt": 0
-					},
-					{
-						"ty": "OTH",
-						"iamt": 0,
-						"camt": 0,
-						"samt": 0,
-						"csamt": 0
-					}
-				],
-				"itc_net": {
-					"samt": 0,
-					"csamt": 0,
-					"camt": 0,
-					"iamt": 0
-				},
-				"itc_inelg": [
-					{
-						"ty": "RUL",
-						"iamt": 0,
-						"camt": 0,
-						"samt": 0,
-						"csamt": 0
-					},
-					{
-						"ty": "OTH",
-						"iamt": 0,
-						"camt": 0,
-						"samt": 0,
-						"csamt": 0
-					}
-				]
-			}
-		}
+		self.report_dict = json.loads(get_json('gstr_3b_report_template'))
 
 		self.gst_details = self.get_company_gst_details()
 		self.report_dict["gstin"] = self.gst_details.get("gstin")
@@ -152,23 +25,19 @@
 		self.month_no = get_period(self.month)
 		self.account_heads = self.get_account_heads()
 
-		outward_supply_tax_amounts = self.get_tax_amounts("Sales Invoice")
-		inward_supply_tax_amounts = self.get_tax_amounts("Purchase Invoice", reverse_charge="Y")
+		self.get_outward_supply_details("Sales Invoice")
+		self.set_outward_taxable_supplies()
+
+		self.get_outward_supply_details("Purchase Invoice", reverse_charge=True)
+		self.set_supplies_liable_to_reverse_charge()
+
 		itc_details = self.get_itc_details()
-
-		self.prepare_data("Sales Invoice", outward_supply_tax_amounts, "sup_details", "osup_det", ["Registered Regular"])
-		self.prepare_data("Sales Invoice", outward_supply_tax_amounts, "sup_details", "osup_zero", ["SEZ", "Deemed Export", "Overseas"])
-		self.prepare_data("Purchase Invoice", inward_supply_tax_amounts, "sup_details", "isup_rev", ["Unregistered", "Overseas"], reverse_charge="Y")
-		self.report_dict["sup_details"]["osup_nil_exmp"]["txval"] = flt(self.get_nil_rated_supply_value(), 2)
 		self.set_itc_details(itc_details)
-
-		inter_state_supplies = self.get_inter_state_supplies(self.gst_details.get("gst_state_number"))
+		self.get_itc_reversal_entries()
 		inward_nil_exempt = self.get_inward_nil_exempt(self.gst_details.get("gst_state"))
-		self.set_inter_state_supply(inter_state_supplies)
 		self.set_inward_nil_exempt(inward_nil_exempt)
 
 		self.missing_field_invoices = self.get_missing_field_invoices()
-
 		self.json_output = frappe.as_json(self.report_dict)
 
 	def set_inward_nil_exempt(self, inward_nil_exempt):
@@ -178,189 +47,95 @@
 		self.report_dict["inward_sup"]["isup_details"][1]["intra"] = flt(inward_nil_exempt.get("non_gst").get("intra"), 2)
 
 	def set_itc_details(self, itc_details):
-
-		itc_type_map = {
+		itc_eligible_type_map = {
 			'IMPG': 'Import Of Capital Goods',
 			'IMPS': 'Import Of Service',
+			'ISRC': 'ITC on Reverse Charge',
 			'ISD': 'Input Service Distributor',
 			'OTH': 'All Other ITC'
 		}
 
+		itc_ineligible_map = {
+			'RUL': 'Ineligible As Per Section 17(5)',
+			'OTH': 'Ineligible Others'
+		}
+
 		net_itc = self.report_dict["itc_elg"]["itc_net"]
 
 		for d in self.report_dict["itc_elg"]["itc_avl"]:
-
-			itc_type = itc_type_map.get(d["ty"])
-
-			if d["ty"] == 'ISRC':
-				reverse_charge = ["Y"]
-				itc_type = 'All Other ITC'
-				gst_category = ['Unregistered', 'Overseas']
-			else:
-				gst_category = ['Unregistered', 'Overseas', 'Registered Regular']
-				reverse_charge = ["N", "Y"]
-
-			for account_head in self.account_heads:
-				for category in gst_category:
-					for charge_type in reverse_charge:
-						for key in [['iamt', 'igst_account'], ['camt', 'cgst_account'], ['samt', 'sgst_account'], ['csamt', 'cess_account']]:
-							d[key[0]] += flt(itc_details.get((category, itc_type, charge_type, account_head.get(key[1])), {}).get("amount"), 2)
-
+			itc_type = itc_eligible_type_map.get(d["ty"])
 			for key in ['iamt', 'camt', 'samt', 'csamt']:
+				d[key] = flt(itc_details.get(itc_type, {}).get(key))
 				net_itc[key] += flt(d[key], 2)
 
-		for account_head in self.account_heads:
-			itc_inelg = self.report_dict["itc_elg"]["itc_inelg"][1]
-			for key in [['iamt', 'igst_account'], ['camt', 'cgst_account'], ['samt', 'sgst_account'], ['csamt', 'cess_account']]:
-				itc_inelg[key[0]] = flt(itc_details.get(("Ineligible", "N", account_head.get(key[1])), {}).get("amount"), 2)
+		for d in self.report_dict["itc_elg"]["itc_inelg"]:
+			itc_type = itc_ineligible_map.get(d["ty"])
+			for key in ['iamt', 'camt', 'samt', 'csamt']:
+				d[key] = flt(itc_details.get(itc_type, {}).get(key))
 
-	def prepare_data(self, doctype, tax_details, supply_type, supply_category, gst_category_list, reverse_charge="N"):
+	def get_itc_reversal_entries(self):
+		reversal_entries = frappe.db.sql("""
+			SELECT ja.account, j.reversal_type, sum(credit_in_account_currency) as amount
+			FROM `tabJournal Entry` j, `tabJournal Entry Account` ja
+			where j.docstatus = 1
+			and j.is_opening = 'No'
+			and ja.parent = j.name
+			and j.voucher_type = 'Reversal Of ITC'
+			and month(j.posting_date) = %s and year(j.posting_date) = %s
+			and j.company = %s and j.company_gstin = %s
+			GROUP BY ja.account, j.reversal_type""", (self.month_no, self.year, self.company,
+			self.gst_details.get("gstin")), as_dict=1)
 
-		account_map = {
-			'sgst_account': 'samt',
-			'cess_account': 'csamt',
-			'cgst_account': 'camt',
-			'igst_account': 'iamt'
-		}
+		net_itc = self.report_dict["itc_elg"]["itc_net"]
 
-		txval = 0
-		total_taxable_value = self.get_total_taxable_value(doctype, reverse_charge)
+		for entry in reversal_entries:
+			if entry.reversal_type == 'As per rules 42 & 43 of CGST Rules':
+				index = 0
+			else:
+				index = 1
 
-		for gst_category in gst_category_list:
-			txval += total_taxable_value.get(gst_category,0)
-			for account_head in self.account_heads:
-				for account_type, account_name in iteritems(account_head):
-					if account_map.get(account_type) in self.report_dict.get(supply_type).get(supply_category):
-						self.report_dict[supply_type][supply_category][account_map.get(account_type)] += \
-							flt(tax_details.get((account_name, gst_category), {}).get("amount"), 2)
-
-		self.report_dict[supply_type][supply_category]["txval"] += flt(txval, 2)
-
-	def set_inter_state_supply(self, inter_state_supply):
-		osup_det = self.report_dict["sup_details"]["osup_det"]
-
-		for key, value in iteritems(inter_state_supply):
-			if key[0] == "Unregistered":
-				self.report_dict["inter_sup"]["unreg_details"].append(value)
-
-			if key[0] == "Registered Composition":
-				self.report_dict["inter_sup"]["comp_details"].append(value)
-
-			if key[0] == "UIN Holders":
-				self.report_dict["inter_sup"]["uin_details"].append(value)
-
-	def get_total_taxable_value(self, doctype, reverse_charge):
-
-		return frappe._dict(frappe.db.sql("""
-			select gst_category, sum(net_total) as total
-			from `tab{doctype}`
-			where docstatus = 1 and month(posting_date) = %s
-			and year(posting_date) = %s and reverse_charge = %s
-			and company = %s and company_gstin = %s
-			group by gst_category
-			""" #nosec
-			.format(doctype = doctype), (self.month_no, self.year, reverse_charge, self.company, self.gst_details.get("gstin"))))
+			for key in ['camt', 'samt', 'iamt', 'csamt']:
+				if entry.account in self.account_heads.get(key):
+					self.report_dict["itc_elg"]["itc_rev"][index][key] += flt(entry.amount)
+					net_itc[key] -= flt(entry.amount)
 
 	def get_itc_details(self):
-		itc_amount = frappe.db.sql("""
-			select s.gst_category, sum(t.base_tax_amount_after_discount_amount) as tax_amount,
-			t.account_head, s.eligibility_for_itc, s.reverse_charge
-			from `tabPurchase Invoice` s , `tabPurchase Taxes and Charges` t
-			where s.docstatus = 1 and t.parent = s.name
-			and month(s.posting_date) = %s and year(s.posting_date) = %s and s.company = %s
-			and s.company_gstin = %s
-			group by t.account_head, s.gst_category, s.eligibility_for_itc
-			""",
-			(self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
+		itc_amounts = frappe.db.sql("""
+			SELECT eligibility_for_itc, sum(itc_integrated_tax) as itc_integrated_tax,
+			sum(itc_central_tax) as itc_central_tax,
+			sum(itc_state_tax) as itc_state_tax,
+			sum(itc_cess_amount) as itc_cess_amount
+			FROM `tabPurchase Invoice`
+			WHERE docstatus = 1
+			and is_opening = 'No'
+			and month(posting_date) = %s and year(posting_date) = %s and company = %s
+			and company_gstin = %s
+			GROUP BY eligibility_for_itc
+		""", (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
 
 		itc_details = {}
-
-		for d in itc_amount:
-			itc_details.setdefault((d.gst_category, d.eligibility_for_itc, d.reverse_charge, d.account_head),{
-				"amount": d.tax_amount
+		for d in itc_amounts:
+			itc_details.setdefault(d.eligibility_for_itc, {
+				'iamt': d.itc_integrated_tax,
+				'camt': d.itc_central_tax,
+				'samt': d.itc_state_tax,
+				'csamt': d.itc_cess_amount
 			})
 
 		return itc_details
 
-	def get_nil_rated_supply_value(self):
-
-		return frappe.db.sql("""
-			select sum(i.base_amount) as total from
-			`tabSales Invoice Item` i, `tabSales Invoice` s
-			where s.docstatus = 1 and i.parent = s.name and i.is_nil_exempt = 1
-			and month(s.posting_date) = %s and year(s.posting_date) = %s
-			and s.company = %s and s.company_gstin = %s""",
-			(self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)[0].total
-
-	def get_inter_state_supplies(self, state_number):
-		inter_state_supply_tax = frappe.db.sql(""" select t.account_head, t.tax_amount_after_discount_amount as tax_amount,
-			s.name, s.net_total, s.place_of_supply, s.gst_category from `tabSales Invoice` s, `tabSales Taxes and Charges` t
-			where t.parent = s.name and s.docstatus = 1 and month(s.posting_date) = %s and year(s.posting_date) = %s
-			and s.company = %s and s.company_gstin = %s and s.gst_category in ('Unregistered', 'Registered Composition', 'UIN Holders')
-		""", (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
-
-		inter_state_supply_tax_mapping = {}
-		inter_state_supply_details = {}
-
-		for d in inter_state_supply_tax:
-			inter_state_supply_tax_mapping.setdefault(d.name, {
-				'place_of_supply': d.place_of_supply,
-				'taxable_value': d.net_total,
-				'gst_category': d.gst_category,
-				'camt': 0.0,
-				'samt': 0.0,
-				'iamt': 0.0,
-				'csamt': 0.0
-			})
-
-			if d.account_head in [a.cgst_account for a in self.account_heads]:
-				inter_state_supply_tax_mapping[d.name]['camt'] += d.tax_amount
-
-			if d.account_head in [a.sgst_account for a in self.account_heads]:
-				inter_state_supply_tax_mapping[d.name]['samt'] += d.tax_amount
-
-			if d.account_head in [a.igst_account for a in self.account_heads]:
-				inter_state_supply_tax_mapping[d.name]['iamt'] += d.tax_amount
-
-			if d.account_head in [a.cess_account for a in self.account_heads]:
-				inter_state_supply_tax_mapping[d.name]['csamt'] += d.tax_amount
-
-		for key, value in iteritems(inter_state_supply_tax_mapping):
-			if value.get('place_of_supply'):
-				osup_det = self.report_dict["sup_details"]["osup_det"]
-				osup_det["txval"] = flt(osup_det["txval"] + value['taxable_value'], 2)
-				osup_det["iamt"] = flt(osup_det["iamt"] + value['iamt'], 2)
-				osup_det["camt"] = flt(osup_det["camt"] + value['camt'], 2)
-				osup_det["samt"] = flt(osup_det["samt"] + value['samt'], 2)
-				osup_det["csamt"] = flt(osup_det["csamt"] + value['csamt'], 2)
-
-				if state_number != value.get('place_of_supply').split("-")[0]:
-					inter_state_supply_details.setdefault((value.get('gst_category'), value.get('place_of_supply')), {
-						"txval": 0.0,
-						"pos": value.get('place_of_supply').split("-")[0],
-						"iamt": 0.0
-					})
-
-					inter_state_supply_details[(value.get('gst_category'), value.get('place_of_supply'))]['txval'] += value['taxable_value']
-					inter_state_supply_details[(value.get('gst_category'), value.get('place_of_supply'))]['iamt'] += value['iamt']
-
-		return inter_state_supply_details
-
 	def get_inward_nil_exempt(self, state):
-		inward_nil_exempt = frappe.db.sql(""" select p.place_of_supply, sum(i.base_amount) as base_amount,
-			i.is_nil_exempt, i.is_non_gst from `tabPurchase Invoice` p , `tabPurchase Invoice Item` i
-			where p.docstatus = 1 and p.name = i.parent
+		inward_nil_exempt = frappe.db.sql("""
+			SELECT p.place_of_supply, sum(i.base_amount) as base_amount, i.is_nil_exempt, i.is_non_gst
+			FROM `tabPurchase Invoice` p , `tabPurchase Invoice Item` i
+			WHERE p.docstatus = 1 and p.name = i.parent
+			and p.is_opening = 'No'
 			and p.gst_category != 'Registered Composition'
-			and (i.is_nil_exempt = 1 or i.is_non_gst = 1) and
-			month(p.posting_date) = %s and year(p.posting_date) = %s and p.company = %s and p.company_gstin = %s
-			group by p.place_of_supply, i.is_nil_exempt, i.is_non_gst""", (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
-
-		inward_nil_exempt += frappe.db.sql("""SELECT sum(base_net_total) as base_amount, gst_category, place_of_supply
-			FROM `tabPurchase Invoice`
-			WHERE docstatus = 1 and gst_category = 'Registered Composition'
-			and month(posting_date) = %s and year(posting_date) = %s
-			and company = %s and company_gstin = %s
-			group by place_of_supply""", (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
+			and (i.is_nil_exempt = 1 or i.is_non_gst = 1 or p.gst_category = 'Registered Composition') and
+			month(p.posting_date) = %s and year(p.posting_date) = %s
+			and p.company = %s and p.company_gstin = %s
+			GROUP BY p.place_of_supply, i.is_nil_exempt, i.is_non_gst""",
+			(self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
 
 		inward_nil_exempt_details = {
 			"gst": {
@@ -388,37 +163,193 @@
 
 		return inward_nil_exempt_details
 
-	def get_tax_amounts(self, doctype, reverse_charge="N"):
+	def get_outward_supply_details(self, doctype, reverse_charge=None):
+		self.get_outward_tax_invoices(doctype, reverse_charge=reverse_charge)
+		self.get_outward_items(doctype)
+		self.get_outward_tax_details(doctype)
 
+	def get_outward_tax_invoices(self, doctype, reverse_charge=None):
+		self.invoices = []
+		self.invoice_detail_map = {}
+		condition = ''
+
+		if reverse_charge:
+			condition += "AND reverse_charge = 'Y'"
+
+		invoice_details = frappe.db.sql("""
+			SELECT
+				name, gst_category, export_type, place_of_supply
+			FROM
+				`tab{doctype}`
+			WHERE
+				docstatus = 1
+				AND month(posting_date) = %s
+				AND year(posting_date) = %s
+				AND company = %s
+				AND company_gstin = %s
+				AND is_opening = 'No'
+				{reverse_charge}
+			ORDER BY name
+		""".format(doctype=doctype, reverse_charge=condition), (self.month_no, self.year,
+			self.company, self.gst_details.get("gstin")), as_dict=1)
+
+		for d in invoice_details:
+			self.invoice_detail_map.setdefault(d.name, d)
+			self.invoices.append(d.name)
+
+	def get_outward_items(self, doctype):
+		self.invoice_items = frappe._dict()
+		self.is_nil_exempt = []
+		self.is_non_gst = []
+
+		if self.get('invoices'):
+			item_details = frappe.db.sql("""
+				SELECT
+					item_code, parent, taxable_value, base_net_amount, item_tax_rate,
+					is_nil_exempt, is_non_gst
+				FROM
+					`tab%s Item`
+				WHERE parent in (%s)
+			""" % (doctype, ', '.join(['%s']*len(self.invoices))), tuple(self.invoices), as_dict=1)
+
+			for d in item_details:
+				if d.item_code not in self.invoice_items.get(d.parent, {}):
+					self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code,
+						sum((i.get('taxable_value', 0) or i.get('base_net_amount', 0)) for i in item_details
+							if i.item_code == d.item_code and i.parent == d.parent))
+
+				if d.is_nil_exempt and d.item_code not in self.is_nil_exempt:
+					self.is_nil_exempt.append(d.item_code)
+
+				if d.is_non_gst and d.item_code not in self.is_non_gst:
+					self.is_non_gst.append(d.item_code)
+
+	def get_outward_tax_details(self, doctype):
 		if doctype == "Sales Invoice":
 			tax_template = 'Sales Taxes and Charges'
 		elif doctype == "Purchase Invoice":
 			tax_template = 'Purchase Taxes and Charges'
 
-		tax_amounts = frappe.db.sql("""
-			select s.gst_category, sum(t.base_tax_amount_after_discount_amount) as tax_amount, t.account_head
-			from `tab{doctype}` s , `tab{template}` t
-			where s.docstatus = 1 and t.parent = s.name and s.reverse_charge = %s
-			and month(s.posting_date) = %s and year(s.posting_date) = %s and s.company = %s
-			and s.company_gstin = %s
-			group by t.account_head, s.gst_category
-			""" #nosec
-			.format(doctype=doctype, template=tax_template),
-			(reverse_charge, self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
+		self.items_based_on_tax_rate = {}
+		self.invoice_cess = frappe._dict()
+		self.cgst_sgst_invoices = []
 
-		tax_details = {}
+		if self.get('invoices'):
+			tax_details = frappe.db.sql("""
+				SELECT
+					parent, account_head, item_wise_tax_detail, base_tax_amount_after_discount_amount
+				FROM `tab%s`
+				WHERE
+					parenttype = %s and docstatus = 1
+					and parent in (%s)
+				ORDER BY account_head
+			""" % (tax_template, '%s', ', '.join(['%s']*len(self.invoices))),
+				tuple([doctype] + list(self.invoices)))
 
-		for d in tax_amounts:
-			tax_details.setdefault(
-				(d.account_head,d.gst_category),{
-					"amount": d.get("tax_amount"),
-				}
-			)
+			for parent, account, item_wise_tax_detail, tax_amount in tax_details:
+				if account in self.account_heads.get('csamt'):
+					self.invoice_cess.setdefault(parent, tax_amount)
+				else:
+					if item_wise_tax_detail:
+						try:
+							item_wise_tax_detail = json.loads(item_wise_tax_detail)
+							cgst_or_sgst = False
+							if account in self.account_heads.get('camt') \
+								or account in self.account_heads.get('samt'):
+								cgst_or_sgst = True
 
-		return tax_details
+							for item_code, tax_amounts in item_wise_tax_detail.items():
+								if not (cgst_or_sgst or account in self.account_heads.get('iamt') or
+									(item_code in self.is_non_gst + self.is_nil_exempt)):
+									continue
+
+								tax_rate = tax_amounts[0]
+								if tax_rate:
+									if cgst_or_sgst:
+										tax_rate *= 2
+										if parent not in self.cgst_sgst_invoices:
+											self.cgst_sgst_invoices.append(parent)
+
+									rate_based_dict = self.items_based_on_tax_rate\
+										.setdefault(parent, {}).setdefault(tax_rate, [])
+									if item_code not in rate_based_dict:
+										rate_based_dict.append(item_code)
+						except ValueError:
+							continue
+
+
+		if self.get('invoice_items'):
+			# Build itemised tax for export invoices, nil and exempted where tax table is blank
+			for invoice, items in iteritems(self.invoice_items):
+				if invoice not in self.items_based_on_tax_rate and (self.invoice_detail_map.get(invoice, {}).get('export_type')
+					== "Without Payment of Tax"):
+					self.items_based_on_tax_rate.setdefault(invoice, {}).setdefault(0, items.keys())
+
+	def set_outward_taxable_supplies(self):
+		inter_state_supply_details = {}
+
+		for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
+			for rate, items in items_based_on_rate.items():
+				for item_code, taxable_value in self.invoice_items.get(inv).items():
+					if item_code in items:
+						if item_code in self.is_nil_exempt:
+							self.report_dict['sup_details']['osup_nil_exmp']['txval'] += taxable_value
+						elif item_code in self.is_non_gst:
+							self.report_dict['sup_details']['osup_nongst']['txval'] += taxable_value
+						elif rate == 0:
+							self.report_dict['sup_details']['osup_zero']['txval'] += taxable_value
+							#self.report_dict['sup_details']['osup_zero'][key] += tax_amount
+						else:
+							if inv in self.cgst_sgst_invoices:
+								tax_rate = rate/2
+								self.report_dict['sup_details']['osup_det']['camt'] += (taxable_value * tax_rate /100)
+								self.report_dict['sup_details']['osup_det']['samt'] += (taxable_value * tax_rate /100)
+								self.report_dict['sup_details']['osup_det']['txval'] += taxable_value
+							else:
+								self.report_dict['sup_details']['osup_det']['iamt'] += (taxable_value * rate /100)
+								self.report_dict['sup_details']['osup_det']['txval'] += taxable_value
+
+								gst_category = self.invoice_detail_map.get(inv, {}).get('gst_category')
+								place_of_supply = self.invoice_detail_map.get(inv, {}).get('place_of_supply') or '00-Other Territory'
+
+								if gst_category in ['Unregistered', 'Registered Composition', 'UIN Holders'] and \
+								self.gst_details.get("gst_state") != place_of_supply.split("-")[1]:
+									inter_state_supply_details.setdefault((gst_category, place_of_supply), {
+										"txval": 0.0,
+										"pos": place_of_supply.split("-")[0],
+										"iamt": 0.0
+									})
+									inter_state_supply_details[(gst_category, place_of_supply)]['txval'] += taxable_value
+									inter_state_supply_details[(gst_category, place_of_supply)]['iamt'] += (taxable_value * rate /100)
+
+		self.set_inter_state_supply(inter_state_supply_details)
+
+	def set_supplies_liable_to_reverse_charge(self):
+		for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
+			for rate, items in items_based_on_rate.items():
+				for item_code, taxable_value in self.invoice_items.get(inv).items():
+					if item_code in items:
+						if inv in self.cgst_sgst_invoices:
+							tax_rate = rate/2
+							self.report_dict['sup_details']['isup_rev']['camt'] += (taxable_value * tax_rate /100)
+							self.report_dict['sup_details']['isup_rev']['samt'] += (taxable_value * tax_rate /100)
+							self.report_dict['sup_details']['isup_rev']['txval'] += taxable_value
+						else:
+							self.report_dict['sup_details']['isup_rev']['iamt'] += (taxable_value * rate /100)
+							self.report_dict['sup_details']['isup_rev']['txval'] += taxable_value
+
+	def set_inter_state_supply(self, inter_state_supply):
+		for key, value in iteritems(inter_state_supply):
+			if key[0] == "Unregistered":
+				self.report_dict["inter_sup"]["unreg_details"].append(value)
+
+			if key[0] == "Registered Composition":
+				self.report_dict["inter_sup"]["comp_details"].append(value)
+
+			if key[0] == "UIN Holders":
+				self.report_dict["inter_sup"]["uin_details"].append(value)
 
 	def get_company_gst_details(self):
-
 		gst_details =  frappe.get_all("Address",
 			fields=["gstin", "gst_state", "gst_state_number"],
 			filters={
@@ -431,20 +362,28 @@
 			frappe.throw(_("Please enter GSTIN and state for the Company Address {0}").format(self.company_address))
 
 	def get_account_heads(self):
+		account_map = {
+			'sgst_account': 'samt',
+			'cess_account': 'csamt',
+			'cgst_account': 'camt',
+			'igst_account': 'iamt'
+		}
 
-		account_heads =  frappe.get_all("GST Account",
-			fields=["cgst_account", "sgst_account", "igst_account", "cess_account"],
-			filters={
-				"company":self.company
-			})
+		account_heads = {}
+		gst_settings_accounts = frappe.get_all("GST Account",
+			filters={'company': self.company, 'is_reverse_charge_account': 0},
+			fields=["cgst_account", "sgst_account", "igst_account", "cess_account"])
 
-		if account_heads:
-			return account_heads
-		else:
-			frappe.throw(_("Please set account heads in GST Settings for Compnay {0}").format(self.company))
+		if not gst_settings_accounts:
+			frappe.throw(_("Please set GST Accounts in GST Settings"))
+
+		for d in gst_settings_accounts:
+			for acc, val in d.items():
+				account_heads.setdefault(account_map.get(acc), []).append(val)
+
+		return account_heads
 
 	def get_missing_field_invoices(self):
-
 		missing_field_invoices = []
 
 		for doctype in ["Sales Invoice", "Purchase Invoice"]:
@@ -456,26 +395,32 @@
 				party_type = 'Supplier'
 				party = 'supplier'
 
-			docnames = frappe.db.sql("""
-				select t1.name from `tab{doctype}` t1, `tab{party_type}` t2
-				where t1.docstatus = 1 and month(t1.posting_date) = %s and year(t1.posting_date) = %s
+			docnames = frappe.db.sql(
+			"""
+				SELECT t1.name FROM `tab{doctype}` t1, `tab{party_type}` t2
+				WHERE t1.docstatus = 1 and t1.is_opening = 'No'
+				and month(t1.posting_date) = %s and year(t1.posting_date) = %s
 				and t1.company = %s and t1.place_of_supply IS NULL and t1.{party} = t2.name and
 				t2.gst_category != 'Overseas'
-			""".format(doctype = doctype, party_type = party_type, party=party), (self.month_no, self.year, self.company), as_dict=1) #nosec
+			""".format(doctype = doctype, party_type = party_type,
+				party=party) ,(self.month_no, self.year, self.company), as_dict=1) #nosec
 
 			for d in docnames:
 				missing_field_invoices.append(d.name)
 
 		return ",".join(missing_field_invoices)
 
-def get_state_code(state):
+def get_json(template):
+	file_path = os.path.join(os.path.dirname(__file__), '{template}.json'.format(template=template))
+	with open(file_path, 'r') as f:
+		return cstr(f.read())
 
+def get_state_code(state):
 	state_code = state_numbers.get(state)
 
 	return state_code
 
 def get_period(month, year=None):
-
 	month_no = {
 		"January": 1,
 		"February": 2,
@@ -499,13 +444,11 @@
 
 @frappe.whitelist()
 def view_report(name):
-
 	json_data = frappe.get_value("GSTR 3B Report", name, 'json_output')
 	return json.loads(json_data)
 
 @frappe.whitelist()
 def make_json(name):
-
 	json_data = frappe.get_value("GSTR 3B Report", name, 'json_output')
 	file_name = "GST3B.json"
 	frappe.local.response.filename = file_name
diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report_template.json b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report_template.json
new file mode 100644
index 0000000..a68bd6a
--- /dev/null
+++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report_template.json
@@ -0,0 +1,127 @@
+{
+	"gstin": "",
+	"ret_period": "",
+	"inward_sup": {
+		"isup_details": [
+			{
+				"ty": "GST",
+				"intra": 0,
+				"inter": 0
+			},
+			{
+				"ty": "NONGST",
+				"inter": 0,
+				"intra": 0
+			}
+		]
+	},
+	"sup_details": {
+		"osup_zero": {
+			"csamt": 0,
+			"txval": 0,
+			"iamt": 0
+		},
+		"osup_nil_exmp": {
+			"txval": 0
+		},
+		"osup_det": {
+			"samt": 0,
+			"csamt": 0,
+			"txval": 0,
+			"camt": 0,
+			"iamt": 0
+		},
+		"isup_rev": {
+			"samt": 0,
+			"csamt": 0,
+			"txval": 0,
+			"camt": 0,
+			"iamt": 0
+		},
+		"osup_nongst": {
+			"txval": 0
+		}
+	},
+	"inter_sup": {
+		"unreg_details": [],
+		"comp_details": [],
+		"uin_details": []
+	},
+	"itc_elg": {
+		"itc_avl": [
+			{
+				"csamt": 0,
+				"samt": 0,
+				"ty": "IMPG",
+				"camt": 0,
+				"iamt": 0
+			},
+			{
+				"csamt": 0,
+				"samt": 0,
+				"ty": "IMPS",
+				"camt": 0,
+				"iamt": 0
+			},
+			{
+				"samt": 0,
+				"csamt": 0,
+				"ty": "ISRC",
+				"camt": 0,
+				"iamt": 0
+			},
+			{
+				"ty": "ISD",
+				"iamt": 0,
+				"camt": 0,
+				"samt": 0,
+				"csamt": 0
+			},
+			{
+				"samt": 0,
+				"csamt": 0,
+				"ty": "OTH",
+				"camt": 0,
+				"iamt": 0
+			}
+		],
+		"itc_rev": [
+			{
+				"ty": "RUL",
+				"iamt": 0,
+				"camt": 0,
+				"samt": 0,
+				"csamt": 0
+			},
+			{
+				"ty": "OTH",
+				"iamt": 0,
+				"camt": 0,
+				"samt": 0,
+				"csamt": 0
+			}
+		],
+		"itc_net": {
+			"samt": 0,
+			"csamt": 0,
+			"camt": 0,
+			"iamt": 0
+		},
+		"itc_inelg": [
+			{
+				"ty": "RUL",
+				"iamt": 0,
+				"camt": 0,
+				"samt": 0,
+				"csamt": 0
+			},
+			{
+				"ty": "OTH",
+				"iamt": 0,
+				"camt": 0,
+				"samt": 0,
+				"csamt": 0
+			}
+		]
+	}
+}
\ 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 ef8af24..3857ce1 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
@@ -60,8 +60,7 @@
 
 		output = json.loads(report.json_output)
 
-		self.assertEqual(output["sup_details"]["osup_det"]["iamt"], 36),
-		self.assertEqual(output["sup_details"]["osup_zero"]["iamt"], 18),
+		self.assertEqual(output["sup_details"]["osup_det"]["iamt"], 54)
 		self.assertEqual(output["inter_sup"]["unreg_details"][0]["iamt"], 18),
 		self.assertEqual(output["sup_details"]["osup_nil_exmp"]["txval"], 100),
 		self.assertEqual(output["inward_sup"]["isup_details"][0]["intra"], 250)
diff --git a/erpnext/regional/germany/utils/datev/datev_csv.py b/erpnext/regional/germany/utils/datev/datev_csv.py
index 826d51f..122c15f 100644
--- a/erpnext/regional/germany/utils/datev/datev_csv.py
+++ b/erpnext/regional/germany/utils/datev/datev_csv.py
@@ -55,8 +55,7 @@
 		quoting=QUOTE_NONNUMERIC
 	)
 
-	if not six.PY2:
-		data = data.encode('latin_1', errors='replace')
+	data = data.encode('latin_1', errors='replace')
 
 	header = get_header(filters, csv_class)
 	header = ';'.join(header).encode('latin_1', errors='replace')
diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
index b4e7a88..843fb01 100644
--- a/erpnext/regional/india/e_invoice/utils.py
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -43,8 +43,9 @@
 	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')
+	has_non_gst_item = any(d for d in doc.get('items', []) if d.get('is_non_gst'))
 
-	if invalid_company or invalid_supply_type or company_transaction or no_taxes_applied:
+	if invalid_company or invalid_supply_type or company_transaction or no_taxes_applied or has_non_gst_item:
 		return False
 
 	return True
@@ -533,11 +534,9 @@
 	return einvoice
 
 def safe_json_load(json_string):
-	JSONDecodeError = ValueError if six.PY2 else json.JSONDecodeError
-
 	try:
 		return json.loads(json_string)
-	except JSONDecodeError as e:
+	except json.JSONDecodeError as e:
 		# print a snippet of 40 characters around the location where error occured
 		pos = e.pos
 		start, end = max(0, pos-20), min(len(json_string)-1, pos+20)
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index b12e152..229e0c0 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -114,9 +114,12 @@
 
 def make_property_setters(patch=False):
 	# GST rules do not allow for an invoice no. bigger than 16 characters
+	journal_entry_types = frappe.get_meta("Journal Entry").get_options("voucher_type").split("\n") + ['Reversal Of ITC']
+
 	if not patch:
 		make_property_setter('Sales Invoice', 'naming_series', 'options', 'SINV-.YY.-\nSRET-.YY.-', '')
 		make_property_setter('Purchase Invoice', 'naming_series', 'options', 'PINV-.YY.-\nPRET-.YY.-', '')
+		make_property_setter('Journal Entry', 'voucher_type', 'options', '\n'.join(journal_entry_types), '')
 
 def make_custom_fields(update=True):
 	hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC',
@@ -198,15 +201,20 @@
 	purchase_invoice_itc_fields = [
 			dict(fieldname='eligibility_for_itc', label='Eligibility For ITC',
 				fieldtype='Select', insert_after='reason_for_issuing_document', print_hide=1,
-				options='Input Service Distributor\nImport Of Service\nImport Of Capital Goods\nIneligible\nAll Other ITC', default="All Other ITC"),
+				options='Input Service Distributor\nImport Of Service\nImport Of Capital Goods\nITC on Reverse Charge\nIneligible As Per Section 17(5)\nIneligible Others\nAll Other ITC',
+				default="All Other ITC"),
 			dict(fieldname='itc_integrated_tax', label='Availed ITC Integrated Tax',
-				fieldtype='Data', insert_after='eligibility_for_itc', print_hide=1),
+				fieldtype='Currency', insert_after='eligibility_for_itc',
+				options='Company:company:default_currency', print_hide=1),
 			dict(fieldname='itc_central_tax', label='Availed ITC Central Tax',
-				fieldtype='Data', insert_after='itc_integrated_tax', print_hide=1),
+				fieldtype='Currency', insert_after='itc_integrated_tax',
+				options='Company:company:default_currency', print_hide=1),
 			dict(fieldname='itc_state_tax', label='Availed ITC State/UT Tax',
-				fieldtype='Data', insert_after='itc_central_tax', print_hide=1),
+				fieldtype='Currency', insert_after='itc_central_tax',
+				options='Company:company:default_currency', print_hide=1),
 			dict(fieldname='itc_cess_amount', label='Availed ITC Cess',
-				fieldtype='Data', insert_after='itc_state_tax', print_hide=1),
+				fieldtype='Currency', insert_after='itc_state_tax',
+				options='Company:company:default_currency', print_hide=1),
 		]
 
 	sales_invoice_gst_fields = [
@@ -236,6 +244,23 @@
 				depends_on="eval:doc.gst_category=='Overseas' "),
 		]
 
+	journal_entry_fields = [
+		dict(fieldname='reversal_type', label='Reversal Type',
+			fieldtype='Select', insert_after='voucher_type', print_hide=1,
+			options="As per rules 42 & 43 of CGST Rules\nOthers",
+			depends_on="eval:doc.voucher_type=='Reversal Of ITC'",
+			mandatory_depends_on="eval:doc.voucher_type=='Reversal Of ITC'"),
+		dict(fieldname='company_address', label='Company Address',
+			fieldtype='Link', options='Address', insert_after='reversal_type',
+			print_hide=1, depends_on="eval:doc.voucher_type=='Reversal Of ITC'",
+			mandatory_depends_on="eval:doc.voucher_type=='Reversal Of ITC'"),
+		dict(fieldname='company_gstin', label='Company GSTIN',
+			fieldtype='Data', read_only=1, insert_after='company_address', print_hide=1,
+			fetch_from='company_address.gstin',
+			depends_on="eval:doc.voucher_type=='Reversal Of ITC'",
+			mandatory_depends_on="eval:doc.voucher_type=='Reversal Of ITC'")
+	]
+
 	inter_state_gst_field = [
 		dict(fieldname='is_inter_state', label='Is Inter State',
 			fieldtype='Check', insert_after='disabled', print_hide=1),
@@ -430,13 +455,13 @@
 
 		dict(fieldname='einvoice_section', label='E-Invoice Fields', fieldtype='Section Break', insert_after='gst_vehicle_type',
 			print_hide=1, hidden=1),
-		
+
 		dict(fieldname='ack_no', label='Ack. No.', fieldtype='Data', read_only=1, hidden=1, insert_after='einvoice_section',
 			no_copy=1, print_hide=1),
-		
+
 		dict(fieldname='ack_date', label='Ack. Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_no', no_copy=1, print_hide=1),
 
-		dict(fieldname='irn_cancel_date', label='Cancel Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_date', 
+		dict(fieldname='irn_cancel_date', label='Cancel Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_date',
 			no_copy=1, print_hide=1),
 
 		dict(fieldname='signed_einvoice', label='Signed E-Invoice', fieldtype='Code', options='JSON', hidden=1, insert_after='irn_cancel_date',
@@ -469,6 +494,7 @@
 		'Purchase Receipt': purchase_invoice_gst_fields,
 		'Sales Invoice': sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_fields + si_einvoice_fields,
 		'Delivery Note': sales_invoice_gst_fields + ewaybill_fields + sales_invoice_shipping_fields + delivery_note_gst_category,
+		'Journal Entry': journal_entry_fields,
 		'Sales Order': sales_invoice_gst_fields,
 		'Tax Category': inter_state_gst_field,
 		'Item': [
@@ -486,7 +512,7 @@
 		'Sales Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value],
 		'Purchase Order Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
 		'Purchase Receipt Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
-		'Purchase Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
+		'Purchase Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value],
 		'Material Request Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
 		'Salary Component': [
 			dict(fieldname=  'component_type',
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index dc2bb93..075c698 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -204,8 +204,6 @@
 
 	if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
 		master_doctype = "Sales Taxes and Charges Template"
-
-		get_tax_template_for_sez(party_details, master_doctype, company, 'Customer')
 		get_tax_template_based_on_category(master_doctype, company, party_details)
 
 		if party_details.get('taxes_and_charges'):
@@ -216,7 +214,6 @@
 
 	elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"):
 		master_doctype = "Purchase Taxes and Charges Template"
-		get_tax_template_for_sez(party_details, master_doctype, company, 'Supplier')
 		get_tax_template_based_on_category(master_doctype, company, party_details)
 
 		if party_details.get('taxes_and_charges'):
@@ -283,20 +280,6 @@
 				{'company': company, 'disabled': 0, 'tax_category': tax_category.name}, 'name')
 	return default_tax
 
-def get_tax_template_for_sez(party_details, master_doctype, company, party_type):
-
-	gst_details = frappe.db.get_value(party_type, {'name': party_details.get(frappe.scrub(party_type))},
-			['gst_category', 'export_type'], as_dict=1)
-
-	if gst_details:
-		if gst_details.gst_category == 'SEZ' and gst_details.export_type == 'With Payment of Tax':
-			default_tax = frappe.db.get_value(master_doctype, {"company": company, "is_inter_state":1, "disabled":0,
-				"gst_state": number_state_mapping[party_details.company_gstin[:2]]})
-
-			party_details["taxes_and_charges"] = default_tax
-			party_details.taxes = get_taxes_and_charges(master_doctype, default_tax)
-
-
 def calculate_annual_eligible_hra_exemption(doc):
 	basic_component, hra_component = frappe.db.get_value('Company',  doc.company,  ["basic_component", "hra_component"])
 	if not (basic_component and hra_component):
@@ -697,13 +680,22 @@
 		return int(state_code)
 
 @frappe.whitelist()
-def get_gst_accounts(company, account_wise=False):
+def get_gst_accounts(company=None, account_wise=False, only_reverse_charge=0, only_non_reverse_charge=0):
+	filters={"parent": "GST Settings"}
+
+	if company:
+		filters.update({'company': company})
+	if only_reverse_charge:
+		filters.update({'is_reverse_charge_account': 1})
+	elif only_non_reverse_charge:
+		filters.update({'is_reverse_charge_account': 0})
+
 	gst_accounts = frappe._dict()
 	gst_settings_accounts = frappe.get_all("GST Account",
-		filters={"parent": "GST Settings", "company": company},
+		filters=filters,
 		fields=["cgst_account", "sgst_account", "igst_account", "cess_account"])
 
-	if not gst_settings_accounts and not frappe.flags.in_test:
+	if not gst_settings_accounts and not frappe.flags.in_test and not frappe.flags.in_migrate:
 		frappe.throw(_("Please set GST Accounts in GST Settings"))
 
 	for d in gst_settings_accounts:
@@ -715,101 +707,63 @@
 
 	return gst_accounts
 
-def update_grand_total_for_rcm(doc, method):
+def validate_reverse_charge_transaction(doc, method):
 	country = frappe.get_cached_value('Company', doc.company, 'country')
 
 	if country != 'India':
 		return
 
-	gst_tax, base_gst_tax = get_gst_tax_amount(doc)
-
-	if not base_gst_tax:
-		return
+	base_gst_tax = 0
+	base_reverse_charge_booked = 0
 
 	if doc.reverse_charge == 'Y':
-		doc.taxes_and_charges_added -= gst_tax
-		doc.total_taxes_and_charges -= gst_tax
-		doc.base_taxes_and_charges_added -= base_gst_tax
-		doc.base_total_taxes_and_charges -= base_gst_tax
+		gst_accounts = get_gst_accounts(doc.company, only_reverse_charge=1)
+		reverse_charge_accounts = gst_accounts.get('cgst_account') + gst_accounts.get('sgst_account') \
+			+ gst_accounts.get('igst_account')
 
-		update_totals(gst_tax, base_gst_tax, doc)
-
-def update_totals(gst_tax, base_gst_tax, doc):
-	doc.base_grand_total -= base_gst_tax
-	doc.grand_total -= gst_tax
-
-	if doc.meta.get_field("rounded_total"):
-		if doc.is_rounded_total_disabled():
-			doc.outstanding_amount = doc.grand_total
-		else:
-			doc.rounded_total = round_based_on_smallest_currency_fraction(doc.grand_total,
-				doc.currency, doc.precision("rounded_total"))
-
-			doc.rounding_adjustment += flt(doc.rounded_total - doc.grand_total,
-				doc.precision("rounding_adjustment"))
-
-			doc.outstanding_amount = doc.rounded_total or doc.grand_total
-
-	doc.in_words = money_in_words(doc.grand_total, doc.currency)
-	doc.base_in_words = money_in_words(doc.base_grand_total, erpnext.get_company_currency(doc.company))
-	doc.set_payment_schedule()
-
-def make_regional_gl_entries(gl_entries, doc):
-	country = frappe.get_cached_value('Company', doc.company, 'country')
-
-	if country != 'India':
-		return gl_entries
-
-	gst_tax, base_gst_tax = get_gst_tax_amount(doc)
-
-	if not base_gst_tax:
-		return gl_entries
-
-	if doc.reverse_charge == 'Y':
-		gst_accounts = get_gst_accounts(doc.company)
-		gst_account_list = gst_accounts.get('cgst_account') + gst_accounts.get('sgst_account') \
+		gst_accounts = get_gst_accounts(doc.company, only_non_reverse_charge=1)
+		non_reverse_charge_accounts = gst_accounts.get('cgst_account') + gst_accounts.get('sgst_account') \
 			+ gst_accounts.get('igst_account')
 
 		for tax in doc.get('taxes'):
-			if tax.category not in ("Total", "Valuation and Total"):
-				continue
+			if tax.account_head in non_reverse_charge_accounts:
+				if tax.add_deduct_tax == 'Add':
+					base_gst_tax += tax.base_tax_amount_after_discount_amount
+				else:
+					base_gst_tax += tax.base_tax_amount_after_discount_amount
+			elif tax.account_head in reverse_charge_accounts:
+				if tax.add_deduct_tax == 'Add':
+					base_reverse_charge_booked += tax.base_tax_amount_after_discount_amount
+				else:
+					base_reverse_charge_booked += tax.base_tax_amount_after_discount_amount
 
-			dr_or_cr = "credit" if tax.add_deduct_tax == "Add" else "debit"
-			if flt(tax.base_tax_amount_after_discount_amount) and tax.account_head in gst_account_list:
-				account_currency = get_account_currency(tax.account_head)
+		if base_gst_tax != base_reverse_charge_booked:
+			msg = _("Booked reverse charge is not equal to applied tax amount")
+			msg += "<br>"
+			msg += _("Please refer {gst_document_link} to learn more about how to setup and create reverse charge invoice").format(
+				gst_document_link='<a href="https://docs.erpnext.com/docs/user/manual/en/regional/india/gst-setup">GST Documentation</a>')
 
-				gl_entries.append(doc.get_gl_dict(
-					{
-						"account": tax.account_head,
-						"cost_center": tax.cost_center,
-						"posting_date": doc.posting_date,
-						"against": doc.supplier,
-						dr_or_cr: tax.base_tax_amount_after_discount_amount,
-						dr_or_cr + "_in_account_currency": tax.base_tax_amount_after_discount_amount \
-							if account_currency==doc.company_currency \
-							else tax.tax_amount_after_discount_amount
-					}, account_currency, item=tax)
-				)
+			frappe.throw(msg)
 
-	return gl_entries
+def update_itc_availed_fields(doc, method):
+	country = frappe.get_cached_value('Company', doc.company, 'country')
 
-def get_gst_tax_amount(doc):
-	gst_accounts = get_gst_accounts(doc.company)
-	gst_account_list = gst_accounts.get('cgst_account', []) + gst_accounts.get('sgst_account', []) \
-		+ gst_accounts.get('igst_account', [])
+	if country != 'India':
+		return
 
-	base_gst_tax = 0
-	gst_tax = 0
+	# Initialize values
+	doc.itc_integrated_tax = doc.itc_state_tax = doc.itc_central_tax = doc.itc_cess_amount = 0
+	gst_accounts = get_gst_accounts(doc.company, only_non_reverse_charge=1)
 
 	for tax in doc.get('taxes'):
-		if tax.category not in ("Total", "Valuation and Total"):
-			continue
-
-		if flt(tax.base_tax_amount_after_discount_amount) and tax.account_head in gst_account_list:
-			base_gst_tax += tax.base_tax_amount_after_discount_amount
-			gst_tax += tax.tax_amount_after_discount_amount
-
-	return gst_tax, base_gst_tax
+		if tax.account_head in gst_accounts.get('igst_account', []):
+			doc.itc_integrated_tax += flt(tax.base_tax_amount_after_discount_amount)
+		if tax.account_head in gst_accounts.get('sgst_account', []):
+			doc.itc_state_tax += flt(tax.base_tax_amount_after_discount_amount)
+		if tax.account_head in gst_accounts.get('cgst_account', []):
+			doc.itc_central_tax += flt(tax.base_tax_amount_after_discount_amount)
+		if tax.account_head in gst_accounts.get('cess_account', []):
+			doc.itc_cess_amount += flt(tax.base_tax_amount_after_discount_amount)
 
 @frappe.whitelist()
 def get_regional_round_off_accounts(company, account_list):
diff --git a/erpnext/regional/report/gstr_1/gstr_1.js b/erpnext/regional/report/gstr_1/gstr_1.js
index 1a7ff2b..444f5db 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.js
+++ b/erpnext/regional/report/gstr_1/gstr_1.js
@@ -46,7 +46,13 @@
 			"label": __("Type of Business"),
 			"fieldtype": "Select",
 			"reqd": 1,
-			"options": ["B2B", "B2C Large", "B2C Small", "CDNR", "EXPORT"],
+			"options": [
+				{ "value": "B2B", "label": __("B2B Invoices - 4A, 4B, 4C, 6B, 6C") },
+				{ "value": "B2C Large", "label": __("B2C(Large) Invoices - 5A, 5B") },
+				{ "value": "B2C Small", "label": __("B2C(Small) Invoices - 7") },
+				{ "value": "CDNR-REG", "label": __("Credit/Debit Notes (Registered) - 9B") },
+				{ "value": "EXPORT", "label": __("Export Invoice - 6A") }
+			],
 			"default": "B2B"
 		}
 	],
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
index 808fd3a..1e28a40 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.py
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -32,6 +32,7 @@
 			reverse_charge,
 			return_against,
 			is_return,
+			is_debit_note,
 			gst_category,
 			export_type,
 			port_code,
@@ -42,7 +43,7 @@
 
 	def run(self):
 		self.get_columns()
-		self.gst_accounts = get_gst_accounts(self.filters.company)
+		self.gst_accounts = get_gst_accounts(self.filters.company, only_non_reverse_charge=1)
 		self.get_invoice_data()
 
 		if self.invoices:
@@ -62,9 +63,9 @@
 				for rate, items in items_based_on_rate.items():
 					row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items)
 
-					if self.filters.get("type_of_business") ==  "CDNR":
+					if self.filters.get("type_of_business") == "CDNR-REG":
 						row.append("Y" if invoice_details.posting_date <= date(2017, 7, 1) else "N")
-						row.append("C" if invoice_details.return_against else "R")
+						row.append("C" if invoice_details.is_return else "D")
 
 					if taxable_value:
 						self.data.append(row)
@@ -105,7 +106,7 @@
 	def get_row_data_for_invoice(self, invoice, invoice_details, tax_rate, items):
 		row = []
 		for fieldname in self.invoice_fields:
-			if self.filters.get("type_of_business") ==  "CDNR" and fieldname == "invoice_value":
+			if self.filters.get("type_of_business") == "CDNR-REG" and fieldname == "invoice_value":
 				row.append(abs(invoice_details.base_rounded_total) or abs(invoice_details.base_grand_total))
 			elif fieldname == "invoice_value":
 				row.append(invoice_details.base_rounded_total or invoice_details.base_grand_total)
@@ -171,7 +172,7 @@
 
 
 		if self.filters.get("type_of_business") ==  "B2B":
-			conditions += "and ifnull(gst_category, '') in ('Registered Regular', 'Deemed Export', 'SEZ') and is_return != 1"
+			conditions += "AND IFNULL(gst_category, '') in ('Registered Regular', 'Deemed Export', 'SEZ') AND is_return != 1"
 
 		if self.filters.get("type_of_business") in ("B2C Large", "B2C Small"):
 			b2c_limit = frappe.db.get_single_value('GST Settings', 'b2c_limit')
@@ -179,19 +180,19 @@
 				frappe.throw(_("Please set B2C Limit in GST Settings."))
 
 		if self.filters.get("type_of_business") ==  "B2C Large":
-			conditions += """ and ifnull(SUBSTR(place_of_supply, 1, 2),'') != ifnull(SUBSTR(company_gstin, 1, 2),'')
-				and grand_total > {0} and is_return != 1 and gst_category ='Unregistered' """.format(flt(b2c_limit))
+			conditions += """ AND ifnull(SUBSTR(place_of_supply, 1, 2),'') != ifnull(SUBSTR(company_gstin, 1, 2),'')
+				AND grand_total > {0} AND is_return != 1 and gst_category ='Unregistered' """.format(flt(b2c_limit))
 
 		elif self.filters.get("type_of_business") ==  "B2C Small":
-			conditions += """ and (
+			conditions += """ AND (
 				SUBSTR(place_of_supply, 1, 2) = SUBSTR(company_gstin, 1, 2)
-					or grand_total <= {0}) and is_return != 1 and gst_category ='Unregistered' """.format(flt(b2c_limit))
+					OR grand_total <= {0}) and is_return != 1 AND gst_category ='Unregistered' """.format(flt(b2c_limit))
 
-		elif self.filters.get("type_of_business") ==  "CDNR":
-			conditions += """ and is_return = 1 """
+		elif self.filters.get("type_of_business") == "CDNR-REG":
+			conditions += """ AND (is_return = 1 OR is_debit_note = 1) AND IFNULL(gst_category, '') in ('Registered Regular', 'Deemed Export', 'SEZ')"""
 
 		elif self.filters.get("type_of_business") ==  "EXPORT":
-			conditions += """ and is_return !=1 and gst_category = 'Overseas' """
+			conditions += """ AND is_return !=1 and gst_category = 'Overseas' """
 		return conditions
 
 	def get_invoice_items(self):
@@ -403,7 +404,7 @@
 						"width": 100
 					}
 				]
-		elif self.filters.get("type_of_business") ==  "CDNR":
+		elif self.filters.get("type_of_business") == "CDNR-REG":
 			self.invoice_columns = [
 				{
 					"fieldname": "customer_gstin",
@@ -438,6 +439,17 @@
 					"width":120
 				},
 				{
+					"fieldname": "reverse_charge",
+					"label": "Reverse Charge",
+					"fieldtype": "Data"
+				},
+				{
+					"fieldname": "export_type",
+					"label": "Export Type",
+					"fieldtype": "Data",
+					"hidden": 1
+				},
+				{
 					"fieldname": "reason_for_issuing_document",
 					"label": "Reason For Issuing document",
 					"fieldtype": "Data",
@@ -450,6 +462,11 @@
 					"width": 120
 				},
 				{
+					"fieldname": "gst_category",
+					"label": "GST Category",
+					"fieldtype": "Data"
+				},
+				{
 					"fieldname": "invoice_value",
 					"label": "Invoice Value",
 					"fieldtype": "Currency",
@@ -458,10 +475,10 @@
 			]
 			self.other_columns = [
 				{
-						"fieldname": "cess_amount",
-						"label": "Cess Amount",
-						"fieldtype": "Currency",
-						"width": 100
+					"fieldname": "cess_amount",
+					"label": "Cess Amount",
+					"fieldtype": "Currency",
+					"width": 100
 				},
 				{
 					"fieldname": "pre_gst",
@@ -589,6 +606,12 @@
 
 		out = get_export_json(res)
 		gst_json["exp"] = out
+	elif filters["type_of_business"] == 'CDNR-REG':
+		for item in report_data[:-1]:
+			res.setdefault(item["customer_gstin"], {}).setdefault(item["invoice_number"],[]).append(item)
+
+		out = get_cdnr_reg_json(res, gstin)
+		gst_json["cdnr"] = out
 
 	return {
 		'report_name': report_name,
@@ -628,7 +651,6 @@
 	return out
 
 def get_b2cs_json(data, gstin):
-
 	company_state_number = gstin[0:2]
 
 	out = []
@@ -713,6 +735,54 @@
 
 	return out
 
+def get_cdnr_reg_json(res, gstin):
+	out = []
+
+	for gst_in in res:
+		cdnr_item, inv = {"ctin": gst_in, "nt": []}, []
+		if not gst_in: continue
+
+		for number, invoice in iteritems(res[gst_in]):
+			if not invoice[0]["place_of_supply"]:
+				frappe.throw(_("""{0} not entered in Invoice {1}.
+					Please update and try again""").format(frappe.bold("Place Of Supply"),
+					frappe.bold(invoice[0]['invoice_number'])))
+
+			inv_item = {
+				"nt_num": invoice[0]["invoice_number"],
+				"nt_dt": getdate(invoice[0]["posting_date"]).strftime('%d-%m-%Y'),
+				"val": abs(flt(invoice[0]["invoice_value"])),
+				"ntty": invoice[0]["document_type"],
+				"pos": "%02d" % int(invoice[0]["place_of_supply"].split('-')[0]),
+				"rchrg": invoice[0]["reverse_charge"],
+				"inv_type": get_invoice_type_for_cdnr(invoice[0])
+			}
+
+			inv_item["itms"] = []
+			for item in invoice:
+				inv_item["itms"].append(get_rate_and_tax_details(item, gstin))
+
+			inv.append(inv_item)
+
+		if not inv: continue
+		cdnr_item["nt"] = inv
+		out.append(cdnr_item)
+
+	return out
+
+def get_invoice_type_for_cdnr(row):
+	if row.get('gst_category') == 'SEZ':
+		if row.get('export_type') == 'WPAY':
+			invoice_type = 'SEWP'
+		else:
+			invoice_type = 'SEWOP'
+	elif row.get('gst_category') == 'Deemed Export':
+		row.invoice_type = 'DE'
+	elif row.get('gst_category') == 'Registered Regular':
+		invoice_type = 'R'
+
+	return invoice_type
+
 def get_basic_invoice_detail(row):
 	return {
 		"inum": row["invoice_number"],
diff --git a/erpnext/selling/page/point_of_sale/pos_past_order_summary.js b/erpnext/selling/page/point_of_sale/pos_past_order_summary.js
index acf4eb3..cec831d 100644
--- a/erpnext/selling/page/point_of_sale/pos_past_order_summary.js
+++ b/erpnext/selling/page/point_of_sale/pos_past_order_summary.js
@@ -241,7 +241,7 @@
 
 	send_email() {
 		const frm = this.events.get_frm();
-		const recipients = this.email_dialog.get_values().recipients;
+		const recipients = this.email_dialog.get_values().email_id;
 		const doc = this.doc || frm.doc;
 		const print_format = frm.pos_print_format;
 
diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js
index 9957aad..b24048d 100644
--- a/erpnext/setup/doctype/company/company.js
+++ b/erpnext/setup/doctype/company/company.js
@@ -90,12 +90,6 @@
 			frm.toggle_enable("default_currency", (frm.doc.__onload &&
 				!frm.doc.__onload.transactions_exist));
 
-			if (frm.has_perm('write')) {
-				frm.add_custom_button(__('Create Tax Template'), function() {
-					frm.trigger("make_default_tax_template");
-				});
-			}
-
 			if (frappe.perm.has_perm("Cost Center", 0, 'read')) {
 				frm.add_custom_button(__('Cost Centers'), function() {
 					frappe.set_route('Tree', 'Cost Center', {'company': frm.doc.name});
@@ -121,17 +115,21 @@
 			}
 
 			if (frm.has_perm('write')) {
-				frm.add_custom_button(__('Default Tax Template'), function() {
+				frm.add_custom_button(__('Create Tax Template'), function() {
 					frm.trigger("make_default_tax_template");
-				}, __('Create'));
+				}, __('Manage'));
+			}
+
+			if (frappe.user.has_role('System Manager')) {
+				if (frm.has_perm('write')) {
+					frm.add_custom_button(__('Delete Transactions'), function() {
+						frm.trigger("delete_company_transactions");
+					}, __('Manage'));
+				}
 			}
 		}
 
 		erpnext.company.set_chart_of_accounts_options(frm.doc);
-
-		if (!frappe.user.has_role('System Manager')) {
-			frm.get_field("delete_company_transactions").hide();
-		}
 	},
 
 	make_default_tax_template: function(frm) {
@@ -145,11 +143,6 @@
 		})
 	},
 
-	onload_post_render: function(frm) {
-		if(frm.get_field("delete_company_transactions").$input)
-			frm.get_field("delete_company_transactions").$input.addClass("btn-danger");
-	},
-
 	country: function(frm) {
 		erpnext.company.set_chart_of_accounts_options(frm.doc);
 	},
diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json
index 83cbf47..061986d 100644
--- a/erpnext/setup/doctype/company/company.json
+++ b/erpnext/setup/doctype/company/company.json
@@ -99,7 +99,6 @@
   "company_description",
   "registration_info",
   "registration_details",
-  "delete_company_transactions",
   "lft",
   "rgt",
   "old_parent"
@@ -667,11 +666,6 @@
    "oldfieldtype": "Code"
   },
   {
-   "fieldname": "delete_company_transactions",
-   "fieldtype": "Button",
-   "label": "Delete Company Transactions"
-  },
-  {
    "fieldname": "lft",
    "fieldtype": "Int",
    "hidden": 1,
@@ -747,7 +741,7 @@
  "image_field": "company_logo",
  "is_tree": 1,
  "links": [],
- "modified": "2021-02-16 15:53:37.167589",
+ "modified": "2021-05-07 03:11:28.189740",
  "modified_by": "Administrator",
  "module": "Setup",
  "name": "Company",
diff --git a/erpnext/setup/doctype/global_defaults/global_defaults.py b/erpnext/setup/doctype/global_defaults/global_defaults.py
index e587217..a0ba1ef 100644
--- a/erpnext/setup/doctype/global_defaults/global_defaults.py
+++ b/erpnext/setup/doctype/global_defaults/global_defaults.py
@@ -59,13 +59,15 @@
 
 		# Make property setters to hide rounded total fields
 		for doctype in ("Quotation", "Sales Order", "Sales Invoice", "Delivery Note",
-			"Supplier Quotation", "Purchase Order", "Purchase Invoice"):
+			"Supplier Quotation", "Purchase Order", "Purchase Invoice", "Purchase Receipt"):
 			make_property_setter(doctype, "base_rounded_total", "hidden", self.disable_rounded_total, "Check", validate_fields_for_doctype=False)
 			make_property_setter(doctype, "base_rounded_total", "print_hide", 1, "Check", validate_fields_for_doctype=False)
 
 			make_property_setter(doctype, "rounded_total", "hidden", self.disable_rounded_total, "Check", validate_fields_for_doctype=False)
 			make_property_setter(doctype, "rounded_total", "print_hide", self.disable_rounded_total, "Check", validate_fields_for_doctype=False)
 
+			make_property_setter(doctype, "disable_rounded_total", "default", cint(self.disable_rounded_total), "Text", validate_fields_for_doctype=False)
+
 	def toggle_in_words(self):
 		self.disable_in_words = cint(self.disable_in_words)
 
diff --git a/erpnext/stock/dashboard/item_dashboard.js b/erpnext/stock/dashboard/item_dashboard.js
index dbf9901..37e9e89 100644
--- a/erpnext/stock/dashboard/item_dashboard.js
+++ b/erpnext/stock/dashboard/item_dashboard.js
@@ -268,7 +268,9 @@
 		frappe.call({
 			method: 'erpnext.stock.doctype.stock_entry.stock_entry_utils.make_stock_entry',
 			args: values,
+			btn: dialog.get_primary_btn(),
 			freeze: true,
+			freeze_message: __('Creating Stock Entry'),
 			callback: function (r) {
 				frappe.show_alert(__('Stock Entry {0} created',
 					['<a href="/app/stock-entry/' + r.message.name + '">' + r.message.name + '</a>']));
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index d326a04..cce51cb 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -732,7 +732,8 @@
 			"doctype": target_doctype,
 			"postprocess": update_details,
 			"field_no_map": [
-				"taxes_and_charges"
+				"taxes_and_charges",
+				"set_warehouse"
 			]
 		},
 		doctype +" Item": {
diff --git a/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.json b/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.json
index 4fcdb4c..9c59c13 100644
--- a/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.json
+++ b/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.json
@@ -10,8 +10,8 @@
   "exchange_rate",
   "description",
   "col_break3",
-  "base_amount",
-  "amount"
+  "amount",
+  "base_amount"
  ],
  "fields": [
   {
@@ -59,7 +59,7 @@
   {
    "fieldname": "base_amount",
    "fieldtype": "Currency",
-   "label": "Base Amount",
+   "label": "Amount (Company Currency)",
    "options": "Company:company:default_currency",
    "read_only": 1
   }
@@ -67,7 +67,7 @@
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-12-26 01:07:23.233604",
+ "modified": "2021-05-17 13:57:10.807980",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Landed Cost Taxes and Charges",
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 61e60f3..f1292d8 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -243,16 +243,23 @@
 
 	def get_gl_entries(self, warehouse_account=None):
 		from erpnext.accounts.general_ledger import process_gl_map
+		gl_entries = []
 
+		self.make_item_gl_entries(gl_entries, warehouse_account=warehouse_account)
+		self.make_tax_gl_entries(gl_entries)
+		self.get_asset_gl_entry(gl_entries)
+
+		return process_gl_map(gl_entries)
+
+	def make_item_gl_entries(self, gl_entries, warehouse_account=None):
 		stock_rbnb = self.get_company_default("stock_received_but_not_billed")
 		landed_cost_entries = get_item_account_wise_additional_cost(self.name)
 		expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
 		auto_accounting_for_non_stock_items = cint(frappe.db.get_value('Company', self.company, 'enable_perpetual_inventory_for_non_stock_items'))
 
-		gl_entries = []
 		warehouse_with_no_account = []
-		negative_expense_to_be_booked = 0.0
 		stock_items = self.get_stock_items()
+
 		for d in self.get("items"):
 			if d.item_code in stock_items and flt(d.valuation_rate) and flt(d.qty):
 				if warehouse_account.get(d.warehouse):
@@ -263,21 +270,22 @@
 					if not stock_value_diff:
 						continue
 
+					warehouse_account_name = warehouse_account[d.warehouse]["account"]
+					warehouse_account_currency = warehouse_account[d.warehouse]["account_currency"]
+					supplier_warehouse_account = warehouse_account.get(self.supplier_warehouse, {}).get("account")
+					supplier_warehouse_account_currency = warehouse_account.get(self.supplier_warehouse, {}).get("account_currency")
+					remarks = self.get("remarks") or _("Accounting Entry for Stock")
+
 					# If PR is sub-contracted and fg item rate is zero
-					# in that case if account for shource and target warehouse are same,
+					# in that case if account for source and target warehouse are same,
 					# then GL entries should not be posted
 					if flt(stock_value_diff) == flt(d.rm_supp_cost) \
 						and warehouse_account.get(self.supplier_warehouse) \
-						and warehouse_account[d.warehouse]["account"] == warehouse_account[self.supplier_warehouse]["account"]:
+						and warehouse_account_name == supplier_warehouse_account:
 							continue
 
-					gl_entries.append(self.get_gl_dict({
-						"account": warehouse_account[d.warehouse]["account"],
-						"against": stock_rbnb,
-						"cost_center": d.cost_center,
-						"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
-						"debit": stock_value_diff
-					}, warehouse_account[d.warehouse]["account_currency"], item=d))
+					self.add_gl_entry(gl_entries, warehouse_account_name, d.cost_center, stock_value_diff, 0.0, remarks,
+						stock_rbnb, account_currency=warehouse_account_currency, item=d)
 
 					# GL Entry for from warehouse or Stock Received but not billed
 					# Intentionally passed negative debit amount to avoid incorrect GL Entry validation
@@ -287,43 +295,28 @@
 					credit_amount = flt(d.base_net_amount, d.precision("base_net_amount")) \
 						if credit_currency == self.company_currency else flt(d.net_amount, d.precision("net_amount"))
 					if credit_amount:
-						gl_entries.append(self.get_gl_dict({
-							"account":  warehouse_account[d.from_warehouse]['account'] \
-								if d.from_warehouse else stock_rbnb,
-							"against": warehouse_account[d.warehouse]["account"],
-							"cost_center": d.cost_center,
-							"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
-							"debit": -1 * flt(d.base_net_amount, d.precision("base_net_amount")),
-							"debit_in_account_currency": -1 * credit_amount
-						}, credit_currency, item=d))
+						account = warehouse_account[d.from_warehouse]['account'] \
+								if d.from_warehouse else stock_rbnb
 
-					negative_expense_to_be_booked += flt(d.item_tax_amount)
+						self.add_gl_entry(gl_entries, account, d.cost_center,
+							-1 * flt(d.base_net_amount, d.precision("base_net_amount")), 0.0, remarks, warehouse_account_name,
+							debit_in_account_currency=-1 * credit_amount, account_currency=credit_currency, item=d)
 
-					# Amount added through landed-cost-voucher
+					# Amount added through landed-cos-voucher
 					if d.landed_cost_voucher_amount and landed_cost_entries:
 						for account, amount in iteritems(landed_cost_entries[(d.item_code, d.name)]):
 							account_currency = get_account_currency(account)
-							gl_entries.append(self.get_gl_dict({
-								"account": account,
-								"account_currency": account_currency,
-								"against": warehouse_account[d.warehouse]["account"],
-								"cost_center": d.cost_center,
-								"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
-								"credit": (flt(amount["base_amount"]) if (amount["base_amount"] or
-									account_currency!=self.company_currency) else flt(amount["amount"])),
-								"credit_in_account_currency": flt(amount["amount"]),
-								"project": d.project
-							}, item=d))
+							credit_amount = (flt(amount["base_amount"]) if (amount["base_amount"] or
+								account_currency!=self.company_currency) else flt(amount["amount"]))
+
+							self.add_gl_entry(gl_entries, account, d.cost_center, 0.0, credit_amount, remarks,
+								warehouse_account_name, credit_in_account_currency=flt(amount["amount"]),
+								account_currency=account_currency, project=d.project, item=d)
 
 					# sub-contracting warehouse
 					if flt(d.rm_supp_cost) and warehouse_account.get(self.supplier_warehouse):
-						gl_entries.append(self.get_gl_dict({
-							"account": warehouse_account[self.supplier_warehouse]["account"],
-							"against": warehouse_account[d.warehouse]["account"],
-							"cost_center": d.cost_center,
-							"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
-							"credit": flt(d.rm_supp_cost)
-						}, warehouse_account[self.supplier_warehouse]["account_currency"], item=d))
+						self.add_gl_entry(gl_entries, supplier_warehouse_account, d.cost_center, 0.0, flt(d.rm_supp_cost),
+							remarks, warehouse_account_name, account_currency=supplier_warehouse_account_currency, item=d)
 
 					# divisional loss adjustment
 					valuation_amount_as_per_doc = flt(d.base_net_amount, d.precision("base_net_amount")) + \
@@ -340,46 +333,32 @@
 
 						cost_center = d.cost_center or frappe.get_cached_value("Company", self.company, "cost_center")
 
-						gl_entries.append(self.get_gl_dict({
-							"account": loss_account,
-							"against": warehouse_account[d.warehouse]["account"],
-							"cost_center": cost_center,
-							"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
-							"debit": divisional_loss,
-							"project": d.project
-						}, credit_currency, item=d))
+						self.add_gl_entry(gl_entries, loss_account, cost_center, divisional_loss, 0.0, remarks,
+							warehouse_account_name, account_currency=credit_currency, project=d.project, item=d)
 
 				elif d.warehouse not in warehouse_with_no_account or \
 					d.rejected_warehouse not in warehouse_with_no_account:
 						warehouse_with_no_account.append(d.warehouse)
 			elif d.item_code not in stock_items and not d.is_fixed_asset and flt(d.qty) and auto_accounting_for_non_stock_items:
-
 				service_received_but_not_billed_account = self.get_company_default("service_received_but_not_billed")
 				credit_currency = get_account_currency(service_received_but_not_billed_account)
-
-				gl_entries.append(self.get_gl_dict({
-					"account": service_received_but_not_billed_account,
-					"against": d.expense_account,
-					"cost_center": d.cost_center,
-					"remarks": self.get("remarks") or _("Accounting Entry for Service"),
-					"project": d.project,
-					"credit": d.amount,
-					"voucher_detail_no": d.name
-				}, credit_currency, item=d))
-
 				debit_currency = get_account_currency(d.expense_account)
+				remarks = self.get("remarks") or _("Accounting Entry for Service")
 
-				gl_entries.append(self.get_gl_dict({
-					"account": d.expense_account,
-					"against": service_received_but_not_billed_account,
-					"cost_center": d.cost_center,
-					"remarks": self.get("remarks") or _("Accounting Entry for Service"),
-					"project": d.project,
-					"debit": d.amount,
-					"voucher_detail_no": d.name
-				}, debit_currency, item=d))
+				self.add_gl_entry(gl_entries, service_received_but_not_billed_account, d.cost_center, 0.0, d.amount,
+					remarks, d.expense_account, account_currency=credit_currency, project=d.project,
+					voucher_detail_no=d.name, item=d)
 
-		self.get_asset_gl_entry(gl_entries)
+				self.add_gl_entry(gl_entries, d.expense_account, d.cost_center, d.amount, 0.0, remarks, service_received_but_not_billed_account,
+					account_currency = debit_currency, project=d.project, voucher_detail_no=d.name, item=d)
+
+		if warehouse_with_no_account:
+			frappe.msgprint(_("No accounting entries for the following warehouses") + ": \n" +
+				"\n".join(warehouse_with_no_account))
+
+	def make_tax_gl_entries(self, gl_entries):
+		expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
+		negative_expense_to_be_booked = sum([flt(d.item_tax_amount) for d in self.get('items')])
 		# Cost center-wise amount breakup for other charges included for valuation
 		valuation_tax = {}
 		for tax in self.get("taxes"):
@@ -420,23 +399,33 @@
 						applicable_amount = negative_expense_to_be_booked * (valuation_tax[tax.name] / total_valuation_amount)
 						amount_including_divisional_loss -= applicable_amount
 
-					gl_entries.append(
-						self.get_gl_dict({
-							"account": account,
-							"cost_center": tax.cost_center,
-							"credit": applicable_amount,
-							"remarks": self.remarks or _("Accounting Entry for Stock"),
-							"against": against_account
-						}, item=tax)
-					)
+					self.add_gl_entry(gl_entries, account, tax.cost_center, 0.0, applicable_amount, self.remarks or _("Accounting Entry for Stock"),
+						against_account, item=tax)
 
 					i += 1
 
-		if warehouse_with_no_account:
-			frappe.msgprint(_("No accounting entries for the following warehouses") + ": \n" +
-				"\n".join(warehouse_with_no_account))
+	def add_gl_entry(self, gl_entries, account, cost_center, debit, credit, remarks, against_account,
+		debit_in_account_currency=None, credit_in_account_currency=None, account_currency=None,
+		project=None, voucher_detail_no=None, item=None):
+		gl_entry = {
+			"account": account,
+			"cost_center": cost_center,
+			"debit": debit,
+			"credit": credit,
+			"against_account": against_account,
+			"remarks": remarks,
+		}
 
-		return process_gl_map(gl_entries)
+		if voucher_detail_no:
+			gl_entry.update({"voucher_detail_no": voucher_detail_no})
+
+		if debit_in_account_currency:
+			gl_entry.update({"debit_in_account_currency": debit_in_account_currency})
+
+		if credit_in_account_currency:
+			gl_entry.update({"credit_in_account_currency": credit_in_account_currency})
+
+		gl_entries.append(self.get_gl_dict(gl_entry, item=item))
 
 	def get_asset_gl_entry(self, gl_entries):
 		for item in self.get("items"):
@@ -458,30 +447,21 @@
 
 		asset_amount = flt(item.net_amount) + flt(item.item_tax_amount/self.conversion_rate)
 		base_asset_amount = flt(item.base_net_amount + item.item_tax_amount)
+		remarks = self.get("remarks") or _("Accounting Entry for Asset")
 
 		cwip_account_currency = get_account_currency(cwip_account)
 		# debit cwip account
-		gl_entries.append(self.get_gl_dict({
-			"account": cwip_account,
-			"against": arbnb_account,
-			"cost_center": item.cost_center,
-			"remarks": self.get("remarks") or _("Accounting Entry for Asset"),
-			"debit": base_asset_amount,
-			"debit_in_account_currency": (base_asset_amount
-				if cwip_account_currency == self.company_currency else asset_amount)
-		}, item=item))
+		debit_in_account_currency = (base_asset_amount
+			if cwip_account_currency == self.company_currency else asset_amount)
+		self.add_gl_entry(gl_entries, cwip_account, item.cost_center, base_asset_amount, 0.0, remarks,
+			arbnb_account, debit_in_account_currency=debit_in_account_currency, item=item)
 
 		asset_rbnb_currency = get_account_currency(arbnb_account)
 		# credit arbnb account
-		gl_entries.append(self.get_gl_dict({
-			"account": arbnb_account,
-			"against": cwip_account,
-			"cost_center": item.cost_center,
-			"remarks": self.get("remarks") or _("Accounting Entry for Asset"),
-			"credit": base_asset_amount,
-			"credit_in_account_currency": (base_asset_amount
-				if asset_rbnb_currency == self.company_currency else asset_amount)
-		}, item=item))
+		credit_in_account_currency = (base_asset_amount
+			if asset_rbnb_currency == self.company_currency else asset_amount)
+		self.add_gl_entry(gl_entries, arbnb_account, item.cost_center, 0.0, base_asset_amount, remarks,
+			cwip_account, credit_in_account_currency=credit_in_account_currency, item=item)
 
 	def add_lcv_gl_entries(self, item, gl_entries):
 		expenses_included_in_asset_valuation = self.get_company_default("expenses_included_in_asset_valuation")
@@ -492,23 +472,13 @@
 			# This returns company's default cwip account
 			asset_account = get_asset_account("capital_work_in_progress_account", company=self.company)
 
-		gl_entries.append(self.get_gl_dict({
-			"account": expenses_included_in_asset_valuation,
-			"against": asset_account,
-			"cost_center": item.cost_center,
-			"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
-			"credit": flt(item.landed_cost_voucher_amount),
-			"project": item.project
-		}, item=item))
+		remarks = self.get("remarks") or _("Accounting Entry for Stock")
 
-		gl_entries.append(self.get_gl_dict({
-			"account": asset_account,
-			"against": expenses_included_in_asset_valuation,
-			"cost_center": item.cost_center,
-			"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
-			"debit": flt(item.landed_cost_voucher_amount),
-			"project": item.project
-		}, item=item))
+		self.add_gl_entry(gl_entries, expenses_included_in_asset_valuation, item.cost_center, 0.0, flt(item.landed_cost_voucher_amount),
+			remarks, asset_account, project=item.project, item=item)
+
+		self.add_gl_entry(gl_entries, asset_account, item.cost_center, 0.0, flt(item.landed_cost_voucher_amount),
+			remarks, expenses_included_in_asset_valuation, project=item.project, item=item)
 
 	def update_assets(self, item, valuation_rate):
 		assets = frappe.db.get_all('Asset',
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 63e9646..5b626ea 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
@@ -140,4 +140,4 @@
 	return frappe.db.sql(""" SELECT name from `tabRepost Item Valuation`
 		WHERE status != 'Completed' and creation <= %s and docstatus = 1
 		ORDER BY timestamp(posting_date, posting_time) asc, creation asc
-	""", date, as_dict=1)
\ No newline at end of file
+	""", date, as_dict=1)
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index 700093f..786285a 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -107,6 +107,7 @@
 				frappe.flags.hide_serial_batch_dialog = true;
 			}
 		});
+		attach_bom_items(frm.doc.bom_no);
 	},
 
 	setup_quality_inspection: function(frm) {
@@ -311,6 +312,7 @@
 		}
 
 		frm.trigger("setup_quality_inspection");
+		attach_bom_items(frm.doc.bom_no)
 	},
 
 	stock_entry_type: function(frm){
@@ -598,7 +600,6 @@
 	add_to_transit: function(frm) {
 		if(frm.doc.add_to_transit && frm.doc.purpose=='Material Transfer') {
 			frm.set_value('to_warehouse', '');
-			frm.set_value('stock_entry_type', 'Material Transfer');
 			frm.fields_dict.to_warehouse.get_query = function() {
 				return {
 					filters:{
@@ -608,12 +609,13 @@
 					}
 				};
 			};
-			frm.trigger('set_tansit_warehouse');
+			frm.trigger('set_transit_warehouse');
 		}
 	},
 
-	set_tansit_warehouse: function(frm) {
-		if(frm.doc.add_to_transit && frm.doc.purpose == 'Material Transfer' && !frm.doc.to_warehouse) {
+	set_transit_warehouse: function(frm) {
+		if(frm.doc.add_to_transit && frm.doc.purpose == 'Material Transfer' && !frm.doc.to_warehouse
+			&& frm.doc.from_warehouse) {
 			let dt = frm.doc.from_warehouse ? 'Warehouse' : 'Company';
 			let dn = frm.doc.from_warehouse ? frm.doc.from_warehouse : frm.doc.company;
 			frappe.db.get_value(dt, dn, 'default_in_transit_warehouse', (r) => {
@@ -919,6 +921,7 @@
 				method: "get_items",
 				callback: function(r) {
 					if(!r.exc) refresh_field("items");
+					if(me.frm.doc.bom_no) attach_bom_items(me.frm.doc.bom_no)
 				}
 			});
 		}
@@ -981,8 +984,8 @@
 		if(!row.t_warehouse) row.t_warehouse = this.frm.doc.to_warehouse;
 	}
 
-	from_warehouse(doc) {
-		this.frm.trigger('set_tansit_warehouse');
+	from_warehouse: function(doc) {
+		this.frm.trigger('set_transit_warehouse');
 		this.set_warehouse_in_children(doc.items, "s_warehouse", doc.from_warehouse);
 	}
 
@@ -1064,4 +1067,22 @@
 
 }
 
-extend_cscript(cur_frm.cscript, new erpnext.stock.StockEntry({frm: cur_frm}));
+function attach_bom_items(bom_no) {
+	if (check_should_not_attach_bom_items(bom_no)) return
+	frappe.db.get_doc("BOM",bom_no).then(bom => {
+		const {name, items} = bom
+		erpnext.stock.bom = {name, items:{}}
+		items.forEach(item => {
+			erpnext.stock.bom.items[item.item_code] = item;
+		});
+	});
+}
+
+function check_should_not_attach_bom_items(bom_no) {
+  return (
+    bom_no === undefined ||
+    (erpnext.stock.bom && erpnext.stock.bom.name === bom_no)
+  );
+}
+
+$.extend(cur_frm.cscript, new erpnext.stock.StockEntry({frm: cur_frm}));
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.json b/erpnext/stock/doctype/stock_entry/stock_entry.json
index 98c047a..7f94591 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.json
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.json
@@ -637,6 +637,8 @@
   {
    "default": "0",
    "depends_on": "eval: doc.purpose=='Material Transfer' && !doc.outgoing_stock_entry",
+   "fetch_from": "stock_entry_type.add_to_transit",
+   "fetch_if_empty": 1,
    "fieldname": "add_to_transit",
    "fieldtype": "Check",
    "label": "Add to Transit",
@@ -655,7 +657,7 @@
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-12-09 14:58:13.267321",
+ "modified": "2021-05-21 11:29:11.917161",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Stock Entry",
diff --git a/erpnext/stock/doctype/stock_entry_type/stock_entry_type.json b/erpnext/stock/doctype/stock_entry_type/stock_entry_type.json
index 0f2b55e..eee38be 100644
--- a/erpnext/stock/doctype/stock_entry_type/stock_entry_type.json
+++ b/erpnext/stock/doctype/stock_entry_type/stock_entry_type.json
@@ -6,7 +6,8 @@
  "editable_grid": 1,
  "engine": "InnoDB",
  "field_order": [
-  "purpose"
+  "purpose",
+  "add_to_transit"
  ],
  "fields": [
   {
@@ -18,10 +19,17 @@
    "options": "\nMaterial Issue\nMaterial Receipt\nMaterial Transfer\nMaterial Transfer for Manufacture\nMaterial Consumption for Manufacture\nManufacture\nRepack\nSend to Subcontractor",
    "reqd": 1,
    "set_only_once": 1
+  },
+  {
+   "default": "0",
+   "depends_on": "eval: doc.purpose == 'Material Transfer'",
+   "fieldname": "add_to_transit",
+   "fieldtype": "Check",
+   "label": "Add to Transit"
   }
  ],
  "links": [],
- "modified": "2020-08-10 23:24:37.160817",
+ "modified": "2021-05-21 11:27:01.144110",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Stock Entry Type",
diff --git a/erpnext/stock/doctype/stock_entry_type/stock_entry_type.py b/erpnext/stock/doctype/stock_entry_type/stock_entry_type.py
index a4116ab..1069ec8 100644
--- a/erpnext/stock/doctype/stock_entry_type/stock_entry_type.py
+++ b/erpnext/stock/doctype/stock_entry_type/stock_entry_type.py
@@ -7,4 +7,6 @@
 from frappe.model.document import Document
 
 class StockEntryType(Document):
-	pass
+	def validate(self):
+		if self.add_to_transit and self.purpose != 'Material Transfer':
+			self.add_to_transit = 0
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index 0278c96..016b593 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -477,19 +477,19 @@
 def get_items(warehouse, posting_date, posting_time, company):
 	lft, rgt = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"])
 	items = frappe.db.sql("""
-		select i.name, i.item_name, bin.warehouse
+		select i.name, i.item_name, bin.warehouse, i.has_serial_no
 		from tabBin bin, tabItem i
 		where i.name=bin.item_code and i.disabled=0 and i.is_stock_item = 1
-		and i.has_variants = 0 and i.has_serial_no = 0 and i.has_batch_no = 0
+		and i.has_variants = 0 and i.has_batch_no = 0
 		and exists(select name from `tabWarehouse` where lft >= %s and rgt <= %s and name=bin.warehouse)
 	""", (lft, rgt))
 
 	items += frappe.db.sql("""
-		select i.name, i.item_name, id.default_warehouse
+		select i.name, i.item_name, id.default_warehouse, i.has_serial_no
 		from tabItem i, `tabItem Default` id
 		where i.name = id.parent
 			and exists(select name from `tabWarehouse` where lft >= %s and rgt <= %s and name=id.default_warehouse)
-			and i.is_stock_item = 1 and i.has_serial_no = 0 and i.has_batch_no = 0
+			and i.is_stock_item = 1 and i.has_batch_no = 0
 			and i.has_variants = 0 and i.disabled = 0 and id.company=%s
 		group by i.name
 	""", (lft, rgt, company))
@@ -497,7 +497,7 @@
 	res = []
 	for d in set(items):
 		stock_bal = get_stock_balance(d[0], d[2], posting_date, posting_time,
-			with_valuation_rate=True)
+			with_valuation_rate=True , with_serial_no=cint(d[3]))
 
 		if frappe.db.get_value("Item", d[0], "disabled") == 0:
 			res.append({
@@ -507,7 +507,9 @@
 				"item_name": d[1],
 				"valuation_rate": stock_bal[1],
 				"current_qty": stock_bal[0],
-				"current_valuation_rate": stock_bal[1]
+				"current_valuation_rate": stock_bal[1],
+				"current_serial_no": stock_bal[2] if cint(d[3]) else '',
+				"serial_no": stock_bal[2] if cint(d[3]) else ''
 			})
 
 	return res
diff --git a/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json b/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json
index 85c7ebe..6bbba05 100644
--- a/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json
+++ b/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json
@@ -1,4 +1,5 @@
 {
+ "actions": [],
  "creation": "2015-02-17 01:06:05.072764",
  "doctype": "DocType",
  "document_type": "Other",
@@ -170,6 +171,7 @@
   },
   {
    "default": "0",
+   "depends_on": "allow_zero_valuation_rate",
    "fieldname": "allow_zero_valuation_rate",
    "fieldtype": "Check",
    "label": "Allow Zero Valuation Rate",
@@ -179,7 +181,7 @@
  ],
  "istable": 1,
  "links": [],
- "modified": "2021-03-23 11:09:44.407157",
+ "modified": "2021-05-21 12:13:33.041266",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Stock Reconciliation Item",
@@ -189,4 +191,4 @@
  "sort_field": "modified",
  "sort_order": "DESC",
  "track_changes": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/warehouse/warehouse.py b/erpnext/stock/doctype/warehouse/warehouse.py
index 6c84f16..2062bdd 100644
--- a/erpnext/stock/doctype/warehouse/warehouse.py
+++ b/erpnext/stock/doctype/warehouse/warehouse.py
@@ -3,8 +3,9 @@
 
 from __future__ import unicode_literals
 import frappe, erpnext
-from frappe.utils import cint, nowdate
+from frappe.utils import cint, flt
 from frappe import throw, _
+from collections import defaultdict
 from frappe.utils.nestedset import NestedSet
 from erpnext.stock import get_warehouse_account
 from frappe.contacts.address_and_contact import load_address_and_contact
@@ -139,8 +140,6 @@
 
 @frappe.whitelist()
 def get_children(doctype, parent=None, company=None, is_root=False):
-	from erpnext.stock.utils import get_stock_value_from_bin
-
 	if is_root:
 		parent = ""
 
@@ -153,13 +152,48 @@
 
 	warehouses = frappe.get_list(doctype, fields=fields, filters=filters, order_by='name')
 
+	company_currency = ''
+	if company:
+		company_currency = frappe.get_cached_value('Company', company, 'default_currency')
+
+	warehouse_wise_value = get_warehouse_wise_stock_value(company)
+
 	# return warehouses
 	for wh in warehouses:
-		wh["balance"] = get_stock_value_from_bin(warehouse=wh.value)
-		if company:
-			wh["company_currency"] = frappe.db.get_value('Company', company, 'default_currency')
+		wh["balance"] = warehouse_wise_value.get(wh.value)
+		if company_currency:
+			wh["company_currency"] = company_currency
 	return warehouses
 
+def get_warehouse_wise_stock_value(company):
+	warehouses = frappe.get_all('Warehouse',
+		fields = ['name', 'parent_warehouse'], filters = {'company': company})
+	parent_warehouse = {d.name : d.parent_warehouse for d in warehouses}
+
+	filters = {'warehouse': ('in', [data.name for data in warehouses])}
+	bin_data = frappe.get_all('Bin', fields = ['sum(stock_value) as stock_value', 'warehouse'],
+		filters = filters, group_by = 'warehouse')
+
+	warehouse_wise_stock_value = defaultdict(float)
+	for row in bin_data:
+		if not row.stock_value:
+			continue
+
+		warehouse_wise_stock_value[row.warehouse] = row.stock_value
+		update_value_in_parent_warehouse(warehouse_wise_stock_value,
+			parent_warehouse, row.warehouse, row.stock_value)
+
+	return warehouse_wise_stock_value
+
+def update_value_in_parent_warehouse(warehouse_wise_stock_value, parent_warehouse_dict, warehouse, stock_value):
+	parent_warehouse = parent_warehouse_dict.get(warehouse)
+	if not parent_warehouse:
+		return
+
+	warehouse_wise_stock_value[parent_warehouse] += flt(stock_value)
+	update_value_in_parent_warehouse(warehouse_wise_stock_value, parent_warehouse_dict,
+		parent_warehouse, stock_value)
+
 @frappe.whitelist()
 def add_node():
 	from frappe.desk.treeview import make_tree_args
diff --git a/erpnext/stock/doctype/warehouse/warehouse_tree.js b/erpnext/stock/doctype/warehouse/warehouse_tree.js
index 3665c05..407d7d1 100644
--- a/erpnext/stock/doctype/warehouse/warehouse_tree.js
+++ b/erpnext/stock/doctype/warehouse/warehouse_tree.js
@@ -20,7 +20,7 @@
 	onrender: function(node) {
 		if (node.data && node.data.balance!==undefined) {
 			$('<span class="balance-area pull-right">'
-			+ format_currency(Math.abs(node.data.balance), node.data.company_currency)
+			+ format_currency((node.data.balance), node.data.company_currency)
 			+ '</span>').insertBefore(node.$ul);
 		}
 	}
diff --git a/erpnext/stock/report/item_variant_details/item_variant_details.py b/erpnext/stock/report/item_variant_details/item_variant_details.py
index e8449cc..d8563d7 100644
--- a/erpnext/stock/report/item_variant_details/item_variant_details.py
+++ b/erpnext/stock/report/item_variant_details/item_variant_details.py
@@ -14,47 +14,58 @@
 	if not item:
 		return []
 	item_dicts = []
-	variants = None
 
-	variant_results = frappe.db.sql("""select name from `tabItem`
-		where variant_of = %s""", item, as_dict=1)
+	variant_results = frappe.db.get_all(
+		"Item",
+		fields=["name"],
+		filters={
+			"variant_of": ["=", item],
+			"disabled": 0
+		}
+	)
+
 	if not variant_results:
-		frappe.msgprint(_("There isn't any item variant for the selected item"))
+		frappe.msgprint(_("There aren't any item variants for the selected item"))
 		return []
 	else:
-		variants = ", ".join([frappe.db.escape(variant['name']) for variant in variant_results])
+		variant_list = [variant['name'] for variant in variant_results]
 
-	order_count_map = get_open_sales_orders_map(variants)
-	stock_details_map = get_stock_details_map(variants)
-	buying_price_map = get_buying_price_map(variants)
-	selling_price_map = get_selling_price_map(variants)
-	attr_val_map = get_attribute_values_map(variants)
+	order_count_map = get_open_sales_orders_count(variant_list)
+	stock_details_map = get_stock_details_map(variant_list)
+	buying_price_map = get_buying_price_map(variant_list)
+	selling_price_map = get_selling_price_map(variant_list)
+	attr_val_map = get_attribute_values_map(variant_list)
 
-	attribute_list = [d[0] for d in frappe.db.sql("""select attribute
-		from `tabItem Variant Attribute`
-		where parent in ({variants}) group by attribute""".format(variants=variants))]
+	attributes = frappe.db.get_all(
+		"Item Variant Attribute",
+		fields=["attribute"],
+		filters={
+			"parent": ["in", variant_list]
+		},
+		group_by="attribute"
+	)
+	attribute_list = [row.get("attribute") for row in attributes]
 
 	# Prepare dicts
 	variant_dicts = [{"variant_name": d['name']} for d in variant_results]
 	for item_dict in variant_dicts:
-		name = item_dict["variant_name"]
+		name = item_dict.get("variant_name")
 
-		for d in attribute_list:
-			attr_dict = attr_val_map[name]
-			if attr_dict and attr_dict.get(d):
-				item_dict[d] = attr_val_map[name][d]
+		for attribute in attribute_list:
+			attr_dict = attr_val_map.get(name)
+			if attr_dict and attr_dict.get(attribute):
+				item_dict[frappe.scrub(attribute)] = attr_val_map.get(name).get(attribute)
 
-		item_dict["Open Orders"] = order_count_map.get(name) or 0
+		item_dict["open_orders"] = order_count_map.get(name) or 0
 
 		if stock_details_map.get(name):
-			item_dict["Inventory"] = stock_details_map.get(name)["Inventory"] or 0
-			item_dict["In Production"] = stock_details_map.get(name)["In Production"] or 0
-			item_dict["Available Selling"] = stock_details_map.get(name)["Available Selling"] or 0
+			item_dict["current_stock"] = stock_details_map.get(name)["Inventory"] or 0
+			item_dict["in_production"] = stock_details_map.get(name)["In Production"] or 0
 		else:
-			item_dict["Inventory"] = item_dict["In Production"] = item_dict["Available Selling"] = 0
+			item_dict["current_stock"] = item_dict["in_production"] = 0
 
-		item_dict["Avg. Buying Price List Rate"] = buying_price_map.get(name) or 0
-		item_dict["Avg. Selling Price List Rate"] = selling_price_map.get(name) or 0
+		item_dict["avg_buying_price_list_rate"] = buying_price_map.get(name) or 0
+		item_dict["avg_selling_price_list_rate"] = selling_price_map.get(name) or 0
 
 		item_dicts.append(item_dict)
 
@@ -71,117 +82,158 @@
 
 	item_doc = frappe.get_doc("Item", item)
 
-	for d in item_doc.attributes:
-		columns.append(d.attribute + ":Data:100")
+	for entry in item_doc.attributes:
+		columns.append({
+			"fieldname": frappe.scrub(entry.attribute),
+			"label": entry.attribute,
+			"fieldtype": "Data",
+			"width": 100
+		})
 
-	columns += [_("Avg. Buying Price List Rate") + ":Currency:110", _("Avg. Selling Price List Rate") + ":Currency:110",
-		_("Inventory") + ":Float:100", _("In Production") + ":Float:100",
-		_("Open Orders") + ":Float:100", _("Available Selling") + ":Float:100"
+	additional_columns = [
+		{
+			"fieldname": "avg_buying_price_list_rate",
+			"label": _("Avg. Buying Price List Rate"),
+			"fieldtype": "Currency",
+			"width": 150
+		},
+		{
+			"fieldname": "avg_selling_price_list_rate",
+			"label": _("Avg. Selling Price List Rate"),
+			"fieldtype": "Currency",
+			"width": 150
+		},
+		{
+			"fieldname": "current_stock",
+			"label": _("Current Stock"),
+			"fieldtype": "Float",
+			"width": 120
+		},
+		{
+			"fieldname": "in_production",
+			"label": _("In Production"),
+			"fieldtype": "Float",
+			"width": 150
+		},
+		{
+			"fieldname": "open_orders",
+			"label": _("Open Sales Orders"),
+			"fieldtype": "Float",
+			"width": 150
+		}
 	]
+	columns.extend(additional_columns)
 
 	return columns
 
-def get_open_sales_orders_map(variants):
-	open_sales_orders = frappe.db.sql("""
-		select
-			count(*) as count,
-			item_code
-		from
-			`tabSales Order Item`
-		where
-			docstatus = 1 and
-			qty > ifnull(delivered_qty, 0) and
-			item_code in ({variants})
-		group by
-			item_code
-	""".format(variants=variants), as_dict=1)
+def get_open_sales_orders_count(variants_list):
+	open_sales_orders = frappe.db.get_list(
+		"Sales Order",
+		fields=[
+			"name",
+			"`tabSales Order Item`.item_code"
+		],
+		filters=[
+			["Sales Order", "docstatus", "=", 1],
+			["Sales Order Item", "item_code", "in", variants_list]
+		],
+		distinct=1
+	)
 
 	order_count_map = {}
-	for d in open_sales_orders:
-		order_count_map[d["item_code"]] = d["count"]
+	for row in open_sales_orders:
+		item_code = row.get("item_code")
+		if order_count_map.get(item_code) is None:
+			order_count_map[item_code] = 1
+		else:
+			order_count_map[item_code] += 1
 
 	return order_count_map
 
-def get_stock_details_map(variants):
-	stock_details = frappe.db.sql("""
-		select
-			sum(planned_qty) as planned_qty,
-			sum(actual_qty) as actual_qty,
-			sum(projected_qty) as projected_qty,
-			item_code
-		from
-			`tabBin`
-		where
-			item_code in ({variants})
-		group by
-			item_code
-	""".format(variants=variants), as_dict=1)
+def get_stock_details_map(variant_list):
+	stock_details = frappe.db.get_all(
+		"Bin",
+		fields=[
+			"sum(planned_qty) as planned_qty",
+			"sum(actual_qty) as actual_qty",
+			"sum(projected_qty) as projected_qty",
+			"item_code",
+		],
+		filters={
+			"item_code": ["in", variant_list]
+		},
+		group_by="item_code"
+	)
 
 	stock_details_map = {}
-	for d in stock_details:
-		name = d["item_code"]
+	for row in stock_details:
+		name = row.get("item_code")
 		stock_details_map[name] = {
-			"Inventory" :d["actual_qty"],
-			"In Production" :d["planned_qty"],
-			"Available Selling" :d["projected_qty"]
+			"Inventory": row.get("actual_qty"),
+			"In Production": row.get("planned_qty")
 		}
 
 	return stock_details_map
 
-def get_buying_price_map(variants):
-	buying = frappe.db.sql("""
-		select
-			avg(price_list_rate) as avg_rate,
-			item_code
-		from
-			`tabItem Price`
-		where
-			item_code in ({variants}) and buying=1
-		group by
-			item_code
-		""".format(variants=variants), as_dict=1)
+def get_buying_price_map(variant_list):
+	buying = frappe.db.get_all(
+		"Item Price",
+		fields=[
+			"avg(price_list_rate) as avg_rate",
+			"item_code",
+		],
+		filters={
+			"item_code": ["in", variant_list],
+			"buying": 1
+		},
+		group_by="item_code"
+	)
 
 	buying_price_map = {}
-	for d in buying:
-		buying_price_map[d["item_code"]] = d["avg_rate"]
+	for row in buying:
+		buying_price_map[row.get("item_code")] = row.get("avg_rate")
 
 	return buying_price_map
 
-def get_selling_price_map(variants):
-	selling = frappe.db.sql("""
-		select
-			avg(price_list_rate) as avg_rate,
-			item_code
-		from
-			`tabItem Price`
-		where
-			item_code in ({variants}) and selling=1
-		group by
-			item_code
-		""".format(variants=variants), as_dict=1)
+def get_selling_price_map(variant_list):
+	selling = frappe.db.get_all(
+		"Item Price",
+		fields=[
+			"avg(price_list_rate) as avg_rate",
+			"item_code",
+		],
+		filters={
+			"item_code": ["in", variant_list],
+			"selling": 1
+		},
+		group_by="item_code"
+	)
 
 	selling_price_map = {}
-	for d in selling:
-		selling_price_map[d["item_code"]] = d["avg_rate"]
+	for row in selling:
+		selling_price_map[row.get("item_code")] = row.get("avg_rate")
 
 	return selling_price_map
 
-def get_attribute_values_map(variants):
-	list_attr = frappe.db.sql("""
-		select
-			attribute, attribute_value, parent
-		from
-			`tabItem Variant Attribute`
-		where
-			parent in ({variants})
-		""".format(variants=variants), as_dict=1)
+def get_attribute_values_map(variant_list):
+	attribute_list = frappe.db.get_all(
+		"Item Variant Attribute",
+		fields=[
+			"attribute",
+			"attribute_value",
+			"parent"
+		],
+		filters={
+			"parent": ["in", variant_list]
+		}
+	)
 
 	attr_val_map = {}
-	for d in list_attr:
-		name = d["parent"]
+	for row in attribute_list:
+		name = row.get("parent")
 		if not attr_val_map.get(name):
 			attr_val_map[name] = {}
 
-		attr_val_map[name][d["attribute"]] = d["attribute_value"]
+		attr_val_map[name][row.get("attribute")] = row.get("attribute_value")
 
 	return attr_val_map
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 9729987..b2825fc 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -232,7 +232,8 @@
 				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)
+			limit 1
+			for update""", args, as_dict=1)
 
 		return sle[0] if sle else frappe._dict()
 
@@ -623,7 +624,7 @@
 							break
 
 					# If no entry found with outgoing rate, collapse stack
-					if index == None:
+					if index is None:  # nosemgrep
 						new_stock_value = sum((d[0]*d[1] for d in self.wh_data.stock_queue)) - qty_to_pop*outgoing_rate
 						new_stock_qty = sum((d[0] for d in self.wh_data.stock_queue)) - qty_to_pop
 						self.wh_data.stock_queue = [[new_stock_qty, new_stock_value/new_stock_qty if new_stock_qty > 0 else outgoing_rate]]
diff --git a/requirements.txt b/requirements.txt
index 65688f4..e30746a 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -11,4 +11,3 @@
 taxjar~=1.9.2
 tweepy~=3.10.0
 Unidecode~=1.2.0
-WooCommerce~=3.0.0