Merge pull request #33579 from rtdany10/repack-fg-valuation

fix(stock entry): wrong valuation rate in repack
diff --git a/.github/workflows/server-tests-mariadb.yml b/.github/workflows/server-tests-mariadb.yml
index bbb8a7e..c70c76f 100644
--- a/.github/workflows/server-tests-mariadb.yml
+++ b/.github/workflows/server-tests-mariadb.yml
@@ -16,12 +16,12 @@
   workflow_dispatch:
     inputs:
       user:
-        description: 'user'
+        description: 'Frappe Framework repository user (add your username for forks)'
         required: true
         default: 'frappe'
         type: string
       branch:
-        description: 'Branch name'
+        description: 'Frappe Framework branch'
         default: 'develop'
         required: false
         type: string
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 68ac982..ea8b7d8 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -6,7 +6,7 @@
 
 import frappe
 from frappe import _, msgprint, scrub
-from frappe.utils import cint, cstr, flt, fmt_money, formatdate, get_link_to_form, nowdate
+from frappe.utils import cstr, flt, fmt_money, formatdate, get_link_to_form, nowdate
 
 import erpnext
 from erpnext.accounts.deferred_revenue import get_deferred_booking_accounts
@@ -23,6 +23,9 @@
 	get_stock_accounts,
 	get_stock_and_account_balance,
 )
+from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
+	get_depr_schedule,
+)
 from erpnext.controllers.accounts_controller import AccountsController
 
 
@@ -283,16 +286,17 @@
 		for d in self.get("accounts"):
 			if d.reference_type == "Asset" and d.reference_name:
 				asset = frappe.get_doc("Asset", d.reference_name)
-				for s in asset.get("schedules"):
-					if s.journal_entry == self.name:
-						s.db_set("journal_entry", None)
+				for row in asset.get("finance_books"):
+					depr_schedule = get_depr_schedule(asset.name, "Active", row.finance_book)
 
-						idx = cint(s.finance_book_id) or 1
-						finance_books = asset.get("finance_books")[idx - 1]
-						finance_books.value_after_depreciation += s.depreciation_amount
-						finance_books.db_update()
+					for s in depr_schedule or []:
+						if s.journal_entry == self.name:
+							s.db_set("journal_entry", None)
 
-						asset.set_status()
+							row.value_after_depreciation += s.depreciation_amount
+							row.db_update()
+
+							asset.set_status()
 
 	def unlink_inter_company_jv(self):
 		if (
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 26192ec..ff2690f 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -622,7 +622,7 @@
 				self.payment_type == "Receive"
 				and self.base_total_allocated_amount < self.base_received_amount + total_deductions
 				and self.total_allocated_amount
-				< self.paid_amount + (total_deductions / self.source_exchange_rate)
+				< flt(self.paid_amount) + (total_deductions / self.source_exchange_rate)
 			):
 				self.unallocated_amount = (
 					self.base_received_amount + total_deductions - self.base_total_allocated_amount
@@ -632,7 +632,7 @@
 				self.payment_type == "Pay"
 				and self.base_total_allocated_amount < (self.base_paid_amount - total_deductions)
 				and self.total_allocated_amount
-				< self.received_amount + (total_deductions / self.target_exchange_rate)
+				< flt(self.received_amount) + (total_deductions / self.target_exchange_rate)
 			):
 				self.unallocated_amount = (
 					self.base_paid_amount - (total_deductions + self.base_total_allocated_amount)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index c276be2..31cf120 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -1185,11 +1185,24 @@
 						if asset.calculate_depreciation:
 							posting_date = frappe.db.get_value("Sales Invoice", self.return_against, "posting_date")
 							reverse_depreciation_entry_made_after_disposal(asset, posting_date)
-							reset_depreciation_schedule(asset, self.posting_date)
+							notes = _(
+								"This schedule was created when Asset {0} was returned after being sold through Sales Invoice {1}."
+							).format(
+								get_link_to_form(asset.doctype, asset.name),
+								get_link_to_form(self.doctype, self.get("name")),
+							)
+							reset_depreciation_schedule(asset, self.posting_date, notes)
+							asset.reload()
 
 					else:
 						if asset.calculate_depreciation:
-							depreciate_asset(asset, self.posting_date)
+							notes = _(
+								"This schedule was created when Asset {0} was sold through Sales Invoice {1}."
+							).format(
+								get_link_to_form(asset.doctype, asset.name),
+								get_link_to_form(self.doctype, self.get("name")),
+							)
+							depreciate_asset(asset, self.posting_date, notes)
 							asset.reload()
 
 						fixed_asset_gl_entries = get_gl_entries_on_asset_disposal(
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 855380e..e96847e 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -21,6 +21,9 @@
 from erpnext.accounts.utils import PaymentEntryUnlinkError
 from erpnext.assets.doctype.asset.depreciation import post_depreciation_entries
 from erpnext.assets.doctype.asset.test_asset import create_asset, create_asset_data
+from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
+	get_depr_schedule,
+)
 from erpnext.controllers.accounts_controller import update_invoice_status
 from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data
 from erpnext.exceptions import InvalidAccountCurrency, InvalidCurrency
@@ -2774,7 +2777,7 @@
 			["2021-09-30", 5041.1, 26407.22],
 		]
 
-		for i, schedule in enumerate(asset.schedules):
+		for i, schedule in enumerate(get_depr_schedule(asset.name, "Active")):
 			self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date)
 			self.assertEqual(expected_values[i][1], schedule.depreciation_amount)
 			self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount)
@@ -2805,7 +2808,7 @@
 
 		expected_values = [["2020-12-31", 30000, 30000], ["2021-12-31", 30000, 60000]]
 
-		for i, schedule in enumerate(asset.schedules):
+		for i, schedule in enumerate(get_depr_schedule(asset.name, "Active")):
 			self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date)
 			self.assertEqual(expected_values[i][1], schedule.depreciation_amount)
 			self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount)
@@ -2834,7 +2837,7 @@
 			["2025-06-06", 18633.88, 100000.0, False],
 		]
 
-		for i, schedule in enumerate(asset.schedules):
+		for i, schedule in enumerate(get_depr_schedule(asset.name, "Active")):
 			self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date)
 			self.assertEqual(expected_values[i][1], schedule.depreciation_amount)
 			self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount)
diff --git a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py
index ad9b1ba..43b95dc 100644
--- a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py
+++ b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py
@@ -131,8 +131,8 @@
 							  else
 								   0
 							  end), 0) as depreciation_amount_during_the_period
-			from `tabAsset` a, `tabDepreciation Schedule` ds
-			where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s and a.name = ds.parent and ifnull(ds.journal_entry, '') != ''
+			from `tabAsset` a, `tabAsset Depreciation Schedule` ads, `tabDepreciation Schedule` ds
+			where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s and ads.asset = a.name and ads.docstatus=1 and ads.name = ds.parent and ifnull(ds.journal_entry, '') != ''
 			group by a.asset_category
 			union
 			SELECT a.asset_category,
diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py
index 8ba2310..130b715 100644
--- a/erpnext/accounts/report/gross_profit/gross_profit.py
+++ b/erpnext/accounts/report/gross_profit/gross_profit.py
@@ -439,6 +439,18 @@
 					row.delivery_note, frappe._dict()
 				)
 				row.item_row = row.dn_detail
+				# Update warehouse and base_amount from 'Packed Item' List
+				if product_bundles and not row.parent:
+					# For Packed Items, row.parent_invoice will be the Bundle name
+					product_bundle = product_bundles.get(row.parent_invoice)
+					if product_bundle:
+						for packed_item in product_bundle:
+							if (
+								packed_item.get("item_code") == row.item_code
+								and packed_item.get("parent_detail_docname") == row.item_row
+							):
+								row.warehouse = packed_item.warehouse
+								row.base_amount = packed_item.base_amount
 
 			# get buying amount
 			if row.item_code in product_bundles:
@@ -589,7 +601,9 @@
 		buying_amount = 0.0
 		for packed_item in product_bundle:
 			if packed_item.get("parent_detail_docname") == row.item_row:
-				buying_amount += self.get_buying_amount(row, packed_item.item_code)
+				packed_item_row = row.copy()
+				packed_item_row.warehouse = packed_item.warehouse
+				buying_amount += self.get_buying_amount(packed_item_row, packed_item.item_code)
 
 		return flt(buying_amount, self.currency_precision)
 
@@ -922,12 +936,25 @@
 	def load_product_bundle(self):
 		self.product_bundles = {}
 
-		for d in frappe.db.sql(
-			"""select parenttype, parent, parent_item,
-			item_code, warehouse, -1*qty as total_qty, parent_detail_docname
-			from `tabPacked Item` where docstatus=1""",
-			as_dict=True,
-		):
+		pki = qb.DocType("Packed Item")
+
+		pki_query = (
+			frappe.qb.from_(pki)
+			.select(
+				pki.parenttype,
+				pki.parent,
+				pki.parent_item,
+				pki.item_code,
+				pki.warehouse,
+				(-1 * pki.qty).as_("total_qty"),
+				pki.rate,
+				(pki.rate * pki.qty).as_("base_amount"),
+				pki.parent_detail_docname,
+			)
+			.where(pki.docstatus == 1)
+		)
+
+		for d in pki_query.run(as_dict=True):
 			self.product_bundles.setdefault(d.parenttype, frappe._dict()).setdefault(
 				d.parent, frappe._dict()
 			).setdefault(d.parent_item, []).append(d)
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index 7e54219..b8185c9 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -76,7 +76,6 @@
 	refresh: function(frm) {
 		frappe.ui.form.trigger("Asset", "is_existing_asset");
 		frm.toggle_display("next_depreciation_date", frm.doc.docstatus < 1);
-		frm.events.make_schedules_editable(frm);
 
 		if (frm.doc.docstatus==1) {
 			if (in_list(["Submitted", "Partially Depreciated", "Fully Depreciated"], frm.doc.status)) {
@@ -188,7 +187,11 @@
 		})
 	},
 
-	setup_chart: function(frm) {
+	setup_chart: async function(frm) {
+		if(frm.doc.finance_books.length > 1) {
+			return
+		}
+
 		var x_intervals = [frm.doc.purchase_date];
 		var asset_values = [frm.doc.gross_purchase_amount];
 		var last_depreciation_date = frm.doc.purchase_date;
@@ -202,7 +205,20 @@
 				flt(frm.doc.opening_accumulated_depreciation));
 		}
 
