From f337392f3ee94e7d2e27c9b6b2bfd8d5a2dcf1d5 Mon Sep 17 00:00:00 2001 From: Khushi Rawat <142375893+khushi8112@users.noreply.github.com> Date: Fri, 26 Apr 2024 12:33:22 +0530 Subject: [PATCH 1/8] fix(wip): daily depreciation bug --- .../asset_depreciation_schedule.py | 114 +++++++++++++++++- 1 file changed, 112 insertions(+), 2 deletions(-) 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 27da403cd35..2b208035b56 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -285,6 +285,7 @@ class AssetDepreciationSchedule(Document): number_of_pending_depreciations = final_number_of_depreciations - start yearly_opening_wdv = value_after_depreciation current_fiscal_year_end_date = None + prev_per_day_depr = True for n in range(start, final_number_of_depreciations): # If depreciation is already completed (for double declining balance) if skip_row: @@ -302,7 +303,7 @@ class AssetDepreciationSchedule(Document): else: prev_depreciation_amount = 0 - depreciation_amount = get_depreciation_amount( + depreciation_amount, prev_per_day_depr = get_depreciation_amount( self, asset_doc, value_after_depreciation, @@ -312,6 +313,7 @@ class AssetDepreciationSchedule(Document): prev_depreciation_amount, has_wdv_or_dd_non_yearly_pro_rata, number_of_pending_depreciations, + prev_per_day_depr, ) if not has_pro_rata or ( n < (cint(final_number_of_depreciations) - 1) or final_number_of_depreciations == 2 @@ -351,6 +353,7 @@ class AssetDepreciationSchedule(Document): and (has_pro_rata or has_wdv_or_dd_non_yearly_pro_rata) and not self.opening_accumulated_depreciation and not self.flags.wdv_it_act_applied + and not self.daily_prorata_based ): from_date = add_days( asset_doc.available_for_use_date, -1 @@ -599,11 +602,12 @@ def get_depreciation_amount( prev_depreciation_amount=0, has_wdv_or_dd_non_yearly_pro_rata=False, number_of_pending_depreciations=0, + prev_per_day_depr=0, ): if fb_row.depreciation_method in ("Straight Line", "Manual"): return get_straight_line_or_manual_depr_amount( asset_depr_schedule, asset, fb_row, schedule_idx, number_of_pending_depreciations - ) + ), None else: return get_wdv_or_dd_depr_amount( asset, @@ -614,6 +618,7 @@ def get_depreciation_amount( prev_depreciation_amount, has_wdv_or_dd_non_yearly_pro_rata, asset_depr_schedule, + prev_per_day_depr, ) @@ -739,6 +744,7 @@ def get_wdv_or_dd_depr_amount( prev_depreciation_amount, has_wdv_or_dd_non_yearly_pro_rata, asset_depr_schedule, + prev_per_day_depr, ): return get_default_wdv_or_dd_depr_amount( asset, @@ -748,6 +754,7 @@ def get_wdv_or_dd_depr_amount( prev_depreciation_amount, has_wdv_or_dd_non_yearly_pro_rata, asset_depr_schedule, + prev_per_day_depr, ) @@ -759,6 +766,42 @@ def get_default_wdv_or_dd_depr_amount( prev_depreciation_amount, has_wdv_or_dd_non_yearly_pro_rata, asset_depr_schedule, + prev_per_day_depr, +): + if cint(fb_row.frequency_of_depreciation) == 12: + return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100) + else: + if not fb_row.daily_prorata_based: + return _get_default_wdv_or_dd_depr_amount( + asset, + fb_row, + depreciable_value, + schedule_idx, + prev_depreciation_amount, + has_wdv_or_dd_non_yearly_pro_rata, + asset_depr_schedule, + ), None + else: + return _get_daily_prorata_based_default_wdv_or_dd_depr_amount( + asset, + fb_row, + depreciable_value, + schedule_idx, + prev_depreciation_amount, + has_wdv_or_dd_non_yearly_pro_rata, + asset_depr_schedule, + prev_per_day_depr, + ) + + +def _get_default_wdv_or_dd_depr_amount( + asset, + fb_row, + depreciable_value, + schedule_idx, + prev_depreciation_amount, + has_wdv_or_dd_non_yearly_pro_rata, + asset_depr_schedule, ): if cint(fb_row.frequency_of_depreciation) == 12: return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100) @@ -785,6 +828,73 @@ def get_default_wdv_or_dd_depr_amount( return prev_depreciation_amount +def _get_daily_prorata_based_default_wdv_or_dd_depr_amount( + asset, + fb_row, + depreciable_value, + schedule_idx, + prev_depreciation_amount, + has_wdv_or_dd_non_yearly_pro_rata, + asset_depr_schedule, + prev_per_day_depr, +): + if has_wdv_or_dd_non_yearly_pro_rata: + if schedule_idx == 0: + print(">>>>>", depreciable_value) + per_day_depr = get_per_day_depr(fb_row, depreciable_value, fb_row.depreciation_start_date) + from_date = asset.available_for_use_date + to_date = add_days(fb_row.depreciation_start_date, -1) + total_days = date_diff(to_date, from_date) + 1 + print("892", per_day_depr, from_date, to_date, total_days) + return (per_day_depr * total_days), per_day_depr + + elif schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 1: + from_date, to_date = get_dates( + fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation) + ) + per_day_depr = get_per_day_depr(fb_row, depreciable_value, from_date) + days_in_month = date_diff(to_date, from_date) + 1 + return (per_day_depr * days_in_month), per_day_depr + + else: + from_date, to_date = get_dates( + fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation) + ) + days_in_month = date_diff(to_date, from_date) + 1 + return (prev_per_day_depr * days_in_month), prev_per_day_depr + else: + if schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 0: + from_date, to_date = get_dates( + fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation) + ) + per_day_depr = get_per_day_depr(fb_row, depreciable_value, from_date) + days_in_month = date_diff(to_date, from_date) + 1 + return (per_day_depr * days_in_month), per_day_depr + else: + from_date, to_date = get_dates( + fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation) + ) + days_in_month = date_diff(to_date, from_date) + 1 + return (prev_per_day_depr * days_in_month), prev_per_day_depr + + +def get_per_day_depr( + fb_row, + depreciable_value, + from_date, +): + to_date = add_years(from_date, 1) + total_days = date_diff(to_date, from_date) + 1 + per_day_depr = (flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100)) / total_days + return per_day_depr + + +def get_dates(depreciation_start_date, schedule_idx, frequency_of_depreciation): + from_date = add_months(depreciation_start_date, (schedule_idx - 1) * frequency_of_depreciation) + to_date = add_days(add_months(from_date, frequency_of_depreciation), -1) + return from_date, to_date + + def make_draft_asset_depr_schedules_if_not_present(asset_doc): asset_depr_schedules_names = [] From b8a98a273b965a25a697944762fad0cd34ca1598 Mon Sep 17 00:00:00 2001 From: Khushi Rawat <142375893+khushi8112@users.noreply.github.com> Date: Mon, 29 Apr 2024 12:03:06 +0530 Subject: [PATCH 2/8] fix: daily prorata based depreciation bug in wdv method --- erpnext/assets/doctype/asset/test_asset.py | 3 +- .../asset_depreciation_schedule.py | 71 +++++++++++-------- .../test_asset_depreciation_schedule.py | 65 +++++++++++++++++ 3 files changed, 110 insertions(+), 29 deletions(-) diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index d2151dcc325..fabc79d4060 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -1000,7 +1000,7 @@ class TestDepreciationBasics(AssetSetup): asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset.name, "Active") - depreciation_amount = get_depreciation_amount( + depreciation_amount, prev_per_day_depr = get_depreciation_amount( asset_depr_schedule_doc, asset, 100000, 100000, asset.finance_books[0] ) self.assertEqual(depreciation_amount, 30000) @@ -1723,6 +1723,7 @@ def create_asset(**args): "depreciation_start_date": args.depreciation_start_date, "daily_prorata_based": args.daily_prorata_based or 0, "shift_based": args.shift_based or 0, + "rate_of_depreciation": args.rate_of_depreciation or 40, }, ) 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 2b208035b56..27e15aea73a 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -302,7 +302,6 @@ class AssetDepreciationSchedule(Document): prev_depreciation_amount = self.get("depreciation_schedule")[n - 1].depreciation_amount else: prev_depreciation_amount = 0 - depreciation_amount, prev_per_day_depr = get_depreciation_amount( self, asset_doc, @@ -353,7 +352,13 @@ class AssetDepreciationSchedule(Document): and (has_pro_rata or has_wdv_or_dd_non_yearly_pro_rata) and not self.opening_accumulated_depreciation and not self.flags.wdv_it_act_applied - and not self.daily_prorata_based + and ( + row.depreciation_method in ("Straight Line", "Manual") + or ( + row.depreciation_method in ("Written Down Value", "Double Declining Balance") + and not row.daily_prorata_based + ) + ) ): from_date = add_days( asset_doc.available_for_use_date, -1 @@ -768,30 +773,27 @@ def get_default_wdv_or_dd_depr_amount( asset_depr_schedule, prev_per_day_depr, ): - if cint(fb_row.frequency_of_depreciation) == 12: - return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100) + if not fb_row.daily_prorata_based: + return _get_default_wdv_or_dd_depr_amount( + asset, + fb_row, + depreciable_value, + schedule_idx, + prev_depreciation_amount, + has_wdv_or_dd_non_yearly_pro_rata, + asset_depr_schedule, + ), None else: - if not fb_row.daily_prorata_based: - return _get_default_wdv_or_dd_depr_amount( - asset, - fb_row, - depreciable_value, - schedule_idx, - prev_depreciation_amount, - has_wdv_or_dd_non_yearly_pro_rata, - asset_depr_schedule, - ), None - else: - return _get_daily_prorata_based_default_wdv_or_dd_depr_amount( - asset, - fb_row, - depreciable_value, - schedule_idx, - prev_depreciation_amount, - has_wdv_or_dd_non_yearly_pro_rata, - asset_depr_schedule, - prev_per_day_depr, - ) + return _get_daily_prorata_based_default_wdv_or_dd_depr_amount( + asset, + fb_row, + depreciable_value, + schedule_idx, + prev_depreciation_amount, + has_wdv_or_dd_non_yearly_pro_rata, + asset_depr_schedule, + prev_per_day_depr, + ) def _get_default_wdv_or_dd_depr_amount( @@ -838,14 +840,27 @@ def _get_daily_prorata_based_default_wdv_or_dd_depr_amount( asset_depr_schedule, prev_per_day_depr, ): - if has_wdv_or_dd_non_yearly_pro_rata: + if cint(fb_row.frequency_of_depreciation) == 12: if schedule_idx == 0: - print(">>>>>", depreciable_value) per_day_depr = get_per_day_depr(fb_row, depreciable_value, fb_row.depreciation_start_date) from_date = asset.available_for_use_date to_date = add_days(fb_row.depreciation_start_date, -1) total_days = date_diff(to_date, from_date) + 1 - print("892", per_day_depr, from_date, to_date, total_days) + return (per_day_depr * total_days), per_day_depr + else: + from_date, to_date = get_dates( + fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation) + ) + days_in_month = date_diff(to_date, from_date) + 1 + return (prev_per_day_depr * days_in_month), prev_per_day_depr + + if has_wdv_or_dd_non_yearly_pro_rata: + if schedule_idx == 0: + per_day_depr = get_per_day_depr(fb_row, depreciable_value, fb_row.depreciation_start_date) + from_date = asset.available_for_use_date + to_date = add_days(fb_row.depreciation_start_date, -1) + total_days = date_diff(to_date, from_date) + 1 + return (per_day_depr * total_days), per_day_depr elif schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 1: 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 index 5971d1662f9..ce877f42376 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py @@ -71,3 +71,68 @@ class TestAssetDepreciationSchedule(FrappeTestCase): for d in get_depr_schedule(asset.name, "Draft") ] self.assertEqual(schedules, expected_schedules) + # Test for Written Down Value Method + def test_daily_prorata_based_depreciation_for_wdv_method(self): + # Frequency of deprciation = 3 + asset = create_asset( + item_code="Macbook Pro", + calculate_depreciation=1, + depreciation_method="Written Down Value", + daily_prorata_based=1, + available_for_use_date="2021-02-20", + depreciation_start_date="2021-03-31", + frequency_of_depreciation=3, + total_number_of_depreciations=18, + rate_of_depreciation=40, + submit=1, + ) + asset_depr_schedule = frappe.get_last_doc("Asset Depreciation Schedule", {"asset": asset.name}) + self.assertEqual(asset_depr_schedule.depreciation_schedule[1].depreciation_amount, 9521.45) + + # Frequency of deprciation = 6 + asset = create_asset( + item_code="Macbook Pro", + calculate_depreciation=1, + depreciation_method="Written Down Value", + daily_prorata_based=1, + available_for_use_date="2020-02-20", + depreciation_start_date="2020-03-01", + frequency_of_depreciation=6, + total_number_of_depreciations=18, + rate_of_depreciation=40, + submit=1, + ) + asset_depr_schedule = frappe.get_last_doc("Asset Depreciation Schedule", {"asset": asset.name}) + self.assertEqual(asset_depr_schedule.depreciation_schedule[1].depreciation_amount, 19889.52) + + # Frequency of deprciation = 12 + asset = create_asset( + item_code="Macbook Pro", + calculate_depreciation=1, + depreciation_method="Written Down Value", + daily_prorata_based=1, + available_for_use_date="2020-02-20", + depreciation_start_date="2020-03-01", + frequency_of_depreciation=12, + total_number_of_depreciations=4, + rate_of_depreciation=40, + submit=1, + ) + asset_depr_schedule = frappe.get_last_doc("Asset Depreciation Schedule", {"asset": asset.name}) + self.assertEqual(asset_depr_schedule.depreciation_schedule[0].depreciation_amount, 1092.90) + + # Test for Straight Line Method + def test_daily_prorata_based_depreciation_for_straight_line_method(self): + asset = create_asset( + item_code="Macbook Pro", + calculate_depreciation=1, + depreciation_method="Straight Line", + daily_prorata_based=0, + available_for_use_date="2020-02-20", + depreciation_start_date="2020-03-01", + frequency_of_depreciation=12, + total_number_of_depreciations=4, + submit=1, + ) + asset_depr_schedule = frappe.get_last_doc("Asset Depreciation Schedule", {"asset": asset.name}) + self.assertEqual(asset_depr_schedule.depreciation_schedule[0].depreciation_amount, 751.37) From fccd37d32d86450cecaf73a4d4aa4bcf67177d97 Mon Sep 17 00:00:00 2001 From: Khushi Rawat <142375893+khushi8112@users.noreply.github.com> Date: Mon, 29 Apr 2024 16:27:13 +0530 Subject: [PATCH 3/8] fix: incorrect total days calculation --- .../asset_depreciation_schedule.py | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) 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 27e15aea73a..2dc4e08902d 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -848,11 +848,10 @@ def _get_daily_prorata_based_default_wdv_or_dd_depr_amount( total_days = date_diff(to_date, from_date) + 1 return (per_day_depr * total_days), per_day_depr else: - from_date, to_date = get_dates( + from_date, days_in_month = _get_total_days( fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation) ) - days_in_month = date_diff(to_date, from_date) + 1 - return (prev_per_day_depr * days_in_month), prev_per_day_depr + return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100), None if has_wdv_or_dd_non_yearly_pro_rata: if schedule_idx == 0: @@ -860,36 +859,31 @@ def _get_daily_prorata_based_default_wdv_or_dd_depr_amount( from_date = asset.available_for_use_date to_date = add_days(fb_row.depreciation_start_date, -1) total_days = date_diff(to_date, from_date) + 1 - return (per_day_depr * total_days), per_day_depr elif schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 1: - from_date, to_date = get_dates( + from_date, days_in_month = _get_total_days( fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation) ) per_day_depr = get_per_day_depr(fb_row, depreciable_value, from_date) - days_in_month = date_diff(to_date, from_date) + 1 return (per_day_depr * days_in_month), per_day_depr else: - from_date, to_date = get_dates( + from_date, days_in_month = _get_total_days( fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation) ) - days_in_month = date_diff(to_date, from_date) + 1 return (prev_per_day_depr * days_in_month), prev_per_day_depr else: if schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 0: - from_date, to_date = get_dates( + from_date, days_in_month = _get_total_days( fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation) ) per_day_depr = get_per_day_depr(fb_row, depreciable_value, from_date) - days_in_month = date_diff(to_date, from_date) + 1 return (per_day_depr * days_in_month), per_day_depr else: - from_date, to_date = get_dates( + from_date, days_in_month = _get_total_days( fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation) ) - days_in_month = date_diff(to_date, from_date) + 1 return (prev_per_day_depr * days_in_month), prev_per_day_depr @@ -904,10 +898,13 @@ def get_per_day_depr( return per_day_depr -def get_dates(depreciation_start_date, schedule_idx, frequency_of_depreciation): +def _get_total_days(depreciation_start_date, schedule_idx, frequency_of_depreciation): from_date = add_months(depreciation_start_date, (schedule_idx - 1) * frequency_of_depreciation) - to_date = add_days(add_months(from_date, frequency_of_depreciation), -1) - return from_date, to_date + to_date = add_months(from_date, frequency_of_depreciation) + if is_last_day_of_the_month(depreciation_start_date): + to_date = get_last_day(to_date) + from_date = get_last_day(from_date) + return from_date, date_diff(to_date, from_date) def make_draft_asset_depr_schedules_if_not_present(asset_doc): From d40b55468ce76ba35caea20fcb20d3db2177aec5 Mon Sep 17 00:00:00 2001 From: Khushi Rawat <142375893+khushi8112@users.noreply.github.com> Date: Tue, 30 Apr 2024 15:52:05 +0530 Subject: [PATCH 4/8] test: made minor change in existing test --- erpnext/assets/doctype/asset/test_asset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index fabc79d4060..5c49c0a8451 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -1723,7 +1723,7 @@ def create_asset(**args): "depreciation_start_date": args.depreciation_start_date, "daily_prorata_based": args.daily_prorata_based or 0, "shift_based": args.shift_based or 0, - "rate_of_depreciation": args.rate_of_depreciation or 40, + "rate_of_depreciation": args.rate_of_depreciation or 0, }, ) From c0c8c1bb02815e084931a450326fa1cd4f0baf0d Mon Sep 17 00:00:00 2001 From: Khushi Rawat <142375893+khushi8112@users.noreply.github.com> Date: Tue, 7 May 2024 11:15:49 +0530 Subject: [PATCH 5/8] fix: pro rata based depreciation with opening accumulated depreciation --- .../asset_depreciation_schedule.py | 21 +---- .../test_asset_depreciation_schedule.py | 87 ++++++++++++------- 2 files changed, 58 insertions(+), 50 deletions(-) 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 2dc4e08902d..88c04419da8 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -352,13 +352,6 @@ class AssetDepreciationSchedule(Document): and (has_pro_rata or has_wdv_or_dd_non_yearly_pro_rata) and not self.opening_accumulated_depreciation and not self.flags.wdv_it_act_applied - and ( - row.depreciation_method in ("Straight Line", "Manual") - or ( - row.depreciation_method in ("Written Down Value", "Double Declining Balance") - and not row.daily_prorata_based - ) - ) ): from_date = add_days( asset_doc.available_for_use_date, -1 @@ -842,11 +835,7 @@ def _get_daily_prorata_based_default_wdv_or_dd_depr_amount( ): if cint(fb_row.frequency_of_depreciation) == 12: if schedule_idx == 0: - per_day_depr = get_per_day_depr(fb_row, depreciable_value, fb_row.depreciation_start_date) - from_date = asset.available_for_use_date - to_date = add_days(fb_row.depreciation_start_date, -1) - total_days = date_diff(to_date, from_date) + 1 - return (per_day_depr * total_days), per_day_depr + return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100), None else: from_date, days_in_month = _get_total_days( fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation) @@ -855,11 +844,7 @@ def _get_daily_prorata_based_default_wdv_or_dd_depr_amount( if has_wdv_or_dd_non_yearly_pro_rata: if schedule_idx == 0: - per_day_depr = get_per_day_depr(fb_row, depreciable_value, fb_row.depreciation_start_date) - from_date = asset.available_for_use_date - to_date = add_days(fb_row.depreciation_start_date, -1) - total_days = date_diff(to_date, from_date) + 1 - return (per_day_depr * total_days), per_day_depr + return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100), None elif schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 1: from_date, days_in_month = _get_total_days( @@ -892,7 +877,7 @@ def get_per_day_depr( depreciable_value, from_date, ): - to_date = add_years(from_date, 1) + to_date = add_days(add_years(from_date, 1), -1) total_days = date_diff(to_date, from_date) + 1 per_day_depr = (flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100)) / total_days return per_day_depr 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 index ce877f42376..236c45f7f41 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py @@ -72,8 +72,8 @@ class TestAssetDepreciationSchedule(FrappeTestCase): ] self.assertEqual(schedules, expected_schedules) # Test for Written Down Value Method - def test_daily_prorata_based_depreciation_for_wdv_method(self): - # Frequency of deprciation = 3 + # Frequency of deprciation = 3 + def test_for_daily_prorata_based_depreciation_wdv_method_frequency_3_months(self): asset = create_asset( item_code="Macbook Pro", calculate_depreciation=1, @@ -82,57 +82,80 @@ class TestAssetDepreciationSchedule(FrappeTestCase): available_for_use_date="2021-02-20", depreciation_start_date="2021-03-31", frequency_of_depreciation=3, - total_number_of_depreciations=18, + total_number_of_depreciations=6, rate_of_depreciation=40, - submit=1, ) - asset_depr_schedule = frappe.get_last_doc("Asset Depreciation Schedule", {"asset": asset.name}) - self.assertEqual(asset_depr_schedule.depreciation_schedule[1].depreciation_amount, 9521.45) - # Frequency of deprciation = 6 + expected_schedules = [ + ["2021-03-31", 4383.56, 4383.56], + ["2021-06-30", 9535.45, 13919.01], + ["2021-09-30", 9640.23, 23559.24], + ["2021-12-31", 9640.23, 33199.47], + ["2022-03-31", 9430.66, 42630.13], + ["2022-06-30", 5721.27, 48351.4], + ["2022-08-20", 51648.6, 100000.0], + ] + + schedules = [ + [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] + for d in get_depr_schedule(asset.name, "Draft") + ] + self.assertEqual(schedules, expected_schedules) + + # Frequency of deprciation = 6 + def test_for_daily_prorata_based_depreciation_wdv_method_frequency_6_months(self): asset = create_asset( item_code="Macbook Pro", calculate_depreciation=1, depreciation_method="Written Down Value", daily_prorata_based=1, available_for_use_date="2020-02-20", - depreciation_start_date="2020-03-01", + depreciation_start_date="2020-02-29", frequency_of_depreciation=6, - total_number_of_depreciations=18, + total_number_of_depreciations=6, rate_of_depreciation=40, - submit=1, ) - asset_depr_schedule = frappe.get_last_doc("Asset Depreciation Schedule", {"asset": asset.name}) - self.assertEqual(asset_depr_schedule.depreciation_schedule[1].depreciation_amount, 19889.52) - # Frequency of deprciation = 12 + expected_schedules = [ + ["2020-02-29", 1092.90, 1092.90], + ["2020-08-31", 19944.01, 21036.91], + ["2021-02-28", 19618.83, 40655.74], + ["2021-08-31", 11966.4, 52622.14], + ["2022-02-28", 11771.3, 64393.44], + ["2022-08-31", 7179.84, 71573.28], + ["2023-02-20", 28426.72, 100000.0], + ] + + schedules = [ + [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] + for d in get_depr_schedule(asset.name, "Draft") + ] + self.assertEqual(schedules, expected_schedules) + + # Frequency of deprciation = 12 + def test_for_daily_prorata_based_depreciation_wdv_method_frequency_12_months(self): asset = create_asset( item_code="Macbook Pro", calculate_depreciation=1, depreciation_method="Written Down Value", daily_prorata_based=1, available_for_use_date="2020-02-20", - depreciation_start_date="2020-03-01", + depreciation_start_date="2020-03-31", frequency_of_depreciation=12, total_number_of_depreciations=4, rate_of_depreciation=40, - submit=1, ) - asset_depr_schedule = frappe.get_last_doc("Asset Depreciation Schedule", {"asset": asset.name}) - self.assertEqual(asset_depr_schedule.depreciation_schedule[0].depreciation_amount, 1092.90) - # Test for Straight Line Method - def test_daily_prorata_based_depreciation_for_straight_line_method(self): - asset = create_asset( - item_code="Macbook Pro", - calculate_depreciation=1, - depreciation_method="Straight Line", - daily_prorata_based=0, - available_for_use_date="2020-02-20", - depreciation_start_date="2020-03-01", - frequency_of_depreciation=12, - total_number_of_depreciations=4, - submit=1, - ) - asset_depr_schedule = frappe.get_last_doc("Asset Depreciation Schedule", {"asset": asset.name}) - self.assertEqual(asset_depr_schedule.depreciation_schedule[0].depreciation_amount, 751.37) + expected_schedules = [ + ["2020-03-31", 4480.87, 4480.87], + ["2021-03-31", 38207.65, 42688.52], + ["2022-03-31", 22924.59, 65613.11], + ["2023-03-31", 13754.76, 79367.87], + ["2024-02-20", 20632.13, 100000], + ] + + schedules = [ + [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] + for d in get_depr_schedule(asset.name, "Draft") + ] + self.assertEqual(schedules, expected_schedules) From 7b264e5e11b79269072fb627317d2224385af30d Mon Sep 17 00:00:00 2001 From: Khushi Rawat <142375893+khushi8112@users.noreply.github.com> Date: Tue, 14 May 2024 19:13:41 +0530 Subject: [PATCH 6/8] refactor: code optimization --- .../asset_depreciation_schedule.py | 53 +++++++++++-------- 1 file changed, 31 insertions(+), 22 deletions(-) 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 88c04419da8..492ccc3c16d 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -842,34 +842,43 @@ def _get_daily_prorata_based_default_wdv_or_dd_depr_amount( ) return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100), None - if has_wdv_or_dd_non_yearly_pro_rata: + if has_wdv_or_dd_non_yearly_pro_rata: # If applicable days for ther first month is less than full month if schedule_idx == 0: return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100), None - elif schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 1: - from_date, days_in_month = _get_total_days( - fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation) - ) - per_day_depr = get_per_day_depr(fb_row, depreciable_value, from_date) - return (per_day_depr * days_in_month), per_day_depr - + elif schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 1: # Year changes + return get_monthly_depr_amount(fb_row, schedule_idx, depreciable_value) else: - from_date, days_in_month = _get_total_days( - fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation) - ) - return (prev_per_day_depr * days_in_month), prev_per_day_depr + return get_monthly_depr_amount_based_on_prev_per_day_depr(fb_row, schedule_idx, prev_per_day_depr) else: - if schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 0: - from_date, days_in_month = _get_total_days( - fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation) - ) - per_day_depr = get_per_day_depr(fb_row, depreciable_value, from_date) - return (per_day_depr * days_in_month), per_day_depr + if schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 0: # year changes + return get_monthly_depr_amount(fb_row, schedule_idx, depreciable_value) else: - from_date, days_in_month = _get_total_days( - fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation) - ) - return (prev_per_day_depr * days_in_month), prev_per_day_depr + return get_monthly_depr_amount_based_on_prev_per_day_depr(fb_row, schedule_idx, prev_per_day_depr) + + +def get_monthly_depr_amount(fb_row, schedule_idx, depreciable_value): + """ " + Returns monthly depreciation amount when year changes + 1. Calculate per day depr based on new year + 2. Calculate monthly amount based on new per day amount + """ + from_date, days_in_month = _get_total_days( + fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation) + ) + per_day_depr = get_per_day_depr(fb_row, depreciable_value, from_date) + return (per_day_depr * days_in_month), per_day_depr + + +def get_monthly_depr_amount_based_on_prev_per_day_depr(fb_row, schedule_idx, prev_per_day_depr): + """ " + Returns monthly depreciation amount based on prev per day depr + Calculate per day depr only for the first month + """ + from_date, days_in_month = _get_total_days( + fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation) + ) + return (prev_per_day_depr * days_in_month), prev_per_day_depr def get_per_day_depr( From d22df324ec69b76d77da6478263043893c4f51e2 Mon Sep 17 00:00:00 2001 From: Khushi Rawat <142375893+khushi8112@users.noreply.github.com> Date: Wed, 15 May 2024 01:10:54 +0530 Subject: [PATCH 7/8] fix: removed same named function --- .../asset_depreciation_schedule.py | 26 +++---------------- 1 file changed, 4 insertions(+), 22 deletions(-) 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 492ccc3c16d..c1ea42ba020 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -682,21 +682,12 @@ def get_daily_prorata_based_straight_line_depr( ) year_end_date = add_days(add_years(year_start_date, 1), -1) daily_depr_amount = every_year_depr / (date_diff(year_end_date, year_start_date) + 1) - total_depreciable_days = _get_total_days( + from_date, total_depreciable_days = _get_total_days( row.depreciation_start_date, schedule_idx, row.frequency_of_depreciation ) return daily_depr_amount * total_depreciable_days -def _get_total_days(depreciation_start_date, schedule_idx, frequency_of_depreciation): - from_date = add_months(depreciation_start_date, (schedule_idx - 1) * frequency_of_depreciation) - to_date = add_months(from_date, frequency_of_depreciation) - if is_last_day_of_the_month(depreciation_start_date): - to_date = get_last_day(to_date) - from_date = add_days(get_last_day(from_date), 1) - return date_diff(to_date, from_date) + 1 - - def get_shift_depr_amount(asset_depr_schedule, asset, row, schedule_idx): if asset_depr_schedule.get("__islocal") and not asset.flags.shift_allocation: return ( @@ -766,7 +757,7 @@ def get_default_wdv_or_dd_depr_amount( asset_depr_schedule, prev_per_day_depr, ): - if not fb_row.daily_prorata_based: + if not fb_row.daily_prorata_based or cint(fb_row.frequency_of_depreciation) == 12: return _get_default_wdv_or_dd_depr_amount( asset, fb_row, @@ -833,15 +824,6 @@ def _get_daily_prorata_based_default_wdv_or_dd_depr_amount( asset_depr_schedule, prev_per_day_depr, ): - if cint(fb_row.frequency_of_depreciation) == 12: - if schedule_idx == 0: - return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100), None - else: - from_date, days_in_month = _get_total_days( - fb_row.depreciation_start_date, schedule_idx, cint(fb_row.frequency_of_depreciation) - ) - return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100), None - if has_wdv_or_dd_non_yearly_pro_rata: # If applicable days for ther first month is less than full month if schedule_idx == 0: return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100), None @@ -897,8 +879,8 @@ def _get_total_days(depreciation_start_date, schedule_idx, frequency_of_deprecia to_date = add_months(from_date, frequency_of_depreciation) if is_last_day_of_the_month(depreciation_start_date): to_date = get_last_day(to_date) - from_date = get_last_day(from_date) - return from_date, date_diff(to_date, from_date) + from_date = add_days(get_last_day(from_date), 1) + return from_date, date_diff(to_date, from_date) + 1 def make_draft_asset_depr_schedules_if_not_present(asset_doc): From 7d86881579b7404323c398434b44250b1ae40e7d Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 15 May 2024 08:18:05 +0530 Subject: [PATCH 8/8] style: new line before function --- .../test_asset_depreciation_schedule.py | 1 + 1 file changed, 1 insertion(+) 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 index 236c45f7f41..6e4966ac6cf 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/test_asset_depreciation_schedule.py @@ -71,6 +71,7 @@ class TestAssetDepreciationSchedule(FrappeTestCase): for d in get_depr_schedule(asset.name, "Draft") ] self.assertEqual(schedules, expected_schedules) + # Test for Written Down Value Method # Frequency of deprciation = 3 def test_for_daily_prorata_based_depreciation_wdv_method_frequency_3_months(self):