fix: incorrect depr schedules after asset repair [develop] (#34544)

* fix: backport missing changes from #30838

* fix: incorrect schedule after repair
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index e1d58a0..1614c28 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -79,6 +79,7 @@
 	def after_insert(self):
 		if not self.split_from:
 			make_draft_asset_depr_schedules(self)
+		self.validate_expected_value_after_useful_life()
 
 	def validate_asset_and_reference(self):
 		if self.purchase_invoice or self.purchase_receipt:
@@ -325,13 +326,13 @@
 
 	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)
+			asset_depr_schedule_doc = get_asset_depr_schedule_doc(self.name, "Draft", row.finance_book)
 
-			if not depr_schedule:
+			if not asset_depr_schedule_doc:
 				continue
 
 			accumulated_depreciation_after_full_schedule = [
-				d.accumulated_depreciation_amount for d in depr_schedule
+				d.accumulated_depreciation_amount for d in asset_depr_schedule_doc.get("depreciation_schedule")
 			]
 
 			if accumulated_depreciation_after_full_schedule:
@@ -355,6 +356,9 @@
 					)
 				elif not row.expected_value_after_useful_life:
 					row.expected_value_after_useful_life = asset_value_after_full_schedule
+					asset_depr_schedule_doc.db_set(
+						"expected_value_after_useful_life", asset_value_after_full_schedule
+					)
 
 	def validate_cancellation(self):
 		if self.status in ("In Maintenance", "Out of Order"):
@@ -474,17 +478,21 @@
 	@erpnext.allow_regional
 	def get_depreciation_amount(self, depreciable_value, fb_row):
 		if fb_row.depreciation_method in ("Straight Line", "Manual"):
-			# if the Depreciation Schedule is being prepared for the first time
-			if not self.flags.increase_in_asset_life:
-				depreciation_amount = (
-					flt(self.gross_purchase_amount) - flt(fb_row.expected_value_after_useful_life)
-				) / flt(fb_row.total_number_of_depreciations)
-
-			# if the Depreciation Schedule is being modified after Asset Repair
-			else:
+			# if the Depreciation Schedule is being modified after Asset Repair due to increase in asset life and value
+			if self.flags.increase_in_asset_life:
 				depreciation_amount = (
 					flt(fb_row.value_after_depreciation) - flt(fb_row.expected_value_after_useful_life)
 				) / (date_diff(self.to_date, self.available_for_use_date) / 365)
+			# if the Depreciation Schedule is being modified after Asset Repair due to increase in asset value
+			elif self.flags.increase_in_asset_value_due_to_repair:
+				depreciation_amount = (
+					flt(fb_row.value_after_depreciation) - flt(fb_row.expected_value_after_useful_life)
+				) / flt(fb_row.total_number_of_depreciations)
+			# if the Depreciation Schedule is being prepared for the first time
+			else:
+				depreciation_amount = (
+					flt(self.gross_purchase_amount) - flt(fb_row.expected_value_after_useful_life)
+				) / flt(fb_row.total_number_of_depreciations)
 		else:
 			depreciation_amount = flt(depreciable_value * (flt(fb_row.rate_of_depreciation) / 100))
 
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
index 5912329..1d90baa 100644
--- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
@@ -283,12 +283,19 @@
 			)
 
 			# 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
+			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
 				)
-				or value_after_depreciation < row.expected_value_after_useful_life
+				and (
+					not asset_doc.flags.increase_in_asset_value_due_to_repair
+					or not row.depreciation_method in ("Written Down Value", "Double Declining Balance")
+				)
 			):
 				depreciation_amount += value_after_depreciation - row.expected_value_after_useful_life
 				skip_row = True
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index a7172a7..3ef8d5d 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -9,6 +9,7 @@
 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_asset_depr_schedule_doc,
 	get_depr_schedule,
 	make_new_active_asset_depr_schedules_and_cancel_current_ones,
 )
@@ -43,53 +44,61 @@
 	def before_submit(self):
 		self.check_repair_status()
 
-		if self.get("stock_consumption") or self.get("capitalize_repair_cost"):
-			self.increase_asset_value()
-		if self.get("stock_consumption"):
-			self.check_for_stock_items_and_warehouse()
-			self.decrease_stock_quantity()
-		if self.get("capitalize_repair_cost"):
-			self.make_gl_entries()
-			if (
-				frappe.db.get_value("Asset", self.asset, "calculate_depreciation")
-				and self.increase_in_asset_life
-			):
-				self.modify_depreciation_schedule()
+		self.asset_doc.flags.increase_in_asset_value_due_to_repair = False
 