-		$.each(frm.doc.schedules || [], function(i, v) {
+		let depr_schedule = [];
+
+		if (frm.doc.finance_books.length == 1) {
+			depr_schedule = (await frappe.call(
+				"erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule.get_depr_schedule",
+				{
+					asset_name: frm.doc.name,
+					status: frm.doc.docstatus ? "Active" : "Draft",
+					finance_book: frm.doc.finance_books[0].finance_book || null
+				}
+			)).message;
+		}
+
+		$.each(depr_schedule || [], function(i, v) {
 			x_intervals.push(v.schedule_date);
 			var asset_value = flt(frm.doc.gross_purchase_amount) - flt(v.accumulated_depreciation_amount);
 			if(v.journal_entry) {
@@ -266,21 +282,6 @@
 		// frm.toggle_reqd("next_depreciation_date", (!frm.doc.is_existing_asset && frm.doc.calculate_depreciation));
 	},
 
-	opening_accumulated_depreciation: function(frm) {
-		erpnext.asset.set_accumulated_depreciation(frm);
-	},
-
-	make_schedules_editable: function(frm) {
-		if (frm.doc.finance_books) {
-			var is_editable = frm.doc.finance_books.filter(d => d.depreciation_method == "Manual").length > 0
-				? true : false;
-
-			frm.toggle_enable("schedules", is_editable);
-			frm.fields_dict["schedules"].grid.toggle_enable("schedule_date", is_editable);
-			frm.fields_dict["schedules"].grid.toggle_enable("depreciation_amount", is_editable);
-		}
-	},
-
 	make_sales_invoice: function(frm) {
 		frappe.call({
 			args: {
@@ -476,7 +477,6 @@
 	depreciation_method: function(frm, cdt, cdn) {
 		const row = locals[cdt][cdn];
 		frm.events.set_depreciation_rate(frm, row);
-		frm.events.make_schedules_editable(frm);
 	},
 
 	expected_value_after_useful_life: function(frm, cdt, cdn) {
@@ -512,41 +512,6 @@
 	}
 });
 
-frappe.ui.form.on('Depreciation Schedule', {
-	make_depreciation_entry: function(frm, cdt, cdn) {
-		var row = locals[cdt][cdn];
-		if (!row.journal_entry) {
-			frappe.call({
-				method: "erpnext.assets.doctype.asset.depreciation.make_depreciation_entry",
-				args: {
-					"asset_name": frm.doc.name,
-					"date": row.schedule_date
-				},
-				callback: function(r) {
-					frappe.model.sync(r.message);
-					frm.refresh();
-				}
-			})
-		}
-	},
-
-	depreciation_amount: function(frm, cdt, cdn) {
-		erpnext.asset.set_accumulated_depreciation(frm);
-	}
-
-})
-
-erpnext.asset.set_accumulated_depreciation = function(frm) {
-	if(frm.doc.depreciation_method != "Manual") return;
-
-	var accumulated_depreciation = flt(frm.doc.opening_accumulated_depreciation);
-	$.each(frm.doc.schedules || [], function(i, row) {
-		accumulated_depreciation  += flt(row.depreciation_amount);
-		frappe.model.set_value(row.doctype, row.name,
-			"accumulated_depreciation_amount", accumulated_depreciation);
-	})
-};
-
 erpnext.asset.scrap_asset = function(frm) {
 	frappe.confirm(__("Do you really want to scrap this asset?"), function () {
 		frappe.call({
diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json
index f0505ff..4bac303 100644
--- a/erpnext/assets/doctype/asset/asset.json
+++ b/erpnext/assets/doctype/asset/asset.json
@@ -52,8 +52,6 @@
   "column_break_24",
   "frequency_of_depreciation",
   "next_depreciation_date",
-  "section_break_14",
-  "schedules",
   "insurance_details",
   "policy_number",
   "insurer",
@@ -308,19 +306,6 @@
    "no_copy": 1
   },
   {
-   "depends_on": "calculate_depreciation",
-   "fieldname": "section_break_14",
-   "fieldtype": "Section Break",
-   "label": "Depreciation Schedule"
-  },
-  {
-   "fieldname": "schedules",
-   "fieldtype": "Table",
-   "label": "Depreciation Schedule",
-   "no_copy": 1,
-   "options": "Depreciation Schedule"
-  },
-  {
    "collapsible": 1,
    "fieldname": "insurance_details",
    "fieldtype": "Section Break",
@@ -508,9 +493,14 @@
    "group": "Value",
    "link_doctype": "Asset Value Adjustment",
    "link_fieldname": "asset"
+  },
+  {
+   "group": "Depreciation",
+   "link_doctype": "Asset Depreciation Schedule",
+   "link_fieldname": "asset"
   }
  ],
- "modified": "2022-07-20 10:15:12.887372",
+ "modified": "2022-11-25 12:47:19.689702",
  "modified_by": "Administrator",
  "module": "Assets",
  "name": "Asset",
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index ca6be9b..df05d5e 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -8,14 +8,15 @@
 import frappe
 from frappe import _
 from frappe.utils import (
-	add_days,
 	add_months,
 	cint,
 	date_diff,
 	flt,
 	get_datetime,
 	get_last_day,
+	get_link_to_form,
 	getdate,
+	is_last_day_of_the_month,
 	month_diff,
 	nowdate,
 	today,
@@ -28,6 +29,16 @@
 	get_disposal_account_and_cost_center,
 )
 from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
+from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
+	cancel_asset_depr_schedules,
+	convert_draft_asset_depr_schedules_into_active,
+	get_asset_depr_schedule_doc,
+	get_depr_schedule,
+	make_draft_asset_depr_schedules,
+	make_draft_asset_depr_schedules_if_not_present,
+	set_draft_asset_depr_schedule_details,
+	update_draft_asset_depr_schedules,
+)
 from erpnext.controllers.accounts_controller import AccountsController
 
 
@@ -40,9 +51,9 @@
 		self.set_missing_values()
 		if not self.split_from:
 			self.prepare_depreciation_data()
+			update_draft_asset_depr_schedules(self)
 		self.validate_gross_and_purchase_amount()
-		if self.get("schedules"):
-			self.validate_expected_value_after_useful_life()
+		self.validate_expected_value_after_useful_life()
 
 		self.status = self.get_status()
 
@@ -52,16 +63,24 @@
 		self.make_asset_movement()
 		if not self.booked_fixed_asset and self.validate_make_gl_entry():
 			self.make_gl_entries()
+		if not self.split_from:
+			make_draft_asset_depr_schedules_if_not_present(self)
+			convert_draft_asset_depr_schedules_into_active(self)
 
 	def on_cancel(self):
 		self.validate_cancellation()
 		self.cancel_movement_entries()
 		self.delete_depreciation_entries()
+		cancel_asset_depr_schedules(self)
 		self.set_status()
 		self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry")
 		make_reverse_gl_entries(voucher_type="Asset", voucher_no=self.name)
 		self.db_set("booked_fixed_asset", 0)
 
+	def after_insert(self):
+		if not self.split_from:
+			make_draft_asset_depr_schedules(self)
+
 	def validate_asset_and_reference(self):
 		if self.purchase_invoice or self.purchase_receipt:
 			reference_doc = "Purchase Invoice" if self.purchase_invoice else "Purchase Receipt"
@@ -79,12 +98,10 @@
 				_("Purchase Invoice cannot be made against an existing asset {0}").format(self.name)
 			)
 
-	def prepare_depreciation_data(self, date_of_disposal=None, date_of_return=None):
+	def prepare_depreciation_data(self):
 		if self.calculate_depreciation:
 			self.value_after_depreciation = 0
 			self.set_depreciation_rate()
-			self.make_depreciation_schedule(date_of_disposal)
-			self.set_accumulated_depreciation(date_of_disposal, date_of_return)
 		else:
 			self.finance_books = []
 			self.value_after_depreciation = flt(self.gross_purchase_amount) - flt(
@@ -223,148 +240,6 @@
 				self.get_depreciation_rate(d, on_validate=True), d.precision("rate_of_depreciation")
 			)
 
-	def make_depreciation_schedule(self, date_of_disposal):
-		if "Manual" not in [d.depreciation_method for d in self.finance_books] and not self.get(
-			"schedules"
-		):
-			self.schedules = []
-
-		if not self.available_for_use_date:
-			return
-
-		start = self.clear_depreciation_schedule()
-
-		for finance_book in self.get("finance_books"):
-			self._make_depreciation_schedule(finance_book, start, date_of_disposal)
-
-	def _make_depreciation_schedule(self, finance_book, start, date_of_disposal):
-		self.validate_asset_finance_books(finance_book)
-
-		value_after_depreciation = self._get_value_after_depreciation(finance_book)
-		finance_book.value_after_depreciation = value_after_depreciation
-
-		number_of_pending_depreciations = cint(finance_book.total_number_of_depreciations) - cint(
-			self.number_of_depreciations_booked
-		)
-
-		has_pro_rata = self.check_is_pro_rata(finance_book)
-		if has_pro_rata:
-			number_of_pending_depreciations += 1
-
-		skip_row = False
-		should_get_last_day = is_last_day_of_the_month(finance_book.depreciation_start_date)
-
-		for n in range(start[finance_book.idx - 1], number_of_pending_depreciations):
-			# If depreciation is already completed (for double declining balance)
-			if skip_row:
-				continue
-
-			depreciation_amount = get_depreciation_amount(self, value_after_depreciation, finance_book)
-
-			if not has_pro_rata or n < cint(number_of_pending_depreciations) - 1:
-				schedule_date = add_months(
-					finance_book.depreciation_start_date, n * cint(finance_book.frequency_of_depreciation)
-				)
-
-				if should_get_last_day:
-					schedule_date = get_last_day(schedule_date)
-
-				# schedule date will be a year later from start date
-				# so monthly schedule date is calculated by removing 11 months from it
-				monthly_schedule_date = add_months(schedule_date, -finance_book.frequency_of_depreciation + 1)
-
-			# if asset is being sold
-			if date_of_disposal:
-				from_date = self.get_from_date(finance_book.finance_book)
-				depreciation_amount, days, months = self.get_pro_rata_amt(
-					finance_book, depreciation_amount, from_date, date_of_disposal
-				)
-
-				if depreciation_amount > 0:
-					self._add_depreciation_row(
-						date_of_disposal,
-						depreciation_amount,
-						finance_book.depreciation_method,
-						finance_book.finance_book,
-						finance_book.idx,
-					)
-
-				break
-
-			# For first row
-			if has_pro_rata and not self.opening_accumulated_depreciation and n == 0:
-				from_date = add_days(
-					self.available_for_use_date, -1
-				)  # needed to calc depr amount for available_for_use_date too
-				depreciation_amount, days, months = self.get_pro_rata_amt(
-					finance_book, depreciation_amount, from_date, finance_book.depreciation_start_date
-				)
-
-				# For first depr schedule date will be the start date
-				# so monthly schedule date is calculated by removing month difference between use date and start date
-				monthly_schedule_date = add_months(finance_book.depreciation_start_date, -months + 1)
-
-			# For last row
-			elif has_pro_rata and n == cint(number_of_pending_depreciations) - 1:
-				if not self.flags.increase_in_asset_life:
-					# In case of increase_in_asset_life, the self.to_date is already set on asset_repair submission
-					self.to_date = add_months(
-						self.available_for_use_date,
-						(n + self.number_of_depreciations_booked) * cint(finance_book.frequency_of_depreciation),
-					)
-
-				depreciation_amount_without_pro_rata = depreciation_amount
-
-				depreciation_amount, days, months = self.get_pro_rata_amt(
-					finance_book, depreciation_amount, schedule_date, self.to_date
-				)
-
-				depreciation_amount = self.get_adjusted_depreciation_amount(
-					depreciation_amount_without_pro_rata, depreciation_amount, finance_book.finance_book
-				)
-
-				monthly_schedule_date = add_months(schedule_date, 1)
-				schedule_date = add_days(schedule_date, days)
-				last_schedule_date = schedule_date
-
-			if not depreciation_amount:
-				continue
-			value_after_depreciation -= flt(depreciation_amount, self.precision("gross_purchase_amount"))
-
-			# Adjust depreciation amount in the last period based on the expected value after useful life
-			if finance_book.expected_value_after_useful_life and (
-				(
-					n == cint(number_of_pending_depreciations) - 1
-					and value_after_depreciation != finance_book.expected_value_after_useful_life
-				)
-				or value_after_depreciation < finance_book.expected_value_after_useful_life
-			):
-				depreciation_amount += value_after_depreciation - finance_book.expected_value_after_useful_life
-				skip_row = True
-
-			if depreciation_amount > 0:
-				self._add_depreciation_row(
-					schedule_date,
-					depreciation_amount,
-					finance_book.depreciation_method,
-					finance_book.finance_book,
-					finance_book.idx,
-				)
-
-	def _add_depreciation_row(
-		self, schedule_date, depreciation_amount, depreciation_method, finance_book, finance_book_id
-	):
-		self.append(
-			"schedules",
-			{
-				"schedule_date": schedule_date,
-				"depreciation_amount": depreciation_amount,
-				"depreciation_method": depreciation_method,
-				"finance_book": finance_book,
-				"finance_book_id": finance_book_id,
-			},
-		)
-
 	def _get_value_after_depreciation(self, finance_book):
 		# value_after_depreciation - current Asset value
 		if self.docstatus == 1 and finance_book.value_after_depreciation:
@@ -376,58 +251,6 @@
 
 		return value_after_depreciation
 
-	# depreciation schedules need to be cleared before modification due to increase in asset life/asset sales
-	# JE: Journal Entry, FB: Finance Book
-	def clear_depreciation_schedule(self):
-		start = []
-		num_of_depreciations_completed = 0
-		depr_schedule = []
-
-		for schedule in self.get("schedules"):
-			# to update start when there are JEs linked with all the schedule rows corresponding to an FB
-			if len(start) == (int(schedule.finance_book_id) - 2):
-				start.append(num_of_depreciations_completed)
-				num_of_depreciations_completed = 0
-
-			# to ensure that start will only be updated once for each FB
-			if len(start) == (int(schedule.finance_book_id) - 1):
-				if schedule.journal_entry:
-					num_of_depreciations_completed += 1
-					depr_schedule.append(schedule)
-				else:
-					start.append(num_of_depreciations_completed)
-					num_of_depreciations_completed = 0
-
-		# to update start when all the schedule rows corresponding to the last FB are linked with JEs
-		if len(start) == (len(self.finance_books) - 1):
-			start.append(num_of_depreciations_completed)
-
-		# when the Depreciation Schedule is being created for the first time
-		if start == []:
-			start = [0] * len(self.finance_books)
-		else:
-			self.schedules = depr_schedule
-
-		return start
-
-	def get_from_date(self, finance_book):
-		if not self.get("schedules"):
-			return self.available_for_use_date
-
-		if len(self.finance_books) == 1:
-			return self.schedules[-1].schedule_date
-
-		from_date = ""
-		for schedule in self.get("schedules"):
-			if schedule.finance_book == finance_book:
-				from_date = schedule.schedule_date
-
-		if from_date:
-			return from_date
-
-		# since depr for available_for_use_date is not yet booked
-		return add_days(self.available_for_use_date, -1)
-
 	# if it returns True, depreciation_amount will not be equal for the first and last rows
 	def check_is_pro_rata(self, row):
 		has_pro_rata = False
@@ -512,83 +335,15 @@
 				).format(row.idx)
 			)
 
-	# to ensure that final accumulated depreciation amount is accurate
-	def get_adjusted_depreciation_amount(
-		self, depreciation_amount_without_pro_rata, depreciation_amount_for_last_row, finance_book
-	):
-		if not self.opening_accumulated_depreciation:
-			depreciation_amount_for_first_row = self.get_depreciation_amount_for_first_row(finance_book)
-
-			if (
-				depreciation_amount_for_first_row + depreciation_amount_for_last_row
-				!= depreciation_amount_without_pro_rata
-			):
-				depreciation_amount_for_last_row = (
-					depreciation_amount_without_pro_rata - depreciation_amount_for_first_row
-				)
-
-		return depreciation_amount_for_last_row
-
-	def get_depreciation_amount_for_first_row(self, finance_book):
-		if self.has_only_one_finance_book():
-			return self.schedules[0].depreciation_amount
-		else:
-			for schedule in self.schedules:
-				if schedule.finance_book == finance_book:
-					return schedule.depreciation_amount
-
-	def has_only_one_finance_book(self):
-		if len(self.finance_books) == 1:
-			return True
-
-	def set_accumulated_depreciation(
-		self, date_of_sale=None, date_of_return=None, ignore_booked_entry=False
-	):
-		straight_line_idx = [
-			d.idx for d in self.get("schedules") if d.depreciation_method == "Straight Line"
-		]
-		finance_books = []
-
-		for i, d in enumerate(self.get("schedules")):
-			if ignore_booked_entry and d.journal_entry:
-				continue
-
-			if int(d.finance_book_id) not in finance_books:
-				accumulated_depreciation = flt(self.opening_accumulated_depreciation)
-				value_after_depreciation = flt(self.get_value_after_depreciation(d.finance_book_id))
-				finance_books.append(int(d.finance_book_id))
-
-			depreciation_amount = flt(d.depreciation_amount, d.precision("depreciation_amount"))
-			value_after_depreciation -= flt(depreciation_amount)
-
-			# for the last row, if depreciation method = Straight Line
-			if (
-				straight_line_idx
-				and i == max(straight_line_idx) - 1
-				and not date_of_sale
-				and not date_of_return
-			):
-				book = self.get("finance_books")[cint(d.finance_book_id) - 1]
-				depreciation_amount += flt(
-					value_after_depreciation - flt(book.expected_value_after_useful_life),
-					d.precision("depreciation_amount"),
-				)
-
-			d.depreciation_amount = depreciation_amount
-			accumulated_depreciation += d.depreciation_amount
-			d.accumulated_depreciation_amount = flt(
-				accumulated_depreciation, d.precision("accumulated_depreciation_amount")
-			)
-
-	def get_value_after_depreciation(self, idx):
-		return flt(self.get("finance_books")[cint(idx) - 1].value_after_depreciation)
-
 	def validate_expected_value_after_useful_life(self):
 		for row in self.get("finance_books"):
+			depr_schedule = get_depr_schedule(self.name, "Draft", row.finance_book)
+
+			if not depr_schedule:
+				continue
+
 			accumulated_depreciation_after_full_schedule = [
-				d.accumulated_depreciation_amount
-				for d in self.get("schedules")
-				if cint(d.finance_book_id) == row.idx
+				d.accumulated_depreciation_amount for d in depr_schedule
 			]
 
 			if accumulated_depreciation_after_full_schedule:
@@ -637,10 +392,13 @@
 			movement.cancel()
 
 	def delete_depreciation_entries(self):
-		for d in self.get("schedules"):
-			if d.journal_entry:
-				frappe.get_doc("Journal Entry", d.journal_entry).cancel()
-				d.db_set("journal_entry", None)
+		for row in self.get("finance_books"):
+			depr_schedule = get_depr_schedule(self.name, "Active", row.finance_book)
+
+			for d in depr_schedule or []:
+				if d.journal_entry:
+					frappe.get_doc("Journal Entry", d.journal_entry).cancel()
+					d.db_set("journal_entry", None)
 
 		self.db_set(
 			"value_after_depreciation",
@@ -1072,32 +830,6 @@
 	return date_diff(date, period_start_date)
 
 
-def is_last_day_of_the_month(date):
-	last_day_of_the_month = get_last_day(date)
-
-	return getdate(last_day_of_the_month) == getdate(date)
-
-
-@erpnext.allow_regional
-def get_depreciation_amount(asset, depreciable_value, row):
-	if row.depreciation_method in ("Straight Line", "Manual"):
-		# if the Depreciation Schedule is being prepared for the first time
-		if not asset.flags.increase_in_asset_life:
-			depreciation_amount = (
-				flt(asset.gross_purchase_amount) - flt(row.expected_value_after_useful_life)
-			) / flt(row.total_number_of_depreciations)
-
-		# if the Depreciation Schedule is being modified after Asset Repair
-		else:
-			depreciation_amount = (
-				flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)
-			) / (date_diff(asset.to_date, asset.available_for_use_date) / 365)
-	else:
-		depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100))
-
-	return depreciation_amount
-
-
 @frappe.whitelist()
 def split_asset(asset_name, split_qty):
 	asset = frappe.get_doc("Asset", asset_name)
@@ -1109,12 +841,12 @@
 	remaining_qty = asset.asset_quantity - split_qty
 
 	new_asset = create_new_asset_after_split(asset, split_qty)
-	update_existing_asset(asset, remaining_qty)
+	update_existing_asset(asset, remaining_qty, new_asset.name)
 
 	return new_asset
 
 
-def update_existing_asset(asset, remaining_qty):
+def update_existing_asset(asset, remaining_qty, new_asset_name):
 	remaining_gross_purchase_amount = flt(
 		(asset.gross_purchase_amount * remaining_qty) / asset.asset_quantity
 	)
@@ -1132,34 +864,49 @@
 		},
 	)
 
-	for finance_book in asset.get("finance_books"):
+	for row in asset.get("finance_books"):
 		value_after_depreciation = flt(
-			(finance_book.value_after_depreciation * remaining_qty) / asset.asset_quantity
+			(row.value_after_depreciation * remaining_qty) / asset.asset_quantity
 		)
 		expected_value_after_useful_life = flt(
-			(finance_book.expected_value_after_useful_life * remaining_qty) / asset.asset_quantity
+			(row.expected_value_after_useful_life * remaining_qty) / asset.asset_quantity
 		)
 		frappe.db.set_value(
-			"Asset Finance Book", finance_book.name, "value_after_depreciation", value_after_depreciation
+			"Asset Finance Book", row.name, "value_after_depreciation", value_after_depreciation
 		)
 		frappe.db.set_value(
 			"Asset Finance Book",
-			finance_book.name,
+			row.name,
 			"expected_value_after_useful_life",
 			expected_value_after_useful_life,
 		)
 
-	accumulated_depreciation = 0
+		current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(
+			asset.name, "Active", row.finance_book
+		)
+		new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc)
 
-	for term in asset.get("schedules"):
-		depreciation_amount = flt((term.depreciation_amount * remaining_qty) / asset.asset_quantity)
-		frappe.db.set_value(
-			"Depreciation Schedule", term.name, "depreciation_amount", depreciation_amount
+		set_draft_asset_depr_schedule_details(new_asset_depr_schedule_doc, asset, row)
+
+		accumulated_depreciation = 0
+
+		for term in new_asset_depr_schedule_doc.get("depreciation_schedule"):
+			depreciation_amount = flt((term.depreciation_amount * remaining_qty) / asset.asset_quantity)
+			term.depreciation_amount = depreciation_amount
+			accumulated_depreciation += depreciation_amount
+			term.accumulated_depreciation_amount = accumulated_depreciation
+
+		notes = _(
+			"This schedule was created when Asset {0} was updated after being split into new Asset {1}."
+		).format(
+			get_link_to_form(asset.doctype, asset.name), get_link_to_form(asset.doctype, new_asset_name)
 		)
-		accumulated_depreciation += depreciation_amount
-		frappe.db.set_value(
-			"Depreciation Schedule", term.name, "accumulated_depreciation_amount", accumulated_depreciation
-		)
+		new_asset_depr_schedule_doc.notes = notes
+
+		current_asset_depr_schedule_doc.flags.should_not_cancel_depreciation_entries = True
+		current_asset_depr_schedule_doc.cancel()
+
+		new_asset_depr_schedule_doc.submit()
 
 
 def create_new_asset_after_split(asset, split_qty):
@@ -1173,31 +920,49 @@
 	new_asset.opening_accumulated_depreciation = opening_accumulated_depreciation
 	new_asset.asset_quantity = split_qty
 	new_asset.split_from = asset.name
-	accumulated_depreciation = 0
 
-	for finance_book in new_asset.get("finance_books"):
-		finance_book.value_after_depreciation = flt(
-			(finance_book.value_after_depreciation * split_qty) / asset.asset_quantity
+	for row in new_asset.get("finance_books"):
+		row.value_after_depreciation = flt(
+			(row.value_after_depreciation * split_qty) / asset.asset_quantity
 		)
-		finance_book.expected_value_after_useful_life = flt(
-			(finance_book.expected_value_after_useful_life * split_qty) / asset.asset_quantity
+		row.expected_value_after_useful_life = flt(
+			(row.expected_value_after_useful_life * split_qty) / asset.asset_quantity
 		)
 
-	for term in new_asset.get("schedules"):
-		depreciation_amount = flt((term.depreciation_amount * split_qty) / asset.asset_quantity)
-		term.depreciation_amount = depreciation_amount
-		accumulated_depreciation += depreciation_amount
-		term.accumulated_depreciation_amount = accumulated_depreciation
-
 	new_asset.submit()
 	new_asset.set_status()
 
-	for term in new_asset.get("schedules"):
-		# Update references in JV
-		if term.journal_entry:
-			add_reference_in_jv_on_split(
-				term.journal_entry, new_asset.name, asset.name, term.depreciation_amount
-			)
+	for row in new_asset.get("finance_books"):
+		current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(
+			asset.name, "Active", row.finance_book
+		)
+		new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc)
+
+		set_draft_asset_depr_schedule_details(new_asset_depr_schedule_doc, new_asset, row)
+
+		accumulated_depreciation = 0
+
+		for term in new_asset_depr_schedule_doc.get("depreciation_schedule"):
+			depreciation_amount = flt((term.depreciation_amount * split_qty) / asset.asset_quantity)
+			term.depreciation_amount = depreciation_amount
+			accumulated_depreciation += depreciation_amount
+			term.accumulated_depreciation_amount = accumulated_depreciation
+
+		notes = _("This schedule was created when new Asset {0} was split from Asset {1}.").format(
+			get_link_to_form(new_asset.doctype, new_asset.name), get_link_to_form(asset.doctype, asset.name)
+		)
+		new_asset_depr_schedule_doc.notes = notes
+
+		new_asset_depr_schedule_doc.submit()
+
+	for row in new_asset.get("finance_books"):
+		depr_schedule = get_depr_schedule(new_asset.name, "Active", row.finance_book)
+		for term in depr_schedule:
+			# Update references in JV
+			if term.journal_entry:
+				add_reference_in_jv_on_split(
+					term.journal_entry, new_asset.name, asset.name, term.depreciation_amount
+				)
 
 	return new_asset
 
diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py
index 9794170..7686c34 100644
--- a/erpnext/assets/doctype/asset/depreciation.py
+++ b/erpnext/assets/doctype/asset/depreciation.py
@@ -4,12 +4,18 @@
 
 import frappe
 from frappe import _
-from frappe.utils import add_months, cint, flt, getdate, nowdate, today
+from frappe.utils import add_months, cint, flt, get_link_to_form, getdate, nowdate, today
 
 from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
 	get_checks_for_pl_and_bs_accounts,
 )
 from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry
+from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
+	get_asset_depr_schedule_doc,
+	get_asset_depr_schedule_name,
+	get_temp_asset_depr_schedule_doc,
+	make_new_active_asset_depr_schedules_and_cancel_current_ones,
+)
 
 
 def post_depreciation_entries(date=None, commit=True):
