Skip to content

Commit

Permalink
Merge pull request #38405 from frappe/mergify/bp/version-14/pr-38404
Browse files Browse the repository at this point in the history
feat: shift depreciation for assets [v14] [backport of #38327] (backport #38404)
  • Loading branch information
anandbaburajan authored Nov 29, 2023
2 parents 47d37aa + 53d083a commit 6c805ff
Show file tree
Hide file tree
Showing 15 changed files with 796 additions and 335 deletions.
11 changes: 7 additions & 4 deletions erpnext/assets/doctype/asset/asset.js
Original file line number Diff line number Diff line change
Expand Up @@ -323,12 +323,15 @@ frappe.ui.form.on('Asset', {

make_schedules_editable: function(frm) {
if (frm.doc.finance_books) {
var is_editable = frm.doc.finance_books.filter(d => d.depreciation_method == "Manual").length > 0
var is_manual_hence_editable = frm.doc.finance_books.filter(d => d.depreciation_method == "Manual").length > 0
? true : false;
var is_shift_hence_editable = frm.doc.finance_books.filter(d => d.shift_based).length > 0
? true : false;

frm.toggle_enable("schedules", is_editable);
frm.fields_dict["schedules"].grid.toggle_enable("schedule_date", is_editable);
frm.fields_dict["schedules"].grid.toggle_enable("depreciation_amount", is_editable);
frm.toggle_enable("depreciation_schedule", is_manual_hence_editable || is_shift_hence_editable);
frm.fields_dict["depreciation_schedule"].grid.toggle_enable("schedule_date", is_manual_hence_editable);
frm.fields_dict["depreciation_schedule"].grid.toggle_enable("depreciation_amount", is_manual_hence_editable);
frm.fields_dict["depreciation_schedule"].grid.toggle_enable("shift", is_shift_hence_editable);
}
},

Expand Down
96 changes: 71 additions & 25 deletions erpnext/assets/doctype/asset/asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def validate(self):
self.validate_finance_books()
if not self.split_from:
self.prepare_depreciation_data()
self.update_shift_depr_schedule()
self.validate_gross_and_purchase_amount()
if self.get("schedules"):
self.validate_expected_value_after_useful_life()
Expand Down Expand Up @@ -104,6 +105,13 @@ def prepare_depreciation_data(
self.opening_accumulated_depreciation
)

def update_shift_depr_schedule(self):
if not any(fb.get("shift_based") for fb in self.finance_books) or self.docstatus != 0:
return

self.make_depreciation_schedule()
self.set_accumulated_depreciation()

def should_prepare_depreciation_schedule(self):
if not self.get("schedules"):
return True
Expand Down Expand Up @@ -318,7 +326,7 @@ def set_depreciation_rate(self):
self.get_depreciation_rate(d, on_validate=True), d.precision("rate_of_depreciation")
)

def make_depreciation_schedule(self, date_of_disposal, value_after_depreciation=None):
def make_depreciation_schedule(self, date_of_disposal=None, value_after_depreciation=None):
if not self.get("schedules"):
self.schedules = []

Expand Down Expand Up @@ -410,13 +418,7 @@ def _make_depreciation_schedule(
)

if depreciation_amount > 0:
self._add_depreciation_row(
date_of_disposal,
depreciation_amount,
finance_book.depreciation_method,
finance_book.finance_book,
finance_book.idx,
)
self._add_depreciation_row(date_of_disposal, depreciation_amount, finance_book, n)

break

Expand Down Expand Up @@ -498,25 +500,27 @@ def _make_depreciation_schedule(
skip_row = True

if flt(depreciation_amount, self.precision("gross_purchase_amount")) > 0:
self._add_depreciation_row(
schedule_date,
depreciation_amount,
finance_book.depreciation_method,
finance_book.finance_book,
finance_book.idx,
)
self._add_depreciation_row(schedule_date, depreciation_amount, finance_book, n)

def _add_depreciation_row(self, schedule_date, depreciation_amount, finance_book, schedule_idx):
if finance_book.shift_based:
shift = (
self.schedules_before_clearing[schedule_idx].shift
if self.schedules_before_clearing and len(self.schedules_before_clearing) > schedule_idx
else frappe.get_cached_value("Asset Shift Factor", {"default": 1}, "shift_name")
)
else:
shift = None

def _add_depreciation_row(
self, schedule_date, depreciation_amount, depreciation_method, finance_book, finance_book_id
):
self.append(
"schedules",
{
"schedule_date": schedule_date,
"depreciation_amount": depreciation_amount,
"depreciation_method": depreciation_method,
"finance_book": finance_book,
"finance_book_id": finance_book_id,
"depreciation_method": finance_book.depreciation_method,
"finance_book": finance_book.finance_book,
"finance_book_id": finance_book.idx,
"shift": shift,
},
)

Expand Down Expand Up @@ -545,6 +549,8 @@ def clear_depreciation_schedule(self):
num_of_depreciations_completed = 0
depr_schedule = []

self.schedules_before_clearing = self.get("schedules")

for schedule in self.get("schedules"):
# to update start when there are JEs linked with all the schedule rows corresponding to an FB
if len(start) == (int(schedule.finance_book_id) - 2):
Expand Down Expand Up @@ -752,10 +758,12 @@ def set_accumulated_depreciation(
and not date_of_return
):
book = self.get("finance_books")[cint(d.finance_book_id) - 1]
depreciation_amount += flt(
value_after_depreciation - flt(book.expected_value_after_useful_life),
d.precision("depreciation_amount"),
)

if not book.shift_based:
depreciation_amount += flt(
value_after_depreciation - flt(book.expected_value_after_useful_life),
d.precision("depreciation_amount"),
)

d.depreciation_amount = depreciation_amount
accumulated_depreciation += d.depreciation_amount
Expand Down Expand Up @@ -1217,6 +1225,7 @@ def get_item_details(item_code, asset_category, gross_purchase_amount):
"total_number_of_depreciations": d.total_number_of_depreciations,
"frequency_of_depreciation": d.frequency_of_depreciation,
"daily_prorata_based": d.daily_prorata_based,
"shift_based": d.shift_based,
"salvage_value_percentage": d.salvage_value_percentage,
"expected_value_after_useful_life": flt(gross_purchase_amount)
* flt(d.salvage_value_percentage / 100),
Expand Down Expand Up @@ -1385,6 +1394,9 @@ def get_updated_rate_of_depreciation_for_wdv_and_dd(asset, depreciable_value, fb
def get_straight_line_or_manual_depr_amount(
asset, row, schedule_idx, number_of_pending_depreciations
):
if row.shift_based:
return get_shift_depr_amount(asset, 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)) / (
Expand Down Expand Up @@ -1479,6 +1491,40 @@ def get_straight_line_or_manual_depr_amount(
) / flt(row.total_number_of_depreciations - asset.number_of_depreciations_booked)


def get_shift_depr_amount(asset, row, schedule_idx):
if asset.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.number_of_depreciations_booked)

asset_shift_factors_map = get_asset_shift_factors_map()
shift = (
asset.schedules_before_clearing[schedule_idx].shift
if len(asset.schedules_before_clearing) > schedule_idx
else None
)
shift_factor = asset_shift_factors_map.get(shift) if shift else 0

shift_factors_sum = sum(
flt(asset_shift_factors_map.get(schedule.shift)) for schedule in asset.schedules_before_clearing
)

return (
(
flt(asset.gross_purchase_amount)
- flt(asset.opening_accumulated_depreciation)
- flt(row.expected_value_after_useful_life)
)
/ flt(shift_factors_sum)
) * shift_factor


def get_asset_shift_factors_map():
return dict(frappe.db.get_all("Asset Shift Factor", ["shift_name", "shift_factor"], as_list=True))


def get_wdv_or_dd_depr_amount(
depreciable_value,
rate_of_depreciation,
Expand Down
1 change: 1 addition & 0 deletions erpnext/assets/doctype/asset/test_asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -1706,6 +1706,7 @@ def create_asset(**args):
"expected_value_after_useful_life": args.expected_value_after_useful_life or 0,
"depreciation_start_date": args.depreciation_start_date,
"daily_prorata_based": args.daily_prorata_based or 0,
"shift_based": args.shift_based or 0,
},
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"depreciation_method",
"total_number_of_depreciations",
"daily_prorata_based",
"shift_based",
"column_break_5",
"frequency_of_depreciation",
"depreciation_start_date",
Expand Down Expand Up @@ -93,12 +94,19 @@
"fieldname": "daily_prorata_based",
"fieldtype": "Check",
"label": "Depreciate based on daily pro-rata"
},
{
"default": "0",
"depends_on": "eval:doc.depreciation_method == \"Straight Line\"",
"fieldname": "shift_based",
"fieldtype": "Check",
"label": "Depreciate based on shifts"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2023-11-03 22:21:52.090191",
"modified": "2023-11-29 03:53:03.591098",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Finance Book",
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt

frappe.ui.form.on('Asset Shift Allocation', {
onload: function(frm) {
frm.events.make_schedules_editable(frm);
},

make_schedules_editable: function(frm) {
frm.toggle_enable("depreciation_schedule", true);
frm.fields_dict["depreciation_schedule"].grid.toggle_enable("schedule_date", false);
frm.fields_dict["depreciation_schedule"].grid.toggle_enable("depreciation_amount", false);
frm.fields_dict["depreciation_schedule"].grid.toggle_enable("shift", true);
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
{
"actions": [],
"allow_rename": 1,
"autoname": "naming_series:",
"creation": "2023-11-29 04:01:33.796458",
"default_view": "List",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"section_break_esaa",
"asset",
"naming_series",
"column_break_tdae",
"finance_book",
"amended_from",
"depreciation_schedule_section",
"depreciation_schedule"
],
"fields": [
{
"fieldname": "section_break_esaa",
"fieldtype": "Section Break"
},
{
"fieldname": "asset",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Asset",
"options": "Asset",
"reqd": 1
},
{
"fieldname": "naming_series",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Naming Series",
"options": "ACC-ASA-.YYYY.-",
"reqd": 1
},
{
"fieldname": "column_break_tdae",
"fieldtype": "Column Break"
},
{
"fieldname": "finance_book",
"fieldtype": "Link",
"label": "Finance Book",
"options": "Finance Book"
},
{
"depends_on": "eval:!doc.__islocal",
"fieldname": "depreciation_schedule_section",
"fieldtype": "Section Break",
"label": "Depreciation Schedule"
},
{
"fieldname": "depreciation_schedule",
"fieldtype": "Table",
"label": "Depreciation Schedule",
"options": "Depreciation Schedule"
},
{
"fieldname": "amended_from",
"fieldtype": "Link",
"label": "Amended From",
"no_copy": 1,
"options": "Asset Shift Allocation",
"print_hide": 1,
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2023-11-29 04:06:20.586168",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Shift Allocation",
"naming_rule": "By \"Naming Series\" field",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
},
{
"amend": 1,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"share": 1,
"submit": 1,
"write": 1
}
],
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
Loading

0 comments on commit 6c805ff

Please sign in to comment.