From e7659a10e4372a871ce3d2efc0428ff57888b55c Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 24 Jun 2022 17:38:41 +0530 Subject: [PATCH] fix: Monthly depreciation using WDV method --- erpnext/assets/doctype/asset/asset.py | 20 ++++--- erpnext/assets/doctype/asset/test_asset.py | 61 +++++++++++++++++++++- 2 files changed, 74 insertions(+), 7 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 651ab9b00e8..4d63a285534 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -257,6 +257,7 @@ class Asset(AccountsController): 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) @@ -270,6 +271,9 @@ class Asset(AccountsController): 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) @@ -845,14 +849,9 @@ class Asset(AccountsController): if args.get("rate_of_depreciation") and on_validate: return args.get("rate_of_depreciation") - no_of_years = ( - flt(args.get("total_number_of_depreciations") * flt(args.get("frequency_of_depreciation"))) - / 12 - ) value = flt(args.get("expected_value_after_useful_life")) / flt(self.gross_purchase_amount) - # square root of flt(salvage_value) / flt(asset_cost) - depreciation_rate = math.pow(value, 1.0 / flt(no_of_years, 2)) + depreciation_rate = math.pow(value, 1.0 / flt(args.get("total_number_of_depreciations"), 2)) return 100 * (1 - flt(depreciation_rate, float_precision)) @@ -1103,9 +1102,18 @@ def is_cwip_accounting_enabled(asset_category): def get_total_days(date, frequency): period_start_date = add_months(date, cint(frequency) * -1) + if is_last_day_of_the_month(date): + period_start_date = get_last_day(period_start_date) + 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"): diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index 226a38a5849..9bfafaf8657 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -701,6 +701,39 @@ class TestDepreciationMethods(AssetSetup): asset.reload() self.assertEquals(asset.finance_books[0].value_after_depreciation, 98000.0) + def test_monthly_depreciation_by_wdv_method(self): + asset = create_asset( + calculate_depreciation=1, + available_for_use_date="2022-02-15", + purchase_date="2022-02-15", + depreciation_method="Written Down Value", + gross_purchase_amount=10000, + expected_value_after_useful_life=5000, + depreciation_start_date="2022-02-28", + total_number_of_depreciations=5, + frequency_of_depreciation=1, + ) + + expected_schedules = [ + ["2022-02-28", 645.0, 645.0], + ["2022-03-31", 1206.8, 1851.8], + ["2022-04-30", 1051.12, 2902.92], + ["2022-05-31", 915.52, 3818.44], + ["2022-06-30", 797.42, 4615.86], + ["2022-07-15", 384.14, 5000.0], + ] + + schedules = [ + [ + cstr(d.schedule_date), + flt(d.depreciation_amount, 2), + flt(d.accumulated_depreciation_amount, 2), + ] + for d in asset.get("schedules") + ] + + self.assertEqual(schedules, expected_schedules) + class TestDepreciationBasics(AssetSetup): def test_depreciation_without_pro_rata(self): @@ -787,7 +820,7 @@ class TestDepreciationBasics(AssetSetup): expected_values = [["2020-12-31", 30000.0], ["2021-12-31", 30000.0], ["2022-12-31", 30000.0]] for i, schedule in enumerate(asset.schedules): - self.assertEqual(expected_values[i][0], schedule.schedule_date) + self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date) self.assertEqual(expected_values[i][1], schedule.depreciation_amount) def test_set_accumulated_depreciation(self): @@ -1261,6 +1294,32 @@ class TestDepreciationBasics(AssetSetup): asset.cost_center = "Main - _TC" asset.submit() + def test_depreciation_on_final_day_of_the_month(self): + """Tests if final day of the month is picked each time, if the depreciation start date is the last day of the month.""" + + asset = create_asset( + item_code="Macbook Pro", + calculate_depreciation=1, + purchase_date="2020-01-30", + available_for_use_date="2020-02-15", + depreciation_start_date="2020-02-29", + frequency_of_depreciation=1, + total_number_of_depreciations=5, + submit=1, + ) + + expected_dates = [ + "2020-02-29", + "2020-03-31", + "2020-04-30", + "2020-05-31", + "2020-06-30", + "2020-07-15", + ] + + for i, schedule in enumerate(asset.schedules): + self.assertEqual(getdate(expected_dates[i]), getdate(schedule.schedule_date)) + def create_asset_data(): if not frappe.db.exists("Asset Category", "Computers"):