diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js index 5d15cab5a2..18ba8f9b5c 100644 --- a/erpnext/assets/doctype/asset/asset.js +++ b/erpnext/assets/doctype/asset/asset.js @@ -299,13 +299,9 @@ frappe.ui.form.on('Asset', { set_depreciation_rate: function(frm, row) { if (row.total_number_of_depreciations && row.frequency_of_depreciation) { frappe.call({ - method: "erpnext.assets.doctype.asset.asset.get_depreciation_rate", - args: { - args: row, - asset_cost: frm.doc.gross_purchase_amount, - number_of_depreciations_booked: frm.doc.is_existing_asset ? - frm.doc.number_of_depreciations_booked : 0 - }, + method: "get_depreciation_rate", + doc: frm.doc, + args: row, callback: function(r) { if (r.message) { frappe.model.set_value(row.doctype, row.name, "rate_of_depreciation", r.message); diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index b703bca772..8011038b1b 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -101,9 +101,7 @@ class Asset(AccountsController): def set_depreciation_rate(self): for d in self.get("finance_books"): - if not d.rate_of_depreciation: - d.rate_of_depreciation = get_depreciation_rate(d, self.gross_purchase_amount, - self.number_of_depreciations_booked) + d.rate_of_depreciation = self.get_depreciation_rate(d) def make_depreciation_schedule(self): depreciation_method = [d.depreciation_method for d in self.finance_books] @@ -405,6 +403,32 @@ class Asset(AccountsController): make_gl_entries(gl_entries) self.db_set('booked_fixed_asset', 1) + def get_depreciation_rate(self, args): + if isinstance(args, string_types): + args = json.loads(args) + + number_of_depreciations_booked = 0 + if self.is_existing_asset: + number_of_depreciations_booked = self.number_of_depreciations_booked + + float_precision = cint(frappe.db.get_default("float_precision")) or 2 + tot_no_of_depreciation = flt(args.get("total_number_of_depreciations")) - flt(number_of_depreciations_booked) + + if args.get("depreciation_method") in ["Straight Line", "Manual"]: + return 1.0 / tot_no_of_depreciation + + if args.get("depreciation_method") == 'Double Declining Balance': + return 200.0 / args.get("total_number_of_depreciations") + + if args.get("depreciation_method") == "Written Down Value" and not 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)) + + return 100 * (1 - flt(depreciation_rate, float_precision)) + def update_maintenance_status(): assets = frappe.get_all('Asset', filters = {'docstatus': 1, 'maintenance_required': 1}) @@ -568,25 +592,3 @@ def make_journal_entry(asset_name): def is_cwip_accounting_disabled(): return cint(frappe.db.get_single_value("Asset Settings", "disable_cwip_accounting")) - -@frappe.whitelist() -def get_depreciation_rate(args, asset_cost, number_of_depreciations_booked=0): - if isinstance(args, string_types): - args = json.loads(args) - - float_precision = cint(frappe.db.get_default("float_precision")) or 2 - - if args.get("depreciation_method") == 'Double Declining Balance': - return 200.0 / flt(args.get("total_number_of_depreciations")) - - if args.get("depreciation_method") in ["Straight Line", "Manual"]: - return 1.0 / (flt(args.get("total_number_of_depreciations")) - flt(number_of_depreciations_booked)) - - if args.get("depreciation_method") == "Written Down Value": - no_of_years = flt(flt(args.get("total_number_of_depreciations")) * flt(args.get("frequency_of_depreciation"))) / 12 - value = flt(args.get("expected_value_after_useful_life")) / flt(asset_cost) - - # square root of flt(salvage_value) / flt(asset_cost) - depreciation_rate = math.pow(value, 1.0/flt(no_of_years, 2)) - - return 100 * (1 - flt(depreciation_rate, float_precision)) \ No newline at end of file diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index a12348e451..985097b447 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -160,9 +160,9 @@ class TestAsset(unittest.TestCase): asset.save() expected_schedules = [ - ["2020-06-06", 66667.0, 66667.0], - ["2021-04-06", 22222.0, 88889.0], - ["2022-02-06", 1111.0, 90000.0] + ["2020-06-06", 66666.67, 66666.67], + ["2021-04-06", 22222.22, 88888.89], + ["2022-02-06", 1111.11, 90000.0] ] schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] @@ -192,8 +192,8 @@ class TestAsset(unittest.TestCase): asset.save() expected_schedules = [ - ["2020-06-06", 33333.0, 83333.0], - ["2021-04-06", 6667.0, 90000.0] + ["2020-06-06", 33333.33, 83333.33], + ["2021-04-06", 6666.67, 90000.0] ] schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] @@ -209,7 +209,7 @@ class TestAsset(unittest.TestCase): asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') asset = frappe.get_doc('Asset', asset_name) asset.calculate_depreciation = 1 - asset.purchase_date = '2020-06-06' + asset.purchase_date = '2020-01-30' asset.is_existing_asset = 0 asset.available_for_use_date = "2020-01-30" asset.append("finance_books", { @@ -244,7 +244,7 @@ class TestAsset(unittest.TestCase): asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') asset = frappe.get_doc('Asset', asset_name) asset.calculate_depreciation = 1 - asset.purchase_date = '2020-06-06' + asset.purchase_date = '2020-01-30' asset.available_for_use_date = "2020-01-30" asset.append("finance_books", { "expected_value_after_useful_life": 10000, @@ -277,6 +277,37 @@ class TestAsset(unittest.TestCase): self.assertEqual(gle, expected_gle) self.assertEqual(asset.get("value_after_depreciation"), 0) + def test_depreciation_entry_for_wdv(self): + pr = make_purchase_receipt(item_code="Macbook Pro", + qty=1, rate=8000.0, location="Test Location") + + asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') + asset = frappe.get_doc('Asset', asset_name) + asset.calculate_depreciation = 1 + asset.available_for_use_date = '2030-06-06' + asset.purchase_date = '2030-06-06' + asset.append("finance_books", { + "expected_value_after_useful_life": 1000, + "depreciation_method": "Written Down Value", + "total_number_of_depreciations": 3, + "frequency_of_depreciation": 12, + "depreciation_start_date": "2030-12-31" + }) + asset.save(ignore_permissions=True) + + self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0) + + expected_schedules = [ + ["2030-12-31", 4000.0, 4000.0], + ["2031-12-31", 2000.0, 6000.0], + ["2032-12-31", 1000.0, 7000.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) + def test_depreciation_entry_cancellation(self): pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=100000.0, location="Test Location")