Merge pull request #25679 from rohitwaghchaure/fixed-new-fields-not-added

fix: updated modified time in purchase invoice to pull new fields
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.yml b/.github/helper/semgrep_rules/translate.yml
index 3737da5..fa4ec9e 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*'    # lines broken by `\`
+  - pattern-regex: '_\(\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/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/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
index 09db7fe..5c1cbaa 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -21,7 +21,10 @@
 	else:
 		party_type = 'Supplier'
 		party = inv.supplier
-	
+
+	if not party:
+		frappe.throw(_("Please select {0} first").format(party_type))
+
 	return party_type, party
 
 def get_party_tax_withholding_details(inv, tax_withholding_category=None):
@@ -324,7 +327,7 @@
 		net_total, ldc.certificate_limit
 	):
 		tds_amount = get_ltds_amount(net_total, limit_consumed, ldc.certificate_limit, ldc.rate, tax_details)
-	
+
 	return tds_amount
 
 def get_debit_note_amount(suppliers, fiscal_year_details, company=None):
diff --git a/erpnext/accounts/workspace/accounting/accounting.json b/erpnext/accounts/workspace/accounting/accounting.json
index 9ffa481..df68318 100644
--- a/erpnext/accounts/workspace/accounting/accounting.json
+++ b/erpnext/accounts/workspace/accounting/accounting.json
@@ -15,6 +15,7 @@
  "hide_custom": 0,
  "icon": "accounting",
  "idx": 0,
+ "is_default": 0,
  "is_standard": 1,
  "label": "Accounting",
  "links": [
@@ -625,9 +626,9 @@
    "dependencies": "",
    "hidden": 0,
    "is_query_report": 0,
-   "label": "Bank Reconciliation",
-   "link_to": "bank-reconciliation",
-   "link_type": "Page",
+   "label": "Bank Reconciliation Tool",
+   "link_to": "Bank Reconciliation Tool",
+   "link_type": "DocType",
    "onboard": 0,
    "type": "Link"
   },
@@ -642,26 +643,6 @@
    "type": "Link"
   },
   {
-   "dependencies": "",
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Bank Statement Transaction Entry",
-   "link_to": "Bank Statement Transaction Entry",
-   "link_type": "DocType",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
-   "dependencies": "",
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Bank Statement Settings",
-   "link_to": "Bank Statement Settings",
-   "link_type": "DocType",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
    "hidden": 0,
    "is_query_report": 0,
    "label": "Subscription Management",
@@ -1071,7 +1052,7 @@
    "type": "Link"
   }
  ],
- "modified": "2021-03-04 00:38:35.349024",
+ "modified": "2021-05-12 11:48:01.905144",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Accounting",
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 9aff144..8799275 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -195,8 +195,7 @@
 				# If depreciation is already completed (for double declining balance)
 				if skip_row: continue
 
