fix: conflicts
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index a181c2d..c90e01c 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.7.1'
+__version__ = '13.8.0'
 
 def get_default_company(user=None):
 	'''Get default company for user'''
diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py
index 4fd8413..8456b49 100644
--- a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py
+++ b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py
@@ -391,5 +391,5 @@
 	})
 
 	company.save()
-	install_country_fixtures(company.name)
+	install_country_fixtures(company.name, company.country)
 	company.create_default_tax_template()
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index 6635128..d788d91 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -306,5 +306,5 @@
 				}
 			]
 		})
-
+		jv.flags.ignore_mandatory = True
 		jv.submit()
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py
index b54d0e7..94abf3b 100644
--- a/erpnext/accounts/doctype/pricing_rule/utils.py
+++ b/erpnext/accounts/doctype/pricing_rule/utils.py
@@ -168,7 +168,7 @@
 			frappe.throw(_("Invalid {0}").format(args.get(field)))
 
 		parent_groups = frappe.db.sql_list("""select name from `tab%s`
-			where lft>=%s and rgt<=%s""" % (parenttype, '%s', '%s'), (lft, rgt))
+			where lft<=%s and rgt>=%s""" % (parenttype, '%s', '%s'), (lft, rgt))
 
 		if parenttype in ["Customer Group", "Item Group", "Territory"]:
 			parent_field = "parent_{0}".format(frappe.scrub(parenttype))
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index db6f143..e90b35f 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -240,7 +240,7 @@
 		pi.conversion_rate = 80
 
 		pi.insert()
-		pi.submit()		
+		pi.submit()
 
 		# Get exchnage gain and loss account
 		exchange_gain_loss_account = frappe.db.get_value('Company', pi.company, 'exchange_gain_loss_account')
@@ -978,7 +978,7 @@
 		unlink_enabled = frappe.db.get_value(
 			"Accounts Settings", "Accounts Settings",
 			"unlink_payment_on_cancel_of_invoice")
-		
+
 		frappe.db.set_value(
 			"Accounts Settings", "Accounts Settings",
 			"unlink_payment_on_cancel_of_invoice", 1)
@@ -1018,8 +1018,8 @@
 
 		expected_gle = [
 			["_Test Account Cost for Goods Sold - _TC", 37500.0],
-			["_Test Payable USD - _TC", -40000.0],
-			["Exchange Gain/Loss - _TC", 2500.0]
+			["_Test Payable USD - _TC", -35000.0],
+			["Exchange Gain/Loss - _TC", -2500.0]
 		]
 
 		gl_entries = frappe.db.sql("""
@@ -1027,7 +1027,7 @@
 			where voucher_no=%s
 			group by account
 			order by account asc""", (pi.name), as_dict=1)
-		
+
 		for i, gle in enumerate(gl_entries):
 			self.assertEqual(expected_gle[i][0], gle.account)
 			self.assertEqual(expected_gle[i][1], gle.balance)
@@ -1049,8 +1049,8 @@
 
 		expected_gle = [
 			["_Test Account Cost for Goods Sold - _TC", 36500.0],
-			["_Test Payable USD - _TC", -38000.0],
-			["Exchange Gain/Loss - _TC", 1500.0]
+			["_Test Payable USD - _TC", -35000.0],
+			["Exchange Gain/Loss - _TC", -1500.0]
 		]
 
 		gl_entries = frappe.db.sql("""
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json
index f9160e2..153906f 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json
@@ -1,263 +1,151 @@
 {
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 1, 
- "allow_rename": 1, 
- "autoname": "Prompt", 
- "beta": 0, 
- "creation": "2018-04-13 18:42:06.431683", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 1, 
- "engine": "InnoDB", 
+ "actions": [],
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "Prompt",
+ "creation": "2018-04-13 18:42:06.431683",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "category_details_section",
+  "category_name",
+  "round_off_tax_amount",
+  "column_break_2",
+  "consider_party_ledger_amount",
+  "tax_on_excess_amount",
+  "section_break_8",
+  "rates",
+  "section_break_7",
+  "accounts"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
    "fieldname": "category_name",
    "fieldtype": "Data",
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
    "in_list_view": 1,
-   "in_standard_filter": 0, 
    "label": "Category Name",
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "show_days": 1,
+   "show_seconds": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
    "fieldname": "section_break_8",
    "fieldtype": "Section Break",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
    "label": "Tax Withholding Rates",
-   "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
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "rates",
    "fieldtype": "Table",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
    "label": "Rates",
-   "length": 0,
-   "no_copy": 0,
    "options": "Tax Withholding Rate",
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
    "reqd": 1,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "section_break_7", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
+   "fieldname": "section_break_7",
+   "fieldtype": "Section Break",
    "label": "Account Details",
-   "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
-  }, 
+   "show_days": 1,
+   "show_seconds": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "accounts", 
-   "fieldtype": "Table", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Accounts", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Tax Withholding Account", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
+   "fieldname": "accounts",
+   "fieldtype": "Table",
+   "label": "Accounts",
+   "options": "Tax Withholding Account",
+   "reqd": 1,
+   "show_days": 1,
+   "show_seconds": 1
+  },
+  {
+   "fieldname": "category_details_section",
+   "fieldtype": "Section Break",
+   "label": "Category Details",
+   "show_days": 1,
+   "show_seconds": 1
+  },
+  {
+   "fieldname": "column_break_2",
+   "fieldtype": "Column Break",
+   "show_days": 1,
+   "show_seconds": 1
+  },
+  {
+   "default": "0",
+   "description": "Even invoices with apply tax withholding unchecked will be considered for checking cumulative threshold breach",
+   "fieldname": "consider_party_ledger_amount",
+   "fieldtype": "Check",
+   "label": "Consider Entire Party Ledger Amount",
+   "show_days": 1,
+   "show_seconds": 1
+  },
+  {
+   "default": "0",
+   "description": "Tax will be withheld only for amount exceeding the cumulative threshold",
+   "fieldname": "tax_on_excess_amount",
+   "fieldtype": "Check",
+   "label": "Only Deduct Tax On Excess Amount ",
+   "show_days": 1,
+   "show_seconds": 1
+  },
+  {
+   "description": "Checking this will round off the tax amount to the nearest integer",
+   "fieldname": "round_off_tax_amount",
+   "fieldtype": "Check",
+   "label": "Round Off Tax Amount",
+   "show_days": 1,
+   "show_seconds": 1
   }