@@ -21,8 +27,11 @@
 
 	if not date:
 		date = today()
-	for asset in get_depreciable_assets(date):
-		make_depreciation_entry(asset, date)
+	for asset_name in get_depreciable_assets(date):
+		asset_doc = frappe.get_doc("Asset", asset_name)
+
+		make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date)
+
 		if commit:
 			frappe.db.commit()
 
@@ -30,21 +39,35 @@
 def get_depreciable_assets(date):
 	return frappe.db.sql_list(
 		"""select distinct a.name
-		from tabAsset a, `tabDepreciation Schedule` ds
-		where a.name = ds.parent and a.docstatus=1 and ds.schedule_date<=%s and a.calculate_depreciation = 1
+		from tabAsset a, `tabAsset Depreciation Schedule` ads, `tabDepreciation Schedule` ds
+		where a.name = ads.asset and ads.name = ds.parent and a.docstatus=1 and ads.docstatus=1
 			and a.status in ('Submitted', 'Partially Depreciated')
+			and a.calculate_depreciation = 1
+			and ds.schedule_date<=%s
 			and ifnull(ds.journal_entry, '')=''""",
 		date,
 	)
 
 
+def make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date=None):
+	for row in asset_doc.get("finance_books"):
+		asset_depr_schedule_name = get_asset_depr_schedule_name(
+			asset_doc.name, "Active", row.finance_book
+		)
+		make_depreciation_entry(asset_depr_schedule_name, date)
+
+
 @frappe.whitelist()
-def make_depreciation_entry(asset_name, date=None):
+def make_depreciation_entry(asset_depr_schedule_name, date=None):
 	frappe.has_permission("Journal Entry", throw=True)
 
 	if not date:
 		date = today()
 
+	asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name)
+
+	asset_name = asset_depr_schedule_doc.asset
+
 	asset = frappe.get_doc("Asset", asset_name)
 	(
 		fixed_asset_account,
@@ -60,14 +83,14 @@
 
 	accounting_dimensions = get_checks_for_pl_and_bs_accounts()
 
-	for d in asset.get("schedules"):
+	for d in asset_depr_schedule_doc.get("depreciation_schedule"):
 		if not d.journal_entry and getdate(d.schedule_date) <= getdate(date):
 			je = frappe.new_doc("Journal Entry")
 			je.voucher_type = "Depreciation Entry"
 			je.naming_series = depreciation_series
 			je.posting_date = d.schedule_date
 			je.company = asset.company
-			je.finance_book = d.finance_book
+			je.finance_book = asset_depr_schedule_doc.finance_book
 			je.remark = "Depreciation Entry against {0} worth {1}".format(asset_name, d.depreciation_amount)
 
 			credit_account, debit_account = get_credit_and_debit_accounts(
@@ -118,14 +141,14 @@
 
 			d.db_set("journal_entry", je.name)
 
-			idx = cint(d.finance_book_id)
-			finance_books = asset.get("finance_books")[idx - 1]
-			finance_books.value_after_depreciation -= d.depreciation_amount
-			finance_books.db_update()
+			idx = cint(asset_depr_schedule_doc.finance_book_id)
+			row = asset.get("finance_books")[idx - 1]
+			row.value_after_depreciation -= d.depreciation_amount
+			row.db_update()
 
 	asset.set_status()
 
-	return asset
+	return asset_depr_schedule_doc
 
 
 def get_depreciation_accounts(asset):
@@ -199,7 +222,11 @@
 
 	date = today()
 
-	depreciate_asset(asset, date)
+	notes = _("This schedule was created when Asset {0} was scrapped.").format(
+		get_link_to_form(asset.doctype, asset.name)
+	)
+
+	depreciate_asset(asset, date, notes)
 	asset.reload()
 
 	depreciation_series = frappe.get_cached_value(
@@ -232,10 +259,15 @@
 	asset = frappe.get_doc("Asset", asset_name)
 
 	reverse_depreciation_entry_made_after_disposal(asset, asset.disposal_date)
-	reset_depreciation_schedule(asset, asset.disposal_date)
 
 	je = asset.journal_entry_for_scrap
 
+	notes = _("This schedule was created when Asset {0} was restored.").format(
+		get_link_to_form(asset.doctype, asset.name)
+	)
+
+	reset_depreciation_schedule(asset, asset.disposal_date, notes)
+
 	asset.db_set("disposal_date", None)
 	asset.db_set("journal_entry_for_scrap", None)
 
@@ -244,22 +276,28 @@
 	asset.set_status()
 
 
-def depreciate_asset(asset, date):
-	asset.flags.ignore_validate_update_after_submit = True
-	asset.prepare_depreciation_data(date_of_disposal=date)
-	asset.save()
+def depreciate_asset(asset_doc, date, notes):
+	asset_doc.flags.ignore_validate_update_after_submit = True
 
-	make_depreciation_entry(asset.name, date)
+	make_new_active_asset_depr_schedules_and_cancel_current_ones(
+		asset_doc, notes, date_of_disposal=date
+	)
+
+	asset_doc.save()
+
+	make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date)
 
 
-def reset_depreciation_schedule(asset, date):
-	asset.flags.ignore_validate_update_after_submit = True
+def reset_depreciation_schedule(asset_doc, date, notes):
+	asset_doc.flags.ignore_validate_update_after_submit = True
 
-	# recreate original depreciation schedule of the asset
-	asset.prepare_depreciation_data(date_of_return=date)
+	make_new_active_asset_depr_schedules_and_cancel_current_ones(
+		asset_doc, notes, date_of_return=date
+	)
 
-	modify_depreciation_schedule_for_asset_repairs(asset)
-	asset.save()
+	modify_depreciation_schedule_for_asset_repairs(asset_doc)
+
+	asset_doc.save()
 
 
 def modify_depreciation_schedule_for_asset_repairs(asset):
@@ -271,35 +309,36 @@
 		if repair.increase_in_asset_life:
 			asset_repair = frappe.get_doc("Asset Repair", repair.name)
 			asset_repair.modify_depreciation_schedule()
-			asset.prepare_depreciation_data()
+			notes = _("This schedule was created when Asset {0} went through Asset Repair {1}.").format(
+				get_link_to_form(asset.doctype, asset.name),
+				get_link_to_form(asset_repair.doctype, asset_repair.name),
+			)
+			make_new_active_asset_depr_schedules_and_cancel_current_ones(asset, notes)
 
 
 def reverse_depreciation_entry_made_after_disposal(asset, date):
-	row = -1
-	finance_book = asset.get("schedules")[0].get("finance_book")
-	for schedule in asset.get("schedules"):
-		if schedule.finance_book != finance_book:
-			row = 0
-			finance_book = schedule.finance_book
-		else:
-			row += 1
+	for row in asset.get("finance_books"):
+		asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset.name, "Active", row.finance_book)
 
-		if schedule.schedule_date == date:
-			if not disposal_was_made_on_original_schedule_date(
-				asset, schedule, row, date
-			) or disposal_happens_in_the_future(date):
+		for schedule_idx, schedule in enumerate(asset_depr_schedule_doc.get("depreciation_schedule")):
+			if schedule.schedule_date == date:
+				if not disposal_was_made_on_original_schedule_date(
+					schedule_idx, row, date
+				) or disposal_happens_in_the_future(date):
 
-				reverse_journal_entry = make_reverse_journal_entry(schedule.journal_entry)
-				reverse_journal_entry.posting_date = nowdate()
-				frappe.flags.is_reverse_depr_entry = True
-				reverse_journal_entry.submit()
+					reverse_journal_entry = make_reverse_journal_entry(schedule.journal_entry)
+					reverse_journal_entry.posting_date = nowdate()
+					frappe.flags.is_reverse_depr_entry = True
+					reverse_journal_entry.submit()
 
-				frappe.flags.is_reverse_depr_entry = False
-				asset.flags.ignore_validate_update_after_submit = True
-				schedule.journal_entry = None
-				depreciation_amount = get_depreciation_amount_in_je(reverse_journal_entry)
-				asset.finance_books[0].value_after_depreciation += depreciation_amount
-				asset.save()
+					frappe.flags.is_reverse_depr_entry = False
+					asset_depr_schedule_doc.flags.ignore_validate_update_after_submit = True
+					asset.flags.ignore_validate_update_after_submit = True
+					schedule.journal_entry = None
+					depreciation_amount = get_depreciation_amount_in_je(reverse_journal_entry)
+					row.value_after_depreciation += depreciation_amount
+					asset_depr_schedule_doc.save()
+					asset.save()
 
 
 def get_depreciation_amount_in_je(journal_entry):
@@ -310,15 +349,14 @@
 
 
 # if the invoice had been posted on the date the depreciation was initially supposed to happen, the depreciation shouldn't be undone
-def disposal_was_made_on_original_schedule_date(asset, schedule, row, posting_date_of_disposal):
-	for finance_book in asset.get("finance_books"):
-		if schedule.finance_book == finance_book.finance_book:
-			orginal_schedule_date = add_months(
-				finance_book.depreciation_start_date, row * cint(finance_book.frequency_of_depreciation)
-			)
+def disposal_was_made_on_original_schedule_date(schedule_idx, row, posting_date_of_disposal):
+	orginal_schedule_date = add_months(
+		row.depreciation_start_date, schedule_idx * cint(row.frequency_of_depreciation)
+	)
 
-			if orginal_schedule_date == posting_date_of_disposal:
-				return True
+	if orginal_schedule_date == posting_date_of_disposal:
+		return True
+
 	return False
 
 
@@ -499,24 +537,27 @@
 def get_value_after_depreciation_on_disposal_date(asset, disposal_date, finance_book=None):
 	asset_doc = frappe.get_doc("Asset", asset)
 
-	if asset_doc.calculate_depreciation:
-		asset_doc.prepare_depreciation_data(getdate(disposal_date))
-
-		finance_book_id = 1
-		if finance_book:
-			for fb in asset_doc.finance_books:
-				if fb.finance_book == finance_book:
-					finance_book_id = fb.idx
-					break
-
-		asset_schedules = [
-			sch for sch in asset_doc.schedules if cint(sch.finance_book_id) == finance_book_id
-		]
-		accumulated_depr_amount = asset_schedules[-1].accumulated_depreciation_amount
-
-		return flt(
-			flt(asset_doc.gross_purchase_amount) - accumulated_depr_amount,
-			asset_doc.precision("gross_purchase_amount"),
-		)
-	else:
+	if not asset_doc.calculate_depreciation:
 		return flt(asset_doc.value_after_depreciation)
+
+	idx = 1
+	if finance_book:
+		for d in asset.finance_books:
+			if d.finance_book == finance_book:
+				idx = d.idx
+				break
+
+	row = asset_doc.finance_books[idx - 1]
+
+	temp_asset_depreciation_schedule = get_temp_asset_depr_schedule_doc(
+		asset_doc, row, getdate(disposal_date)
+	)
+
+	accumulated_depr_amount = temp_asset_depreciation_schedule.get("depreciation_schedule")[
+		-1
+	].accumulated_depreciation_amount
+
+	return flt(
+		flt(asset_doc.gross_purchase_amount) - accumulated_depr_amount,
+		asset_doc.precision("gross_purchase_amount"),
+	)
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index 2bec273..d61ef8e 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -27,6 +27,11 @@
 	restore_asset,
 	scrap_asset,
 )
+from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
+	clear_depr_schedule,
+	get_asset_depr_schedule_doc,
+	get_depr_schedule,
+)
 from erpnext.stock.doctype.purchase_receipt.purchase_receipt import (
 	make_purchase_invoice as make_invoice,
 )
@@ -205,6 +210,9 @@
 			submit=1,
 		)
 
+		first_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
+		self.assertEquals(first_asset_depr_schedule.status, "Active")
+
 		post_depreciation_entries(date=add_months(purchase_date, 2))
 		asset.load_from_db()
 
@@ -216,6 +224,11 @@
 
 		scrap_asset(asset.name)
 		asset.load_from_db()
+		first_asset_depr_schedule.load_from_db()
+
+		second_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
+		self.assertEquals(second_asset_depr_schedule.status, "Active")
+		self.assertEquals(first_asset_depr_schedule.status, "Cancelled")
 
 		accumulated_depr_amount = flt(
 			asset.gross_purchase_amount - asset.finance_books[0].value_after_depreciation,
@@ -256,6 +269,11 @@
 		self.assertSequenceEqual(gle, expected_gle)
 
 		restore_asset(asset.name)
+		second_asset_depr_schedule.load_from_db()
+
+		third_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
+		self.assertEquals(third_asset_depr_schedule.status, "Active")
+		self.assertEquals(second_asset_depr_schedule.status, "Cancelled")
 
 		asset.load_from_db()
 		self.assertFalse(asset.journal_entry_for_scrap)
@@ -283,6 +301,9 @@
 			submit=1,
 		)
 
+		first_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
+		self.assertEquals(first_asset_depr_schedule.status, "Active")
+
 		post_depreciation_entries(date=add_months(purchase_date, 2))
 
 		si = make_sales_invoice(asset=asset.name, item_code="Macbook Pro", company="_Test Company")
@@ -294,6 +315,12 @@
 
 		self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Sold")
 
+		first_asset_depr_schedule.load_from_db()
+
+		second_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
+		self.assertEquals(second_asset_depr_schedule.status, "Active")
+		self.assertEquals(first_asset_depr_schedule.status, "Cancelled")
+
 		pro_rata_amount, _, _ = asset.get_pro_rata_amt(
 			asset.finance_books[0], 9000, get_last_day(add_months(purchase_date, 1)), date
 		)
@@ -370,6 +397,9 @@
 			submit=1,
 		)
 
+		first_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
+		self.assertEquals(first_asset_depr_schedule.status, "Active")
+
 		post_depreciation_entries(date="2021-01-01")
 
 		self.assertEqual(asset.asset_quantity, 10)
@@ -378,21 +408,31 @@
 
 		new_asset = split_asset(asset.name, 2)
 		asset.load_from_db()
+		first_asset_depr_schedule.load_from_db()
+
+		second_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
+		first_asset_depr_schedule_of_new_asset = get_asset_depr_schedule_doc(new_asset.name, "Active")
+		self.assertEquals(second_asset_depr_schedule.status, "Active")
+		self.assertEquals(first_asset_depr_schedule_of_new_asset.status, "Active")
+		self.assertEquals(first_asset_depr_schedule.status, "Cancelled")
+
+		depr_schedule_of_asset = second_asset_depr_schedule.get("depreciation_schedule")
+		depr_schedule_of_new_asset = first_asset_depr_schedule_of_new_asset.get("depreciation_schedule")
 
 		self.assertEqual(new_asset.asset_quantity, 2)
 		self.assertEqual(new_asset.gross_purchase_amount, 24000)
 		self.assertEqual(new_asset.opening_accumulated_depreciation, 4000)
 		self.assertEqual(new_asset.split_from, asset.name)