-				depreciation_amount = self.get_depreciation_amount(value_after_depreciation,
-					d.total_number_of_depreciations, d)
+				depreciation_amount = get_depreciation_amount(self, value_after_depreciation, d)
 
 				if not has_pro_rata or n < cint(number_of_pending_depreciations) - 1:
 					schedule_date = add_months(d.depreciation_start_date,
@@ -208,7 +207,7 @@
 
 				# For first row
 				if has_pro_rata and n==0:
-					depreciation_amount, days, months = get_pro_rata_amt(d, depreciation_amount,
+					depreciation_amount, days, months = self.get_pro_rata_amt(d, depreciation_amount,
 						self.available_for_use_date, d.depreciation_start_date)
 
 					# For first depr schedule date will be the start date
@@ -220,7 +219,7 @@
 					to_date = add_months(self.available_for_use_date,
 						n * cint(d.frequency_of_depreciation))
 
-					depreciation_amount, days, months = get_pro_rata_amt(d,
+					depreciation_amount, days, months = self.get_pro_rata_amt(d,
 						depreciation_amount, schedule_date, to_date)
 
 					monthly_schedule_date = add_months(schedule_date, 1)
@@ -365,24 +364,6 @@
 	def get_value_after_depreciation(self, idx):
 		return flt(self.get('finance_books')[cint(idx)-1].value_after_depreciation)
 
-	def get_depreciation_amount(self, depreciable_value, total_number_of_depreciations, row):
-		precision = self.precision("gross_purchase_amount")
-
-		if row.depreciation_method in ("Straight Line", "Manual"):
-			depreciation_left = (cint(row.total_number_of_depreciations) - cint(self.number_of_depreciations_booked))
-
-			if not depreciation_left:
-				frappe.msgprint(_("All the depreciations has been booked"))
-				depreciation_amount = flt(row.expected_value_after_useful_life)
-				return depreciation_amount
-
-			depreciation_amount = (flt(row.value_after_depreciation) -
-				flt(row.expected_value_after_useful_life)) / depreciation_left
-		else:
-			depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100), precision)
-
-		return depreciation_amount
-
 	def validate_expected_value_after_useful_life(self):
 		for row in self.get('finance_books'):
 			accumulated_depreciation_after_full_schedule = [d.accumulated_depreciation_amount
@@ -575,6 +556,13 @@
 
 			return 100 * (1 - flt(depreciation_rate, float_precision))
 
+	def get_pro_rata_amt(self, row, depreciation_amount, from_date, to_date):
+		days = date_diff(to_date, from_date)
+		months = month_diff(to_date, from_date)
+		total_days = get_total_days(to_date, row.frequency_of_depreciation)
+
+		return (depreciation_amount * flt(days)) / flt(total_days), days, months
+
 def update_maintenance_status():
 	assets = frappe.get_all(
 		"Asset", filters={"docstatus": 1, "maintenance_required": 1}
@@ -758,15 +746,20 @@
 def is_cwip_accounting_enabled(asset_category):
 	return cint(frappe.db.get_value("Asset Category", asset_category, "enable_cwip_accounting"))
 
-def get_pro_rata_amt(row, depreciation_amount, from_date, to_date):
-	days = date_diff(to_date, from_date)
-	months = month_diff(to_date, from_date)
-	total_days = get_total_days(to_date, row.frequency_of_depreciation)
-
-	return (depreciation_amount * flt(days)) / flt(total_days), days, months
-
 def get_total_days(date, frequency):
 	period_start_date = add_months(date,
 		cint(frequency) * -1)
 
 	return date_diff(date, period_start_date)
+
+@erpnext.allow_regional
+def get_depreciation_amount(asset, depreciable_value, row):
+	depreciation_left = flt(row.total_number_of_depreciations) - flt(asset.number_of_depreciations_booked)
+
+	if row.depreciation_method in ("Straight Line", "Manual"):
+		depreciation_amount = (flt(row.value_after_depreciation) -
+			flt(row.expected_value_after_useful_life)) / depreciation_left
+	else:
+		depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100))
+
+	return depreciation_amount
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index 40a8f85..30a270c 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -635,6 +635,45 @@
 		frappe.db.set_value("Asset Category Account", name, "capital_work_in_progress_account", cwip_acc)
 		frappe.db.get_value("Company", "_Test Company", "capital_work_in_progress_account", cwip_acc)
 
+	def test_discounted_wdv_depreciation_rate_for_indian_region(self):
+		# set indian company
+		company_flag = frappe.flags.company
+		frappe.flags.company = "_Test Company"
+
+		pr = make_purchase_receipt(item_code="Macbook Pro",
+			qty=1, rate=8000.0, location="Test Location")
+
+		asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
+		asset = frappe.get_doc('Asset', asset_name)
+		asset.calculate_depreciation = 1
+		asset.available_for_use_date = '2030-06-12'
+		asset.purchase_date = '2030-01-01'
+		asset.append("finance_books", {
+			"expected_value_after_useful_life": 1000,
+			"depreciation_method": "Written Down Value",
+			"total_number_of_depreciations": 3,
+			"frequency_of_depreciation": 12,
+			"depreciation_start_date": "2030-12-31"
+		})
+		asset.save(ignore_permissions=True)
+
+		self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0)
+
+		expected_schedules = [
+			["2030-12-31", 1106.85, 1106.85],
+			["2031-12-31", 3446.58, 4553.43],
+			["2032-12-31", 1723.29, 6276.72],
+			["2033-06-12", 723.28, 7000.00]
+		]
+
+		schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)]
+			for d in asset.get("schedules")]
+
+		self.assertEqual(schedules, expected_schedules)
+
+		# reset indian company
+		frappe.flags.company = company_flag
+
 def create_asset_data():
 	if not frappe.db.exists("Asset Category", "Computers"):
 		create_asset_category()
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index c409850..996c4ed 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/status_updater.py b/erpnext/controllers/status_updater.py
index 4bb6138..ed3aee5 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -100,6 +100,10 @@
 		["Queued", "eval:self.status == 'Queued'"],
 		["Failed", "eval:self.status == 'Failed'"],
 		["Cancelled", "eval:self.docstatus == 2"],
+	],
+	"Transaction Deletion Record": [
+		["Draft", None],
+		["Completed", "eval:self.docstatus == 1"],
 	]
 }
 
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
index 16c6573..21f1db6 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
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/sync_customer.py b/erpnext/erpnext_integrations/doctype/shopify_settings/sync_customer.py
index 7866fde..2af57f4 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/sync_customer.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/sync_customer.py
@@ -32,10 +32,12 @@
 		raise e
 
 def create_customer_address(customer, shopify_customer):