- ], 
- "has_web_view": 0, 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "idx": 0, 
- "image_view": 0, 
- "in_create": 0, 
- "is_submittable": 0, 
- "issingle": 0, 
- "istable": 0, 
- "max_attachments": 0, 
- "modified": "2018-07-17 22:53:26.193179",
- "modified_by": "Administrator", 
- "module": "Accounts", 
- "name": "Tax Withholding Category", 
- "name_case": "", 
- "owner": "Administrator", 
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2021-07-27 21:47:34.396071",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Tax Withholding Category",
+ "owner": "Administrator",
  "permissions": [
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "System Manager", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
    "write": 1
-  }, 
+  },
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Accounts Manager", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Accounts Manager",
+   "share": 1,
    "write": 1
-  }, 
+  },
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Accounts User", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Accounts User",
+   "share": 1,
    "write": 1
   }
- ], 
- "quick_entry": 0,
- "read_only": 0, 
- "read_only_onload": 0, 
- "show_name_in_global_search": 0, 
- "sort_field": "modified", 
- "sort_order": "DESC", 
- "track_changes": 1, 
- "track_seen": 0,
- "track_views": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
index b9ee4a0..481ef28 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -6,7 +6,7 @@
 import frappe
 from frappe import _
 from frappe.model.document import Document
-from frappe.utils import flt, getdate
+from frappe.utils import flt, getdate, cint
 from erpnext.accounts.utils import get_fiscal_year
 
 class TaxWithholdingCategory(Document):
@@ -86,7 +86,10 @@
 				"rate": tax_rate_detail.tax_withholding_rate,
 				"threshold": tax_rate_detail.single_threshold,
 				"cumulative_threshold": tax_rate_detail.cumulative_threshold,
-				"description": tax_withholding.category_name if tax_withholding.category_name else tax_withholding_category
+				"description": tax_withholding.category_name if tax_withholding.category_name else tax_withholding_category,
+				"consider_party_ledger_amount": tax_withholding.consider_party_ledger_amount,
+				"tax_on_excess_amount": tax_withholding.tax_on_excess_amount,
+				"round_off_tax_amount": tax_withholding.round_off_tax_amount
 			})
 
 def get_tax_withholding_rates(tax_withholding, fiscal_year):
@@ -145,6 +148,7 @@
 def get_tax_amount(party_type, parties, inv, tax_details, fiscal_year_details, pan_no=None):
 	fiscal_year = fiscal_year_details[0]
 
+
 	vouchers = get_invoice_vouchers(parties, fiscal_year, inv.company, party_type=party_type)
 	advance_vouchers = get_advance_vouchers(parties, fiscal_year, inv.company, party_type=party_type)
 	taxable_vouchers = vouchers + advance_vouchers
@@ -235,10 +239,18 @@
 
 def get_tds_amount(ldc, parties, inv, tax_details, fiscal_year_details, tax_deducted, vouchers):
 	tds_amount = 0
+	invoice_filters = {
+		'name': ('in', vouchers), 
+		'docstatus': 1
+	}
 
-	supp_credit_amt = frappe.db.get_value('Purchase Invoice', {
-		'name': ('in', vouchers), 'docstatus': 1, 'apply_tds': 1
-	}, 'sum(net_total)') or 0.0
+	field = 'sum(net_total)'
+
+	if not cint(tax_details.consider_party_ledger_amount):
+		invoice_filters.update({'apply_tds': 1})
+		field = 'sum(grand_total)'
+
+	supp_credit_amt = frappe.db.get_value('Purchase Invoice', invoice_filters, field) or 0.0
 
 	supp_jv_credit_amt = frappe.db.get_value('Journal Entry Account', {
 		'parent': ('in', vouchers), 'docstatus': 1,
@@ -255,6 +267,13 @@
 	cumulative_threshold = tax_details.get('cumulative_threshold', 0)
 
 	if ((threshold and inv.net_total >= threshold) or (cumulative_threshold and supp_credit_amt >= cumulative_threshold)):
+		if (cumulative_threshold and supp_credit_amt >= cumulative_threshold) and cint(tax_details.tax_on_excess_amount):
+			# Get net total again as TDS is calculated on net total
+			# Grand is used to just check for threshold breach
+			net_total = frappe.db.get_value('Purchase Invoice', invoice_filters, 'sum(net_total)') or 0.0
+			net_total += inv.net_total
+			supp_credit_amt = net_total - cumulative_threshold
+
 		if ldc and is_valid_certificate(
 			ldc.valid_from, ldc.valid_upto,
 			inv.get('posting_date') or inv.get('transaction_date'), tax_deducted,
@@ -263,6 +282,9 @@
 			tds_amount = get_ltds_amount(supp_credit_amt, 0, ldc.certificate_limit, ldc.rate, tax_details)
 		else:
 			tds_amount = supp_credit_amt * tax_details.rate / 100 if supp_credit_amt > 0 else 0
+	
+	if cint(tax_details.round_off_tax_amount):
+		tds_amount = round(tds_amount)
 
 	return tds_amount
 
diff --git a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
index dd26be7..2ba22ca 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
@@ -87,6 +87,31 @@
 		for d in invoices:
 			d.cancel()
 
+	def test_tax_withholding_category_checks(self):
+		invoices = []
+		frappe.db.set_value("Supplier", "Test TDS Supplier3", "tax_withholding_category", "New TDS Category")
+
+		# First Invoice with no tds check
+		pi = create_purchase_invoice(supplier = "Test TDS Supplier3", rate = 20000, do_not_save=True)
+		pi.apply_tds = 0
+		pi.save()
+		pi.submit()
+		invoices.append(pi)
+		
+		# Second Invoice will apply TDS checked
+		pi1 = create_purchase_invoice(supplier = "Test TDS Supplier3", rate = 20000)
+		pi1.submit()
+		invoices.append(pi1)
+
+		# Cumulative threshold is 30000
+		# Threshold calculation should be on both the invoices
+		# TDS should be applied only on 1000
+		self.assertEqual(pi1.taxes[0].tax_amount, 1000)
+
+		for d in invoices:
+			d.cancel()
+
+
 	def test_cumulative_threshold_tcs(self):
 		frappe.db.set_value("Customer", "Test TCS Customer", "tax_withholding_category", "Cumulative Threshold TCS")
 		invoices = []
@@ -195,7 +220,7 @@
 
 def create_records():
 	# create a new suppliers
-	for name in ['Test TDS Supplier', 'Test TDS Supplier1', 'Test TDS Supplier2']:
+	for name in ['Test TDS Supplier', 'Test TDS Supplier1', 'Test TDS Supplier2', 'Test TDS Supplier3']:
 		if frappe.db.exists('Supplier', name):
 			continue
 
@@ -311,3 +336,23 @@
 				'account': 'TDS - _TC'
 			}]
 		}).insert()
