From cbd26e3b2cd36e2060fabf13d655ab58ed93bb87 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 18 Nov 2016 17:19:45 +0530 Subject: [PATCH] Manual Depreciation Schedule for Asset --- erpnext/accounts/doctype/asset/asset.js | 33 +++++++++++++++ erpnext/accounts/doctype/asset/asset.json | 8 ++-- erpnext/accounts/doctype/asset/asset.py | 40 ++++++++++--------- erpnext/accounts/doctype/asset/test_asset.py | 24 +++++++++++ .../depreciation_schedule.json | 24 ++++++++--- 5 files changed, 102 insertions(+), 27 deletions(-) diff --git a/erpnext/accounts/doctype/asset/asset.js b/erpnext/accounts/doctype/asset/asset.js index 8ff4b83d68..664ed4da25 100644 --- a/erpnext/accounts/doctype/asset/asset.js +++ b/erpnext/accounts/doctype/asset/asset.js @@ -28,6 +28,7 @@ frappe.ui.form.on('Asset', { refresh: function(frm) { frappe.ui.form.trigger("Asset", "is_existing_asset"); frm.toggle_display("next_depreciation_date", frm.doc.docstatus < 1); + frm.events.make_schedules_editable(frm); if (frm.doc.docstatus==1) { if (frm.doc.status=='Submitted' && !frm.doc.is_existing_asset && !frm.doc.purchase_invoice) { @@ -141,6 +142,22 @@ frappe.ui.form.on('Asset', { frm.toggle_enable("supplier", frm.doc.is_existing_asset); frm.toggle_reqd("next_depreciation_date", !frm.doc.is_existing_asset); }, + + opening_accumulated_depreciation: function(frm) { + erpnext.asset.set_accululated_depreciation(frm); + }, + + depreciation_method: function(frm) { + frm.events.make_schedules_editable(frm); + }, + + make_schedules_editable: function(frm) { + var is_editable = frm.doc.depreciation_method==="Manual" ? 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); + } + }); frappe.ui.form.on('Depreciation Schedule', { @@ -159,9 +176,25 @@ frappe.ui.form.on('Depreciation Schedule', { } }) } + }, + + depreciation_amount: function(frm, cdt, cdn) { + erpnext.asset.set_accululated_depreciation(frm); } + }) +erpnext.asset.set_accululated_depreciation = function(frm) { + if(frm.doc.depreciation_method != "Manual") return; + + accumulated_depreciation = flt(frm.doc.opening_accumulated_depreciation); + $.each(frm.doc.schedules || [], function(i, row) { + accumulated_depreciation += flt(row.depreciation_amount); + frappe.model.set_value(row.doctype, row.name, + "accumulated_depreciation_amount", accumulated_depreciation); + }) +} + erpnext.asset.make_purchase_invoice = function(frm) { frappe.call({ args: { diff --git a/erpnext/accounts/doctype/asset/asset.json b/erpnext/accounts/doctype/asset/asset.json index d3a88fbaa4..95d9b48603 100644 --- a/erpnext/accounts/doctype/asset/asset.json +++ b/erpnext/accounts/doctype/asset/asset.json @@ -516,7 +516,7 @@ "columns": 0, "fieldname": "value_after_depreciation", "fieldtype": "Currency", - "hidden": 0, + "hidden": 1, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, @@ -580,7 +580,7 @@ "label": "Depreciation Method", "length": 0, "no_copy": 0, - "options": "\nStraight Line\nDouble Declining Balance", + "options": "\nStraight Line\nDouble Declining Balance\nManual", "permlevel": 0, "precision": "", "print_hide": 0, @@ -750,7 +750,7 @@ "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 1, + "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, @@ -797,7 +797,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-11-03 14:58:53.710357", + "modified": "2016-11-18 15:59:19.774500", "modified_by": "Administrator", "module": "Accounts", "name": "Asset", diff --git a/erpnext/accounts/doctype/asset/asset.py b/erpnext/accounts/doctype/asset/asset.py index da73218b25..9caac071f9 100644 --- a/erpnext/accounts/doctype/asset/asset.py +++ b/erpnext/accounts/doctype/asset/asset.py @@ -18,6 +18,7 @@ class Asset(Document): self.set_missing_values() self.validate_asset_values() self.make_depreciation_schedule() + self.set_accumulated_depreciation() self.validate_expected_value_after_useful_life() # Validate depreciation related accounts get_depreciation_accounts(self) @@ -48,7 +49,7 @@ class Asset(Document): for field, value in item_details.items(): if not self.get(field): self.set(field, value) - + self.value_after_depreciation = (flt(self.gross_purchase_amount) - flt(self.opening_accumulated_depreciation)) @@ -87,9 +88,10 @@ class Asset(Document): frappe.throw(_("Please set Next Depreciation Date")) def make_depreciation_schedule(self): - self.schedules = [] + if self.depreciation_method != 'Manual': + self.schedules = [] + if not self.get("schedules") and self.next_depreciation_date: - accumulated_depreciation = flt(self.opening_accumulated_depreciation) value_after_depreciation = flt(self.value_after_depreciation) number_of_pending_depreciations = cint(self.total_number_of_depreciations) - \ @@ -100,18 +102,21 @@ class Asset(Document): n * cint(self.frequency_of_depreciation)) depreciation_amount = self.get_depreciation_amount(value_after_depreciation) - - accumulated_depreciation += flt(depreciation_amount) value_after_depreciation -= flt(depreciation_amount) self.append("schedules", { "schedule_date": schedule_date, - "depreciation_amount": depreciation_amount, - "accumulated_depreciation_amount": accumulated_depreciation + "depreciation_amount": depreciation_amount }) + + def set_accumulated_depreciation(self): + accumulated_depreciation = flt(self.opening_accumulated_depreciation) + for d in self.get("schedules"): + accumulated_depreciation += flt(d.depreciation_amount) + d.accumulated_depreciation_amount = accumulated_depreciation def get_depreciation_amount(self, depreciable_value): - if self.depreciation_method == "Straight Line": + if self.depreciation_method in ("Straight Line", "Manual"): depreciation_amount = (flt(self.value_after_depreciation) - flt(self.expected_value_after_useful_life)) / (cint(self.total_number_of_depreciations) - cint(self.number_of_depreciations_booked)) @@ -126,16 +131,15 @@ class Asset(Document): return depreciation_amount def validate_expected_value_after_useful_life(self): - if self.depreciation_method == "Double Declining Balance": - accumulated_depreciation_after_full_schedule = \ - max([d.accumulated_depreciation_amount for d in self.get("schedules")]) - - asset_value_after_full_schedule = (flt(self.gross_purchase_amount) - - flt(accumulated_depreciation_after_full_schedule)) - - if self.expected_value_after_useful_life < asset_value_after_full_schedule: - frappe.throw(_("Expected value after useful life must be greater than or equal to {0}") - .format(asset_value_after_full_schedule)) + accumulated_depreciation_after_full_schedule = \ + max([d.accumulated_depreciation_amount for d in self.get("schedules")]) + + asset_value_after_full_schedule = (flt(self.gross_purchase_amount) - + flt(accumulated_depreciation_after_full_schedule)) + + if self.expected_value_after_useful_life < asset_value_after_full_schedule: + frappe.throw(_("Expected value after useful life must be greater than or equal to {0}") + .format(asset_value_after_full_schedule)) def validate_cancellation(self): if self.status not in ("Submitted", "Partially Depreciated", "Fully Depreciated"): diff --git a/erpnext/accounts/doctype/asset/test_asset.py b/erpnext/accounts/doctype/asset/test_asset.py index b409ec3a25..51496b918c 100644 --- a/erpnext/accounts/doctype/asset/test_asset.py +++ b/erpnext/accounts/doctype/asset/test_asset.py @@ -119,6 +119,30 @@ class TestAsset(unittest.TestCase): for d in asset.get("schedules")] self.assertEqual(schedules, expected_schedules) + + def test_schedule_for_manual_method(self): + asset = frappe.get_doc("Asset", "Macbook Pro 1") + asset.depreciation_method = "Manual" + asset.schedules = [] + for schedule_date, amount in [["2020-12-31", 40000], ["2021-06-30", 30000], ["2021-10-31", 20000]]: + asset.append("schedules", { + "schedule_date": schedule_date, + "depreciation_amount": amount + }) + asset.save() + + self.assertEqual(asset.status, "Draft") + + expected_schedules = [ + ["2020-12-31", 40000, 40000], + ["2021-06-30", 30000, 70000], + ["2021-10-31", 20000, 90000] + ] + + schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] + for d in asset.get("schedules")] + + self.assertEqual(schedules, expected_schedules) def test_depreciation(self): asset = frappe.get_doc("Asset", "Macbook Pro 1") diff --git a/erpnext/accounts/doctype/depreciation_schedule/depreciation_schedule.json b/erpnext/accounts/doctype/depreciation_schedule/depreciation_schedule.json index 57c14b7974..1fadf5eb4f 100644 --- a/erpnext/accounts/doctype/depreciation_schedule/depreciation_schedule.json +++ b/erpnext/accounts/doctype/depreciation_schedule/depreciation_schedule.json @@ -10,11 +10,13 @@ "doctype": "DocType", "document_type": "Document", "editable_grid": 1, + "engine": "InnoDB", "fields": [ { "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "schedule_date", "fieldtype": "Date", "hidden": 0, @@ -29,7 +31,8 @@ "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 1, + "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 1, "search_index": 0, @@ -40,6 +43,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "depreciation_amount", "fieldtype": "Currency", "hidden": 0, @@ -55,7 +59,8 @@ "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 1, + "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 1, "search_index": 0, @@ -66,6 +71,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "column_break_3", "fieldtype": "Column Break", "hidden": 0, @@ -80,6 +86,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -90,6 +97,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "accumulated_depreciation_amount", "fieldtype": "Currency", "hidden": 0, @@ -106,8 +114,9 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 1, + "reqd": 0, "search_index": 0, "set_only_once": 0, "unique": 0 @@ -116,6 +125,8 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.docstatus==1", "fieldname": "journal_entry", "fieldtype": "Link", "hidden": 0, @@ -132,6 +143,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -142,7 +154,8 @@ "allow_on_submit": 1, "bold": 0, "collapsible": 0, - "depends_on": "eval:(!doc.journal_entry && doc.schedule_date <= get_today())", + "columns": 0, + "depends_on": "eval:(doc.docstatus==1 && !doc.journal_entry && doc.schedule_date <= get_today())", "fieldname": "make_depreciation_entry", "fieldtype": "Button", "hidden": 0, @@ -158,6 +171,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -175,7 +189,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2016-07-11 03:27:59.603924", + "modified": "2016-11-18 16:42:19.543657", "modified_by": "Administrator", "module": "Accounts", "name": "Depreciation Schedule",