-	if not shopify_customer.get("addresses"):
-		return
+	addresses = shopify_customer.get("addresses", [])
 
-	for i, address in enumerate(shopify_customer.get("addresses")):
+	if not addresses and "default_address" in shopify_customer:
+		addresses.append(shopify_customer["default_address"])
+
+	for i, address in enumerate(addresses):
 		address_title, address_type = get_address_title_and_type(customer.customer_name, i)
 		try :
 			frappe.get_doc({
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index bb6cd8b..9d1ce9b 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -426,7 +426,8 @@
 		'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.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'
 	},
 	'United Arab Emirates': {
 		'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.united_arab_emirates.utils.update_itemised_tax_data',
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 0af8da7..e153e6c 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -1329,7 +1329,7 @@
 
 		this.toggle_item_grid_columns(company_currency);
 
-		if(this.frm.fields_dict["operations"]) {
+		if (this.frm.doc.operations && this.frm.doc.operations.length > 0) {
 			this.frm.set_currency_labels(["operating_cost", "hour_rate"], this.frm.doc.currency, "operations");
 			this.frm.set_currency_labels(["base_operating_cost", "base_hour_rate"], company_currency, "operations");
 
@@ -1340,7 +1340,7 @@
 			});
 		}
 
-		if(this.frm.fields_dict["scrap_items"]) {
+		if (this.frm.doc.scrap_items && this.frm.doc.scrap_items.length > 0) {
 			this.frm.set_currency_labels(["rate", "amount"], this.frm.doc.currency, "scrap_items");
 			this.frm.set_currency_labels(["base_rate", "base_amount"], company_currency, "scrap_items");
 
@@ -1351,13 +1351,13 @@
 			});
 		}
 