-		self.assertEqual(new_asset.schedules[0].depreciation_amount, 4000)
-		self.assertEqual(new_asset.schedules[1].depreciation_amount, 4000)
+		self.assertEqual(depr_schedule_of_new_asset[0].depreciation_amount, 4000)
+		self.assertEqual(depr_schedule_of_new_asset[1].depreciation_amount, 4000)
 
 		self.assertEqual(asset.asset_quantity, 8)
 		self.assertEqual(asset.gross_purchase_amount, 96000)
 		self.assertEqual(asset.opening_accumulated_depreciation, 16000)
-		self.assertEqual(asset.schedules[0].depreciation_amount, 16000)
-		self.assertEqual(asset.schedules[1].depreciation_amount, 16000)
+		self.assertEqual(depr_schedule_of_asset[0].depreciation_amount, 16000)
+		self.assertEqual(depr_schedule_of_asset[1].depreciation_amount, 16000)
 
-		journal_entry = asset.schedules[0].journal_entry
+		journal_entry = depr_schedule_of_asset[0].journal_entry
 
 		jv = frappe.get_doc("Journal Entry", journal_entry)
 		self.assertEqual(jv.accounts[0].credit_in_account_currency, 16000)
@@ -629,7 +669,7 @@
 
 		schedules = [
 			[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
-			for d in asset.get("schedules")
+			for d in get_depr_schedule(asset.name, "Draft")
 		]
 
 		self.assertEqual(schedules, expected_schedules)
@@ -651,7 +691,7 @@
 		expected_schedules = [["2032-12-31", 30000.0, 77095.89], ["2033-06-06", 12904.11, 90000.0]]
 		schedules = [
 			[cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount]
-			for d in asset.get("schedules")
+			for d in get_depr_schedule(asset.name, "Draft")
 		]
 
 		self.assertEqual(schedules, expected_schedules)
@@ -678,7 +718,7 @@
 
 		schedules = [
 			[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
-			for d in asset.get("schedules")
+			for d in get_depr_schedule(asset.name, "Draft")
 		]
 
 		self.assertEqual(schedules, expected_schedules)
@@ -703,7 +743,7 @@
 
 		schedules = [
 			[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
-			for d in asset.get("schedules")
+			for d in get_depr_schedule(asset.name, "Draft")
 		]
 
 		self.assertEqual(schedules, expected_schedules)
@@ -733,7 +773,7 @@
 				flt(d.depreciation_amount, 2),
 				flt(d.accumulated_depreciation_amount, 2),
 			]
-			for d in asset.get("schedules")
+			for d in get_depr_schedule(asset.name, "Draft")
 		]
 
 		self.assertEqual(schedules, expected_schedules)
@@ -765,7 +805,7 @@
 				flt(d.depreciation_amount, 2),
 				flt(d.accumulated_depreciation_amount, 2),
 			]
-			for d in asset.get("schedules")
+			for d in get_depr_schedule(asset.name, "Draft")
 		]
 
 		self.assertEqual(schedules, expected_schedules)
@@ -798,7 +838,7 @@
 				flt(d.depreciation_amount, 2),
 				flt(d.accumulated_depreciation_amount, 2),
 			]
-			for d in asset.get("schedules")
+			for d in get_depr_schedule(asset.name, "Draft")
 		]
 
 		self.assertEqual(schedules, expected_schedules)
@@ -831,7 +871,7 @@
 				flt(d.depreciation_amount, 2),
 				flt(d.accumulated_depreciation_amount, 2),
 			]
-			for d in asset.get("schedules")
+			for d in get_depr_schedule(asset.name, "Draft")
 		]
 		self.assertEqual(schedules, expected_schedules)
 
@@ -854,7 +894,7 @@
 			["2022-12-31", 30000, 90000],
 		]
 
-		for i, schedule in enumerate(asset.schedules):
+		for i, schedule in enumerate(get_depr_schedule(asset.name, "Active")):
 			self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date)
 			self.assertEqual(expected_values[i][1], schedule.depreciation_amount)
 			self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount)
@@ -877,7 +917,7 @@
 			["2023-01-01", 15000, 90000],
 		]
 
-		for i, schedule in enumerate(asset.schedules):
+		for i, schedule in enumerate(get_depr_schedule(asset.name, "Active")):
 			self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date)
 			self.assertEqual(expected_values[i][1], schedule.depreciation_amount)
 			self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount)
@@ -885,7 +925,9 @@
 	def test_get_depreciation_amount(self):
 		"""Tests if get_depreciation_amount() returns the right value."""
 
-		from erpnext.assets.doctype.asset.asset import get_depreciation_amount
+		from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
+			get_depreciation_amount,
+		)
 
 		asset = create_asset(item_code="Macbook Pro", available_for_use_date="2019-12-31")
 
@@ -904,8 +946,8 @@
 		depreciation_amount = get_depreciation_amount(asset, 100000, asset.finance_books[0])
 		self.assertEqual(depreciation_amount, 30000)
 
-	def test_make_depreciation_schedule(self):
-		"""Tests if make_depreciation_schedule() returns the right values."""
+	def test_make_depr_schedule(self):
+		"""Tests if make_depr_schedule() returns the right values."""
 
 		asset = create_asset(
 			item_code="Macbook Pro",
@@ -920,7 +962,7 @@
 
 		expected_values = [["2020-12-31", 30000.0], ["2021-12-31", 30000.0], ["2022-12-31", 30000.0]]
 
-		for i, schedule in enumerate(asset.schedules):
+		for i, schedule in enumerate(get_depr_schedule(asset.name, "Draft")):
 			self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date)
 			self.assertEqual(expected_values[i][1], schedule.depreciation_amount)
 
@@ -940,7 +982,7 @@
 
 		expected_values = [30000.0, 60000.0, 90000.0]
 
-		for i, schedule in enumerate(asset.schedules):
+		for i, schedule in enumerate(get_depr_schedule(asset.name, "Draft")):
 			self.assertEqual(expected_values[i], schedule.accumulated_depreciation_amount)
 
 	def test_check_is_pro_rata(self):
@@ -1120,9 +1162,11 @@
 		post_depreciation_entries(date="2021-06-01")
 		asset.load_from_db()
 
-		self.assertTrue(asset.schedules[0].journal_entry)
-		self.assertFalse(asset.schedules[1].journal_entry)
-		self.assertFalse(asset.schedules[2].journal_entry)
+		depr_schedule = get_depr_schedule(asset.name, "Active")
+
+		self.assertTrue(depr_schedule[0].journal_entry)
+		self.assertFalse(depr_schedule[1].journal_entry)
+		self.assertFalse(depr_schedule[2].journal_entry)
 
 	def test_depr_entry_posting_when_depr_expense_account_is_an_expense_account(self):
 		"""Tests if the Depreciation Expense Account gets debited and the Accumulated Depreciation Account gets credited when the former's an Expense Account."""
@@ -1141,7 +1185,7 @@
 		post_depreciation_entries(date="2021-06-01")
 		asset.load_from_db()
 
