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 98cdb5c8b20..bf2f3fad049 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -175,12 +175,6 @@ class AssetDepreciationSchedule(Document): update_asset_finance_book_row=True, value_after_depreciation=None, ): - # if not self.get("depreciation_schedule"): - # self.depreciation_schedule = [] - - # if not asset_doc.available_for_use_date: - # return - start = self.clear_depr_schedule() self._make_depr_schedule( @@ -230,7 +224,7 @@ class AssetDepreciationSchedule(Document): prev_per_day_depr = True self.current_fiscal_year_end_date = None yearly_opening_wdv = value_after_depreciation - number_of_pending_depreciations = final_number_of_depreciations - start + pending_months = self.get_number_of_pending_months(asset_doc, row, start) for n in range(start, final_number_of_depreciations): # If depreciation is already completed (for double declining balance) @@ -251,7 +245,7 @@ class AssetDepreciationSchedule(Document): n, prev_depreciation_amount, has_wdv_or_dd_non_yearly_pro_rata, - number_of_pending_depreciations, + pending_months, prev_per_day_depr, ) @@ -314,8 +308,38 @@ class AssetDepreciationSchedule(Document): if has_pro_rata: final_number_of_depreciations += 1 + if row.increase_in_asset_life: + final_number_of_depreciations = ( + self.get_final_number_of_depreciations_considering_increase_in_asset_life( + asset_doc, row, final_number_of_depreciations + ) + ) + return final_number_of_depreciations, has_pro_rata + def get_final_number_of_depreciations_considering_increase_in_asset_life( + self, asset_doc, row, final_number_of_depreciations + ): + # final schedule date after increasing asset life + self.final_schedule_date = add_months( + asset_doc.available_for_use_date, + (row.total_number_of_depreciations * cint(row.frequency_of_depreciation)) + + row.increase_in_asset_life, + ) + + number_of_pending_depreciations = cint(row.total_number_of_depreciations) - cint( + asset_doc.opening_number_of_booked_depreciations + ) + schedule_date = add_months( + row.depreciation_start_date, + number_of_pending_depreciations * cint(row.frequency_of_depreciation), + ) + + if self.final_schedule_date > schedule_date: + final_number_of_depreciations += 1 + + return final_number_of_depreciations + def is_wdv_or_dd_non_yearly_pro_rata(self, asset_doc, row): has_wdv_or_dd_non_yearly_pro_rata = False if ( @@ -326,6 +350,22 @@ class AssetDepreciationSchedule(Document): return has_wdv_or_dd_non_yearly_pro_rata + def get_number_of_pending_months(self, asset_doc, row, start): + print(row.total_number_of_depreciations) + total_months = cint(row.total_number_of_depreciations) * cint(row.frequency_of_depreciation) + cint( + row.increase_in_asset_life + ) + depr_booked_for_months = 0 + if start > 0: + last_depr_date = self.depreciation_schedule[start - 1].schedule_date + elif asset_doc.opening_number_of_booked_depreciations > 0: + last_depr_date = add_months(row.depreciation_start_date, -1 * row.frequency_of_depreciation) + + if last_depr_date: + depr_booked_for_months = date_diff(last_depr_date, asset_doc.available_for_use_date) / (365 / 12) + print(total_months, depr_booked_for_months) + return total_months - depr_booked_for_months + def has_fiscal_year_changed(self, row, row_no): fiscal_year_changed = False @@ -352,13 +392,9 @@ class AssetDepreciationSchedule(Document): def get_next_schedule_date( self, row, n, has_pro_rata, should_get_last_day, final_number_of_depreciations=None ): - if not has_pro_rata or ( - n < (cint(final_number_of_depreciations) - 1) or final_number_of_depreciations == 2 - ): - 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 = add_months(row.depreciation_start_date, n * cint(row.frequency_of_depreciation)) + if should_get_last_day: + schedule_date = get_last_day(schedule_date) return schedule_date @@ -435,27 +471,28 @@ class AssetDepreciationSchedule(Document): def get_depreciation_amount_for_last_row( self, asset_doc, row, n, depreciation_amount, schedule_date, has_wdv_or_dd_non_yearly_pro_rata ): - if not asset_doc.flags.increase_in_asset_life: + if not row.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( + self.final_schedule_date = add_months( asset_doc.available_for_use_date, (n + self.opening_number_of_booked_depreciations) * cint(row.frequency_of_depreciation), ) if is_last_day_of_the_month(getdate(asset_doc.available_for_use_date)): - asset_doc.to_date = get_last_day(asset_doc.to_date) + self.final_schedule_date = get_last_day(self.final_schedule_date) if self.opening_accumulated_depreciation: depreciation_amount, days, months = _get_pro_rata_amt( row, depreciation_amount, schedule_date, - asset_doc.to_date, + self.final_schedule_date, has_wdv_or_dd_non_yearly_pro_rata, ) else: # if not existing asset, remaining amount of first row is depreciated in the last row - depreciation_amount -= self.get("depreciation_schedule")[0].depreciation_amount - days = date_diff(asset_doc.to_date, schedule_date) + 1 + if not row.increase_in_asset_life: + depreciation_amount -= self.get("depreciation_schedule")[0].depreciation_amount + days = date_diff(self.final_schedule_date, schedule_date) + 1 schedule_date = add_days(schedule_date, days - 1) return depreciation_amount, schedule_date diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/utils.py b/erpnext/assets/doctype/asset_depreciation_schedule/utils.py index 2617493751c..c13ad5ebdcb 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/utils.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/utils.py @@ -4,6 +4,7 @@ from frappe.utils import ( add_months, add_years, cint, + cstr, date_diff, flt, get_last_day, @@ -16,7 +17,7 @@ import erpnext def get_depreciation_amount( asset_depr_schedule, asset, - depreciable_value, + value_after_depreciation, yearly_opening_wdv, fb_row, schedule_idx=0, @@ -27,13 +28,18 @@ def get_depreciation_amount( ): 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 + asset_depr_schedule, + asset, + fb_row, + schedule_idx, + value_after_depreciation, + number_of_pending_depreciations, ), None else: return get_wdv_or_dd_depr_amount( asset, fb_row, - depreciable_value, + value_after_depreciation, yearly_opening_wdv, schedule_idx, prev_depreciation_amount, @@ -44,83 +50,59 @@ def get_depreciation_amount( def get_straight_line_or_manual_depr_amount( - asset_depr_schedule, asset, row, schedule_idx, number_of_pending_depreciations + asset_depr_schedule, + asset, + fb_row, + schedule_idx, + value_after_depreciation, + number_of_pending_depreciations, ): - if row.shift_based: - return get_shift_depr_amount(asset_depr_schedule, asset, row, schedule_idx) + if fb_row.shift_based: + return get_shift_depr_amount(asset_depr_schedule, asset, fb_row, schedule_idx) - # if the Depreciation Schedule is being modified after Asset Repair due to increase in asset life and value - if asset.flags.increase_in_asset_life: - return (flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)) / ( - date_diff(asset.to_date, asset.available_for_use_date) / 365 + if fb_row.daily_prorata_based: + amount = flt(asset.gross_purchase_amount) - flt(fb_row.expected_value_after_useful_life) + return get_daily_prorata_based_straight_line_depr( + asset, fb_row, schedule_idx, number_of_pending_depreciations, 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( - 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: - if row.daily_prorata_based: - amount = flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life) - - return get_daily_prorata_based_straight_line_depr( - asset, - row, - schedule_idx, - number_of_pending_depreciations, - amount, - ) - else: - return ( - flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life) - ) / number_of_pending_depreciations - # if the Depreciation Schedule is being prepared for the first time else: - if row.daily_prorata_based: - amount = flt(asset.gross_purchase_amount) - flt(row.expected_value_after_useful_life) - return get_daily_prorata_based_straight_line_depr( - asset, row, schedule_idx, number_of_pending_depreciations, amount - ) - else: - depreciation_amount = ( - flt(asset.gross_purchase_amount) - flt(row.expected_value_after_useful_life) - ) / flt(row.total_number_of_depreciations) - return depreciation_amount + return (flt(fb_row.value_after_depreciation) - flt(fb_row.expected_value_after_useful_life)) / ( + flt(number_of_pending_depreciations) / flt(fb_row.frequency_of_depreciation) + ) def get_daily_prorata_based_straight_line_depr( - asset, row, schedule_idx, number_of_pending_depreciations, amount + asset, fb_row, schedule_idx, number_of_pending_depreciations, amount ): - daily_depr_amount = get_daily_depr_amount(asset, row, schedule_idx, amount) + daily_depr_amount = get_daily_depr_amount(asset, fb_row, schedule_idx, amount) from_date, total_depreciable_days = _get_total_days( - row.depreciation_start_date, schedule_idx, row.frequency_of_depreciation + fb_row.depreciation_start_date, schedule_idx, fb_row.frequency_of_depreciation ) return daily_depr_amount * total_depreciable_days -def get_daily_depr_amount(asset, row, schedule_idx, amount): +def get_daily_depr_amount(asset, fb_row, schedule_idx, amount): if cint(frappe.db.get_single_value("Accounts Settings", "calculate_depr_using_total_days")): total_days = ( date_diff( get_last_day( add_months( - row.depreciation_start_date, + fb_row.depreciation_start_date, flt( - row.total_number_of_depreciations + fb_row.total_number_of_depreciations - asset.opening_number_of_booked_depreciations - 1 ) - * row.frequency_of_depreciation, + * fb_row.frequency_of_depreciation, ) ), add_days( get_last_day( add_months( - row.depreciation_start_date, + fb_row.depreciation_start_date, ( - row.frequency_of_depreciation + fb_row.frequency_of_depreciation * (asset.opening_number_of_booked_depreciations + 1) ) * -1, @@ -136,8 +118,8 @@ def get_daily_depr_amount(asset, row, schedule_idx, amount): else: total_years = ( flt( - (row.total_number_of_depreciations - row.total_number_of_booked_depreciations) - * row.frequency_of_depreciation + (fb_row.total_number_of_depreciations - fb_row.total_number_of_booked_depreciations) + * fb_row.frequency_of_depreciation ) / 12 ) @@ -145,24 +127,24 @@ def get_daily_depr_amount(asset, row, schedule_idx, amount): every_year_depr = amount / total_years depr_period_start_date = add_days( - get_last_day(add_months(row.depreciation_start_date, row.frequency_of_depreciation * -1)), 1 + get_last_day(add_months(fb_row.depreciation_start_date, fb_row.frequency_of_depreciation * -1)), 1 ) year_start_date = add_years( - depr_period_start_date, ((row.frequency_of_depreciation * schedule_idx) // 12) + depr_period_start_date, ((fb_row.frequency_of_depreciation * schedule_idx) // 12) ) year_end_date = add_days(add_years(year_start_date, 1), -1) return every_year_depr / (date_diff(year_end_date, year_start_date) + 1) -def get_shift_depr_amount(asset_depr_schedule, asset, row, schedule_idx): +def get_shift_depr_amount(asset_depr_schedule, asset, fb_row, schedule_idx): if asset_depr_schedule.get("__islocal") and not asset.flags.shift_allocation: return ( flt(asset.gross_purchase_amount) - flt(asset.opening_accumulated_depreciation) - - flt(row.expected_value_after_useful_life) - ) / flt(row.total_number_of_depreciations - asset.opening_number_of_booked_depreciations) + - flt(fb_row.expected_value_after_useful_life) + ) / flt(fb_row.total_number_of_depreciations - asset.opening_number_of_booked_depreciations) asset_shift_factors_map = get_asset_shift_factors_map() shift = ( @@ -181,7 +163,7 @@ def get_shift_depr_amount(asset_depr_schedule, asset, row, schedule_idx): ( flt(asset.gross_purchase_amount) - flt(asset.opening_accumulated_depreciation) - - flt(row.expected_value_after_useful_life) + - flt(fb_row.expected_value_after_useful_life) ) / flt(shift_factors_sum) ) * shift_factor @@ -195,7 +177,7 @@ def get_asset_shift_factors_map(): def get_wdv_or_dd_depr_amount( asset, fb_row, - depreciable_value, + value_after_depreciation, yearly_opening_wdv, schedule_idx, prev_depreciation_amount, @@ -206,7 +188,7 @@ def get_wdv_or_dd_depr_amount( return get_default_wdv_or_dd_depr_amount( asset, fb_row, - depreciable_value, + value_after_depreciation, schedule_idx, prev_depreciation_amount, has_wdv_or_dd_non_yearly_pro_rata, @@ -218,7 +200,7 @@ def get_wdv_or_dd_depr_amount( def get_default_wdv_or_dd_depr_amount( asset, fb_row, - depreciable_value, + value_after_depreciation, schedule_idx, prev_depreciation_amount, has_wdv_or_dd_non_yearly_pro_rata, @@ -229,7 +211,7 @@ def get_default_wdv_or_dd_depr_amount( return _get_default_wdv_or_dd_depr_amount( asset, fb_row, - depreciable_value, + value_after_depreciation, schedule_idx, prev_depreciation_amount, has_wdv_or_dd_non_yearly_pro_rata, @@ -239,7 +221,7 @@ def get_default_wdv_or_dd_depr_amount( return _get_daily_prorata_based_default_wdv_or_dd_depr_amount( asset, fb_row, - depreciable_value, + value_after_depreciation, schedule_idx, prev_depreciation_amount, has_wdv_or_dd_non_yearly_pro_rata, @@ -251,21 +233,21 @@ def get_default_wdv_or_dd_depr_amount( def _get_default_wdv_or_dd_depr_amount( asset, fb_row, - depreciable_value, + value_after_depreciation, 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) + return flt(value_after_depreciation) * (flt(fb_row.rate_of_depreciation) / 100) else: if has_wdv_or_dd_non_yearly_pro_rata: if schedule_idx == 0: - return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100) + return flt(value_after_depreciation) * (flt(fb_row.rate_of_depreciation) / 100) elif schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 1: return ( - flt(depreciable_value) + flt(value_after_depreciation) * flt(fb_row.frequency_of_depreciation) * (flt(fb_row.rate_of_depreciation) / 1200) ) @@ -274,7 +256,7 @@ def _get_default_wdv_or_dd_depr_amount( else: if schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 0: return ( - flt(depreciable_value) + flt(value_after_depreciation) * flt(fb_row.frequency_of_depreciation) * (flt(fb_row.rate_of_depreciation) / 1200) ) @@ -285,7 +267,7 @@ def _get_default_wdv_or_dd_depr_amount( def _get_daily_prorata_based_default_wdv_or_dd_depr_amount( asset, fb_row, - depreciable_value, + value_after_depreciation, schedule_idx, prev_depreciation_amount, has_wdv_or_dd_non_yearly_pro_rata, @@ -294,20 +276,20 @@ def _get_daily_prorata_based_default_wdv_or_dd_depr_amount( ): 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 + return flt(value_after_depreciation) * (flt(fb_row.rate_of_depreciation) / 100), None elif schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 1: # Year changes - return get_monthly_depr_amount(fb_row, schedule_idx, depreciable_value) + return get_monthly_depr_amount(fb_row, schedule_idx, value_after_depreciation) else: 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: # year changes - return get_monthly_depr_amount(fb_row, schedule_idx, depreciable_value) + return get_monthly_depr_amount(fb_row, schedule_idx, value_after_depreciation) else: 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): +def get_monthly_depr_amount(fb_row, schedule_idx, value_after_depreciation): """ Returns monthly depreciation amount when year changes 1. Calculate per day depr based on new year @@ -316,7 +298,7 @@ def get_monthly_depr_amount(fb_row, schedule_idx, depreciable_value): 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) + per_day_depr = get_per_day_depr(fb_row, value_after_depreciation, from_date) return (per_day_depr * days_in_month), per_day_depr @@ -333,12 +315,12 @@ def get_monthly_depr_amount_based_on_prev_per_day_depr(fb_row, schedule_idx, pre def get_per_day_depr( fb_row, - depreciable_value, + value_after_depreciation, from_date, ): 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 + per_day_depr = (flt(value_after_depreciation) * (flt(fb_row.rate_of_depreciation) / 100)) / total_days return per_day_depr diff --git a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json index c97ae1a8545..be035f7ea7a 100644 --- a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json +++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json @@ -9,6 +9,7 @@ "depreciation_method", "frequency_of_depreciation", "total_number_of_depreciations", + "increase_in_asset_life", "depreciation_start_date", "column_break_5", "salvage_value_percentage", @@ -61,7 +62,6 @@ { "fieldname": "depreciation_start_date", "fieldtype": "Date", - "hidden": 1, "in_list_view": 1, "label": "Depreciation Posting Date", "mandatory_depends_on": "eval:parent.doctype == 'Asset'" @@ -101,7 +101,7 @@ "default": "0", "fieldname": "daily_prorata_based", "fieldtype": "Check", - "label": "Depreciate based on days per period" + "label": "Depreciate based on daily pro-rata" }, { "default": "0", @@ -125,12 +125,20 @@ { "fieldname": "column_break_sigk", "fieldtype": "Column Break" + }, + { + "description": "via Asset Repair", + "fieldname": "increase_in_asset_life", + "fieldtype": "Int", + "label": "Increase In Asset Life (Months)", + "no_copy": 1, + "read_only": 1 } ], "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2024-12-13 12:11:03.743209", + "modified": "2024-12-19 17:50:24.012434", "modified_by": "Administrator", "module": "Assets", "name": "Asset Finance Book", diff --git a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py index d06d6355ec3..d629aefd967 100644 --- a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py +++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py @@ -22,6 +22,7 @@ class AssetFinanceBook(Document): expected_value_after_useful_life: DF.Currency finance_book: DF.Link | None frequency_of_depreciation: DF.Int + increase_in_asset_life: DF.Int parent: DF.Data parentfield: DF.Data parenttype: DF.Data diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py index 4b4ff1a5383..8a179ea5b68 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/asset_repair.py @@ -419,5 +419,6 @@ def get_expense_accounts(doctype, txt, searchfield, start, page_len, filters): return ( frappe.qb.from_(PurchaseInvoiceItem) .select(PurchaseInvoiceItem.expense_account) + .distinct() .where(PurchaseInvoiceItem.parent == filters.get("purchase_invoice")) ).run(as_list=1) diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js index 4435b2b1845..135fb76684e 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js @@ -45,6 +45,9 @@ frappe.ui.form.on("Asset Value Adjustment", { asset: function (frm) { frm.trigger("set_acc_dimension"); + if (frm.doc.asset) { + frm.trigger("set_current_asset_value"); + } }, finance_book: function (frm) { diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.json b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.json index e584c3d8202..e60d401055d 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.json +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.json @@ -54,8 +54,8 @@ "fieldname": "journal_entry", "fieldtype": "Link", "label": "Journal Entry", - "options": "Journal Entry", "no_copy": 1, + "options": "Journal Entry", "read_only": 1 }, { @@ -125,18 +125,18 @@ "fieldtype": "Column Break" }, { - "fieldname": "difference_account", - "fieldtype": "Link", - "label": "Difference Account", - "no_copy": 1, - "options": "Account", - "reqd": 1 + "fieldname": "difference_account", + "fieldtype": "Link", + "label": "Difference Account", + "no_copy": 1, + "options": "Account", + "reqd": 1 } ], "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2024-08-13 16:21:18.639208", + "modified": "2024-12-18 15:04:18.726505", "modified_by": "Administrator", "module": "Assets", "name": "Asset Value Adjustment", @@ -188,7 +188,6 @@ "write": 1 } ], - "quick_entry": 1, "sort_field": "creation", "sort_order": "DESC", "states": [],