-		if(this.frm.fields_dict["taxes"]) {
+		if (this.frm.doc.taxes && this.frm.doc.taxes.length > 0) {
 			this.frm.set_currency_labels(["tax_amount", "total", "tax_amount_after_discount"], this.frm.doc.currency, "taxes");
 
 			this.frm.set_currency_labels(["base_tax_amount", "base_total", "base_tax_amount_after_discount"], company_currency, "taxes");
 		}
 
-		if(this.frm.fields_dict["advances"]) {
+		if (this.frm.doc.advances && this.frm.doc.advances.length > 0) {
 			this.frm.set_currency_labels(["advance_amount", "allocated_amount"],
 				this.frm.doc.party_account_currency, "advances");
 		}
diff --git a/erpnext/public/scss/point-of-sale.scss b/erpnext/public/scss/point-of-sale.scss
index 0bb8e68..9bdaa8d 100644
--- a/erpnext/public/scss/point-of-sale.scss
+++ b/erpnext/public/scss/point-of-sale.scss
@@ -129,11 +129,20 @@
 				@extend .pointer-no-select;
 				border-radius: var(--border-radius-md);
 				box-shadow: var(--shadow-base);
+				position: relative;
 
 				&:hover {
 					transform: scale(1.02, 1.02);
 				}
 
+				.item-qty-pill {
+					position: absolute;
+					display: flex;
+					margin: var(--margin-sm);
+					justify-content: flex-end;
+					right: 0px;
+				}
+
 				.item-display {
 					display: flex;
 					align-items: center;
@@ -766,9 +775,10 @@
 		> .payment-modes {
 			display: flex;
 			padding-bottom: var(--padding-sm);
-			margin-bottom: var(--margin-xs);
+			margin-bottom: var(--margin-sm);
 			overflow-x: scroll;
 			overflow-y: hidden;
+			flex-shrink: 0;
 
 			> .payment-mode-wrapper {
 				min-width: 40%;
@@ -825,9 +835,24 @@
 		> .fields-numpad-container {
 			display: flex;
 			flex: 1;
+			height: 100%;
+    		position: relative;
+			justify-content: flex-end;
 
 			> .fields-section {
 				flex: 1;
+				position: absolute;
+				display: flex;
+				flex-direction: column;
+				width: 50%;
+				height: 100%;
+				top: 0;
+				left: 0;
+				padding-bottom: var(--margin-md);
+
+				.invoice-fields {
+					overflow-y: scroll;
+				}
 			}
 
 			> .number-pad {
@@ -835,6 +860,7 @@
 				display: flex;
 				justify-content: flex-end;
 				align-items: flex-end;
+				max-width: 50%;
 
 				.numpad-container {
 					display: grid;
@@ -861,6 +887,7 @@
 			margin-bottom: var(--margin-sm);
 			justify-content: center;
 			flex-direction: column;
+			flex-shrink: 0;
 
 			> .totals {
 				display: flex;
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 6338056..052d7bd 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -879,3 +879,24 @@
 	if total_charges != additional_taxes:
 		diff = additional_taxes - total_charges
 		doc.get('items')[item_count - 1].taxable_value += diff
+
+def get_depreciation_amount(asset, depreciable_value, row):
+	depreciation_left = flt(row.total_number_of_depreciations) - flt(asset.number_of_depreciations_booked)
+
+	if row.depreciation_method in ("Straight Line", "Manual"):
+		depreciation_amount = (flt(row.value_after_depreciation) -
+			flt(row.expected_value_after_useful_life)) / depreciation_left
+	else:
+		rate_of_depreciation = row.rate_of_depreciation
+		# if its the first depreciation
+		if depreciable_value == asset.gross_purchase_amount:
+			# as per IT act, if the asset is purchased in the 2nd half of fiscal year, then rate is divided by 2
+			diff = date_diff(asset.available_for_use_date, row.depreciation_start_date)
+			if diff <= 180:
+				rate_of_depreciation = rate_of_depreciation / 2
+				frappe.msgprint(
+					_('As per IT Act, the rate of depreciation for the first depreciation entry is reduced by 50%.'))
+
+		depreciation_amount = flt(depreciable_value * (flt(rate_of_depreciation) / 100))
+
+	return depreciation_amount
\ No newline at end of file
diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js
index 8adf5bf..8e0a1e1 100644
--- a/erpnext/selling/page/point_of_sale/pos_controller.js
+++ b/erpnext/selling/page/point_of_sale/pos_controller.js
@@ -58,7 +58,7 @@
 		}
 		const pos_profile_query = {
 			query: 'erpnext.accounts.doctype.pos_profile.pos_profile.pos_profile_query',
-			filters: { company: frappe.defaults.get_default('company') }
+			filters: { company: dialog.fields_dict.company.get_value() }
 		}
 		const dialog = new frappe.ui.Dialog({
 			title: __('Create POS Opening Entry'),
diff --git a/erpnext/selling/page/point_of_sale/pos_item_selector.js b/erpnext/selling/page/point_of_sale/pos_item_selector.js
index 9384ae5..b8a82a9 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_selector.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_selector.js
@@ -90,14 +90,16 @@
 
 		function get_item_image_html() {
 			if (!me.hide_images && item_image) {
-				return `<div class="flex" style="margin: 8px; justify-content: flex-end">
-						<span class="indicator-pill whitespace-nowrap ${indicator_color}" id="text">${qty_to_display}</span></div>
+				return `<div class="item-qty-pill">
+							<span class="indicator-pill whitespace-nowrap ${indicator_color}">${qty_to_display}</span>
+						</div>
 						<div class="flex items-center justify-center h-32 border-b-grey text-6xl text-grey-100">
 							<img class="h-full" src="${item_image}" alt="${frappe.get_abbr(item.item_name)}" style="object-fit: cover;">
 						</div>`;
 			} else {
-				return `<div class="flex" style="margin: 8px; justify-content: flex-end">
-						<span class="indicator-pill whitespace-nowrap ${indicator_color}">${qty_to_display}</span></div>
+				return `<div class="item-qty-pill">
+							<span class="indicator-pill whitespace-nowrap ${indicator_color}">${qty_to_display}</span>
+						</div>
 						<div class="item-display abbr">${frappe.get_abbr(item.item_name)}</div>`;
 			}
 		}
diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js
index c2b5e4f..9957aad 100644
--- a/erpnext/setup/doctype/company/company.js
+++ b/erpnext/setup/doctype/company/company.js
@@ -169,9 +169,9 @@
 					return;
 				}
 				frappe.call({
-					method: "erpnext.setup.doctype.company.delete_company_transactions.delete_company_transactions",
+					method: "erpnext.setup.doctype.company.company.create_transaction_deletion_request",
 					args: {
-						company_name: data.company_name
+						company: data.company_name
 					},
 					freeze: true,
 					callback: function(r, rt) {
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 64e027d..077538d 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -613,4 +613,13 @@
 	if out:
 		return sorted(out, key = functools.cmp_to_key(lambda x,y: cmp(y[1], x[1])))[0][0]
 	else:
-		return None
\ No newline at end of file
+		return None
+
+@frappe.whitelist()
+def create_transaction_deletion_request(company):
+	tdr = frappe.get_doc({
+		'doctype': 'Transaction Deletion Record',
+		'company': company
+	})
+	tdr.insert()
+	tdr.submit()
diff --git a/erpnext/setup/doctype/company/delete_company_transactions.py b/erpnext/setup/doctype/company/delete_company_transactions.py
deleted file mode 100644
index 8367a25..0000000
--- a/erpnext/setup/doctype/company/delete_company_transactions.py
+++ /dev/null
@@ -1,117 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-import frappe
-
-from frappe.utils import cint
-from frappe import _
-from frappe.desk.notifications import clear_notifications
-
-import functools
-
-@frappe.whitelist()
-def delete_company_transactions(company_name):
-	frappe.only_for("System Manager")
-	doc = frappe.get_doc("Company", company_name)
-
-	if frappe.session.user != doc.owner and frappe.session.user != 'Administrator':
-		frappe.throw(_("Transactions can only be deleted by the creator of the Company"),
-			frappe.PermissionError)
-
-	delete_bins(company_name)
-	delete_lead_addresses(company_name)
-
-	for doctype in frappe.db.sql_list("""select parent from
-		tabDocField where fieldtype='Link' and options='Company'"""):
-		if doctype not in ("Account", "Cost Center", "Warehouse", "Budget",
-			"Party Account", "Employee", "Sales Taxes and Charges Template",
-			"Purchase Taxes and Charges Template", "POS Profile", "BOM",
-			"Company", "Bank Account", "Item Tax Template", "Mode Of Payment", "Mode of Payment Account",
-			"Item Default", "Customer", "Supplier", "GST Account"):
-				delete_for_doctype(doctype, company_name)
-
-	# reset company values
-	doc.total_monthly_sales = 0
-	doc.sales_monthly_history = None
-	doc.save()
-	# Clear notification counts
-	clear_notifications()
-
-def delete_for_doctype(doctype, company_name):
-	meta = frappe.get_meta(doctype)
-	company_fieldname = meta.get("fields", {"fieldtype": "Link",
-		"options": "Company"})[0].fieldname
-
-	if not meta.issingle:
-		if not meta.istable:
-			# delete communication
-			delete_communications(doctype, company_name, company_fieldname)
-
-			# delete children
-			for df in meta.get_table_fields():
-				frappe.db.sql("""delete from `tab{0}` where parent in
-					(select name from `tab{1}` where `{2}`=%s)""".format(df.options,
-						doctype, company_fieldname), company_name)
-
-		#delete version log
-		frappe.db.sql("""delete from `tabVersion` where ref_doctype=%s and docname in
-			(select name from `tab{0}` where `{1}`=%s)""".format(doctype,
-				company_fieldname), (doctype, company_name))
-
-		# delete parent
-		frappe.db.sql("""delete from `tab{0}`
-			where {1}= %s """.format(doctype, company_fieldname), company_name)
-
-		# reset series
-		naming_series = meta.get_field("naming_series")
-		if naming_series and naming_series.options:
-			prefixes = sorted(naming_series.options.split("\n"),
-				key=functools.cmp_to_key(lambda a, b: len(b) - len(a)))
-
-			for prefix in prefixes:
-				if prefix:
-					last = frappe.db.sql("""select max(name) from `tab{0}`
-						where name like %s""".format(doctype), prefix + "%")
-					if last and last[0][0]:
-						last = cint(last[0][0].replace(prefix, ""))
-					else:
-						last = 0
-
-					frappe.db.sql("""update tabSeries set current = %s
-						where name=%s""", (last, prefix))
-
-def delete_bins(company_name):
-	frappe.db.sql("""delete from tabBin where warehouse in
-			(select name from tabWarehouse where company=%s)""", company_name)
-
-def delete_lead_addresses(company_name):
-	"""Delete addresses to which leads are linked"""
-	leads = frappe.get_all("Lead", filters={"company": company_name})
-	leads = [ "'%s'"%row.get("name") for row in leads ]
-	addresses = []
-	if leads:
-		addresses = frappe.db.sql_list("""select parent from `tabDynamic Link` where link_name
-			in ({leads})""".format(leads=",".join(leads)))
-
-		if addresses:
-			addresses = ["%s" % frappe.db.escape(addr) for addr in addresses]
-
-			frappe.db.sql("""delete from tabAddress where name in ({addresses}) and
-				name not in (select distinct dl1.parent from `tabDynamic Link` dl1
-				inner join `tabDynamic Link` dl2 on dl1.parent=dl2.parent
-				and dl1.link_doctype<>dl2.link_doctype)""".format(addresses=",".join(addresses)))
-
-			frappe.db.sql("""delete from `tabDynamic Link` where link_doctype='Lead'
-				and parenttype='Address' and link_name in ({leads})""".format(leads=",".join(leads)))
-
-		frappe.db.sql("""update tabCustomer set lead_name=NULL where lead_name in ({leads})""".format(leads=",".join(leads)))
-
-def delete_communications(doctype, company_name, company_fieldname):
-		reference_docs = frappe.get_all(doctype, filters={company_fieldname:company_name})
-		reference_doc_names = [r.name for r in reference_docs]
-
-		communications = frappe.get_all("Communication", filters={"reference_doctype":doctype,"reference_name":["in", reference_doc_names]})
-		communication_names = [c.name for c in communications]
-
-		frappe.delete_doc("Communication", communication_names, ignore_permissions=True)
diff --git a/erpnext/setup/doctype/company/test_company.py b/erpnext/setup/doctype/company/test_company.py
index 29f6c37..e1c803a 100644
--- a/erpnext/setup/doctype/company/test_company.py
+++ b/erpnext/setup/doctype/company/test_company.py
@@ -86,15 +86,6 @@
 					self.delete_mode_of_payment(template)
 					frappe.delete_doc("Company", template)
 
-	def test_delete_communication(self):
-		from erpnext.setup.doctype.company.delete_company_transactions import delete_communications
-		company = create_child_company()
-		lead = create_test_lead_in_company(company)
-		communication = create_company_communication("Lead", lead)
-		delete_communications("Lead", "Test Company", "company")
-		self.assertFalse(frappe.db.exists("Communcation", communication))
-		self.assertFalse(frappe.db.exists({"doctype":"Comunication Link", "link_name": communication}))
-
 	def delete_mode_of_payment(self, company):
 		frappe.db.sql(""" delete from `tabMode of Payment Account`
 			where company =%s """, (company))
diff --git a/erpnext/setup/doctype/transaction_deletion_record/__init__.py b/erpnext/setup/doctype/transaction_deletion_record/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record/__init__.py
diff --git a/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py b/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py
new file mode 100644
index 0000000..bbe6836
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py
@@ -0,0 +1,68 @@
+# -*- 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 TestTransactionDeletionRecord(unittest.TestCase):
+	def setUp(self):
+		create_company('Dunder Mifflin Paper Co')
+
+	def tearDown(self):
+		frappe.db.rollback()
+
+	def test_doctypes_contain_company_field(self):
+		tdr = create_transaction_deletion_request('Dunder Mifflin Paper Co')
+		for doctype in tdr.doctypes:
+			contains_company = False
+			doctype_fields = frappe.get_meta(doctype.doctype_name).as_dict()['fields']
+			for doctype_field in doctype_fields:
+				if doctype_field['fieldtype'] == 'Link' and doctype_field['options'] == 'Company':
+					contains_company = True
+					break
+			self.assertTrue(contains_company)
+	
+	def test_no_of_docs_is_correct(self):
+		for i in range(5):
+			create_task('Dunder Mifflin Paper Co')
+		tdr = create_transaction_deletion_request('Dunder Mifflin Paper Co')
+		for doctype in tdr.doctypes:
+			if doctype.doctype_name == 'Task':
+				self.assertEqual(doctype.no_of_docs, 5)
+
+	def test_deletion_is_successful(self):
+		create_task('Dunder Mifflin Paper Co')
+		create_transaction_deletion_request('Dunder Mifflin Paper Co')
+		tasks_containing_company = frappe.get_all('Task',
+		filters = {
+			'company' : 'Dunder Mifflin Paper Co'
+		})
+		self.assertEqual(tasks_containing_company, [])
+		
+def create_company(company_name):
+	company = frappe.get_doc({
+		'doctype': 'Company',
+		'company_name': company_name,
+		'default_currency': 'INR'
+	})		
+	company.insert(ignore_if_duplicate = True)
+
+def create_transaction_deletion_request(company):
+	tdr = frappe.get_doc({
+		'doctype': 'Transaction Deletion Record',
+		'company': company
+	})
+	tdr.insert()
+	tdr.submit()
+	return tdr
+
+
+def create_task(company):
+	task = frappe.get_doc({
+		'doctype': 'Task',
+		'company': company,
+		'subject': 'Delete'
+	})
+	task.insert()
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.js b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.js
new file mode 100644
index 0000000..20caa15
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.js
@@ -0,0 +1,40 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Transaction Deletion Record', {
+	onload: function(frm) {
+		if (frm.doc.docstatus == 0) {
+			let doctypes_to_be_ignored_array;	
+			frappe.call({
+				method: 'erpnext.setup.doctype.transaction_deletion_record.transaction_deletion_record.get_doctypes_to_be_ignored',
+				callback: function(r) {
+					doctypes_to_be_ignored_array = r.message;
+					populate_doctypes_to_be_ignored(doctypes_to_be_ignored_array, frm);
+					frm.fields_dict['doctypes_to_be_ignored'].grid.set_column_disp('no_of_docs', false);
+					frm.refresh_field('doctypes_to_be_ignored');
+				}
+			});
+		}
+
+		frm.get_field('doctypes_to_be_ignored').grid.cannot_add_rows = true;
+		frm.fields_dict['doctypes_to_be_ignored'].grid.set_column_disp('no_of_docs', false);
+		frm.refresh_field('doctypes_to_be_ignored');
+	},
+
+	refresh: function(frm) {
+		frm.fields_dict['doctypes_to_be_ignored'].grid.set_column_disp('no_of_docs', false);
+		frm.refresh_field('doctypes_to_be_ignored');
+	}
+	
+});
+
+function populate_doctypes_to_be_ignored(doctypes_to_be_ignored_array, frm) {
+	if (!(frm.doc.doctypes_to_be_ignored)) {
+		var i;
+		for (i = 0; i < doctypes_to_be_ignored_array.length; i++) {     
+			frm.add_child('doctypes_to_be_ignored', {
+				doctype_name: doctypes_to_be_ignored_array[i]					
+			});
+		}
+	}
+}
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json
new file mode 100644
index 0000000..9313f95
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json
@@ -0,0 +1,79 @@
+{
+ "actions": [],
+ "autoname": "TDL.####",
+ "creation": "2021-04-06 20:17:18.404716",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "company",
+  "doctypes",
+  "doctypes_to_be_ignored",
+  "amended_from",
+  "status"
+ ],
+ "fields": [
+  {
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Company",
+   "options": "Company",
+   "reqd": 1
+  },
+  {
+   "fieldname": "doctypes",
+   "fieldtype": "Table",
+   "label": "Summary",
+   "options": "Transaction Deletion Record Item",
+   "read_only": 1
+  },
+  {
+   "fieldname": "doctypes_to_be_ignored",
+   "fieldtype": "Table",
+   "label": "Excluded DocTypes",
+   "options": "Transaction Deletion Record Item"
+  },
+  {
+   "fieldname": "amended_from",
+   "fieldtype": "Link",
+   "label": "Amended From",
+   "no_copy": 1,
+   "options": "Transaction Deletion Record",
+   "print_hide": 1,
+   "read_only": 1
+  },
+  {
+   "fieldname": "status",
+   "fieldtype": "Select",
+   "hidden": 1,
+   "label": "Status",
+   "options": "Draft\nCompleted"
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2021-05-08 23:13:48.049879",
+ "modified_by": "Administrator",
+ "module": "Setup",
+ "name": "Transaction Deletion Record",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
+   "write": 1
+  }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
new file mode 100644
index 0000000..38f8de7
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
@@ -0,0 +1,147 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from frappe.utils import cint
+import frappe
+from frappe.model.document import Document
+from frappe import _
+from frappe.desk.notifications import clear_notifications
+
+class TransactionDeletionRecord(Document):
+	def validate(self):
+		frappe.only_for('System Manager')
+		company_obj = frappe.get_doc('Company', self.company)
+		if frappe.session.user != company_obj.owner and frappe.session.user != 'Administrator':
+			frappe.throw(_('Transactions can only be deleted by the creator of the Company or the Administrator.'), 
+				frappe.PermissionError)
+		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. "), title=_("Not Allowed"))
+
+	def before_submit(self):
+		if not self.doctypes_to_be_ignored:
+			self.populate_doctypes_to_be_ignored_table()
+
+		self.delete_bins()
+		self.delete_lead_addresses()
+		
+		company_obj = frappe.get_doc('Company', self.company)
+		# reset company values
+		company_obj.total_monthly_sales = 0
+		company_obj.sales_monthly_history = None
+		company_obj.save()
+		# Clear notification counts
+		clear_notifications()
+
+		singles = frappe.get_all('DocType', filters = {'issingle': 1}, pluck = 'name')
+		tables = frappe.get_all('DocType', filters = {'istable': 1}, pluck = 'name')
+		doctypes_to_be_ignored_list = singles
+		for doctype in self.doctypes_to_be_ignored:
+			doctypes_to_be_ignored_list.append(doctype.doctype_name)
+
+		docfields = frappe.get_all('DocField', 
+			filters = {
+				'fieldtype': 'Link', 
+				'options': 'Company',
+				'parent': ['not in', doctypes_to_be_ignored_list]},
+			fields=['parent', 'fieldname'])
+	
+		for docfield in docfields:
+			if docfield['parent'] != self.doctype:
+				no_of_docs = frappe.db.count(docfield['parent'], {
+							docfield['fieldname'] : self.company
+						})
+
+				if no_of_docs > 0:
+					self.delete_version_log(docfield['parent'], docfield['fieldname'])
+					self.delete_communications(docfield['parent'], docfield['fieldname'])
+
+					# populate DocTypes table
+					if docfield['parent'] not in tables:
+						self.append('doctypes', {
+							'doctype_name' : docfield['parent'],
+							'no_of_docs' : no_of_docs
+						})
+
+					# delete the docs linked with the specified company
+					frappe.db.delete(docfield['parent'], {
+						docfield['fieldname'] : self.company
+					})
+
+					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'])	
+
+	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', {
+						'doctype_name' : doctype
+					})
+
+	def update_naming_series(self, naming_series, doctype_name):
+		if '.' in naming_series:
+			prefix, hashes = naming_series.rsplit('.', 1)
+		else:
+			prefix, hashes = naming_series.rsplit('{', 1)
+		last = frappe.db.sql("""select max(name) from `tab{0}`
+						where name like %s""".format(doctype_name), prefix + '%')
+		if last and last[0][0]:
+			last = cint(last[0][0].replace(prefix, ''))
+		else:
+			last = 0
+
+		frappe.db.sql("""update tabSeries set current = %s where name=%s""", (last, prefix))
+
+	def delete_version_log(self, doctype, company_fieldname):
+		frappe.db.sql("""delete from `tabVersion` where ref_doctype=%s and docname in
+			(select name from `tab{0}` where `{1}`=%s)""".format(doctype,
+				company_fieldname), (doctype, self.company))
+
+	def delete_communications(self, doctype, company_fieldname):
+		reference_docs = frappe.get_all(doctype, filters={company_fieldname:self.company})
+		reference_doc_names = [r.name for r in reference_docs]
+
+		communications = frappe.get_all('Communication', filters={'reference_doctype':doctype,'reference_name':['in', reference_doc_names]})
+		communication_names = [c.name for c in communications]
+
+		frappe.delete_doc('Communication', communication_names, ignore_permissions=True)
+
+	def delete_bins(self):
+		frappe.db.sql("""delete from tabBin where warehouse in
+				(select name from tabWarehouse where company=%s)""", self.company)
+
+	def delete_lead_addresses(self):
+		"""Delete addresses to which leads are linked"""
+		leads = frappe.get_all('Lead', filters={'company': self.company})
+		leads = ["'%s'" % row.get("name") for row in leads]
+		addresses = []
+		if leads:
+			addresses = frappe.db.sql_list("""select parent from `tabDynamic Link` where link_name
+				in ({leads})""".format(leads=",".join(leads)))
+
+			if addresses:
+				addresses = ["%s" % frappe.db.escape(addr) for addr in addresses]
+
+				frappe.db.sql("""delete from tabAddress where name in ({addresses}) and
+					name not in (select distinct dl1.parent from `tabDynamic Link` dl1
+					inner join `tabDynamic Link` dl2 on dl1.parent=dl2.parent
+					and dl1.link_doctype<>dl2.link_doctype)""".format(addresses=",".join(addresses)))
+
+				frappe.db.sql("""delete from `tabDynamic Link` where link_doctype='Lead'
+					and parenttype='Address' and link_name in ({leads})""".format(leads=",".join(leads)))
+
+			frappe.db.sql("""update tabCustomer set lead_name=NULL where lead_name in ({leads})""".format(leads=",".join(leads)))
+
+@frappe.whitelist()
+def get_doctypes_to_be_ignored():
+	doctypes_to_be_ignored_list = ['Account', 'Cost Center', 'Warehouse', 'Budget',
+		'Party Account', 'Employee', 'Sales Taxes and Charges Template',
+		'Purchase Taxes and Charges Template', 'POS Profile', 'BOM',
+		'Company', 'Bank Account', 'Item Tax Template', 'Mode of Payment',
+		'Item Default', 'Customer', 'Supplier', 'GST Account']
+	return doctypes_to_be_ignored_list
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record_list.js b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record_list.js
new file mode 100644
index 0000000..d7175dd
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record_list.js
@@ -0,0 +1,12 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+// License: GNU General Public License v3. See license.txt
+
+frappe.listview_settings['Transaction Deletion Record'] = {
+	get_indicator: function(doc) {
+		if (doc.docstatus == 0) {
+			return [__("Draft"), "red"];
+		} else {
+			return [__("Completed"), "green"];
+		}
+	}
+};
\ No newline at end of file
diff --git a/erpnext/setup/doctype/transaction_deletion_record_item/__init__.py b/erpnext/setup/doctype/transaction_deletion_record_item/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record_item/__init__.py
diff --git a/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.json b/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.json
new file mode 100644
index 0000000..be0be94
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.json
@@ -0,0 +1,39 @@
+{
+ "actions": [],
+ "creation": "2021-04-07 07:34:00.124124",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "doctype_name",
+  "no_of_docs"
+ ],
+ "fields": [
+  {
+   "fieldname": "doctype_name",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "DocType",
+   "options": "DocType",
+   "reqd": 1
+  },
+  {
+   "fieldname": "no_of_docs",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Number of Docs"
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-05-08 23:10:46.166744",
+ "modified_by": "Administrator",
+ "module": "Setup",
+ "name": "Transaction Deletion Record Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py b/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py
new file mode 100644
index 0000000..2176cb1
--- /dev/null
+++ b/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class TransactionDeletionRecordItem(Document):
+	pass