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 d7dcfac3aab8..bad89e93259a 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -509,7 +509,10 @@ def set_accumulated_depreciation( continue if not accumulated_depreciation: - if i > 0 and asset_doc.flags.decrease_in_asset_value_due_to_value_adjustment: + if i > 0 and ( + asset_doc.flags.decrease_in_asset_value_due_to_value_adjustment + or asset_doc.flags.increase_in_asset_value_due_to_repair + ): accumulated_depreciation = self.get("depreciation_schedule")[ i - 1 ].accumulated_depreciation_amount @@ -677,7 +680,7 @@ def get_straight_line_or_manual_depr_amount( # if the Depreciation Schedule is being modified after Asset Repair due to increase in asset value elif asset.flags.increase_in_asset_value_due_to_repair: return (flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)) / flt( - row.total_number_of_depreciations + number_of_pending_depreciations ) # if the Depreciation Schedule is being modified after Asset Value Adjustment due to decrease in asset value elif asset.flags.decrease_in_asset_value_due_to_value_adjustment: @@ -1041,6 +1044,7 @@ def make_new_active_asset_depr_schedules_and_cancel_current_ones( date_of_return=None, value_after_depreciation=None, ignore_booked_entry=False, + difference_amount=None, ): for row in asset_doc.get("finance_books"): current_asset_depr_schedule_doc = get_asset_depr_schedule_doc( @@ -1055,6 +1059,8 @@ def make_new_active_asset_depr_schedules_and_cancel_current_ones( ) new_asset_depr_schedule_doc = frappe.copy_doc(current_asset_depr_schedule_doc) + if asset_doc.flags.decrease_in_asset_value_due_to_value_adjustment and not value_after_depreciation: + value_after_depreciation = row.value_after_depreciation + difference_amount if asset_doc.flags.increase_in_asset_value_due_to_repair and row.depreciation_method in ( "Written Down Value", diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.js b/erpnext/assets/doctype/asset_repair/asset_repair.js index 9284c86bd92d..67ce6e6f7efe 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.js +++ b/erpnext/assets/doctype/asset_repair/asset_repair.js @@ -29,6 +29,15 @@ frappe.ui.form.on("Asset Repair", { }; }); + frm.set_query("purchase_invoice", function () { + return { + filters: { + company: frm.doc.company, + docstatus: 1, + }, + }; + }); + frm.set_query("warehouse", "stock_items", function () { return { filters: { diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py index 903e68e32e0e..4e73148828d0 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/asset_repair.py @@ -117,7 +117,9 @@ def before_submit(self): 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) + make_new_active_asset_depr_schedules_and_cancel_current_ones( + self.asset_doc, notes, ignore_booked_entry=True + ) self.asset_doc.save() add_asset_activity( @@ -154,7 +156,9 @@ def before_cancel(self): 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) + make_new_active_asset_depr_schedules_and_cancel_current_ones( + self.asset_doc, notes, ignore_booked_entry=True + ) self.asset_doc.save() add_asset_activity( 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 8dfed9cba8a1..9b0212b037f3 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py @@ -57,7 +57,7 @@ def on_submit(self): def on_cancel(self): frappe.get_doc("Journal Entry", self.journal_entry).cancel() - self.update_asset(self.current_asset_value) + self.update_asset() add_asset_activity( self.asset, _("Asset's value adjusted after cancellation of Asset Value Adjustment {0}").format( @@ -145,7 +145,7 @@ def make_depreciation_entry(self): self.db_set("journal_entry", je.name) - def update_asset(self, asset_value): + def update_asset(self, asset_value=None): asset = frappe.get_doc("Asset", self.asset) if not asset.calculate_depreciation: @@ -171,7 +171,11 @@ def update_asset(self, asset_value): ) make_new_active_asset_depr_schedules_and_cancel_current_ones( - asset, notes, value_after_depreciation=asset_value, ignore_booked_entry=True + asset, + notes, + value_after_depreciation=asset_value, + ignore_booked_entry=True, + difference_amount=self.difference_amount, ) asset.flags.ignore_validate_update_after_submit = True asset.save() 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 634ed4137738..963be704524b 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 @@ -12,6 +12,7 @@ from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( get_asset_depr_schedule_doc, ) +from erpnext.assets.doctype.asset_repair.test_asset_repair import create_asset_repair from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt @@ -128,6 +129,136 @@ def test_asset_depreciation_value_adjustment(self): self.assertEqual(schedules, expected_schedules) + def test_depreciation_after_cancelling_asset_repair(self): + pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=120000.0, location="Test Location") + + asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, "name") + asset_doc = frappe.get_doc("Asset", asset_name) + asset_doc.calculate_depreciation = 1 + asset_doc.available_for_use_date = "2023-01-15" + asset_doc.purchase_date = "2023-01-15" + + asset_doc.append( + "finance_books", + { + "expected_value_after_useful_life": 200, + "depreciation_method": "Straight Line", + "total_number_of_depreciations": 12, + "frequency_of_depreciation": 1, + "depreciation_start_date": "2023-01-31", + }, + ) + asset_doc.submit() + + post_depreciation_entries(getdate("2023-08-21")) + + # create asset repair + asset_repair = create_asset_repair(asset=asset_doc, capitalize_repair_cost=1, submit=1) + + first_asset_depr_schedule = get_asset_depr_schedule_doc(asset_doc.name, "Active") + self.assertEqual(first_asset_depr_schedule.status, "Active") + + # create asset value adjustment + current_value = get_asset_value_after_depreciation(asset_doc.name) + + adj_doc = make_asset_value_adjustment( + asset=asset_doc.name, + current_asset_value=current_value, + new_asset_value=50000.0, + date="2023-08-21", + ) + adj_doc.submit() + + first_asset_depr_schedule.load_from_db() + + second_asset_depr_schedule = get_asset_depr_schedule_doc(asset_doc.name, "Active") + self.assertEqual(second_asset_depr_schedule.status, "Active") + self.assertEqual(first_asset_depr_schedule.status, "Cancelled") + + # Test gl entry creted from asset value adjustemnet + expected_gle = ( + ("_Test Accumulated Depreciations - _TC", 0.0, 5625.29), + ("_Test Depreciations - _TC", 5625.29, 0.0), + ) + + gle = frappe.db.sql( + """select account, debit, credit from `tabGL Entry` + where voucher_type='Journal Entry' and voucher_no = %s + order by account""", + adj_doc.journal_entry, + ) + + self.assertSequenceEqual(gle, expected_gle) + + # test depreciation schedule after asset repair and asset value adjustemnet + expected_schedules = [ + ["2023-01-31", 5474.73, 5474.73], + ["2023-02-28", 9983.33, 15458.06], + ["2023-03-31", 9983.33, 25441.39], + ["2023-04-30", 9983.33, 35424.72], + ["2023-05-31", 9983.33, 45408.05], + ["2023-06-30", 9983.33, 55391.38], + ["2023-07-31", 9983.33, 65374.71], + ["2023-08-31", 2766.67, 68141.38], + ["2023-09-30", 2766.67, 70908.05], + ["2023-10-31", 2766.67, 73674.72], + ["2023-11-30", 2766.67, 76441.39], + ["2023-12-31", 2766.67, 79208.06], + ["2024-01-31", 2766.67, 81974.73], + ["2024-02-29", 2766.67, 84741.4], + ["2024-03-31", 2766.67, 87508.07], + ["2024-04-30", 2766.67, 90274.74], + ["2024-05-31", 2766.67, 93041.41], + ["2024-06-30", 2766.67, 95808.08], + ["2024-07-31", 2766.67, 98574.75], + ["2024-08-31", 2766.67, 101341.42], + ["2024-09-30", 2766.67, 104108.09], + ["2024-10-31", 2766.67, 106874.76], + ["2024-11-30", 2766.67, 109641.43], + ["2024-12-31", 2766.67, 112408.1], + ["2025-01-15", 2766.61, 115174.71], + ] + + schedules = [ + [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] + for d in second_asset_depr_schedule.get("depreciation_schedule") + ] + + self.assertEqual(schedules, expected_schedules) + + # Cancel asset repair + asset_repair.cancel() + asset_repair.load_from_db() + second_asset_depr_schedule.load_from_db() + + third_asset_depr_schedule = get_asset_depr_schedule_doc(asset_doc.name, "Active") + self.assertEqual(third_asset_depr_schedule.status, "Active") + self.assertEqual(second_asset_depr_schedule.status, "Cancelled") + + # After cancelling asset repair asset life will be decreased and new depreciation schedule should be calculated + expected_schedules = [ + ["2023-01-31", 5474.73, 5474.73], + ["2023-02-28", 9983.33, 15458.06], + ["2023-03-31", 9983.33, 25441.39], + ["2023-04-30", 9983.33, 35424.72], + ["2023-05-31", 9983.33, 45408.05], + ["2023-06-30", 9983.33, 55391.38], + ["2023-07-31", 9983.33, 65374.71], + ["2023-08-31", 8133.33, 73508.04], + ["2023-09-30", 8133.33, 81641.37], + ["2023-10-31", 8133.33, 89774.7], + ["2023-11-30", 8133.33, 97908.03], + ["2023-12-31", 8133.33, 106041.36], + ["2024-01-15", 8133.35, 114174.71], + ] + + schedules = [ + [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] + for d in third_asset_depr_schedule.get("depreciation_schedule") + ] + + self.assertEqual(schedules, expected_schedules) + def make_asset_value_adjustment(**args): args = frappe._dict(args)