+
+	if not frappe.db.exists("Tax Withholding Category", "New TDS Category"):
+		frappe.get_doc({
+			"doctype": "Tax Withholding Category",
+			"name": "New TDS Category",
+			"category_name": "New TDS Category",
+			"round_off_tax_amount": 1,
+			"consider_party_ledger_amount": 1,
+			"tax_on_excess_amount": 1,
+			"rates": [{
+				'fiscal_year': fiscal_year,
+				'tax_withholding_rate': 10,
+				'single_threshold': 0,
+				'cumulative_threshold': 30000
+			}],
+			"accounts": [{
+				'company': '_Test Company',
+				'account': 'TDS - _TC'
+			}]
+		}).insert()
diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py
index 84c7454..6d8623c 100644
--- a/erpnext/accounts/report/gross_profit/gross_profit.py
+++ b/erpnext/accounts/report/gross_profit/gross_profit.py
@@ -241,6 +241,7 @@
 						sle.voucher_detail_no == row.item_row:
 							previous_stock_value = len(my_sle) > i+1 and \
 								flt(my_sle[i+1].stock_value) or 0.0
+
 							if previous_stock_value:
 								return (previous_stock_value - flt(sle.stock_value)) * flt(row.qty) / abs(flt(sle.qty))
 							else:
@@ -335,7 +336,7 @@
 		res = frappe.db.sql("""select item_code, voucher_type, voucher_no,
 				voucher_detail_no, stock_value, warehouse, actual_qty as qty
 			from `tabStock Ledger Entry`
-			where company=%(company)s
+			where company=%(company)s and is_cancelled = 0
 			order by
 				item_code desc, warehouse desc, posting_date desc,
 				posting_time desc, creation desc""", self.filters, as_dict=True)