-		je = frappe.get_doc("Journal Entry", asset.schedules[0].journal_entry)
+		je = frappe.get_doc("Journal Entry", get_depr_schedule(asset.name, "Active")[0].journal_entry)
 		accounting_entries = [
 			{"account": entry.account, "debit": entry.debit, "credit": entry.credit}
 			for entry in je.accounts
@@ -1177,7 +1221,7 @@
 		post_depreciation_entries(date="2021-06-01")
 		asset.load_from_db()
 
-		je = frappe.get_doc("Journal Entry", asset.schedules[0].journal_entry)
+		je = frappe.get_doc("Journal Entry", get_depr_schedule(asset.name, "Active")[0].journal_entry)
 		accounting_entries = [
 			{"account": entry.account, "debit": entry.debit, "credit": entry.credit}
 			for entry in je.accounts
@@ -1196,8 +1240,8 @@
 		depr_expense_account.parent_account = "Expenses - _TC"
 		depr_expense_account.save()
 
-	def test_clear_depreciation_schedule(self):
-		"""Tests if clear_depreciation_schedule() works as expected."""
+	def test_clear_depr_schedule(self):
+		"""Tests if clear_depr_schedule() works as expected."""
 
 		asset = create_asset(
 			item_code="Macbook Pro",
@@ -1213,17 +1257,20 @@
 		post_depreciation_entries(date="2021-06-01")
 		asset.load_from_db()
 
-		asset.clear_depreciation_schedule()
+		asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset.name, "Active")
 
-		self.assertEqual(len(asset.schedules), 1)
+		clear_depr_schedule(asset_depr_schedule_doc)
 
-	def test_clear_depreciation_schedule_for_multiple_finance_books(self):
+		self.assertEqual(len(asset_depr_schedule_doc.get("depreciation_schedule")), 1)
+
+	def test_clear_depr_schedule_for_multiple_finance_books(self):
 		asset = create_asset(item_code="Macbook Pro", available_for_use_date="2019-12-31", do_not_save=1)
 
 		asset.calculate_depreciation = 1
 		asset.append(
 			"finance_books",
 			{
+				"finance_book": "Test Finance Book 1",
 				"depreciation_method": "Straight Line",
 				"frequency_of_depreciation": 1,
 				"total_number_of_depreciations": 3,
@@ -1234,6 +1281,7 @@
 		asset.append(
 			"finance_books",
 			{
+				"finance_book": "Test Finance Book 2",
 				"depreciation_method": "Straight Line",
 				"frequency_of_depreciation": 1,
 				"total_number_of_depreciations": 6,
@@ -1244,6 +1292,7 @@
 		asset.append(
 			"finance_books",
 			{
+				"finance_book": "Test Finance Book 3",
 				"depreciation_method": "Straight Line",
 				"frequency_of_depreciation": 12,
 				"total_number_of_depreciations": 3,
@@ -1256,15 +1305,23 @@
 		post_depreciation_entries(date="2020-04-01")
 		asset.load_from_db()
 
-		asset.clear_depreciation_schedule()
+		asset_depr_schedule_doc_1 = get_asset_depr_schedule_doc(
+			asset.name, "Active", "Test Finance Book 1"
+		)
+		clear_depr_schedule(asset_depr_schedule_doc_1)
+		self.assertEqual(len(asset_depr_schedule_doc_1.get("depreciation_schedule")), 3)
 
-		self.assertEqual(len(asset.schedules), 6)
+		asset_depr_schedule_doc_2 = get_asset_depr_schedule_doc(
+			asset.name, "Active", "Test Finance Book 2"
+		)
+		clear_depr_schedule(asset_depr_schedule_doc_2)
+		self.assertEqual(len(asset_depr_schedule_doc_2.get("depreciation_schedule")), 3)
 
-		for schedule in asset.schedules:
-			if schedule.idx <= 3:
-				self.assertEqual(schedule.finance_book_id, "1")
-			else:
-				self.assertEqual(schedule.finance_book_id, "2")
+		asset_depr_schedule_doc_3 = get_asset_depr_schedule_doc(
+			asset.name, "Active", "Test Finance Book 3"
+		)
+		clear_depr_schedule(asset_depr_schedule_doc_3)
+		self.assertEqual(len(asset_depr_schedule_doc_3.get("depreciation_schedule")), 0)
 
 	def test_depreciation_schedules_are_set_up_for_multiple_finance_books(self):
 		asset = create_asset(item_code="Macbook Pro", available_for_use_date="2019-12-31", do_not_save=1)
@@ -1273,6 +1330,7 @@
 		asset.append(
 			"finance_books",
 			{
+				"finance_book": "Test Finance Book 1",
 				"depreciation_method": "Straight Line",
 				"frequency_of_depreciation": 12,
 				"total_number_of_depreciations": 3,
@@ -1283,6 +1341,7 @@
 		asset.append(
 			"finance_books",
 			{
+				"finance_book": "Test Finance Book 2",
 				"depreciation_method": "Straight Line",
 				"frequency_of_depreciation": 12,
 				"total_number_of_depreciations": 6,
@@ -1292,13 +1351,15 @@
 		)
 		asset.save()
 
-		self.assertEqual(len(asset.schedules), 9)
+		asset_depr_schedule_doc_1 = get_asset_depr_schedule_doc(
+			asset.name, "Draft", "Test Finance Book 1"
+		)
+		self.assertEqual(len(asset_depr_schedule_doc_1.get("depreciation_schedule")), 3)
 
-		for schedule in asset.schedules:
-			if schedule.idx <= 3:
-				self.assertEqual(schedule.finance_book_id, 1)
-			else:
-				self.assertEqual(schedule.finance_book_id, 2)
+		asset_depr_schedule_doc_2 = get_asset_depr_schedule_doc(
+			asset.name, "Draft", "Test Finance Book 2"
+		)
+		self.assertEqual(len(asset_depr_schedule_doc_2.get("depreciation_schedule")), 6)
 
 	def test_depreciation_entry_cancellation(self):
 		asset = create_asset(
@@ -1318,12 +1379,12 @@
 		asset.load_from_db()
 
 		# cancel depreciation entry
-		depr_entry = asset.get("schedules")[0].journal_entry
+		depr_entry = get_depr_schedule(asset.name, "Active")[0].journal_entry
 		self.assertTrue(depr_entry)
+
 		frappe.get_doc("Journal Entry", depr_entry).cancel()
 
-		asset.load_from_db()
-		depr_entry = asset.get("schedules")[0].journal_entry
+		depr_entry = get_depr_schedule(asset.name, "Active")[0].journal_entry
 		self.assertFalse(depr_entry)
 
 	def test_asset_expected_value_after_useful_life(self):
@@ -1338,7 +1399,7 @@
 		)
 
 		accumulated_depreciation_after_full_schedule = max(
-			d.accumulated_depreciation_amount for d in asset.get("schedules")
+			d.accumulated_depreciation_amount for d in get_depr_schedule(asset.name, "Draft")
 		)
 
 		asset_value_after_full_schedule = flt(asset.gross_purchase_amount) - flt(
@@ -1369,7 +1430,7 @@
 		asset.load_from_db()
 
 		# check depreciation entry series
-		self.assertEqual(asset.get("schedules")[0].journal_entry[:4], "DEPR")
+		self.assertEqual(get_depr_schedule(asset.name, "Active")[0].journal_entry[:4], "DEPR")
 
 		expected_gle = (
 			("_Test Accumulated Depreciations - _TC", 0.0, 30000.0),
@@ -1439,7 +1500,7 @@
 			"2020-07-15",
 		]
 
-		for i, schedule in enumerate(asset.schedules):
+		for i, schedule in enumerate(get_depr_schedule(asset.name, "Active")):
 			self.assertEqual(getdate(expected_dates[i]), getdate(schedule.schedule_date))
 
 
@@ -1453,6 +1514,15 @@
 	if not frappe.db.exists("Location", "Test Location"):
 		frappe.get_doc({"doctype": "Location", "location_name": "Test Location"}).insert()
 
+	if not frappe.db.exists("Finance Book", "Test Finance Book 1"):
+		frappe.get_doc({"doctype": "Finance Book", "finance_book_name": "Test Finance Book 1"}).insert()
+
+	if not frappe.db.exists("Finance Book", "Test Finance Book 2"):
+		frappe.get_doc({"doctype": "Finance Book", "finance_book_name": "Test Finance Book 2"}).insert()
+
+	if not frappe.db.exists("Finance Book", "Test Finance Book 3"):
+		frappe.get_doc({"doctype": "Finance Book", "finance_book_name": "Test Finance Book 3"}).insert()
+
 
 def create_asset(**args):
 	args = frappe._dict(args)
diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
index 08355f0..7d3b645 100644
--- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
+++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
@@ -7,7 +7,7 @@
 
 # import erpnext
 from frappe import _
-from frappe.utils import cint, flt
+from frappe.utils import cint, flt, get_link_to_form
 from six import string_types
 
 import erpnext
@@ -19,6 +19,9 @@
 	reverse_depreciation_entry_made_after_disposal,
 )
 from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
+from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
+	make_new_active_asset_depr_schedules_and_cancel_current_ones,
+)
 from erpnext.assets.doctype.asset_value_adjustment.asset_value_adjustment import (
 	get_current_asset_value,
 )
@@ -427,7 +430,12 @@
 			asset = self.get_asset(item)
 
 			if asset.calculate_depreciation:
-				depreciate_asset(asset, self.posting_date)
+				notes = _(
+					"This schedule was created when Asset {0} was consumed when Asset Capitalization {1} was submitted."
+				).format(
+					get_link_to_form(asset.doctype, asset.name), get_link_to_form(self.doctype, self.get("name"))
+				)
+				depreciate_asset(asset, self.posting_date, notes)
 				asset.reload()
 
 			fixed_asset_gl_entries = get_gl_entries_on_asset_disposal(
@@ -513,7 +521,12 @@
 			asset_doc.purchase_date = self.posting_date
 			asset_doc.gross_purchase_amount = total_target_asset_value
 			asset_doc.purchase_receipt_amount = total_target_asset_value
-			asset_doc.prepare_depreciation_data()
+			notes = _(
+				"This schedule was created when target Asset {0} was updated when Asset Capitalization {1} was submitted."
+			).format(
+				get_link_to_form(asset_doc.doctype, asset_doc.name), get_link_to_form(self.doctype, self.name)
+			)
+			make_new_active_asset_depr_schedules_and_cancel_current_ones(asset_doc, notes)
 			asset_doc.flags.ignore_validate_update_after_submit = True
 			asset_doc.save()
 		elif self.docstatus == 2:
@@ -524,7 +537,12 @@
 
 				if asset.calculate_depreciation:
 					reverse_depreciation_entry_made_after_disposal(asset, self.posting_date)
-					reset_depreciation_schedule(asset, self.posting_date)
+					notes = _(
+						"This schedule was created when Asset {0} was restored when Asset Capitalization {1} was cancelled."
+					).format(
+						get_link_to_form(asset.doctype, asset.name), get_link_to_form(self.doctype, self.name)
+					)
+					reset_depreciation_schedule(asset, self.posting_date, notes)
 
 	def get_asset(self, item):
 		asset = frappe.get_doc("Asset", item.asset)
diff --git a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py
index 86861f0..4d519a6 100644
--- a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py
+++ b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py
@@ -12,6 +12,9 @@
 	create_asset_data,
 	set_depreciation_settings_in_company,
 )
+from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
+	get_asset_depr_schedule_doc,
+)
 from erpnext.stock.doctype.item.test_item import create_item
 
 
@@ -253,6 +256,9 @@
 			submit=1,
 		)
 
+		first_asset_depr_schedule = get_asset_depr_schedule_doc(consumed_asset.name, "Active")
+		self.assertEquals(first_asset_depr_schedule.status, "Active")
+
 		# Create and submit Asset Captitalization
 		asset_capitalization = create_asset_capitalization(
 			entry_type="Decapitalization",
@@ -282,8 +288,18 @@
 		consumed_asset.reload()
 		self.assertEqual(consumed_asset.status, "Decapitalized")
 
+		first_asset_depr_schedule.load_from_db()
+
+		second_asset_depr_schedule = get_asset_depr_schedule_doc(consumed_asset.name, "Active")
+		self.assertEquals(second_asset_depr_schedule.status, "Active")
+		self.assertEquals(first_asset_depr_schedule.status, "Cancelled")
+
+		depr_schedule_of_consumed_asset = second_asset_depr_schedule.get("depreciation_schedule")
+
 		consumed_depreciation_schedule = [
-			d for d in consumed_asset.schedules if getdate(d.schedule_date) == getdate(capitalization_date)
+			d
+			for d in depr_schedule_of_consumed_asset
+			if getdate(d.schedule_date) == getdate(capitalization_date)
 		]
 		self.assertTrue(
 			consumed_depreciation_schedule and consumed_depreciation_schedule[0].journal_entry
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/__init__.py b/erpnext/assets/doctype/asset_depreciation_schedule/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/__init__.py
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js
new file mode 100644
index 0000000..c28b2b3
--- /dev/null
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.js
@@ -0,0 +1,51 @@
+// Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+frappe.provide("erpnext.asset");
+
+frappe.ui.form.on('Asset Depreciation Schedule', {
+	onload: function(frm) {
+		frm.events.make_schedules_editable(frm);
+	},
+
+	make_schedules_editable: function(frm) {
+		var is_editable = frm.doc.depreciation_method == "Manual" ? true : false;
+
+		frm.toggle_enable("depreciation_schedule", is_editable);
+		frm.fields_dict["depreciation_schedule"].grid.toggle_enable("schedule_date", is_editable);
+		frm.fields_dict["depreciation_schedule"].grid.toggle_enable("depreciation_amount", is_editable);
+	}
+});
+
+frappe.ui.form.on('Depreciation Schedule', {
+	make_depreciation_entry: function(frm, cdt, cdn) {
+		var row = locals[cdt][cdn];
+		if (!row.journal_entry) {
+			frappe.call({
+				method: "erpnext.assets.doctype.asset.depreciation.make_depreciation_entry",
+				args: {
+					"asset_depr_schedule_name": frm.doc.name,
+					"date": row.schedule_date
+				},
+				callback: function(r) {
+					frappe.model.sync(r.message);
+					frm.refresh();
+				}
+			})
+		}
+	},
+
+	depreciation_amount: function(frm, cdt, cdn) {
+		erpnext.asset.set_accumulated_depreciation(frm);
+	}
+});
+
+erpnext.asset.set_accumulated_depreciation = function(frm) {
+	if(frm.doc.depreciation_method != "Manual") return;
+
+	var accumulated_depreciation = flt(frm.doc.opening_accumulated_depreciation);
+	$.each(frm.doc.schedules || [], function(i, row) {
+		accumulated_depreciation  += flt(row.depreciation_amount);
+		frappe.model.set_value(row.doctype, row.name,
+			"accumulated_depreciation_amount", accumulated_depreciation);
+	})
+};
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json
new file mode 100644
index 0000000..af09cda
--- /dev/null
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json
@@ -0,0 +1,202 @@
+{
+ "actions": [],
+ "allow_rename": 1,
+ "autoname": "naming_series:",
+ "creation": "2022-10-31 15:03:35.424877",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "asset",
+  "naming_series",
+  "column_break_2",
+  "opening_accumulated_depreciation",
+  "finance_book",
+  "finance_book_id",
+  "depreciation_details_section",
+  "depreciation_method",
+  "total_number_of_depreciations",
+  "rate_of_depreciation",
+  "column_break_8",
+  "frequency_of_depreciation",
+  "expected_value_after_useful_life",
+  "depreciation_schedule_section",
+  "depreciation_schedule",
+  "details_section",
+  "notes",
+  "status",
+  "amended_from"
+ ],
+ "fields": [
+  {
+   "fieldname": "asset",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Asset",
+   "options": "Asset",
+   "reqd": 1
+  },
+  {
+   "fieldname": "naming_series",
+   "fieldtype": "Select",
+   "label": "Naming Series",
+   "options": "ACC-ADS-.YYYY.-"
+  },
+  {
+   "fieldname": "amended_from",
+   "fieldtype": "Link",
+   "label": "Amended From",
+   "no_copy": 1,
+   "options": "Asset Depreciation Schedule",
+   "print_hide": 1,
+   "read_only": 1
+  },
+  {
+   "fieldname": "column_break_2",
+   "fieldtype": "Column Break"
+  },
+  {
+   "collapsible": 1,
+   "fieldname": "depreciation_details_section",
+   "fieldtype": "Section Break",
+   "label": "Depreciation Details"
+  },
+  {
+   "fieldname": "finance_book",
+   "fieldtype": "Link",
+   "label": "Finance Book",
+   "options": "Finance Book"
+  },
+  {
+   "fieldname": "depreciation_method",
+   "fieldtype": "Select",
+   "label": "Depreciation Method",
+   "options": "\nStraight Line\nDouble Declining Balance\nWritten Down Value\nManual",
+   "read_only": 1
+  },
+  {
+   "depends_on": "eval:doc.depreciation_method == 'Written Down Value'",
+   "description": "In Percentage",
+   "fieldname": "rate_of_depreciation",
+   "fieldtype": "Percent",
+   "label": "Rate of Depreciation",
+   "read_only": 1
+  },
+  {
+   "fieldname": "column_break_8",
+   "fieldtype": "Column Break"
+  },
+  {
+   "depends_on": "total_number_of_depreciations",
+   "fieldname": "total_number_of_depreciations",
+   "fieldtype": "Int",
+   "label": "Total Number of Depreciations",
+   "read_only": 1
+  },
+  {
+   "fieldname": "depreciation_schedule_section",
+   "fieldtype": "Section Break",
+   "label": "Depreciation Schedule"
+  },
+  {
+   "fieldname": "depreciation_schedule",
+   "fieldtype": "Table",
+   "label": "Depreciation Schedule",
+   "options": "Depreciation Schedule"
+  },
+  {
+   "collapsible": 1,
+   "collapsible_depends_on": "notes",
+   "fieldname": "details_section",
+   "fieldtype": "Section Break",
+   "label": "Details"
+  },
+  {
+   "fieldname": "notes",
+   "fieldtype": "Small Text",
+   "label": "Notes",
+   "read_only": 1
+  },
+  {
+   "fieldname": "status",
+   "fieldtype": "Select",
+   "hidden": 1,
+   "label": "Status",
+   "options": "Draft\nActive\nCancelled",
+   "read_only": 1
+  },
+  {
+   "depends_on": "frequency_of_depreciation",
+   "fieldname": "frequency_of_depreciation",
+   "fieldtype": "Int",
+   "label": "Frequency of Depreciation (Months)",
+   "read_only": 1
+  },
+  {
+   "fieldname": "expected_value_after_useful_life",
+   "fieldtype": "Currency",
+   "label": "Expected Value After Useful Life",
+   "options": "Company:company:default_currency",
+   "read_only": 1
+  },
+  {
+   "fieldname": "finance_book_id",
+   "fieldtype": "Int",
+   "hidden": 1,
+   "label": "Finance Book Id",
+   "print_hide": 1,
+   "read_only": 1
+  },
+  {
+   "depends_on": "opening_accumulated_depreciation",
+   "fieldname": "opening_accumulated_depreciation",
+   "fieldtype": "Currency",
+   "label": "Opening Accumulated Depreciation",
+   "options": "Company:company:default_currency",
+   "read_only": 1
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2023-01-02 15:38:30.766779",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Asset Depreciation Schedule",
+ "naming_rule": "By \"Naming Series\" field",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "amend": 1,
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Accounts User",
+   "share": 1,
+   "submit": 1,
+   "write": 1
+  },
+  {
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Quality Manager",
+   "share": 1,
+   "submit": 1,
+   "write": 1
+  }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": []
+}
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
new file mode 100644
index 0000000..1446a6e
--- /dev/null
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
@@ -0,0 +1,516 @@
+# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+import frappe
+from frappe import _
+from frappe.model.document import Document
+from frappe.utils import (
+	add_days,
+	add_months,
+	cint,
+	date_diff,
+	flt,
+	get_last_day,
+	is_last_day_of_the_month,
+)
+
+import erpnext
+
+
+class AssetDepreciationSchedule(Document):
+	def before_save(self):
+		if not self.finance_book_id:
+			self.prepare_draft_asset_depr_schedule_data_from_asset_name_and_fb_name(
+				self.asset, self.finance_book
+			)
+
+	def validate(self):
+		self.validate_another_asset_depr_schedule_does_not_exist()
+
+	def validate_another_asset_depr_schedule_does_not_exist(self):
+		finance_book_filter = ["finance_book", "is", "not set"]
+		if self.finance_book:
+			finance_book_filter = ["finance_book", "=", self.finance_book]
+
+		asset_depr_schedule = frappe.db.exists(
+			"Asset Depreciation Schedule",
+			[
+				["asset", "=", self.asset],
+				finance_book_filter,
+				["docstatus", "<", 2],
+			],
+		)
+
+		if asset_depr_schedule and asset_depr_schedule != self.name:
+			if self.finance_book:
+				frappe.throw(
+					_(
+						"Asset Depreciation Schedule {0} for Asset {1} and Finance Book {2} already exists."
+					).format(asset_depr_schedule, self.asset, self.finance_book)
+				)
+			else:
+				frappe.throw(
+					_("Asset Depreciation Schedule {0} for Asset {1} already exists.").format(
+						asset_depr_schedule, self.asset
+					)
+				)
+
+	def on_submit(self):
+		self.db_set("status", "Active")
+
+	def before_cancel(self):
+		if not self.flags.should_not_cancel_depreciation_entries:
+			self.cancel_depreciation_entries()
+
+	def cancel_depreciation_entries(self):
+		for d in self.get("depreciation_schedule"):
+			if d.journal_entry:
+				frappe.get_doc("Journal Entry", d.journal_entry).cancel()
+
+	def on_cancel(self):
+		self.db_set("status", "Cancelled")
+
+	def prepare_draft_asset_depr_schedule_data_from_asset_name_and_fb_name(self, asset_name, fb_name):
+		asset_doc = frappe.get_doc("Asset", asset_name)
+
+		finance_book_filter = ["finance_book", "is", "not set"]
+		if fb_name:
+			finance_book_filter = ["finance_book", "=", fb_name]
+
+		asset_finance_book_name = frappe.db.get_value(
+			doctype="Asset Finance Book",
+			filters=[["parent", "=", asset_name], finance_book_filter],
+		)
+		asset_finance_book_doc = frappe.get_doc("Asset Finance Book", asset_finance_book_name)
+
+		prepare_draft_asset_depr_schedule_data(self, asset_doc, asset_finance_book_doc)
+
+
+def make_draft_asset_depr_schedules_if_not_present(asset_doc):
+	for row in asset_doc.get("finance_books"):
+		draft_asset_depr_schedule_name = get_asset_depr_schedule_name(
+			asset_doc.name, "Draft", row.finance_book
+		)
+
+		active_asset_depr_schedule_name = get_asset_depr_schedule_name(
+			asset_doc.name, "Active", row.finance_book
+		)
+
+		if not draft_asset_depr_schedule_name and not active_asset_depr_schedule_name:
+			make_draft_asset_depr_schedule(asset_doc, row)
+
+
+def make_draft_asset_depr_schedules(asset_doc):
+	for row in asset_doc.get("finance_books"):
+		make_draft_asset_depr_schedule(asset_doc, row)
+
+
+def make_draft_asset_depr_schedule(asset_doc, row):
+	asset_depr_schedule_doc = frappe.new_doc("Asset Depreciation Schedule")
+
+	prepare_draft_asset_depr_schedule_data(asset_depr_schedule_doc, asset_doc, row)
+
+	asset_depr_schedule_doc.insert()
+
+
+def update_draft_asset_depr_schedules(asset_doc):
+	for row in asset_doc.get("finance_books"):
+		asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_doc.name, "Draft", row.finance_book)
+
+		if not asset_depr_schedule_doc:
+			continue
+
+		prepare_draft_asset_depr_schedule_data(asset_depr_schedule_doc, asset_doc, row)
+
+		asset_depr_schedule_doc.save()
+
+
+def prepare_draft_asset_depr_schedule_data(
+	asset_depr_schedule_doc,
+	asset_doc,
+	row,
+	date_of_disposal=None,
+	date_of_return=None,
+	update_asset_finance_book_row=True,
+):
+	set_draft_asset_depr_schedule_details(asset_depr_schedule_doc, asset_doc, row)
+	make_depr_schedule(
+		asset_depr_schedule_doc, asset_doc, row, date_of_disposal, update_asset_finance_book_row
+	)
+	set_accumulated_depreciation(asset_depr_schedule_doc, row, date_of_disposal, date_of_return)
+
+
+def set_draft_asset_depr_schedule_details(asset_depr_schedule_doc, asset_doc, row):
+	asset_depr_schedule_doc.asset = asset_doc.name
+	asset_depr_schedule_doc.finance_book = row.finance_book
+	asset_depr_schedule_doc.finance_book_id = row.idx
+	asset_depr_schedule_doc.opening_accumulated_depreciation = (
+		asset_doc.opening_accumulated_depreciation
+	)
+	asset_depr_schedule_doc.depreciation_method = row.depreciation_method
+	asset_depr_schedule_doc.total_number_of_depreciations = row.total_number_of_depreciations
+	asset_depr_schedule_doc.frequency_of_depreciation = row.frequency_of_depreciation
+	asset_depr_schedule_doc.rate_of_depreciation = row.rate_of_depreciation
+	asset_depr_schedule_doc.expected_value_after_useful_life = row.expected_value_after_useful_life
+	asset_depr_schedule_doc.status = "Draft"
+
+
+def convert_draft_asset_depr_schedules_into_active(asset_doc):
+	for row in asset_doc.get("finance_books"):
+		asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_doc.name, "Draft", row.finance_book)
+
+		if not asset_depr_schedule_doc:
+			continue
+
+		asset_depr_schedule_doc.submit()
+
+
+def cancel_asset_depr_schedules(asset_doc):
+	for row in asset_doc.get("finance_books"):
+		asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_doc.name, "Active", row.finance_book)
+
+		if not asset_depr_schedule_doc:
+			continue
+
+		asset_depr_schedule_doc.cancel()
+
+
+def make_new_active_asset_depr_schedules_and_cancel_current_ones(
+	asset_doc, notes, date_of_disposal=None, date_of_return=None
+):
+	for row in asset_doc.get("finance_books"):
+		current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(
+			asset_doc.name, "Active", row.finance_book
+		)
+
+		if not current_asset_depr_schedule_doc:
+			frappe.throw(
+				_("Asset Depreciation Schedule not found for Asset {0} and Finance Book {1}").format(
+					asset_doc.name, row.finance_book
+				)
+			)
+
+		new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc)
+
+		make_depr_schedule(new_asset_depr_schedule_doc, asset_doc, row, date_of_disposal)
+		set_accumulated_depreciation(new_asset_depr_schedule_doc, row, date_of_disposal, date_of_return)
+
+		new_asset_depr_schedule_doc.notes = notes
+
+		current_asset_depr_schedule_doc.flags.should_not_cancel_depreciation_entries = True
+		current_asset_depr_schedule_doc.cancel()
+
+		new_asset_depr_schedule_doc.submit()
+
+
+def get_temp_asset_depr_schedule_doc(
+	asset_doc, row, date_of_disposal=None, date_of_return=None, update_asset_finance_book_row=False
+):
+	asset_depr_schedule_doc = frappe.new_doc("Asset Depreciation Schedule")
+
+	prepare_draft_asset_depr_schedule_data(
+		asset_depr_schedule_doc,
+		asset_doc,
+		row,
+		date_of_disposal,
+		date_of_return,
+		update_asset_finance_book_row,
+	)
+
+	return asset_depr_schedule_doc
+
+
+def get_asset_depr_schedule_name(asset_name, status, finance_book=None):
+	finance_book_filter = ["finance_book", "is", "not set"]
+	if finance_book:
+		finance_book_filter = ["finance_book", "=", finance_book]
+
+	return frappe.db.get_value(
+		doctype="Asset Depreciation Schedule",
+		filters=[
+			["asset", "=", asset_name],
+			finance_book_filter,
+			["status", "=", status],
+		],
+	)
+
+
+@frappe.whitelist()
+def get_depr_schedule(asset_name, status, finance_book=None):
+	asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset_name, status, finance_book)
+
+	if not asset_depr_schedule_doc:
+		return
+
+	return asset_depr_schedule_doc.get("depreciation_schedule")
+
+
+def get_asset_depr_schedule_doc(asset_name, status, finance_book=None):
+	asset_depr_schedule_name = get_asset_depr_schedule_name(asset_name, status, finance_book)
+
+	if not asset_depr_schedule_name:
+		return
+
+	asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name)
+
+	return asset_depr_schedule_doc
+
+
+def make_depr_schedule(
+	asset_depr_schedule_doc, asset_doc, row, date_of_disposal, update_asset_finance_book_row=True
+):
+	if row.depreciation_method != "Manual" and not asset_depr_schedule_doc.get(
+		"depreciation_schedule"
+	):
+		asset_depr_schedule_doc.depreciation_schedule = []
+
+	if not asset_doc.available_for_use_date:
+		return
+
+	start = clear_depr_schedule(asset_depr_schedule_doc)
+
+	_make_depr_schedule(
+		asset_depr_schedule_doc, asset_doc, row, start, date_of_disposal, update_asset_finance_book_row
+	)
+
+
+def clear_depr_schedule(asset_depr_schedule_doc):
+	start = 0
+	num_of_depreciations_completed = 0
+	depr_schedule = []
+
+	for schedule in asset_depr_schedule_doc.get("depreciation_schedule"):
+		if schedule.journal_entry:
+			num_of_depreciations_completed += 1
+			depr_schedule.append(schedule)
+		else:
+			start = num_of_depreciations_completed
+			break
+
+	asset_depr_schedule_doc.depreciation_schedule = depr_schedule
+
+	return start
+
+
+def _make_depr_schedule(
+	asset_depr_schedule_doc, asset_doc, row, start, date_of_disposal, update_asset_finance_book_row
+):
+	asset_doc.validate_asset_finance_books(row)
+
+	value_after_depreciation = asset_doc._get_value_after_depreciation(row)
+	row.value_after_depreciation = value_after_depreciation
+
+	if update_asset_finance_book_row:
+		row.db_update()
+
+	number_of_pending_depreciations = cint(row.total_number_of_depreciations) - cint(
+		asset_doc.number_of_depreciations_booked
+	)
+
+	has_pro_rata = asset_doc.check_is_pro_rata(row)
+	if has_pro_rata:
+		number_of_pending_depreciations += 1
+
+	skip_row = False
+	should_get_last_day = is_last_day_of_the_month(row.depreciation_start_date)
+
+	for n in range(start, number_of_pending_depreciations):
+		# If depreciation is already completed (for double declining balance)
+		if skip_row:
+			continue
+
+		depreciation_amount = get_depreciation_amount(asset_doc, value_after_depreciation, row)
+
+		if not has_pro_rata or n < cint(number_of_pending_depreciations) - 1:
+			schedule_date = add_months(row.depreciation_start_date, n * cint(row.frequency_of_depreciation))
+
+			if should_get_last_day:
+				schedule_date = get_last_day(schedule_date)
+
+			# schedule date will be a year later from start date
+			# so monthly schedule date is calculated by removing 11 months from it
+			monthly_schedule_date = add_months(schedule_date, -row.frequency_of_depreciation + 1)
+
+		# if asset is being sold or scrapped
+		if date_of_disposal:
+			from_date = asset_doc.available_for_use_date
+			if asset_depr_schedule_doc.depreciation_schedule:
+				from_date = asset_depr_schedule_doc.depreciation_schedule[-1].schedule_date
+
+			depreciation_amount, days, months = asset_doc.get_pro_rata_amt(
+				row, depreciation_amount, from_date, date_of_disposal
+			)
+
+			if depreciation_amount > 0:
+				add_depr_schedule_row(
+					asset_depr_schedule_doc,
+					date_of_disposal,
+					depreciation_amount,
+					row.depreciation_method,
+				)
+
+			break
+
+		# For first row
+		if has_pro_rata and not asset_doc.opening_accumulated_depreciation and n == 0:
+			from_date = add_days(
+				asset_doc.available_for_use_date, -1
+			)  # needed to calc depr amount for available_for_use_date too
+			depreciation_amount, days, months = asset_doc.get_pro_rata_amt(
+				row, depreciation_amount, from_date, row.depreciation_start_date
+			)
+
+			# For first depr schedule date will be the start date
+			# so monthly schedule date is calculated by removing
+			# month difference between use date and start date
+			monthly_schedule_date = add_months(row.depreciation_start_date, -months + 1)
+
+		# For last row
+		elif has_pro_rata and n == cint(number_of_pending_depreciations) - 1:
+			if not asset_doc.flags.increase_in_asset_life:
+				# In case of increase_in_asset_life, the asset.to_date is already set on asset_repair submission
+				asset_doc.to_date = add_months(
+					asset_doc.available_for_use_date,
+					(n + asset_doc.number_of_depreciations_booked) * cint(row.frequency_of_depreciation),
+				)
+
+			depreciation_amount_without_pro_rata = depreciation_amount
+
+			depreciation_amount, days, months = asset_doc.get_pro_rata_amt(
+				row, depreciation_amount, schedule_date, asset_doc.to_date
+			)
+
+			depreciation_amount = get_adjusted_depreciation_amount(
+				asset_depr_schedule_doc, depreciation_amount_without_pro_rata, depreciation_amount
+			)
+
+			monthly_schedule_date = add_months(schedule_date, 1)
+			schedule_date = add_days(schedule_date, days)
+			last_schedule_date = schedule_date
+
+		if not depreciation_amount:
+			continue
+		value_after_depreciation -= flt(
+			depreciation_amount, asset_doc.precision("gross_purchase_amount")
+		)
+
+		# Adjust depreciation amount in the last period based on the expected value after useful life
+		if row.expected_value_after_useful_life and (
+			(
+				n == cint(number_of_pending_depreciations) - 1
+				and value_after_depreciation != row.expected_value_after_useful_life
+			)
+			or value_after_depreciation < row.expected_value_after_useful_life
+		):
+			depreciation_amount += value_after_depreciation - row.expected_value_after_useful_life
+			skip_row = True
+
+		if depreciation_amount > 0:
+			add_depr_schedule_row(
+				asset_depr_schedule_doc,
+				schedule_date,
+				depreciation_amount,
+				row.depreciation_method,
+			)
+
+
+# to ensure that final accumulated depreciation amount is accurate
+def get_adjusted_depreciation_amount(
+	asset_depr_schedule_doc, depreciation_amount_without_pro_rata, depreciation_amount_for_last_row
+):
+	if not asset_depr_schedule_doc.opening_accumulated_depreciation:
+		depreciation_amount_for_first_row = get_depreciation_amount_for_first_row(
+			asset_depr_schedule_doc
+		)
+
+		if (
+			depreciation_amount_for_first_row + depreciation_amount_for_last_row
+			!= depreciation_amount_without_pro_rata
+		):
+			depreciation_amount_for_last_row = (
+				depreciation_amount_without_pro_rata - depreciation_amount_for_first_row
+			)
+
+	return depreciation_amount_for_last_row
+
+
+def get_depreciation_amount_for_first_row(asset_depr_schedule_doc):
+	return asset_depr_schedule_doc.get("depreciation_schedule")[0].depreciation_amount
+
+
+@erpnext.allow_regional
+def get_depreciation_amount(asset_doc, depreciable_value, row):
+	if row.depreciation_method in ("Straight Line", "Manual"):
+		# if the Depreciation Schedule is being prepared for the first time
+		if not asset_doc.flags.increase_in_asset_life:
+			depreciation_amount = (
+				flt(asset_doc.gross_purchase_amount) - flt(row.expected_value_after_useful_life)
+			) / flt(row.total_number_of_depreciations)
+
+		# if the Depreciation Schedule is being modified after Asset Repair
+		else:
+			depreciation_amount = (
+				flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)
+			) / (date_diff(asset_doc.to_date, asset_doc.available_for_use_date) / 365)
+	else:
+		depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100))
+
+	return depreciation_amount
+
+
+def add_depr_schedule_row(
+	asset_depr_schedule_doc,
+	schedule_date,
+	depreciation_amount,
+	depreciation_method,
+):
+	asset_depr_schedule_doc.append(
+		"depreciation_schedule",
+		{
+			"schedule_date": schedule_date,
+			"depreciation_amount": depreciation_amount,
+			"depreciation_method": depreciation_method,
+		},
+	)
+
+
+def set_accumulated_depreciation(
+	asset_depr_schedule_doc,
+	row,
+	date_of_disposal=None,
+	date_of_return=None,
+	ignore_booked_entry=False,
+):
+	straight_line_idx = [
+		d.idx
+		for d in asset_depr_schedule_doc.get("depreciation_schedule")
+		if d.depreciation_method == "Straight Line"
+	]
+
+	accumulated_depreciation = flt(asset_depr_schedule_doc.opening_accumulated_depreciation)
+	value_after_depreciation = flt(row.value_after_depreciation)
+
+	for i, d in enumerate(asset_depr_schedule_doc.get("depreciation_schedule")):
+		if ignore_booked_entry and d.journal_entry:
+			continue
+
+		depreciation_amount = flt(d.depreciation_amount, d.precision("depreciation_amount"))
+		value_after_depreciation -= flt(depreciation_amount)
+
+		# for the last row, if depreciation method = Straight Line
+		if (
+			straight_line_idx
+			and i == max(straight_line_idx) - 1
+			and not date_of_disposal
+			and not date_of_return
+		):
+			depreciation_amount += flt(
+				value_after_depreciation - flt(row.expected_value_after_useful_life),
+				d.precision("depreciation_amount"),
+			)
+
+		d.depreciation_amount = depreciation_amount
+		accumulated_depreciation += d.depreciation_amount
+		d.accumulated_depreciation_amount = flt(
+			accumulated_depreciation, d.precision("accumulated_depreciation_amount")
+		)
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py
new file mode 100644
index 0000000..024121d
--- /dev/null
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py
@@ -0,0 +1,27 @@
+# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+import frappe
+from frappe.tests.utils import FrappeTestCase
+
+from erpnext.assets.doctype.asset.test_asset import create_asset, create_asset_data
+from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
+	get_asset_depr_schedule_doc,
+)
+
+
+class TestAssetDepreciationSchedule(FrappeTestCase):
+	def setUp(self):
+		create_asset_data()
+
+	def test_throw_error_if_another_asset_depr_schedule_exist(self):
+		asset = create_asset(item_code="Macbook Pro", calculate_depreciation=1, submit=1)
+
+		first_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
+		self.assertEquals(first_asset_depr_schedule.status, "Active")
+
+		second_asset_depr_schedule = frappe.get_doc(
+			{"doctype": "Asset Depreciation Schedule", "asset": asset.name, "finance_book": None}
+		)
+
+		self.assertRaises(frappe.ValidationError, second_asset_depr_schedule.insert)
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index d5913c5..b8cd115 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -3,11 +3,15 @@
 
 import frappe
 from frappe import _
