From cd0e8ce8ad33fb4e9e0bb474510688f7a84f3e84 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Sat, 9 Apr 2016 16:06:28 +0530 Subject: [PATCH] Fixes and modification in fixed asset --- erpnext/accounts/doctype/asset/asset.js | 2 +- erpnext/accounts/doctype/asset/asset.json | 62 +++++++++++++++++-- erpnext/accounts/doctype/asset/asset.py | 51 ++++++++------- .../accounts/doctype/asset/depreciation.py | 16 +++-- erpnext/accounts/doctype/asset/test_asset.py | 2 +- .../doctype/sales_invoice/sales_invoice.py | 1 + erpnext/config/accounts.py | 12 ++++ erpnext/controllers/accounts_controller.py | 4 +- .../en/accounts/managing-fixed-assets.md | 2 +- 9 files changed, 113 insertions(+), 39 deletions(-) diff --git a/erpnext/accounts/doctype/asset/asset.js b/erpnext/accounts/doctype/asset/asset.js index 4c034714e8..548de08dfc 100644 --- a/erpnext/accounts/doctype/asset/asset.js +++ b/erpnext/accounts/doctype/asset/asset.js @@ -49,7 +49,7 @@ frappe.ui.form.on('Asset', { }, is_existing_asset: function(frm) { - frm.toggle_enable(["purchase_date", "supplier"], frm.doc.is_existing_asset); + frm.toggle_enable("supplier", frm.doc.is_existing_asset); frm.toggle_reqd("next_depreciation_date", !frm.doc.is_existing_asset); } }); diff --git a/erpnext/accounts/doctype/asset/asset.json b/erpnext/accounts/doctype/asset/asset.json index ea2dfb13c3..cf03bf6922 100644 --- a/erpnext/accounts/doctype/asset/asset.json +++ b/erpnext/accounts/doctype/asset/asset.json @@ -232,9 +232,9 @@ "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 1, + "read_only": 0, "report_hide": 0, - "reqd": 0, + "reqd": 1, "search_index": 0, "set_only_once": 0, "unique": 0 @@ -291,6 +291,31 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "disposal_date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Disposal Date", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -526,14 +551,15 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "current_value", + "depends_on": "is_existing_asset", + "fieldname": "opening_accumulated_depreciation", "fieldtype": "Currency", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, - "label": "Current Value (After Depreciation)", + "label": "Opening Accumulated Depreciation", "length": 0, "no_copy": 1, "options": "Company:company:default_currency", @@ -548,6 +574,32 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "value_after_depreciation", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Value After Depreciation", + "length": 0, + "no_copy": 0, + "options": "Company:company:default_currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -634,7 +686,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-04-07 18:15:36.509712", + "modified": "2016-04-08 18:42:52.810809", "modified_by": "Administrator", "module": "Accounts", "name": "Asset", diff --git a/erpnext/accounts/doctype/asset/asset.py b/erpnext/accounts/doctype/asset/asset.py index d055dbbd9f..1807d70acd 100644 --- a/erpnext/accounts/doctype/asset/asset.py +++ b/erpnext/accounts/doctype/asset/asset.py @@ -33,24 +33,27 @@ class Asset(Document): frappe.throw(_("Item {0} has been disabled").format(self.item_code)) def validate_asset_values(self): + self.value_after_depreciation = flt(self.gross_purchase_amount) - flt(self.opening_accumulated_depreciation) + if flt(self.expected_value_after_useful_life) >= flt(self.gross_purchase_amount): frappe.throw(_("Expected Value After Useful Life must be less than Gross Purchase Amount")) if not flt(self.gross_purchase_amount): frappe.throw(_("Gross Purchase Amount is mandatory"), frappe.MandatoryError) - - if not self.is_existing_asset and not self.next_depreciation_date: - frappe.throw(_("Next Depreciation Date is mandatory for new asset")) - + + if not self.is_existing_asset: + self.opening_accumulated_depreciation = 0 + if not self.next_depreciation_date: + frappe.throw(_("Next Depreciation Date is mandatory for new asset")) + else: + depreciable_amount = flt(self.gross_purchase_amount) - flt(self.expected_value_after_useful_life) + if flt(self.opening_accumulated_depreciation) > depreciable_amount: + frappe.throw(_("Opening Accumulated Depreciation must be less than equal to {0}") + .format(depreciable_amount)) + if self.next_depreciation_date and getdate(self.next_depreciation_date) < getdate(nowdate()): frappe.throw(_("Next Depreciation Date must be on or after today")) - - if not self.current_value and self.next_depreciation_date: - self.current_value = flt(self.gross_purchase_amount) - else: - if flt(self.current_value) > flt(self.gross_purchase_amount): - frappe.throw(_("Current Value After Depreciation must be less than equal to {0}") - .format(flt(self.gross_purchase_amount))) + def set_depreciation_settings(self): asset_category = frappe.get_doc("Asset Category", self.asset_category) @@ -62,25 +65,26 @@ class Asset(Document): def make_depreciation_schedule(self): self.schedules = [] if not self.get("schedules") and self.next_depreciation_date: - accumulated_depreciation = 0 - value_after_depreciation = flt(self.current_value) + accumulated_depreciation = flt(self.opening_accumulated_depreciation) + value_after_depreciation = flt(self.value_after_depreciation) for n in xrange(self.number_of_depreciations): schedule_date = add_months(self.next_depreciation_date, 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 + "accumulated_depreciation_amount": accumulated_depreciation }) - accumulated_depreciation += flt(depreciation_amount) - value_after_depreciation -= flt(depreciation_amount) def get_depreciation_amount(self, depreciable_value): if self.depreciation_method == "Straight Line": - depreciation_amount = (flt(self.current_value) - + depreciation_amount = (flt(self.value_after_depreciation) - flt(self.expected_value_after_useful_life)) / cint(self.number_of_depreciations) else: factor = 200.0 / cint(self.number_of_depreciations) @@ -100,14 +104,13 @@ class Asset(Document): frappe.throw(_("Please cancel Purchase Invoice {0} first").format(self.purchase_invoice)) def delete_depreciation_entries(self): - total_depreciation_amount = 0 for d in self.get("schedules"): if d.journal_entry: frappe.get_doc("Journal Entry", d.journal_entry).cancel() - - d.db_set("journal_entry", None) - total_depreciation_amount += flt(d.depreciation_amount) - self.db_set("current_value", (self.current_value + total_depreciation_amount)) + d.db_set("journal_entry", None) + + self.db_set("value_after_depreciation", + (flt(self.gross_purchase_amount) - flt(self.opening_accumulated_depreciation))) def validate_depreciation_settings_in_company(self): company = frappe.get_doc("Company", self.company) @@ -131,9 +134,9 @@ class Asset(Document): status = "Submitted" if self.journal_entry_for_scrap: status = "Scrapped" - elif flt(self.current_value) <= flt(self.expected_value_after_useful_life): + elif flt(self.value_after_depreciation) <= flt(self.expected_value_after_useful_life): status = "Fully Depreciated" - elif flt(self.current_value) < flt(self.gross_purchase_amount): + elif flt(self.value_after_depreciation) < flt(self.gross_purchase_amount): status = 'Partially Depreciated' elif self.docstatus == 2: status = "Cancelled" diff --git a/erpnext/accounts/doctype/asset/depreciation.py b/erpnext/accounts/doctype/asset/depreciation.py index 15ff9a9bb0..d045ced3ea 100644 --- a/erpnext/accounts/doctype/asset/depreciation.py +++ b/erpnext/accounts/doctype/asset/depreciation.py @@ -58,9 +58,9 @@ def make_depreciation_entry(asset_name, date=None): je.submit() d.db_set("journal_entry", je.name) - asset.current_value -= d.depreciation_amount + asset.value_after_depreciation -= d.depreciation_amount - asset.db_set("current_value", asset.current_value) + asset.db_set("value_after_depreciation", asset.value_after_depreciation) asset.set_status() def get_depreciation_accounts(asset): @@ -115,7 +115,8 @@ def scrap_asset(asset_name): je.flags.ignore_permissions = True je.submit() - + + frappe.db.set_value("Asset", asset_name, "disposal_date", today()) frappe.db.set_value("Asset", asset_name, "journal_entry_for_scrap", je.name) asset.set_status("Scrapped") @@ -124,7 +125,10 @@ def restore_asset(asset_name): asset = frappe.get_doc("Asset", asset_name) je = asset.journal_entry_for_scrap + + asset.db_set("disposal_date", None) asset.db_set("journal_entry_for_scrap", None) + frappe.get_doc("Journal Entry", je).cancel() asset.set_status() @@ -133,7 +137,7 @@ def restore_asset(asset_name): def get_gl_entries_on_asset_disposal(asset, selling_amount=0): fixed_asset_account, accumulated_depr_account, depr_expense_account = get_depreciation_accounts(asset) disposal_account, depreciation_cost_center = get_disposal_account_and_cost_center(asset.company) - accumulated_depr_amount = flt(asset.gross_purchase_amount) - flt(asset.current_value) + accumulated_depr_amount = flt(asset.gross_purchase_amount) - flt(asset.value_after_depreciation) gl_entries = [ { @@ -148,8 +152,8 @@ def get_gl_entries_on_asset_disposal(asset, selling_amount=0): } ] - profit_amount = flt(selling_amount) - flt(asset.current_value) - if flt(asset.current_value) and profit_amount: + profit_amount = flt(selling_amount) - flt(asset.value_after_depreciation) + if flt(asset.value_after_depreciation) and profit_amount: debit_or_credit = "debit" if profit_amount < 0 else "credit" gl_entries.append({ "account": disposal_account, diff --git a/erpnext/accounts/doctype/asset/test_asset.py b/erpnext/accounts/doctype/asset/test_asset.py index 102af5977d..ea1d6a2308 100644 --- a/erpnext/accounts/doctype/asset/test_asset.py +++ b/erpnext/accounts/doctype/asset/test_asset.py @@ -104,7 +104,7 @@ class TestAsset(unittest.TestCase): order by account""", asset.name) self.assertEqual(gle, expected_gle) - self.assertEqual(asset.get("current_value"), 70000) + self.assertEqual(asset.get("value_after_depreciation"), 70000) def test_scrap_asset(self): asset = frappe.get_doc("Asset", "Macbook Pro 1") diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 76c5e94aed..a72b3bac9f 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -567,6 +567,7 @@ class SalesInvoice(SellingController): gle["against"] = self.customer gl_entries.append(self.get_gl_dict(gle)) + asset.db_set("disposal_date", self.posting_date) asset.set_status("Sold" if self.docstatus==1 else None) else: account_currency = get_account_currency(item.income_account) diff --git a/erpnext/config/accounts.py b/erpnext/config/accounts.py index 3d6fb544a0..72ed0f9bbc 100644 --- a/erpnext/config/accounts.py +++ b/erpnext/config/accounts.py @@ -340,6 +340,18 @@ def get_data(): "label": _("Other Reports"), "icon": "icon-table", "items": [ + { + "type": "report", + "name": "Asset Depreciation Ledger", + "doctype": "Asset", + "is_query_report": True, + }, + { + "type": "report", + "name": "Asset Depreciations and Balances", + "doctype": "Asset", + "is_query_report": True, + }, { "type": "report", "name": "Trial Balance for Party", diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index cba4d6a4b4..204c236ac6 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe from frappe import _, throw -from frappe.utils import today, flt, cint, fmt_money, formatdate +from frappe.utils import today, flt, cint, fmt_money, formatdate, getdate from erpnext.setup.utils import get_company_currency, get_exchange_rate from erpnext.accounts.utils import get_fiscal_years, validate_fiscal_year, get_account_currency from erpnext.utilities.transaction_base import TransactionBase @@ -498,6 +498,8 @@ class AccountsController(TransactionBase): if asset.status != "Submitted": frappe.throw(_("Row #{0}: Asset {1} is already {2}") .format(d.idx, d.asset, asset.status)) + elif getdate(asset.purchase_date) != getdate(self.posting_date): + frappe.throw(_("Row #{0}: Posting Date must be same as purchase date {1} of asset {2}").format(d.idx, asset.purchase_date, d.asset)) elif asset.is_existing_asset: frappe.throw(_("Row #{0}: Purchase Invoice cannot be made against an existing asset {1}").format(d.idx, d.asset)) diff --git a/erpnext/docs/user/manual/en/accounts/managing-fixed-assets.md b/erpnext/docs/user/manual/en/accounts/managing-fixed-assets.md index 93239a50d4..dc07de378d 100644 --- a/erpnext/docs/user/manual/en/accounts/managing-fixed-assets.md +++ b/erpnext/docs/user/manual/en/accounts/managing-fixed-assets.md @@ -18,7 +18,7 @@ Next step will be creating the fixed asset records. Asset record is the heart of Explanation of the fields: 1. Asset Category: The category of assets it belongs to. -2. Is Existing Asset: Check if adding an existing asset. The existing assets which are partially / fully depreciated can also be created/maintained for the future reference. +2. Is Existing Asset: Check if the asset is being carried forward from the previous Fiscal Year. The existing assets which are partially / fully depreciated can also be created/maintained for the future reference. 3. Status: The options are - Draft, Submitted, Partially Depreciated, Fully Depreciated, Sold and Scrapped. 4. Warehouse: Set the location of the asset. 5. Gross Purchase Amount: The purchase cost of the asset