diff --git a/erpnext/change_log/v13/v13_8_0.md b/erpnext/change_log/v13/v13_8_0.md
new file mode 100644
index 0000000..98ed95a
--- /dev/null
+++ b/erpnext/change_log/v13/v13_8_0.md
@@ -0,0 +1,39 @@
+# Version 13.8.0 Release Notes
+
+### Features & Enhancements
+- Report to show COGS by item groups ([#26222](https://github.com/frappe/erpnext/pull/26222))
+- Enhancements in TDS ([#26677](https://github.com/frappe/erpnext/pull/26677))
+- API Endpoint to update halted Razorpay subscriptions ([#26564](https://github.com/frappe/erpnext/pull/26564))
+
+### Fixes
+- Incorrect bom name ([#26600](https://github.com/frappe/erpnext/pull/26600))
+- Exchange rate revaluation posting date and precision fixes ([#26651](https://github.com/frappe/erpnext/pull/26651))
+- POS item cart dom updates ([#26460](https://github.com/frappe/erpnext/pull/26460))
+- General Ledger report not working with filter group by ([#26439](https://github.com/frappe/erpnext/pull/26438))
+- Tax calculation for Recurring additional salary ([#24206](https://github.com/frappe/erpnext/pull/24206))
+- Validation check for batch for stock reconciliation type in stock entry ([#26487](https://github.com/frappe/erpnext/pull/26487))
+- Improved UX for additional discount field ([#26502](https://github.com/frappe/erpnext/pull/26502))
+- Add missing cess amount in GSTR-3B report ([#26644](https://github.com/frappe/erpnext/pull/26644))
+- Optimized code for reposting item valuation ([#26431](https://github.com/frappe/erpnext/pull/26431))
+- FG item not fetched in manufacture entry ([#26508](https://github.com/frappe/erpnext/pull/26508))
+- Errors on parallel requests creation of company for India  ([#26420](https://github.com/frappe/erpnext/pull/26420))
+- Incorrect valuation rate calculation in gross profit report ([#26558](https://github.com/frappe/erpnext/pull/26558))
+- Empty "against account" in Purchase Receipt GLE ([#26712](https://github.com/frappe/erpnext/pull/26712))
+- Remove cancelled entries from Stock and Account Value comparison report ([#26721](https://github.com/frappe/erpnext/pull/26721))
+- Remove manual permission checking ([#26691](https://github.com/frappe/erpnext/pull/26691))
+- Delete child docs when parent doc is deleted ([#26518](https://github.com/frappe/erpnext/pull/26518))
+- GST Reports timeout issue ([#26646](https://github.com/frappe/erpnext/pull/26646))
+- Parent condition in pricing rules ([#26727](https://github.com/frappe/erpnext/pull/26727))
+- Added Company filters for Loan ([#26294](https://github.com/frappe/erpnext/pull/26294))
+- Incorrect discount amount on amended document ([#26292](https://github.com/frappe/erpnext/pull/26292))
+- Exchange gain loss not set for advances linked with invoices ([#26436](https://github.com/frappe/erpnext/pull/26436))
+- Unallocated amount in Payment Entry after taxes ([#26412](https://github.com/frappe/erpnext/pull/26412))
+- Wrong operation time in Work Order ([#26613](https://github.com/frappe/erpnext/pull/26613))
+- Serial No and Batch validation ([#26614](https://github.com/frappe/erpnext/pull/26614))
+- Gl Entries for exchange gain loss ([#26734](https://github.com/frappe/erpnext/pull/26734))
+- TDS computation summary shows cancelled invoices ([#26485](https://github.com/frappe/erpnext/pull/26485))
+- Price List rate not fetched for return sales invoice fixed ([#26560](https://github.com/frappe/erpnext/pull/26560))
+- Included company in link document type filters for contact ([#26576](https://github.com/frappe/erpnext/pull/26576))
+- Ignore mandatory fields while creating payment reconciliation Journal Entry ([#26643](https://github.com/frappe/erpnext/pull/26643))
+- Unable to download GSTR-1 json ([#26418](https://github.com/frappe/erpnext/pull/26418))
+- Paging buttons not working on item group portal page ([#26498](https://github.com/frappe/erpnext/pull/26498))
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index d5c5d42..bf4ab1a 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -674,19 +674,24 @@
 		if self.get('doctype') in ['Purchase Invoice', 'Sales Invoice']:
 			for d in self.get("advances"):
 				if d.exchange_gain_loss:
-					party = self.supplier if self.get('doctype') == 'Purchase Invoice' else self.customer
-					party_account = self.credit_to if self.get('doctype') == 'Purchase Invoice' else self.debit_to
-					party_type = "Supplier" if self.get('doctype') == 'Purchase Invoice' else "Customer"
+					is_purchase_invoice = self.get('doctype') == 'Purchase Invoice'
+					party = self.supplier if is_purchase_invoice else self.customer
+					party_account = self.credit_to if is_purchase_invoice else self.debit_to
+					party_type = "Supplier" if is_purchase_invoice else "Customer"
 
 					gain_loss_account = frappe.db.get_value('Company', self.company, 'exchange_gain_loss_account')
+					if not gain_loss_account:
+						frappe.throw(_("Please set Default Exchange Gain/Loss Account in Company {}")
+							.format(self.get('company')))
 					account_currency = get_account_currency(gain_loss_account)
 					if account_currency != self.company_currency:
-						frappe.throw(_("Currency for {0} must be {1}").format(d.account, self.company_currency))
+						frappe.throw(_("Currency for {0} must be {1}").format(gain_loss_account, self.company_currency))
 
 					# for purchase
 					dr_or_cr = 'debit' if d.exchange_gain_loss > 0 else 'credit'
-					# just reverse for sales?
-					dr_or_cr = 'debit' if dr_or_cr == 'credit' else 'credit'
+					if not is_purchase_invoice:
+						# just reverse for sales?
+						dr_or_cr = 'debit' if dr_or_cr == 'credit' else 'credit'
 
 					gl_entries.append(
 						self.get_gl_dict({
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index 2803193..21c052a 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -407,6 +407,7 @@
 				INNER JOIN `tabBatch` batch on sle.batch_no = batch.name
 			where
 				batch.disabled = 0
+				and sle.is_cancelled = 0
 				and sle.item_code = %(item_code)s
 				and sle.warehouse = %(warehouse)s
 				and (sle.batch_no like %(txt)s
diff --git a/erpnext/loan_management/doctype/loan_application/loan_application.js b/erpnext/loan_management/doctype/loan_application/loan_application.js
index 017026c..5142178 100644
--- a/erpnext/loan_management/doctype/loan_application/loan_application.js
+++ b/erpnext/loan_management/doctype/loan_application/loan_application.js
@@ -14,7 +14,7 @@
 	refresh: function(frm) {
 		frm.trigger("toggle_fields");
 		frm.trigger("add_toolbar_buttons");
-		frm.set_query("loan_type", () => {
+		frm.set_query('loan_type', () => {
 			return {
 				filters: {
 					company: frm.doc.company
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index c68198b..4e93fc6 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -748,7 +748,7 @@
 	if valuation_rate <= 0:
 		last_valuation_rate = frappe.db.sql("""select valuation_rate
 			from `tabStock Ledger Entry`
-			where item_code = %s and valuation_rate > 0
+			where item_code = %s and valuation_rate > 0 and is_cancelled = 0
 			order by posting_date desc, posting_time desc, creation desc limit 1""", args['item_code'])
 
 		valuation_rate = flt(last_valuation_rate[0][0]) if last_valuation_rate else 0
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index a029627a..744196a 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -297,3 +297,5 @@
 erpnext.patches.v13_0.add_missing_fg_item_for_stock_entry
 erpnext.patches.v13_0.update_subscription_status_in_memberships
 erpnext.patches.v13_0.update_amt_in_work_order_required_items
+erpnext.patches.v13_0.update_export_type_for_gst
+erpnext.patches.v13_0.update_tds_check_field #3
diff --git a/erpnext/patches/v13_0/update_export_type_for_gst.py b/erpnext/patches/v13_0/update_export_type_for_gst.py
new file mode 100644
index 0000000..478a2a6
--- /dev/null
+++ b/erpnext/patches/v13_0/update_export_type_for_gst.py
@@ -0,0 +1,24 @@
+import frappe
+
+def execute():
+	company = frappe.get_all('Company', filters = {'country': 'India'})
+	if not company:
+		return
+
+	# Update custom fields
+	fieldname = frappe.db.get_value('Custom Field', {'dt': 'Customer', 'fieldname': 'export_type'})
+	if fieldname:
+		frappe.db.set_value('Custom Field', fieldname, 'default', '')
+
+	fieldname = frappe.db.get_value('Custom Field', {'dt': 'Supplier', 'fieldname': 'export_type'})
+	if fieldname:
+		frappe.db.set_value('Custom Field', fieldname, 'default', '')
+
+	# Update Customer/Supplier Masters
+	frappe.db.sql("""
+		UPDATE `tabCustomer` set export_type = '' WHERE gst_category NOT IN ('SEZ', 'Overseas', 'Deemed Export')
+	""")
+
+	frappe.db.sql("""
+		UPDATE `tabSupplier` set export_type = '' WHERE gst_category NOT IN ('SEZ', 'Overseas')
+	""")
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/update_tds_check_field.py b/erpnext/patches/v13_0/update_tds_check_field.py
new file mode 100644
index 0000000..3d14958
--- /dev/null
+++ b/erpnext/patches/v13_0/update_tds_check_field.py
@@ -0,0 +1,9 @@
+import frappe
+
+def execute():
+	if frappe.db.has_table("Tax Withholding Category") \
+		and frappe.db.has_column("Tax Withholding Category", "round_off_tax_amount"):
+		frappe.db.sql("""
+			UPDATE `tabTax Withholding Category` set round_off_tax_amount = 0
+			WHERE round_off_tax_amount IS NULL
+		""")
\ No newline at end of file
diff --git a/erpnext/payroll/doctype/additional_salary/additional_salary.py b/erpnext/payroll/doctype/additional_salary/additional_salary.py
index 381f399..b978cbe 100644
--- a/erpnext/payroll/doctype/additional_salary/additional_salary.py
+++ b/erpnext/payroll/doctype/additional_salary/additional_salary.py
@@ -112,11 +112,11 @@
 		no_of_days = date_diff(getdate(end_date), getdate(start_date)) + 1
 		return amount_per_day * no_of_days
 
+@frappe.whitelist()
 def get_additional_salaries(employee, start_date, end_date, component_type):
 	additional_salary_list = frappe.db.sql("""
-		select name, salary_component as component, type, amount,
-		overwrite_salary_structure_amount as overwrite,
-		deduct_full_tax_on_selected_payroll_date
+		select name, salary_component as component, type, amount, overwrite_salary_structure_amount as overwrite,
+		deduct_full_tax_on_selected_payroll_date, is_recurring
 		from `tabAdditional Salary`
 		where employee=%(employee)s
 			and docstatus = 1
diff --git a/erpnext/payroll/doctype/salary_detail/salary_detail.json b/erpnext/payroll/doctype/salary_detail/salary_detail.json
index 393f647..97608d7 100644
--- a/erpnext/payroll/doctype/salary_detail/salary_detail.json
+++ b/erpnext/payroll/doctype/salary_detail/salary_detail.json
@@ -12,6 +12,7 @@
   "year_to_date",
   "section_break_5",
   "additional_salary",
+  "is_recurring_additional_salary",
   "statistical_component",
   "depends_on_payment_days",
   "exempted_from_income_tax",
@@ -235,11 +236,19 @@
    "label": "Year To Date",
    "options": "currency",
    "read_only": 1
+  },
+  {
+   "default": "0",
+   "depends_on": "eval:doc.parenttype=='Salary Slip' && doc.parentfield=='earnings' && doc.additional_salary",
+   "fieldname": "is_recurring_additional_salary",
+   "fieldtype": "Check",
+   "label": "Is Recurring Additional Salary",
+   "read_only": 1
   }
  ],
  "istable": 1,
  "links": [],
- "modified": "2021-01-14 13:39:15.847158",
+ "modified": "2021-03-14 13:39:15.847158",
  "modified_by": "Administrator",
  "module": "Payroll",
  "name": "Salary Detail",
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py
index c321f6f..b39cef8 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py
@@ -7,12 +7,12 @@
 
 from frappe.utils import add_days, cint, cstr, flt, getdate, rounded, date_diff, money_in_words, formatdate, get_first_day
 from frappe.model.naming import make_autoname
+from frappe.utils.background_jobs import enqueue
 
 from frappe import msgprint, _
 from erpnext.payroll.doctype.payroll_entry.payroll_entry import get_start_end_dates
 from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
 from erpnext.utilities.transaction_base import TransactionBase
-from frappe.utils.background_jobs import enqueue
 from erpnext.payroll.doctype.additional_salary.additional_salary import get_additional_salaries
 from erpnext.payroll.doctype.payroll_period.payroll_period import get_period_factor, get_payroll_period
 from erpnext.payroll.doctype.employee_benefit_application.employee_benefit_application import get_benefit_component_amount
@@ -618,7 +618,8 @@
 				get_salary_component_data(additional_salary.component),
 				additional_salary.amount,
 				component_type,
-				additional_salary
+				additional_salary,
+				is_recurring = additional_salary.is_recurring
 			)
 
 	def add_tax_components(self, payroll_period):
@@ -639,7 +640,7 @@
 			tax_row = get_salary_component_data(d)
 			self.update_component_row(tax_row, tax_amount, "deductions")
 
-	def update_component_row(self, component_data, amount, component_type, additional_salary=None):
+	def update_component_row(self, component_data, amount, component_type, additional_salary=None, is_recurring = 0):
 		component_row = None
 		for d in self.get(component_type):
 			if d.salary_component != component_data.salary_component:
@@ -677,6 +678,7 @@
 				component_row.set(attr, component_data.get(attr))
 
 		if additional_salary:
+			component_row.is_recurring_additional_salary = is_recurring
 			component_row.default_amount = 0
 			component_row.additional_amount = amount
 			component_row.additional_salary = additional_salary.name
@@ -710,6 +712,7 @@
 		# get remaining numbers of sub-period (period for which one salary is processed)
 		remaining_sub_periods = get_period_factor(self.employee,
 			self.start_date, self.end_date, self.payroll_frequency, payroll_period)[1]
+
 		# get taxable_earnings, paid_taxes for previous period
 		previous_taxable_earnings = self.get_taxable_earnings_for_prev_period(payroll_period.start_date,
 			self.start_date, tax_slab.allow_tax_exemption)
@@ -869,8 +872,16 @@
 
 			if earning.is_tax_applicable:
 				if additional_amount:
-					taxable_earnings += (amount - additional_amount)
-					additional_income += additional_amount
+					if not earning.is_recurring_additional_salary:
+						taxable_earnings += (amount - additional_amount)
+						additional_income += additional_amount
+					else:
+						to_date = frappe.db.get_value("Additional Salary", earning.additional_salary, 'to_date')
+						period = (getdate(to_date).month - getdate(self.start_date).month) + 1
+						if period > 0:
+							taxable_earnings += (amount - additional_amount) * period
+							additional_income += additional_amount * period
+
 					if earning.deduct_full_tax_on_selected_payroll_date:
 						additional_income_with_full_tax += additional_amount
 					continue
diff --git a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py
index 374dd7e..3957d83 100644
--- a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py
+++ b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py
@@ -129,7 +129,7 @@
 		"earnings": make_earning_salary_component(setup=True,  test_tax=test_tax, company_list=["_Test Company"]),
 		"deductions": make_deduction_salary_component(setup=True, test_tax=test_tax, company_list=["_Test Company"]),
 		"payroll_frequency": payroll_frequency,
-		"payment_account": get_random("Account", filters={"account_currency": currency}),
+		"payment_account": get_random("Account", filters={'account_currency': currency}),
 		"currency": currency
 	}
 	if other_details and isinstance(other_details, dict):
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 ea39fe1..0ee5b09 100644
--- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
+++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
@@ -280,9 +280,15 @@
 		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"):
+				if invoice not in self.items_based_on_tax_rate and self.invoice_detail_map.get(invoice, {}).get('export_type') \
+					== "Without Payment of Tax" and self.invoice_detail_map.get(invoice, {}).get('gst_category') == "Overseas":
 					self.items_based_on_tax_rate.setdefault(invoice, {}).setdefault(0, items.keys())
+				else:
+					for item in items.keys():
+						if item in self.is_nil_exempt + self.is_non_gst and \
+							item not in self.items_based_on_tax_rate.get(invoice, {}).get(0, []):
+								self.items_based_on_tax_rate.setdefault(invoice, {}).setdefault(0, [])
+								self.items_based_on_tax_rate[invoice][0].append(item)
 
 	def set_outward_taxable_supplies(self):
 		inter_state_supply_details = {}
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 9265460..e9372f9 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -641,7 +641,6 @@
 				'label': 'Export Type',
 				'fieldtype': 'Select',
 				'insert_after': 'gst_category',
-				'default': 'Without Payment of Tax',
 				'depends_on':'eval:in_list(["SEZ", "Overseas"], doc.gst_category)',
 				'options': '\nWith Payment of Tax\nWithout Payment of Tax'
 			}
@@ -660,7 +659,6 @@
 				'label': 'Export Type',
 				'fieldtype': 'Select',
 				'insert_after': 'gst_category',
-				'default': 'Without Payment of Tax',
 				'depends_on':'eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)',
 				'options': '\nWith Payment of Tax\nWithout Payment of Tax'
 			}
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
index b81fa81..4b73094 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.py
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -286,7 +286,8 @@
 		# Build itemised tax for export invoices where tax table is blank
 		for invoice, items in iteritems(self.invoice_items):
 			if invoice not in self.items_based_on_tax_rate and invoice not in unidentified_gst_accounts_invoice \
-				and frappe.db.get_value(self.doctype, invoice, "export_type") == "Without Payment of Tax":
+				and self.invoices.get(invoice, {}).get('export_type') == "Without Payment of Tax" \
+				and self.invoices.get(invoice, {}).get('gst_category') == "Overseas":
 					self.items_based_on_tax_rate.setdefault(invoice, {}).setdefault(0, items.keys())
 
 	def get_columns(self):
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
index 691d331..8a49155 100644
--- a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
@@ -18,7 +18,7 @@
 		doctypes_to_be_ignored_list = get_doctypes_to_be_ignored()
 		for doctype in self.doctypes_to_be_ignored:
 			if doctype.doctype_name not in doctypes_to_be_ignored_list:
-				frappe.throw(_("DocTypes should not be added manually to the 'Excluded DocTypes' table. You are only allowed to remove entries from it. "), 
+				frappe.throw(_("DocTypes should not be added manually to the 'Excluded DocTypes' table. You are only allowed to remove entries from it."),
 					title=_("Not Allowed"))
 
 	def before_submit(self):
@@ -31,7 +31,7 @@
 		clear_notifications()
 		self.delete_company_transactions()
 
-	def populate_doctypes_to_be_ignored_table(self):		
+	def populate_doctypes_to_be_ignored_table(self):
 		doctypes_to_be_ignored_list = get_doctypes_to_be_ignored()
 		for doctype in doctypes_to_be_ignored_list:
 			self.append('doctypes_to_be_ignored', {
@@ -74,7 +74,7 @@
 		doctypes_to_be_ignored_list = self.get_doctypes_to_be_ignored_list()
 		docfields = self.get_doctypes_with_company_field(doctypes_to_be_ignored_list)
 
-		tables = self.get_all_child_doctypes()	
+		tables = self.get_all_child_doctypes()
 		for docfield in docfields:
 			if docfield['parent'] != self.doctype:
 				no_of_docs = self.get_number_of_docs_linked_with_specified_company(docfield['parent'], docfield['fieldname'])
@@ -90,7 +90,7 @@
 					naming_series = frappe.db.get_value('DocType', docfield['parent'], 'autoname')
 					if naming_series:
 						if '#' in naming_series:
-							self.update_naming_series(naming_series, docfield['parent'])	
+							self.update_naming_series(naming_series, docfield['parent'])
 
 	def get_doctypes_to_be_ignored_list(self):
 		singles = frappe.get_all('DocType', filters = {'issingle': 1}, pluck = 'name')
@@ -101,9 +101,9 @@
 		return doctypes_to_be_ignored_list
 
 	def get_doctypes_with_company_field(self, doctypes_to_be_ignored_list):
-		docfields = frappe.get_all('DocField', 
+		docfields = frappe.get_all('DocField',
 			filters = {
-				'fieldtype': 'Link', 
+				'fieldtype': 'Link',
 				'options': 'Company',
 				'parent': ['not in', doctypes_to_be_ignored_list]},
 			fields=['parent', 'fieldname'])
@@ -121,7 +121,7 @@
 			self.append('doctypes', {
 				'doctype_name' : doctype,
 				'no_of_docs' : no_of_docs
-			})		
+			})
 
 	def delete_child_tables(self, doctype, company_fieldname):
 		parent_docs_to_be_deleted = frappe.get_all(doctype, {
@@ -129,7 +129,7 @@
 		}, pluck = 'name')
 
 		child_tables = frappe.get_all('DocField', filters = {
-			'fieldtype': 'Table', 
+			'fieldtype': 'Table',
 			'parent': doctype
 		}, pluck = 'options')
 
diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py
index b6eef6c..b37ae3f 100644
--- a/erpnext/stock/doctype/batch/batch.py
+++ b/erpnext/stock/doctype/batch/batch.py
@@ -162,19 +162,19 @@
 
 		out = float(frappe.db.sql("""select sum(actual_qty)
 			from `tabStock Ledger Entry`
-			where warehouse=%s and batch_no=%s {0}""".format(cond),
+			where is_cancelled = 0 and warehouse=%s and batch_no=%s {0}""".format(cond),
 			(warehouse, batch_no))[0][0] or 0)
 
 	if batch_no and not warehouse:
 		out = frappe.db.sql('''select warehouse, sum(actual_qty) as qty
 			from `tabStock Ledger Entry`
-			where batch_no=%s
+			where is_cancelled = 0 and batch_no=%s
 			group by warehouse''', batch_no, as_dict=1)
 
 	if not batch_no and item_code and warehouse:
 		out = frappe.db.sql('''select batch_no, sum(actual_qty) as qty
 			from `tabStock Ledger Entry`
-			where item_code = %s and warehouse=%s
+			where is_cancelled = 0 and item_code = %s and warehouse=%s
 			group by batch_no''', (item_code, warehouse), as_dict=1)
 
 	return out
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index e795742..516ae43 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -239,6 +239,7 @@
 			and sle.`item_code`=%(item_code)s
 			and sle.`company` = %(company)s
 			and batch.disabled = 0
+			and sle.is_cancelled=0
 			and IFNULL(batch.`expiry_date`, '2200-01-01') > %(today)s
 			{warehouse_condition}
 		GROUP BY
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index fcb6f0f..95c7311 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -1789,7 +1789,7 @@
 	from `tabBatch` b, `tabStock Ledger Entry` sle
 	where b.expiry_date <= %s
 	and b.expiry_date is not NULL
-	and b.batch_id = sle.batch_no
+	and b.batch_id = sle.batch_no and sle.is_cancelled = 0
 	group by sle.warehouse, sle.item_code, sle.batch_no""",(nowdate()), as_dict=1)
 
 @frappe.whitelist()
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
index 93482e8..b4f4583 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
@@ -60,7 +60,7 @@
 		if self.batch_no and not self.get("allow_negative_stock"):
 			batch_bal_after_transaction = flt(frappe.db.sql("""select sum(actual_qty)
 				from `tabStock Ledger Entry`
-				where warehouse=%s and item_code=%s and batch_no=%s""",
+				where is_cancelled =0 and warehouse=%s and item_code=%s and batch_no=%s""",
 				(self.warehouse, self.item_code, self.batch_no))[0][0])
 
 			if batch_bal_after_transaction < 0:
@@ -152,7 +152,7 @@
 				last_transaction_time = frappe.db.sql("""
 					select MAX(timestamp(posting_date, posting_time)) as posting_time
 					from `tabStock Ledger Entry`
-					where docstatus = 1 and item_code = %s
+					where docstatus = 1 and is_cancelled = 0 and item_code = %s
 					and warehouse = %s""", (self.item_code, self.warehouse))[0][0]
 
 				cur_doc_posting_datetime = "%s %s" % (self.posting_date, self.get("posting_time") or "00:00:00")
diff --git a/erpnext/stock/report/cogs_by_item_group/__init__.py b/erpnext/stock/report/cogs_by_item_group/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/stock/report/cogs_by_item_group/__init__.py
diff --git a/erpnext/stock/report/cogs_by_item_group/cogs_by_item_group.js b/erpnext/stock/report/cogs_by_item_group/cogs_by_item_group.js
new file mode 100644
index 0000000..d7c50a6
--- /dev/null
+++ b/erpnext/stock/report/cogs_by_item_group/cogs_by_item_group.js
@@ -0,0 +1,31 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+
+frappe.query_reports["COGS By Item Group"] = {
+	filters: [
+    {
+      label: __("Company"),
+      fieldname: "company",
+      fieldtype: "Link",
+      options: "Company",
+      mandatory: true,
+      default: frappe.defaults.get_user_default("Company"),
+    },
+    {
+      label: __("From Date"),
+      fieldname: "from_date",
+      fieldtype: "Date",
+      mandatory: true,
+      default: frappe.datetime.year_start(),
+    },
+    {
+      label: __("To Date"),
+      fieldname: "to_date",
+      fieldtype: "Date",
+      mandatory: true,
+      default: frappe.datetime.get_today(),
+    },
+	]
+};
diff --git a/erpnext/stock/report/cogs_by_item_group/cogs_by_item_group.json b/erpnext/stock/report/cogs_by_item_group/cogs_by_item_group.json
new file mode 100644
index 0000000..a14adf8
--- /dev/null
+++ b/erpnext/stock/report/cogs_by_item_group/cogs_by_item_group.json
@@ -0,0 +1,32 @@
+{
+ "add_total_row": 0,
+ "columns": [],
+ "creation": "2021-06-02 18:59:19.830928",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "filters": [],
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2021-06-02 18:59:55.470621",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "COGS By Item Group",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "GL Entry",
+ "report_name": "COGS By Item Group",
+ "report_type": "Script Report",
+ "roles": [
+  {
+   "role": "Accounts User"
+  },
+  {
+   "role": "Accounts Manager"
+  },
+  {
+   "role": "Auditor"
+  }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/stock/report/cogs_by_item_group/cogs_by_item_group.py b/erpnext/stock/report/cogs_by_item_group/cogs_by_item_group.py
new file mode 100644
index 0000000..9e5e63e
--- /dev/null
+++ b/erpnext/stock/report/cogs_by_item_group/cogs_by_item_group.py
@@ -0,0 +1,188 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from collections import OrderedDict
+import datetime
+from typing import Dict, List, Tuple, Union
+
+import frappe
+from frappe import _
+from frappe.utils import date_diff
+
+from erpnext.accounts.report.general_ledger.general_ledger import get_gl_entries
+
+
+Filters = frappe._dict
+Row = frappe._dict
+Data = List[Row]
+Columns = List[Dict[str, str]]
+DateTime = Union[datetime.date, datetime.datetime]
+FilteredEntries = List[Dict[str, Union[str, float, DateTime, None]]]
+ItemGroupsDict = Dict[Tuple[int, int], Dict[str, Union[str, int]]]
+SVDList = List[frappe._dict]
+
+
+def execute(filters: Filters) -> Tuple[Columns, Data]:
+	update_filters_with_account(filters)
+	validate_filters(filters)
+	columns = get_columns()
+	data = get_data(filters)
+	return columns, data
+
+
+def update_filters_with_account(filters: Filters) -> None:
+	account = frappe.get_value("Company", filters.get("company"), "default_expense_account")
+	filters.update(dict(account=account))
+
+
+def validate_filters(filters: Filters) -> None:
+	if filters.from_date > filters.to_date:
+		frappe.throw(_("From Date must be before To Date"))
+
+
+def get_columns() -> Columns:
+	return [
+		{
+			'label': 'Item Group',
+			'fieldname': 'item_group',
+			'fieldtype': 'Data',
+			'width': '200'
+		},
+		{
+			'label': 'COGS Debit',
+			'fieldname': 'cogs_debit',
+			'fieldtype': 'Currency',
+			'width': '200'
+		}
+	]
+
+
+def get_data(filters: Filters) -> Data:
+	filtered_entries = get_filtered_entries(filters)
+	svd_list = get_stock_value_difference_list(filtered_entries)
+	leveled_dict = get_leveled_dict()
+
+	assign_self_values(leveled_dict, svd_list)
+	assign_agg_values(leveled_dict)
+	
+	data = []
+	for item in leveled_dict.items():
+		i = item[1]
+		if i['agg_value'] == 0:
+			continue
+		data.append(get_row(i['name'], i['agg_value'], i['is_group'], i['level']))
+		if i['self_value'] < i['agg_value'] and i['self_value'] > 0:
+			data.append(get_row(i['name'], i['self_value'], 0, i['level'] + 1))
+	return data
+
+
+def get_filtered_entries(filters: Filters) -> FilteredEntries:
+	gl_entries = get_gl_entries(filters, [])
+	filtered_entries = []
+	for entry in gl_entries:
+		posting_date = entry.get('posting_date')
+		from_date = filters.get('from_date')
+		if date_diff(from_date, posting_date) > 0:
+			continue
+		filtered_entries.append(entry)
+	return filtered_entries
+
+
+def get_stock_value_difference_list(filtered_entries: FilteredEntries) -> SVDList:
+	voucher_nos = [fe.get('voucher_no') for fe in filtered_entries]
+	svd_list = frappe.get_list(
+		'Stock Ledger Entry', fields=['item_code','stock_value_difference'],
+		filters=[('voucher_no', 'in', voucher_nos)]
+	)
+	assign_item_groups_to_svd_list(svd_list)
+	return svd_list
+
+
+def get_leveled_dict() -> OrderedDict:
+	item_groups_dict = get_item_groups_dict()
+	lr_list = sorted(item_groups_dict, key=lambda x : int(x[0]))
+	leveled_dict = OrderedDict()
+	current_level = 0
+	nesting_r = []
+	for l, r in lr_list:
+		while current_level > 0 and nesting_r[-1] < l:
+			nesting_r.pop()
+			current_level -= 1
+
+		leveled_dict[(l,r)] = {
+			'level' : current_level,
+			'name' : item_groups_dict[(l,r)]['name'],
+			'is_group' : item_groups_dict[(l,r)]['is_group']
+		}
+
+		if int(r) - int(l) > 1:
+			current_level += 1
+			nesting_r.append(r)
+
+	update_leveled_dict(leveled_dict)
+	return leveled_dict
+
+
+def assign_self_values(leveled_dict: OrderedDict, svd_list: SVDList) -> None:
+	key_dict = {v['name']:k for k, v in leveled_dict.items()}
+	for item in svd_list:
+		key = key_dict[item.get("item_group")]
+		leveled_dict[key]['self_value'] += -item.get("stock_value_difference")
+
+
+def assign_agg_values(leveled_dict: OrderedDict) -> None:
+	keys = list(leveled_dict.keys())[::-1]
+	prev_level = leveled_dict[keys[-1]]['level']
+	accu = [0]
+	for k in keys[:-1]:
+		curr_level = leveled_dict[k]['level']
+		if curr_level == prev_level:
+			accu[-1] += leveled_dict[k]['self_value']
+			leveled_dict[k]['agg_value'] = leveled_dict[k]['self_value']
+
+		elif curr_level > prev_level:
+			accu.append(leveled_dict[k]['self_value'])
+			leveled_dict[k]['agg_value'] = accu[-1]
+
+		elif curr_level < prev_level:
+			accu[-1] += leveled_dict[k]['self_value']
+			leveled_dict[k]['agg_value'] = accu[-1]
+
+		prev_level = curr_level
+
+	# root node
+	rk = keys[-1]
+	leveled_dict[rk]['agg_value'] = sum(accu) + leveled_dict[rk]['self_value']
+
+
+def get_row(name:str, value:float, is_bold:int, indent:int) -> Row:
+	item_group = name
+	if is_bold:
+		item_group = frappe.bold(item_group)
+	return frappe._dict(item_group=item_group, cogs_debit=value, indent=indent)
+			
+
+def assign_item_groups_to_svd_list(svd_list: SVDList) -> None:
+	ig_map = get_item_groups_map(svd_list)
+	for item in svd_list:
+		item.item_group = ig_map[item.get("item_code")]
+
+
+def get_item_groups_map(svd_list: SVDList) -> Dict[str, str]:
+	item_codes = set(i['item_code'] for i in svd_list)
+	ig_list = frappe.get_list(
+		'Item', fields=['item_code','item_group'],
+		filters=[('item_code', 'in', item_codes)]
+	)
+	return {i['item_code']:i['item_group'] for i in ig_list}
+
+
+def get_item_groups_dict() -> ItemGroupsDict:
+	item_groups_list = frappe.get_all("Item Group", fields=("name", "is_group", "lft", "rgt"))
+	return {(i['lft'],i['rgt']):{'name':i['name'], 'is_group':i['is_group']}
+		for i in item_groups_list}
+
+
+def update_leveled_dict(leveled_dict: OrderedDict) -> None:
+	for k in leveled_dict:
+		leveled_dict[k].update({'self_value':0, 'agg_value':0})
diff --git a/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py b/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py
index 5873a7a..4108a57 100644
--- a/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py
+++ b/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py
@@ -69,7 +69,7 @@
 		i.stock_uom, sle.actual_qty, sle.stock_value_difference,
 		sle.voucher_no, sle.voucher_type
 		from `tabStock Ledger Entry` sle, `tabItem` i
-		where sle.item_code=i.name and sle.actual_qty < 0 %s""" % conditions, values, as_dict=1):
+		where sle.is_cancelled = 0 and sle.item_code=i.name and sle.actual_qty < 0 %s""" % conditions, values, as_dict=1):
 			consumed_details.setdefault(d.item_code, []).append(d)
 
 	return consumed_details