From 44e45b55d4b0ee3d072e925d088c699136315853 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 23 Dec 2024 18:24:10 +0530 Subject: [PATCH] refactor: asset value adjustment --- .../doctype/journal_entry/journal_entry.py | 23 +-- erpnext/assets/doctype/asset/asset.py | 4 +- .../asset_depreciation_schedule.py | 45 ++--- .../doctype/asset_repair/asset_repair.json | 16 +- .../doctype/asset_repair/asset_repair.py | 25 +-- .../asset_value_adjustment.py | 163 +++++++++--------- 6 files changed, 119 insertions(+), 157 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index a3047c9339d..ea7583e6218 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -196,7 +196,6 @@ class JournalEntry(AccountsController): self.update_asset_value() self.update_inter_company_jv() self.update_invoice_discounting() - self.update_booked_depreciation() def on_update_after_submit(self): # Flag will be set on Reconciliation @@ -232,7 +231,6 @@ class JournalEntry(AccountsController): self.unlink_inter_company_jv() self.unlink_asset_adjustment_entry() self.update_invoice_discounting() - self.update_booked_depreciation(1) def get_title(self): return self.pay_to_recd_from or self.accounts[0].account @@ -405,6 +403,7 @@ class JournalEntry(AccountsController): asset.db_set("value_after_depreciation", asset.value_after_depreciation - d.debit) asset.set_status() + asset.set_total_booked_depreciations() def update_inter_company_jv(self): if self.voucher_type == "Inter Company Journal Entry" and self.inter_company_journal_entry_reference: @@ -459,25 +458,6 @@ class JournalEntry(AccountsController): if status: inv_disc_doc.set_status(status=status) - def update_booked_depreciation(self, cancel=0): - for d in self.get("accounts"): - if ( - self.voucher_type == "Depreciation Entry" - and d.reference_type == "Asset" - and d.reference_name - and frappe.get_cached_value("Account", d.account, "root_type") == "Expense" - and d.debit - ): - asset = frappe.get_doc("Asset", d.reference_name) - for fb_row in asset.get("finance_books"): - if fb_row.finance_book == self.finance_book: - if cancel: - fb_row.total_number_of_booked_depreciations -= 1 - else: - fb_row.total_number_of_booked_depreciations += 1 - fb_row.db_update() - break - def unlink_advance_entry_reference(self): for d in self.get("accounts"): if d.is_advance == "Yes" and d.reference_type in ("Sales Invoice", "Purchase Invoice"): @@ -530,6 +510,7 @@ class JournalEntry(AccountsController): else: asset.db_set("value_after_depreciation", asset.value_after_depreciation + d.debit) asset.set_status() + asset.set_total_booked_depreciations() elif self.voucher_type == "Journal Entry" and d.reference_type == "Asset" and d.reference_name: journal_entry_for_scrap = frappe.db.get_value( "Asset", d.reference_name, "journal_entry_for_scrap" diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index de3fb10324d..a65246ee820 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -130,8 +130,6 @@ class Asset(AccountsController): self.set_missing_values() self.validate_gross_and_purchase_amount() self.validate_finance_books() - self.validate_expected_value_after_useful_life() - self.set_total_booked_depreciations() self.total_asset_cost = self.gross_purchase_amount self.status = self.get_status() @@ -178,6 +176,8 @@ class Asset(AccountsController): def on_update(self): self.create_asset_depreciation_schedule() + self.validate_expected_value_after_useful_life() + self.set_total_booked_depreciations() def on_submit(self): self.validate_in_use_date() 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 bf2f3fad049..4566f52b20a 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -351,11 +351,11 @@ 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 + last_depr_date = None if start > 0: last_depr_date = self.depreciation_schedule[start - 1].schedule_date elif asset_doc.opening_number_of_booked_depreciations > 0: @@ -363,7 +363,7 @@ class AssetDepreciationSchedule(Document): 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): @@ -516,7 +516,7 @@ class AssetDepreciationSchedule(Document): return depreciation_amount, skip_row def validate_depreciation_amount_for_low_value_assets(self, asset_doc, row, depreciation_amount): - """ " + """ If gross purchase amount is too low, then depreciation amount can come zero sometimes based on the frequency and number of depreciations. """ @@ -553,42 +553,23 @@ class AssetDepreciationSchedule(Document): row, date_of_disposal=None, date_of_return=None, - ignore_booked_entry=False, ): - straight_line_idx = [ - d.idx - for d in self.get("depreciation_schedule") - if self.depreciation_method == "Straight Line" or self.depreciation_method == "Manual" - ] - - accumulated_depreciation = None + accumulated_depreciation = flt(self.opening_accumulated_depreciation) value_after_depreciation = flt(row.value_after_depreciation) for i, d in enumerate(self.get("depreciation_schedule")): - if ignore_booked_entry and d.journal_entry: + if d.journal_entry: + accumulated_depreciation = d.accumulated_depreciation_amount continue - if not accumulated_depreciation: - 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 - else: - accumulated_depreciation = flt( - self.opening_accumulated_depreciation, - asset_doc.precision("opening_accumulated_depreciation"), - ) - - value_after_depreciation -= flt(d.depreciation_amount) - value_after_depreciation = flt(value_after_depreciation, d.precision("depreciation_amount")) + value_after_depreciation = flt( + value_after_depreciation - flt(d.depreciation_amount), d.precision("depreciation_amount") + ) # for the last row, if depreciation method = Straight Line if ( - straight_line_idx - and i == max(straight_line_idx) - 1 + self.depreciation_method in ("Straight Line", "Manual") + and i == len(self.get("depreciation_schedule")) - 1 and not date_of_disposal and not date_of_return and not row.shift_based @@ -757,7 +738,6 @@ def make_new_active_asset_depr_schedules_and_cancel_current_ones( date_of_disposal=None, date_of_return=None, value_after_depreciation=None, - ignore_booked_entry=False, difference_amount=None, ): for row in asset_doc.get("finance_books"): @@ -773,6 +753,7 @@ 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 @@ -790,7 +771,7 @@ def make_new_active_asset_depr_schedules_and_cancel_current_ones( asset_doc, row, date_of_disposal, value_after_depreciation=value_after_depreciation ) new_asset_depr_schedule_doc.set_accumulated_depreciation( - asset_doc, row, date_of_disposal, date_of_return, ignore_booked_entry + asset_doc, row, date_of_disposal, date_of_return ) new_asset_depr_schedule_doc.notes = notes diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.json b/erpnext/assets/doctype/asset_repair/asset_repair.json index b74292a093e..54a067063b2 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.json +++ b/erpnext/assets/doctype/asset_repair/asset_repair.json @@ -27,7 +27,7 @@ "column_break_ajbh", "column_break_hkem", "repair_cost", - "asset_depreciation_details_section", + "accounting_dimensions_section", "cost_center", "column_break_14", "project", @@ -185,12 +185,6 @@ "label": "Total Repair Cost", "read_only": 1 }, - { - "depends_on": "capitalize_repair_cost", - "fieldname": "asset_depreciation_details_section", - "fieldtype": "Section Break", - "label": "Asset Depreciation Details" - }, { "depends_on": "capitalize_repair_cost", "fieldname": "increase_in_asset_life", @@ -253,12 +247,18 @@ { "fieldname": "column_break_xebe", "fieldtype": "Column Break" + }, + { + "depends_on": "capitalize_repair_cost", + "fieldname": "accounting_dimensions_section", + "fieldtype": "Section Break", + "label": "Accounting Dimensions" } ], "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2024-12-20 13:10:31.540666", + "modified": "2024-12-23 18:08:35.159964", "modified_by": "Administrator", "module": "Assets", "name": "Asset Repair", diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py index 8a179ea5b68..8b541163179 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/asset_repair.py @@ -148,15 +148,12 @@ class AssetRepair(AccountsController): self.decrease_stock_quantity() if self.get("capitalize_repair_cost"): - self.asset_doc.flags.ignore_validate_update_after_submit = True self.update_asset_value() self.make_gl_entries() self.set_increase_in_asset_life() depreciation_note = self.get_depreciation_note() - make_new_active_asset_depr_schedules_and_cancel_current_ones( - self.asset_doc, depreciation_note, ignore_booked_entry=True - ) + make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, depreciation_note) self.add_asset_activity() def on_cancel(self): @@ -164,16 +161,13 @@ class AssetRepair(AccountsController): if self.get("capitalize_repair_cost"): self.asset_doc.flags.increase_in_asset_value_due_to_repair = True - self.asset_doc.flags.ignore_validate_update_after_submit = True self.update_asset_value() self.make_gl_entries(cancel=True) self.set_increase_in_asset_life() depreciation_note = self.get_depreciation_note() - make_new_active_asset_depr_schedules_and_cancel_current_ones( - self.asset_doc, depreciation_note, ignore_booked_entry=True - ) + make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, depreciation_note) self.add_asset_activity() def after_delete(self): @@ -184,16 +178,16 @@ class AssetRepair(AccountsController): frappe.throw(_("Please update Repair Status.")) def update_asset_value(self): - if self.docstaus == 2: - self.total_repair_cost *= -1 + total_repair_cost = self.total_repair_cost if self.docstatus == 1 else -1 * self.total_repair_cost - self.asset_doc.total_asset_cost += flt(self.total_repair_cost) - self.asset_doc.additional_asset_cost += flt(self.total_repair_cost) + self.asset_doc.total_asset_cost += flt(total_repair_cost) + self.asset_doc.additional_asset_cost += flt(total_repair_cost) if self.asset_doc.calculate_depreciation: for row in self.asset_doc.finance_books: - row.value_after_depreciation += flt(self.total_repair_cost) + row.value_after_depreciation += flt(total_repair_cost) + self.asset_doc.flags.ignore_validate_update_after_submit = True self.asset_doc.save() def get_total_value_of_stock_consumed(self): @@ -377,9 +371,8 @@ class AssetRepair(AccountsController): def add_asset_activity(self, subject=None): if not subject: subject = _("Asset updated due to Asset Repair {0} {1}.").format( - get_link_to_form( - self.doctype, self.name, "submission" if self.docstatus == 1 else "cancellation" - ), + get_link_to_form(self.doctype, self.name), + "submission" if self.docstatus == 1 else "cancellation", ) add_asset_activity(self.asset, subject) 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 6766b827f7f..07817d8e6ad 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py @@ -5,7 +5,7 @@ import frappe from frappe import _ from frappe.model.document import Document -from frappe.utils import flt, formatdate, get_link_to_form, getdate +from frappe.utils import cstr, flt, formatdate, get_link_to_form, getdate from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_checks_for_pl_and_bs_accounts, @@ -46,10 +46,26 @@ class AssetValueAdjustment(Document): self.set_current_asset_value() self.set_difference_amount() + def validate_date(self): + asset_purchase_date = frappe.db.get_value("Asset", self.asset, "purchase_date") + if getdate(self.date) < getdate(asset_purchase_date): + frappe.throw( + _("Asset Value Adjustment cannot be posted before Asset's purchase date {0}.").format( + formatdate(asset_purchase_date) + ), + title=_("Incorrect Date"), + ) + + def set_difference_amount(self): + self.difference_amount = flt(self.new_asset_value - self.current_asset_value) + + def set_current_asset_value(self): + if not self.current_asset_value and self.asset: + self.current_asset_value = get_asset_value_after_depreciation(self.asset, self.finance_book) + def on_submit(self): self.make_depreciation_entry() - self.set_value_after_depreciation() - self.update_asset(self.new_asset_value) + self.update_asset() add_asset_activity( self.asset, _("Asset's value adjusted after submission of Asset Value Adjustment {0}").format( @@ -67,26 +83,6 @@ class AssetValueAdjustment(Document): ), ) - def validate_date(self): - asset_purchase_date = frappe.db.get_value("Asset", self.asset, "purchase_date") - if getdate(self.date) < getdate(asset_purchase_date): - frappe.throw( - _("Asset Value Adjustment cannot be posted before Asset's purchase date {0}.").format( - formatdate(asset_purchase_date) - ), - title=_("Incorrect Date"), - ) - - def set_difference_amount(self): - self.difference_amount = flt(self.new_asset_value - self.current_asset_value) - - def set_value_after_depreciation(self): - frappe.db.set_value("Asset", self.asset, "value_after_depreciation", self.new_asset_value) - - def set_current_asset_value(self): - if not self.current_asset_value and self.asset: - self.current_asset_value = get_asset_value_after_depreciation(self.asset, self.finance_book) - def make_depreciation_entry(self): asset = frappe.get_doc("Asset", self.asset) ( @@ -114,46 +110,15 @@ class AssetValueAdjustment(Document): } if self.difference_amount < 0: - credit_entry = { - "account": fixed_asset_account, - "credit_in_account_currency": -self.difference_amount, - **entry_template, - } - debit_entry = { - "account": self.difference_account, - "debit_in_account_currency": -self.difference_amount, - **entry_template, - } + credit_entry, debit_entry = self.get_entry_for_asset_value_decrease( + fixed_asset_account, entry_template + ) elif self.difference_amount > 0: - credit_entry = { - "account": self.difference_account, - "credit_in_account_currency": self.difference_amount, - **entry_template, - } - debit_entry = { - "account": fixed_asset_account, - "debit_in_account_currency": self.difference_amount, - **entry_template, - } + credit_entry, debit_entry = self.get_entry_for_asset_value_increase( + fixed_asset_account, entry_template + ) - accounting_dimensions = get_checks_for_pl_and_bs_accounts() - - for dimension in accounting_dimensions: - if dimension.get("mandatory_for_bs"): - credit_entry.update( - { - dimension["fieldname"]: self.get(dimension["fieldname"]) - or dimension.get("default_dimension") - } - ) - - if dimension.get("mandatory_for_pl"): - debit_entry.update( - { - dimension["fieldname"]: self.get(dimension["fieldname"]) - or dimension.get("default_dimension") - } - ) + self.update_accounting_dimensions(credit_entry, debit_entry) je.append("accounts", credit_entry) je.append("accounts", debit_entry) @@ -163,40 +128,82 @@ class AssetValueAdjustment(Document): self.db_set("journal_entry", je.name) - def update_asset(self, asset_value=None): + def get_entry_for_asset_value_decrease(self, fixed_asset_account, entry_template): + credit_entry = { + "account": fixed_asset_account, + "credit_in_account_currency": -self.difference_amount, + **entry_template, + } + debit_entry = { + "account": self.difference_account, + "debit_in_account_currency": -self.difference_amount, + **entry_template, + } + + return credit_entry, debit_entry + + def get_entry_for_asset_value_increase(self, fixed_asset_account, entry_template): + credit_entry = { + "account": self.difference_account, + "credit_in_account_currency": self.difference_amount, + **entry_template, + } + debit_entry = { + "account": fixed_asset_account, + "debit_in_account_currency": self.difference_amount, + **entry_template, + } + + return credit_entry, debit_entry + + def update_accounting_dimensions(self, credit_entry, debit_entry): + accounting_dimensions = get_checks_for_pl_and_bs_accounts() + + for dimension in accounting_dimensions: + dimension_value = self.get(dimension["fieldname"]) or dimension.get("default_dimension") + if dimension.get("mandatory_for_bs"): + credit_entry.update({dimension["fieldname"]: dimension_value}) + + if dimension.get("mandatory_for_pl"): + debit_entry.update({dimension["fieldname"]: dimension_value}) + + def update_asset(self): + asset = self.update_asset_value_after_depreciation() + note = self.get_adjustment_note() + make_new_active_asset_depr_schedules_and_cancel_current_ones(asset, note) + + def update_asset_value_after_depreciation(self): + difference_amount = self.difference_amount if self.docstatus == 1 else -1 * self.difference_amount + asset = frappe.get_doc("Asset", self.asset) - if not asset.calculate_depreciation: - asset.value_after_depreciation = asset_value - asset.save() - return + asset.value_after_depreciation += flt(difference_amount) + asset.db_update() + else: + for row in asset.finance_books: + if cstr(row.finance_book) == cstr(self.finance_book): + row.value_after_depreciation += flt(difference_amount) + row.db_update() - asset.flags.decrease_in_asset_value_due_to_value_adjustment = True + return asset + def get_adjustment_note(self): if self.docstatus == 1: notes = _( "This schedule was created when Asset {0} was adjusted through Asset Value Adjustment {1}." ).format( - get_link_to_form("Asset", asset.name), + get_link_to_form("Asset", self.asset), get_link_to_form(self.get("doctype"), self.get("name")), ) elif self.docstatus == 2: notes = _( "This schedule was created when Asset {0}'s Asset Value Adjustment {1} was cancelled." ).format( - get_link_to_form("Asset", asset.name), + get_link_to_form("Asset", self.asset), get_link_to_form(self.get("doctype"), self.get("name")), ) - make_new_active_asset_depr_schedules_and_cancel_current_ones( - 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() + return notes @frappe.whitelist()