-from frappe.utils import add_months, cint, flt, getdate, time_diff_in_hours
+from frappe.utils import add_months, cint, flt, get_link_to_form, getdate, time_diff_in_hours
 
 import erpnext
 from erpnext.accounts.general_ledger import make_gl_entries
 from erpnext.assets.doctype.asset.asset import get_asset_account
+from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
+	get_depr_schedule,
+	make_new_active_asset_depr_schedules_and_cancel_current_ones,
+)
 from erpnext.controllers.accounts_controller import AccountsController
 
 
@@ -52,8 +56,11 @@
 			):
 				self.modify_depreciation_schedule()
 
+		notes = _("This schedule was created when Asset Repair {0} was submitted.").format(
+			get_link_to_form(self.doctype, self.name)
+		)
 		self.asset_doc.flags.ignore_validate_update_after_submit = True
-		self.asset_doc.prepare_depreciation_data()
+		make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, notes)
 		self.asset_doc.save()
 
 	def before_cancel(self):
@@ -73,8 +80,11 @@
 			):
 				self.revert_depreciation_schedule_on_cancellation()
 
+		notes = _("This schedule was created when Asset Repair {0} was cancelled.").format(
+			get_link_to_form(self.doctype, self.name)
+		)
 		self.asset_doc.flags.ignore_validate_update_after_submit = True
-		self.asset_doc.prepare_depreciation_data()
+		make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, notes)
 		self.asset_doc.save()
 
 	def check_repair_status(self):
@@ -279,8 +289,10 @@
 			asset.number_of_depreciations_booked
 		)
 
+		depr_schedule = get_depr_schedule(asset.name, "Active", row.finance_book)
+
 		# the Schedule Date in the final row of the old Depreciation Schedule
-		last_schedule_date = asset.schedules[len(asset.schedules) - 1].schedule_date
+		last_schedule_date = depr_schedule[len(depr_schedule) - 1].schedule_date
 
 		# the Schedule Date in the final row of the new Depreciation Schedule
 		asset.to_date = add_months(last_schedule_date, extra_months)
@@ -310,8 +322,10 @@
 			asset.number_of_depreciations_booked
 		)
 
+		depr_schedule = get_depr_schedule(asset.name, "Active", row.finance_book)
+
 		# the Schedule Date in the final row of the modified Depreciation Schedule
-		last_schedule_date = asset.schedules[len(asset.schedules) - 1].schedule_date
+		last_schedule_date = depr_schedule[len(depr_schedule) - 1].schedule_date
 
 		# the Schedule Date in the final row of the original Depreciation Schedule
 		asset.to_date = add_months(last_schedule_date, -extra_months)
diff --git a/erpnext/assets/doctype/asset_repair/test_asset_repair.py b/erpnext/assets/doctype/asset_repair/test_asset_repair.py
index 6e06f52..ff72aa9 100644
--- a/erpnext/assets/doctype/asset_repair/test_asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/test_asset_repair.py
@@ -12,6 +12,9 @@
 	create_asset_data,
 	set_depreciation_settings_in_company,
 )
+from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
+	get_asset_depr_schedule_doc,
+)
 from erpnext.stock.doctype.item.test_item import create_item
 
 
@@ -232,13 +235,23 @@
 
 	def test_increase_in_asset_life(self):
 		asset = create_asset(calculate_depreciation=1, submit=1)
+
+		first_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
+		self.assertEquals(first_asset_depr_schedule.status, "Active")
+
 		initial_num_of_depreciations = num_of_depreciations(asset)
 		create_asset_repair(asset=asset, capitalize_repair_cost=1, submit=1)
+
 		asset.reload()
+		first_asset_depr_schedule.load_from_db()
+
+		second_asset_depr_schedule = get_asset_depr_schedule_doc(asset.name, "Active")
+		self.assertEquals(second_asset_depr_schedule.status, "Active")
+		self.assertEquals(first_asset_depr_schedule.status, "Cancelled")
 
 		self.assertEqual((initial_num_of_depreciations + 1), num_of_depreciations(asset))
 		self.assertEqual(
-			asset.schedules[-1].accumulated_depreciation_amount,
+			second_asset_depr_schedule.get("depreciation_schedule")[-1].accumulated_depreciation_amount,
 			asset.finance_books[0].value_after_depreciation,
 		)
 
diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py
index 84aa8fa..262d552 100644
--- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py
+++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py
@@ -5,13 +5,17 @@
 import frappe
 from frappe import _
 from frappe.model.document import Document
-from frappe.utils import cint, date_diff, flt, formatdate, getdate
+from frappe.utils import date_diff, flt, formatdate, get_link_to_form, getdate
 
 from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
 	get_checks_for_pl_and_bs_accounts,
 )
-from erpnext.assets.doctype.asset.asset import get_depreciation_amount
 from erpnext.assets.doctype.asset.depreciation import get_depreciation_accounts
+from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
+	get_asset_depr_schedule_doc,
+	get_depreciation_amount,
+	set_accumulated_depreciation,
+)
 
 
 class AssetValueAdjustment(Document):
@@ -112,21 +116,40 @@
 		for d in asset.finance_books:
 			d.value_after_depreciation = asset_value
 
+			current_asset_depr_schedule_doc = get_asset_depr_schedule_doc(
+				asset.name, "Active", d.finance_book
+			)
+
+			new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc)
+			new_asset_depr_schedule_doc.status = "Draft"
+			new_asset_depr_schedule_doc.docstatus = 0
+
+			current_asset_depr_schedule_doc.flags.should_not_cancel_depreciation_entries = True
+			current_asset_depr_schedule_doc.cancel()
+
+			notes = _(
+				"This schedule was created when Asset {0} was adjusted through Asset Value Adjustment {1}."
+			).format(
+				get_link_to_form(asset.doctype, asset.name),
+				get_link_to_form(self.get("doctype"), self.get("name")),
+			)
+			new_asset_depr_schedule_doc.notes = notes
+
+			new_asset_depr_schedule_doc.insert()
+
+			depr_schedule = new_asset_depr_schedule_doc.get("depreciation_schedule")
+
 			if d.depreciation_method in ("Straight Line", "Manual"):
-				end_date = max(s.schedule_date for s in asset.schedules if cint(s.finance_book_id) == d.idx)
+				end_date = max(s.schedule_date for s in depr_schedule)
 				total_days = date_diff(end_date, self.date)
 				rate_per_day = flt(d.value_after_depreciation) / flt(total_days)
 				from_date = self.date
 			else:
-				no_of_depreciations = len(
-					[
-						s.name for s in asset.schedules if (cint(s.finance_book_id) == d.idx and not s.journal_entry)
-					]
-				)
+				no_of_depreciations = len([s.name for s in depr_schedule if not s.journal_entry])
 
 			value_after_depreciation = d.value_after_depreciation