-		notes = _(
-			"This schedule was created when Asset {0} was repaired through Asset Repair {1}."
-		).format(
-			get_link_to_form(self.asset_doc.doctype, self.asset_doc.name),
-			get_link_to_form(self.doctype, self.name),
-		)
-		self.asset_doc.flags.ignore_validate_update_after_submit = True
-		make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, notes)
-		self.asset_doc.save()
+		if self.get("stock_consumption") or self.get("capitalize_repair_cost"):
+			self.asset_doc.flags.increase_in_asset_value_due_to_repair = True
+
+			self.increase_asset_value()
+
+			if self.get("stock_consumption"):
+				self.check_for_stock_items_and_warehouse()
+				self.decrease_stock_quantity()
+			if self.get("capitalize_repair_cost"):
+				self.make_gl_entries()
+				if self.asset_doc.calculate_depreciation and self.increase_in_asset_life:
+					self.modify_depreciation_schedule()
+
+			notes = _(
+				"This schedule was created when Asset {0} was repaired through Asset Repair {1}."
+			).format(
+				get_link_to_form(self.asset_doc.doctype, self.asset_doc.name),
+				get_link_to_form(self.doctype, self.name),
+			)
+			self.asset_doc.flags.ignore_validate_update_after_submit = True
+			make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, notes)
+			if self.asset_doc.calculate_depreciation:
+				self.update_asset_expected_value_after_useful_life()
+			self.asset_doc.save()
 
 	def before_cancel(self):
 		self.asset_doc = frappe.get_doc("Asset", self.asset)
 
-		if self.get("stock_consumption") or self.get("capitalize_repair_cost"):
-			self.decrease_asset_value()
-		if self.get("stock_consumption"):
-			self.increase_stock_quantity()
-		if self.get("capitalize_repair_cost"):
-			self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry")
-			self.make_gl_entries(cancel=True)
-			self.db_set("stock_entry", None)
-			if (
-				frappe.db.get_value("Asset", self.asset, "calculate_depreciation")
-				and self.increase_in_asset_life
-			):
-				self.revert_depreciation_schedule_on_cancellation()
+		self.asset_doc.flags.increase_in_asset_value_due_to_repair = False
 
-		notes = _("This schedule was created when Asset {0}'s Asset Repair {1} was cancelled.").format(
-			get_link_to_form(self.asset_doc.doctype, self.asset_doc.name),
-			get_link_to_form(self.doctype, self.name),
-		)
-		self.asset_doc.flags.ignore_validate_update_after_submit = True
-		make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, notes)
-		self.asset_doc.save()
+		if self.get("stock_consumption") or self.get("capitalize_repair_cost"):
+			self.asset_doc.flags.increase_in_asset_value_due_to_repair = True
+
+			self.decrease_asset_value()
+
+			if self.get("stock_consumption"):
+				self.increase_stock_quantity()
+			if self.get("capitalize_repair_cost"):
+				self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry")
+				self.make_gl_entries(cancel=True)
+				self.db_set("stock_entry", None)
+				if self.asset_doc.calculate_depreciation and self.increase_in_asset_life:
+					self.revert_depreciation_schedule_on_cancellation()
+
+			notes = _("This schedule was created when Asset {0}'s Asset Repair {1} was cancelled.").format(
+				get_link_to_form(self.asset_doc.doctype, self.asset_doc.name),
+				get_link_to_form(self.doctype, self.name),
+			)
+			self.asset_doc.flags.ignore_validate_update_after_submit = True
+			make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, notes)
+			if self.asset_doc.calculate_depreciation:
+				self.update_asset_expected_value_after_useful_life()
+			self.asset_doc.save()
 
 	def after_delete(self):
 		frappe.get_doc("Asset", self.asset).set_status()
@@ -109,6 +118,32 @@
 				title=_("Missing Warehouse"),
 			)
 
+	def update_asset_expected_value_after_useful_life(self):
+		for row in self.asset_doc.get("finance_books"):
+			if row.depreciation_method in ("Written Down Value", "Double Declining Balance"):
+				asset_depr_schedule_doc = get_asset_depr_schedule_doc(
+					self.asset_doc.name, "Active", row.finance_book
+				)
+
+				accumulated_depreciation_after_full_schedule = [
+					d.accumulated_depreciation_amount
+					for d in asset_depr_schedule_doc.get("depreciation_schedule")
+				]
+
+				accumulated_depreciation_after_full_schedule = max(
+					accumulated_depreciation_after_full_schedule
+				)
+
+				asset_value_after_full_schedule = flt(
+					flt(row.value_after_depreciation) - flt(accumulated_depreciation_after_full_schedule),
+					row.precision("expected_value_after_useful_life"),
+				)
+
+				row.expected_value_after_useful_life = asset_value_after_full_schedule
+				asset_depr_schedule_doc.db_set(
+					"expected_value_after_useful_life", asset_value_after_full_schedule
+				)
+
 	def increase_asset_value(self):
 		total_value_of_stock_consumed = self.get_total_value_of_stock_consumed()