-			for data in asset.schedules:
-				if cint(data.finance_book_id) == d.idx and not data.journal_entry:
+			for data in depr_schedule:
+				if not data.journal_entry:
 					if d.depreciation_method in ("Straight Line", "Manual"):
 						days = date_diff(data.schedule_date, from_date)
 						depreciation_amount = days * rate_per_day
@@ -140,10 +163,12 @@
 
 			d.db_update()
 
-		asset.set_accumulated_depreciation(ignore_booked_entry=True)
-		for asset_data in asset.schedules:
-			if not asset_data.journal_entry:
-				asset_data.db_update()
+			set_accumulated_depreciation(new_asset_depr_schedule_doc, d, ignore_booked_entry=True)
+			for asset_data in depr_schedule:
+				if not asset_data.journal_entry:
+					asset_data.db_update()
+
+			new_asset_depr_schedule_doc.submit()
 
 
 @frappe.whitelist()
diff --git a/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py
index 62c6366..03dcea9 100644
--- a/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py
+++ b/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py
@@ -7,6 +7,9 @@
 from frappe.utils import add_days, get_last_day, nowdate
 
 from erpnext.assets.doctype.asset.test_asset import create_asset_data
+from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
+	get_asset_depr_schedule_doc,
+)
 from erpnext.assets.doctype.asset_value_adjustment.asset_value_adjustment import (
 	get_current_asset_value,
 )
@@ -73,12 +76,21 @@
 		)
 		asset_doc.submit()
 
+		first_asset_depr_schedule = get_asset_depr_schedule_doc(asset_doc.name, "Active")
+		self.assertEquals(first_asset_depr_schedule.status, "Active")
+
 		current_value = get_current_asset_value(asset_doc.name)
 		adj_doc = make_asset_value_adjustment(
 			asset=asset_doc.name, current_asset_value=current_value, new_asset_value=50000.0
 		)
 		adj_doc.submit()
 
+		first_asset_depr_schedule.load_from_db()
+
+		second_asset_depr_schedule = get_asset_depr_schedule_doc(asset_doc.name, "Active")
+		self.assertEquals(second_asset_depr_schedule.status, "Active")
+		self.assertEquals(first_asset_depr_schedule.status, "Cancelled")
+
 		expected_gle = (
 			("_Test Accumulated Depreciations - _TC", 0.0, 50000.0),
 			("_Test Depreciations - _TC", 50000.0, 0.0),
diff --git a/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json b/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json
index 35a2c9d..882c4bf 100644
--- a/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json
+++ b/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json
@@ -1,318 +1,84 @@
 {
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 1, 
- "autoname": "", 
- "beta": 0, 
- "creation": "2016-03-02 15:11:01.278862", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "Document", 
- "editable_grid": 1, 
- "engine": "InnoDB", 
+ "actions": [],
+ "allow_rename": 1,
+ "creation": "2016-03-02 15:11:01.278862",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "schedule_date",
+  "depreciation_amount",
+  "column_break_3",
+  "accumulated_depreciation_amount",
+  "journal_entry",
+  "make_depreciation_entry",
+  "depreciation_method"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "finance_book", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Finance Book", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Finance Book", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "schedule_date",
+   "fieldtype": "Date",
+   "in_list_view": 1,
+   "label": "Schedule Date",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "schedule_date", 
-   "fieldtype": "Date", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Schedule Date", 
-   "length": 0, 
-   "no_copy": 1, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "depreciation_amount",
+   "fieldtype": "Currency",
+   "in_list_view": 1,
+   "label": "Depreciation Amount",
+   "options": "Company:company:default_currency",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "depreciation_amount", 
-   "fieldtype": "Currency", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Depreciation Amount", 
-   "length": 0, 
-   "no_copy": 1, 
-   "options": "Company:company:default_currency", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "column_break_3",
+   "fieldtype": "Column Break"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break_3", 
-   "fieldtype": "Column Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "accumulated_depreciation_amount",
+   "fieldtype": "Currency",
+   "in_list_view": 1,
+   "label": "Accumulated Depreciation Amount",
+   "options": "Company:company:default_currency",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "accumulated_depreciation_amount", 
-   "fieldtype": "Currency", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Accumulated Depreciation Amount", 
-   "length": 0, 
-   "no_copy": 1, 
-   "options": "Company:company:default_currency", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "depends_on": "eval:doc.docstatus==1",
+   "fieldname": "journal_entry",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Journal Entry",
+   "options": "Journal Entry",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "depends_on": "eval:doc.docstatus==1", 
-   "fieldname": "journal_entry", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Journal Entry", 
-   "length": 0, 
-   "no_copy": 1, 
-   "options": "Journal Entry", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "allow_on_submit": 1,
+   "depends_on": "eval:(doc.docstatus==1 && !doc.journal_entry && doc.schedule_date <= get_today())",
+   "fieldname": "make_depreciation_entry",
+   "fieldtype": "Button",
+   "label": "Make Depreciation Entry"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 1, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "depends_on": "eval:(doc.docstatus==1 && !doc.journal_entry && doc.schedule_date <= get_today())", 
-   "fieldname": "make_depreciation_entry", 
-   "fieldtype": "Button", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Make Depreciation Entry", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "finance_book_id", 
-   "fieldtype": "Data", 
-   "hidden": 1, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Finance Book Id", 
-   "length": 0, 
-   "no_copy": 1, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "depreciation_method", 
-   "fieldtype": "Select", 
-   "hidden": 1, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Depreciation Method", 
-   "length": 0, 
-   "no_copy": 1, 
-   "options": "\nStraight Line\nDouble Declining Balance\nWritten Down Value\nManual", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
+   "fieldname": "depreciation_method",
+   "fieldtype": "Select",
+   "hidden": 1,
+   "label": "Depreciation Method",
+   "options": "\nStraight Line\nDouble Declining Balance\nWritten Down Value\nManual",
+   "print_hide": 1,
+   "read_only": 1
   }
- ], 
- "has_web_view": 0, 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "idx": 0, 
- "image_view": 0, 
- "in_create": 0, 
- "is_submittable": 0, 
- "issingle": 0, 
- "istable": 1, 
- "max_attachments": 0, 
- "modified": "2018-05-10 15:12:41.679436", 
- "modified_by": "Administrator", 
- "module": "Assets", 
- "name": "Depreciation Schedule", 
- "name_case": "", 
- "owner": "Administrator", 
- "permissions": [], 
- "quick_entry": 1, 
- "read_only": 0, 
- "read_only_onload": 0, 
- "show_name_in_global_search": 0, 
- "sort_field": "modified", 
- "sort_order": "DESC", 
- "track_changes": 0, 
- "track_seen": 0
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2022-12-06 20:35:50.264281",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Depreciation Schedule",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": []
 }
\ No newline at end of file
diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
index 6b14dce..bb50df0 100644
--- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
+++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
@@ -176,15 +176,17 @@
 	return frappe._dict(
 		frappe.db.sql(
 			""" Select
-		parent, SUM(depreciation_amount)
-		FROM `tabDepreciation Schedule`
+		ads.asset, SUM(depreciation_amount)
+		FROM `tabAsset Depreciation Schedule` ads, `tabDepreciation Schedule` ds
 		WHERE
-			parentfield='schedules'
-			AND schedule_date<=%s
-			AND journal_entry IS NOT NULL
-			AND ifnull(finance_book, '')=%s
-		GROUP BY parent""",
-			(date, cstr(filters.finance_book or "")),
+			ds.parent = ads.name
+			AND ifnull(ads.finance_book, '')=%s
+			AND ads.docstatus=1
+			AND ds.parentfield='depreciation_schedule'
+			AND ds.schedule_date<=%s
+			AND ds.journal_entry IS NOT NULL
+		GROUP BY ads.asset""",
+			(cstr(filters.finance_book or ""), date),
 		)
 	)
 
diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.json b/erpnext/buying/doctype/buying_settings/buying_settings.json
index 28158a3..34417f7 100644
--- a/erpnext/buying/doctype/buying_settings/buying_settings.json
+++ b/erpnext/buying/doctype/buying_settings/buying_settings.json
@@ -9,8 +9,8 @@
   "supplier_and_price_defaults_section",
   "supp_master_name",
   "supplier_group",
-  "column_break_4",
   "buying_price_list",
+  "column_break_4",
   "maintain_same_rate_action",
   "role_to_override_stop_action",
   "transaction_settings_section",
@@ -20,6 +20,7 @@
   "maintain_same_rate",
   "allow_multiple_items",
   "bill_for_rejected_quantity_in_purchase_invoice",
+  "disable_last_purchase_rate",
   "subcontract",
   "backflush_raw_materials_of_subcontract_based_on",
   "column_break_11",
@@ -71,7 +72,7 @@
   },
   {
    "fieldname": "subcontract",
-   "fieldtype": "Section Break",
+   "fieldtype": "Tab Break",
    "label": "Subcontracting Settings"
   },
   {
@@ -118,8 +119,8 @@
   },
   {
    "fieldname": "supplier_and_price_defaults_section",
-   "fieldtype": "Section Break",
-   "label": "Supplier and Price Defaults"
+   "fieldtype": "Tab Break",
+   "label": "Naming Series and Price Defaults"
   },
   {
    "fieldname": "column_break_4",
@@ -127,12 +128,18 @@
   },
   {
    "fieldname": "transaction_settings_section",
-   "fieldtype": "Section Break",
+   "fieldtype": "Tab Break",
    "label": "Transaction Settings"
   },
   {
    "fieldname": "column_break_12",
    "fieldtype": "Column Break"
+  },
+  {
+   "default": "0",
+   "fieldname": "disable_last_purchase_rate",
+   "fieldtype": "Check",
+   "label": "Disable Last Purchase Rate"
   }
  ],
  "icon": "fa fa-cog",
@@ -140,7 +147,7 @@
  "index_web_pages_for_search": 1,
  "issingle": 1,
  "links": [],
- "modified": "2022-09-27 10:50:27.050252",
+ "modified": "2023-01-09 17:08:28.828173",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Buying Settings",
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 7989a40..54f0d94 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -274,6 +274,9 @@
 		if self.doctype not in ("Purchase Receipt", "Purchase Invoice", "Purchase Order"):
 			return
 
+		if not self.is_internal_transfer():
+			return
+
 		ref_doctype_map = {
 			"Purchase Order": "Sales Order Item",
 			"Purchase Receipt": "Delivery Note Item",
@@ -544,7 +547,9 @@
 			self.process_fixed_asset()
 			self.update_fixed_asset(field)
 
-		if self.doctype in ["Purchase Order", "Purchase Receipt"]:
+		if self.doctype in ["Purchase Order", "Purchase Receipt"] and not frappe.db.get_single_value(
+			"Buying Settings", "disable_last_purchase_rate"
+		):
 			update_last_purchase_rate(self, is_submit=1)
 
 	def on_cancel(self):
@@ -553,7 +558,9 @@
 		if self.get("is_return"):
 			return
 
-		if self.doctype in ["Purchase Order", "Purchase Receipt"]:
+		if self.doctype in ["Purchase Order", "Purchase Receipt"] and not frappe.db.get_single_value(
+			"Buying Settings", "disable_last_purchase_rate"
+		):
 			update_last_purchase_rate(self, is_submit=0)
 
 		if self.doctype in ["Purchase Receipt", "Purchase Invoice"]:
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 2420a23..6be6e06 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -268,6 +268,7 @@
 erpnext.patches.v13_0.reset_corrupt_defaults
 erpnext.patches.v13_0.create_accounting_dimensions_for_asset_repair
 erpnext.patches.v15_0.delete_taxjar_doctypes
+erpnext.patches.v15_0.create_asset_depreciation_schedules_from_assets
 
 [post_model_sync]
 execute:frappe.delete_doc_if_exists('Workspace', 'ERPNext Integrations Settings')
@@ -319,4 +320,5 @@
 erpnext.patches.v14_0.update_partial_tds_fields
 erpnext.patches.v14_0.create_incoterms_and_migrate_shipment
 erpnext.patches.v14_0.setup_clear_repost_logs
-erpnext.patches.v14_0.create_accounting_dimensions_for_payment_request
\ No newline at end of file
+erpnext.patches.v14_0.create_accounting_dimensions_for_payment_request
+erpnext.patches.v14_0.update_entry_type_for_journal_entry
diff --git a/erpnext/patches/v14_0/update_entry_type_for_journal_entry.py b/erpnext/patches/v14_0/update_entry_type_for_journal_entry.py
new file mode 100644
index 0000000..bce9255
--- /dev/null
+++ b/erpnext/patches/v14_0/update_entry_type_for_journal_entry.py
@@ -0,0 +1,18 @@
+import frappe
+
+
+def execute():
+	"""
+	Update Propery Setters for Journal Entry with new 'Entry Type'
+	"""
+	new_voucher_type = "Exchange Gain Or Loss"
+	prop_setter = frappe.db.get_list(
+		"Property Setter",
+		filters={"doc_type": "Journal Entry", "field_name": "voucher_type", "property": "options"},
+	)
+	if prop_setter:
+		property_setter_doc = frappe.get_doc("Property Setter", prop_setter[0].get("name"))
+
+		if new_voucher_type not in property_setter_doc.value.split("\n"):
+			property_setter_doc.value += "\n" + new_voucher_type
+			property_setter_doc.save()
diff --git a/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py b/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py
new file mode 100644
index 0000000..5dc3cdd
--- /dev/null
+++ b/erpnext/patches/v15_0/create_asset_depreciation_schedules_from_assets.py
@@ -0,0 +1,80 @@
+import frappe
+
+from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import (
+	set_draft_asset_depr_schedule_details,
+)
+
+
+def execute():
+	frappe.reload_doc("assets", "doctype", "Asset Depreciation Schedule")
+
+	assets = get_details_of_draft_or_submitted_depreciable_assets()
+
+	for asset in assets:
+		finance_book_rows = get_details_of_asset_finance_books_rows(asset.name)
+
+		for fb_row in finance_book_rows:
+			asset_depr_schedule_doc = frappe.new_doc("Asset Depreciation Schedule")
+
+			set_draft_asset_depr_schedule_details(asset_depr_schedule_doc, asset, fb_row)
+
+			asset_depr_schedule_doc.insert()
+
+			if asset.docstatus == 1:
+				asset_depr_schedule_doc.submit()
+
+			update_depreciation_schedules(asset.name, asset_depr_schedule_doc.name, fb_row.idx)
+
+
+def get_details_of_draft_or_submitted_depreciable_assets():
+	asset = frappe.qb.DocType("Asset")
+
+	records = (
+		frappe.qb.from_(asset)
+		.select(asset.name, asset.opening_accumulated_depreciation, asset.docstatus)
+		.where(asset.calculate_depreciation == 1)
+		.where(asset.docstatus < 2)
+	).run(as_dict=True)
+
+	return records
+
+
+def get_details_of_asset_finance_books_rows(asset_name):
+	afb = frappe.qb.DocType("Asset Finance Book")
+
+	records = (
+		frappe.qb.from_(afb)
+		.select(
+			afb.finance_book,
+			afb.idx,
+			afb.depreciation_method,
+			afb.total_number_of_depreciations,
+			afb.frequency_of_depreciation,
+			afb.rate_of_depreciation,
+			afb.expected_value_after_useful_life,
+		)
+		.where(afb.parent == asset_name)
+	).run(as_dict=True)
+
+	return records
+
+
+def update_depreciation_schedules(asset_name, asset_depr_schedule_name, fb_row_idx):
+	ds = frappe.qb.DocType("Depreciation Schedule")
+
+	depr_schedules = (
+		frappe.qb.from_(ds)
+		.select(ds.name)
+		.where((ds.parent == asset_name) & (ds.finance_book_id == str(fb_row_idx)))
+		.orderby(ds.idx)
+	).run(as_dict=True)
+
+	for idx, depr_schedule in enumerate(depr_schedules, start=1):
+		(
+			frappe.qb.update(ds)
+			.set(ds.idx, idx)
+			.set(ds.parent, asset_depr_schedule_name)
+			.set(ds.parentfield, "depreciation_schedule")
+			.set(ds.parenttype, "Asset Depreciation Schedule")
+			.where(ds.name == depr_schedule.name)
+		).run()
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index 4735f24..7d80ac1 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -7,6 +7,8 @@
 from frappe import _
 from frappe.desk.reportview import get_match_cond
 from frappe.model.document import Document
+from frappe.query_builder import Interval
+from frappe.query_builder.functions import Count, CurDate, Date, UnixTimestamp
 from frappe.utils import add_days, flt, get_datetime, get_time, get_url, nowtime, today
 
 from erpnext import get_default_company
@@ -297,17 +299,19 @@
 				user.welcome_email_sent = 1
 
 
-def get_timeline_data(doctype, name):
+def get_timeline_data(doctype: str, name: str) -> dict[int, int]:
 	"""Return timeline for attendance"""
+
+	timesheet_detail = frappe.qb.DocType("Timesheet Detail")
+
 	return dict(
-		frappe.db.sql(
-			"""select unix_timestamp(from_time), count(*)
-		from `tabTimesheet Detail` where project=%s
-			and from_time > date_sub(curdate(), interval 1 year)
-			and docstatus < 2
-			group by date(from_time)""",
-			name,
-		)
+		frappe.qb.from_(timesheet_detail)
+		.select(UnixTimestamp(timesheet_detail.from_time), Count("*"))
+		.where(timesheet_detail.project == name)
+		.where(timesheet_detail.from_time > CurDate() - Interval(years=1))
+		.where(timesheet_detail.docstatus < 2)
+		.groupby(Date(timesheet_detail.from_time))
+		.run()
 	)
 
 
diff --git a/erpnext/public/js/erpnext.bundle.js b/erpnext/public/js/erpnext.bundle.js
index 14a088e..7b230af 100644
--- a/erpnext/public/js/erpnext.bundle.js
+++ b/erpnext/public/js/erpnext.bundle.js
@@ -13,6 +13,7 @@
 import "./agriculture/ternary_plot";
 import "./templates/item_quick_entry.html";
 import "./utils/item_quick_entry";
+import "./utils/contact_address_quick_entry";
 import "./utils/customer_quick_entry";
 import "./utils/supplier_quick_entry";
 import "./call_popup/call_popup";
diff --git a/erpnext/public/js/utils/contact_address_quick_entry.js b/erpnext/public/js/utils/contact_address_quick_entry.js
new file mode 100644
index 0000000..adabf08
--- /dev/null
+++ b/erpnext/public/js/utils/contact_address_quick_entry.js
@@ -0,0 +1,100 @@
+frappe.provide('frappe.ui.form');
+
+frappe.ui.form.ContactAddressQuickEntryForm = class ContactAddressQuickEntryForm extends frappe.ui.form.QuickEntryForm {
+	constructor(doctype, after_insert, init_callback, doc, force) {
+		super(doctype, after_insert, init_callback, doc, force);
+		this.skip_redirect_on_error = true;
+	}
+
+	render_dialog() {
+		this.mandatory = this.mandatory.concat(this.get_variant_fields());
+		super.render_dialog();
+	}
+
+	insert() {
+		/**
+		 * Using alias fieldnames because the doctype definition define "email_id" and "mobile_no" as readonly fields.
+		 * Therefor, resulting in the fields being "hidden".
+		 */
+		const map_field_names = {
+			"email_address": "email_id",
+			"mobile_number": "mobile_no",
+		};
+
+		Object.entries(map_field_names).forEach(([fieldname, new_fieldname]) => {
+			this.dialog.doc[new_fieldname] = this.dialog.doc[fieldname];
+			delete this.dialog.doc[fieldname];
+		});
+
+		return super.insert();
+	}
+
+	get_variant_fields() {
+		var variant_fields = [{
+			fieldtype: "Section Break",
+			label: __("Primary Contact Details"),
+			collapsible: 1
+		},
+		{
+			label: __("Email Id"),
+			fieldname: "email_address",
+			fieldtype: "Data",
+			options: "Email",
+		},
+		{
+			fieldtype: "Column Break"
+		},
+		{
+			label: __("Mobile Number"),
+			fieldname: "mobile_number",
+			fieldtype: "Data"
+		},
+		{
+			fieldtype: "Section Break",
+			label: __("Primary Address Details"),
+			collapsible: 1
+		},
+		{
+			label: __("Address Line 1"),
+			fieldname: "address_line1",
+			fieldtype: "Data"
+		},
+		{
+			label: __("Address Line 2"),
+			fieldname: "address_line2",
+			fieldtype: "Data"
+		},
+		{
+			label: __("ZIP Code"),
+			fieldname: "pincode",
+			fieldtype: "Data"
+		},
+		{
+			fieldtype: "Column Break"
+		},
+		{
+			label: __("City"),
+			fieldname: "city",
+			fieldtype: "Data"
+		},
+		{
+			label: __("State"),
+			fieldname: "state",
+			fieldtype: "Data"
+		},
+		{
+			label: __("Country"),
+			fieldname: "country",
+			fieldtype: "Link",
+			options: "Country"
+		},
+		{
+			label: __("Customer POS Id"),
+			fieldname: "customer_pos_id",
+			fieldtype: "Data",
+			hidden: 1
+		}];
+
+		return variant_fields;
+	}
+}
diff --git a/erpnext/public/js/utils/customer_quick_entry.js b/erpnext/public/js/utils/customer_quick_entry.js
index d2c5c72..b253208 100644
--- a/erpnext/public/js/utils/customer_quick_entry.js
+++ b/erpnext/public/js/utils/customer_quick_entry.js
@@ -1,81 +1,3 @@
 frappe.provide('frappe.ui.form');
 
-frappe.ui.form.CustomerQuickEntryForm = class CustomerQuickEntryForm extends frappe.ui.form.QuickEntryForm {
-	constructor(doctype, after_insert, init_callback, doc, force) {
-		super(doctype, after_insert, init_callback, doc, force);
-		this.skip_redirect_on_error = true;
-	}
-
-	render_dialog() {
-		this.mandatory = this.mandatory.concat(this.get_variant_fields());
-		super.render_dialog();
-	}
-
-	get_variant_fields() {
-		var variant_fields = [{
-			fieldtype: "Section Break",
-			label: __("Primary Contact Details"),
-			collapsible: 1
-		},
-		{
-			label: __("Email Id"),
-			fieldname: "email_id",
-			fieldtype: "Data"
-		},
-		{
-			fieldtype: "Column Break"
-		},
-		{
-			label: __("Mobile Number"),
-			fieldname: "mobile_no",
-			fieldtype: "Data"
-		},
-		{
-			fieldtype: "Section Break",
-			label: __("Primary Address Details"),
-			collapsible: 1
-		},
-		{
-			label: __("Address Line 1"),
-			fieldname: "address_line1",
-			fieldtype: "Data"
-		},
-		{
-			label: __("Address Line 2"),
-			fieldname: "address_line2",
-			fieldtype: "Data"
-		},
-		{
-			label: __("ZIP Code"),
-			fieldname: "pincode",
-			fieldtype: "Data"
-		},
-		{
-			fieldtype: "Column Break"
-		},
-		{
-			label: __("City"),
-			fieldname: "city",
-			fieldtype: "Data"
-		},
-		{
-			label: __("State"),
-			fieldname: "state",
-			fieldtype: "Data"
-		},
-		{
-			label: __("Country"),
-			fieldname: "country",
-			fieldtype: "Link",
-			options: "Country"
-		},
-		{
-			label: __("Customer POS Id"),
-			fieldname: "customer_pos_id",
-			fieldtype: "Data",
-			hidden: 1
-		}];
-
-		return variant_fields;
-	}
-}
+frappe.ui.form.CustomerQuickEntryForm = frappe.ui.form.ContactAddressQuickEntryForm;
diff --git a/erpnext/public/js/utils/supplier_quick_entry.js b/erpnext/public/js/utils/supplier_quick_entry.js
index 8d591a9..687b014 100644
--- a/erpnext/public/js/utils/supplier_quick_entry.js
+++ b/erpnext/public/js/utils/supplier_quick_entry.js
@@ -1,77 +1,3 @@
 frappe.provide('frappe.ui.form');
 
-frappe.ui.form.SupplierQuickEntryForm = class SupplierQuickEntryForm extends frappe.ui.form.QuickEntryForm {
-	constructor(doctype, after_insert, init_callback, doc, force) {
-		super(doctype, after_insert, init_callback, doc, force);
-		this.skip_redirect_on_error = true;
-	}
-
-	render_dialog() {
-		this.mandatory = this.mandatory.concat(this.get_variant_fields());
-		super.render_dialog();
-	}
-
-	get_variant_fields() {
-		var variant_fields = [
-			{
-				fieldtype: "Section Break",
-				label: __("Primary Contact Details"),
-				collapsible: 1
-			},
-			{
-				label: __("Email Id"),
-				fieldname: "email_id",
-				fieldtype: "Data"
-			},
-			{
-				fieldtype: "Column Break"
-			},
-			{
-				label: __("Mobile Number"),
-				fieldname: "mobile_no",
-				fieldtype: "Data"
-			},
-			{
-				fieldtype: "Section Break",
-				label: __("Primary Address Details"),
-				collapsible: 1
-			},
-			{
-				label: __("Address Line 1"),
-				fieldname: "address_line1",
-				fieldtype: "Data"
-			},
-			{
-				label: __("Address Line 2"),
-				fieldname: "address_line2",
-				fieldtype: "Data"
-			},
-			{
-				label: __("ZIP Code"),
-				fieldname: "pincode",
-				fieldtype: "Data"
-			},
-			{
-				fieldtype: "Column Break"
-			},
-			{
-				label: __("City"),
-				fieldname: "city",
-				fieldtype: "Data"
-			},
-			{
-				label: __("State"),
-				fieldname: "state",
-				fieldtype: "Data"
-			},
-			{
-				label: __("Country"),
-				fieldname: "country",
-				fieldtype: "Link",
-				options: "Country"
-			}
-		];
-
-		return variant_fields;
-	}
-};
+frappe.ui.form.SupplierQuickEntryForm = frappe.ui.form.ContactAddressQuickEntryForm;
diff --git a/erpnext/setup/doctype/sales_person/sales_person.py b/erpnext/setup/doctype/sales_person/sales_person.py
index 0082c70..beff7f5 100644
--- a/erpnext/setup/doctype/sales_person/sales_person.py
+++ b/erpnext/setup/doctype/sales_person/sales_person.py
@@ -2,8 +2,13 @@
 # License: GNU General Public License v3. See license.txt
 
 
+from collections import defaultdict
+from itertools import chain
+
 import frappe
 from frappe import _
+from frappe.query_builder import Interval
+from frappe.query_builder.functions import Count, CurDate, UnixTimestamp
 from frappe.utils import flt
 from frappe.utils.nestedset import NestedSet, get_root_of
 
@@ -77,61 +82,31 @@
 	frappe.db.add_index("Sales Person", ["lft", "rgt"])
 
 
-def get_timeline_data(doctype, name):
+def get_timeline_data(doctype: str, name: str) -> dict[int, int]:
+	def _fetch_activity(doctype: str, date_field: str):
+		sales_team = frappe.qb.DocType("Sales Team")
+		transaction = frappe.qb.DocType(doctype)
 
-	out = {}
-
-	out.update(
-		dict(
-			frappe.db.sql(
-				"""select
-			unix_timestamp(dt.transaction_date), count(st.parenttype)
-		from
-			`tabSales Order` dt, `tabSales Team` st
-		where
-			st.sales_person = %s and st.parent = dt.name and dt.transaction_date > date_sub(curdate(), interval 1 year)
-			group by dt.transaction_date """,
-				name,
-			)
+		return dict(
+			frappe.qb.from_(transaction)
+			.join(sales_team)
+			.on(transaction.name == sales_team.parent)
+			.select(UnixTimestamp(transaction[date_field]), Count("*"))
+			.where(sales_team.sales_person == name)
+			.where(transaction[date_field] > CurDate() - Interval(years=1))
+			.groupby(transaction[date_field])
+			.run()
 		)
-	)
 
-	sales_invoice = dict(
-		frappe.db.sql(
-			"""select
-			unix_timestamp(dt.posting_date), count(st.parenttype)
-		from
-			`tabSales Invoice` dt, `tabSales Team` st
-		where
-			st.sales_person = %s and st.parent = dt.name and dt.posting_date > date_sub(curdate(), interval 1 year)
-			group by dt.posting_date """,
-			name,
-		)
-	)
+	sales_order_activity = _fetch_activity("Sales Order", "transaction_date")
+	sales_invoice_activity = _fetch_activity("Sales Invoice", "posting_date")
+	delivery_note_activity = _fetch_activity("Delivery Note", "posting_date")
 
-	for key in sales_invoice:
-		if out.get(key):
-			out[key] += sales_invoice[key]
-		else:
-			out[key] = sales_invoice[key]
+	merged_activities = defaultdict(int)
 
-	delivery_note = dict(
-		frappe.db.sql(
-			"""select
-			unix_timestamp(dt.posting_date), count(st.parenttype)
-		from
-			`tabDelivery Note` dt, `tabSales Team` st
-		where
-			st.sales_person = %s and st.parent = dt.name and dt.posting_date > date_sub(curdate(), interval 1 year)
-			group by dt.posting_date """,
-			name,
-		)
-	)
+	for ts, count in chain(
+		sales_order_activity.items(), sales_invoice_activity.items(), delivery_note_activity.items()
+	):
+		merged_activities[ts] += count
 
-	for key in delivery_note:
-		if out.get(key):
-			out[key] += delivery_note[key]
-		else:
-			out[key] = delivery_note[key]
-
-	return out
+	return merged_activities
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 20bc9d9..686e6cb 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -8,6 +8,8 @@
 import frappe
 from frappe import _
 from frappe.model.document import Document
+from frappe.query_builder import Interval
+from frappe.query_builder.functions import Count, CurDate, UnixTimestamp
 from frappe.utils import (
 	cint,
 	cstr,
@@ -164,10 +166,7 @@
 		if not self.is_stock_item or self.has_serial_no or self.has_batch_no:
 			return
 
-		if not self.valuation_rate and self.standard_rate:
-			self.valuation_rate = self.standard_rate
-
-		if not self.valuation_rate and not self.is_customer_provided_item:
+		if not self.valuation_rate and not self.standard_rate and not self.is_customer_provided_item:
 			frappe.throw(_("Valuation Rate is mandatory if Opening Stock entered"))
 
 		from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
@@ -192,7 +191,7 @@
 					item_code=self.name,
 					target=default_warehouse,
 					qty=self.opening_stock,
-					rate=self.valuation_rate,
+					rate=self.valuation_rate or self.standard_rate,
 					company=default.company,
 					posting_date=getdate(),
 					posting_time=nowtime(),
@@ -279,7 +278,7 @@
 				frappe.throw(_("Row #{0}: Maximum Net Rate cannot be greater than Minimum Net Rate"))
 
 	def update_template_tables(self):
-		template = frappe.get_doc("Item", self.variant_of)
+		template = frappe.get_cached_doc("Item", self.variant_of)
 
 		# add item taxes from template
 		for d in template.get("taxes"):
@@ -997,18 +996,19 @@
 	).insert()
 
 
-def get_timeline_data(doctype, name):
+def get_timeline_data(doctype: str, name: str) -> dict[int, int]:
 	"""get timeline data based on Stock Ledger Entry. This is displayed as heatmap on the item page."""
 
-	items = frappe.db.sql(
-		"""select unix_timestamp(posting_date), count(*)
-							from `tabStock Ledger Entry`
-							where item_code=%s and posting_date > date_sub(curdate(), interval 1 year)
-							group by posting_date""",
-		name,
-	)
+	sle = frappe.qb.DocType("Stock Ledger Entry")
 
-	return dict(items)
+	return dict(
+		frappe.qb.from_(sle)
+		.select(UnixTimestamp(sle.posting_date), Count("*"))
+		.where(sle.item_code == name)
+		.where(sle.posting_date > CurDate() - Interval(years=1))
+		.groupby(sle.posting_date)
+		.run()
+	)
 
 
 def validate_end_of_life(item_code, end_of_life=None, disabled=None):
diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py
index d606751..dbd8de4 100644
--- a/erpnext/stock/doctype/packed_item/packed_item.py
+++ b/erpnext/stock/doctype/packed_item/packed_item.py
@@ -83,8 +83,8 @@
 		# 1. items were deleted
 		# 2. if bundle item replaced by another item (same no. of items but different items)
 		# we maintain list to track recurring item rows as well
-		items_before_save = [item.item_code for item in doc_before_save.get("items")]
-		items_after_save = [item.item_code for item in doc.get("items")]
+		items_before_save = [(item.name, item.item_code) for item in doc_before_save.get("items")]
+		items_after_save = [(item.name, item.item_code) for item in doc.get("items")]
 		reset_table = items_before_save != items_after_save
 	else:
 		# reset: if via Update Items OR
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index dc9f2b2..b634146 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -1501,6 +1501,49 @@
 
 		self.assertTrue(return_pi.docstatus == 1)
 
+	def test_disable_last_purchase_rate(self):
+		from erpnext.stock.get_item_details import get_item_details
+
+		item = make_item(
+			"_Test Disable Last Purchase Rate",
+			{"is_purchase_item": 1, "is_stock_item": 1},
+		)
+
+		frappe.db.set_single_value("Buying Settings", "disable_last_purchase_rate", 1)
+
+		pr = make_purchase_receipt(
+			qty=1,
+			rate=100,
+			item_code=item.name,
+		)
+
+		args = pr.items[0].as_dict()
+		args.update(
+			{
+				"supplier": pr.supplier,
+				"doctype": pr.doctype,
+				"conversion_rate": pr.conversion_rate,
+				"currency": pr.currency,
+				"company": pr.company,
+				"posting_date": pr.posting_date,
+				"posting_time": pr.posting_time,
+			}
+		)
+
+		res = get_item_details(args)
+		self.assertEqual(res.get("last_purchase_rate"), 0)
+
+		frappe.db.set_single_value("Buying Settings", "disable_last_purchase_rate", 0)
+
+		pr = make_purchase_receipt(
+			qty=1,
+			rate=100,
+			item_code=item.name,
+		)
+
+		res = get_item_details(args)
+		self.assertEqual(res.get("last_purchase_rate"), 100)
+
 
 def prepare_data_for_internal_transfer():
 	from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 8561dc2..f7fcb30 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -411,7 +411,9 @@
 	args.stock_qty = out.stock_qty
 
 	# calculate last purchase rate
-	if args.get("doctype") in purchase_doctypes:
+	if args.get("doctype") in purchase_doctypes and not frappe.db.get_single_value(
+		"Buying Settings", "disable_last_purchase_rate"
+	):
 		from erpnext.buying.doctype.purchase_order.purchase_order import item_last_purchase_rate
 
 		out.last_purchase_rate = item_last_purchase_rate(
@@ -813,6 +815,9 @@
 			flt(price_list_rate) * flt(args.plc_conversion_rate) / flt(args.conversion_rate)
 		)
 
+		if frappe.db.get_single_value("Buying Settings", "disable_last_purchase_rate"):
+			return out
+
 		if not out.price_list_rate and args.transaction_type == "buying":
 			from erpnext.stock.doctype.item.item import get_last_purchase_details