diff --git a/erpnext/accounts/doctype/asset/asset.js b/erpnext/accounts/doctype/asset/asset.js index e3afc359b65..6693d3be0de 100644 --- a/erpnext/accounts/doctype/asset/asset.js +++ b/erpnext/accounts/doctype/asset/asset.js @@ -1,299 +1,8 @@ -// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors // For license information, please see license.txt -frappe.provide("erpnext.asset"); - frappe.ui.form.on('Asset', { - onload: function(frm) { - frm.set_query("item_code", function() { - return { - "filters": { - "disabled": 0, - "is_fixed_asset": 1, - "is_stock_item": 0 - } - }; - }); - - frm.set_query("warehouse", function() { - return { - "filters": { - "company": frm.doc.company, - "is_group": 0 - } - }; - }); - }, - 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) { - frm.add_custom_button("Make Purchase Invoice", function() { - erpnext.asset.make_purchase_invoice(frm); - }); - } - if (in_list(["Submitted", "Partially Depreciated", "Fully Depreciated"], frm.doc.status)) { - frm.add_custom_button("Transfer Asset", function() { - erpnext.asset.transfer_asset(frm); - }); - - frm.add_custom_button("Scrap Asset", function() { - erpnext.asset.scrap_asset(frm); - }); - - frm.add_custom_button("Sell Asset", function() { - erpnext.asset.make_sales_invoice(frm); - }); - - } else if (frm.doc.status=='Scrapped') { - frm.add_custom_button("Restore Asset", function() { - erpnext.asset.restore_asset(frm); - }); - } - - frm.trigger("setup_chart"); - } - }, - - setup_chart: function(frm) { - var x_intervals = [frm.doc.purchase_date]; - var asset_values = [frm.doc.gross_purchase_amount]; - var last_depreciation_date = frm.doc.purchase_date; - - if(frm.doc.opening_accumulated_depreciation) { - last_depreciation_date = frappe.datetime.add_months(frm.doc.next_depreciation_date, - -1*frm.doc.frequency_of_depreciation); - - x_intervals.push(last_depreciation_date); - asset_values.push(flt(frm.doc.gross_purchase_amount) - - flt(frm.doc.opening_accumulated_depreciation)); - } - - $.each(frm.doc.schedules || [], function(i, v) { - x_intervals.push(v.schedule_date); - var asset_value = flt(frm.doc.gross_purchase_amount) - flt(v.accumulated_depreciation_amount); - if(v.journal_entry) { - last_depreciation_date = v.schedule_date; - asset_values.push(asset_value) - } else { - if (in_list(["Scrapped", "Sold"], frm.doc.status)) { - asset_values.push(null) - } else { - asset_values.push(asset_value) - } - } - }) - - if(in_list(["Scrapped", "Sold"], frm.doc.status)) { - x_intervals.push(frm.doc.disposal_date); - asset_values.push(0); - last_depreciation_date = frm.doc.disposal_date; - } - - frm.dashboard.render_graph({ - title: "Asset Value", - data: { - labels: x_intervals, - datasets: [{ - color: 'green', - values: asset_values, - formatted: asset_values.map(d => d.toFixed(2)) - }] - }, - type: 'line' - }); - }, - - - item_code: function(frm) { - if(frm.doc.item_code) { - frappe.call({ - method: "erpnext.accounts.doctype.asset.asset.get_item_details", - args: { - item_code: frm.doc.item_code - }, - callback: function(r, rt) { - if(r.message) { - $.each(r.message, function(field, value) { - frm.set_value(field, value); - }) - } - } - }) - } - }, - - is_existing_asset: function(frm) { - 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', { - make_depreciation_entry: function(frm, cdt, cdn) { - var row = locals[cdt][cdn]; - if (!row.journal_entry) { - frappe.call({ - method: "erpnext.accounts.doctype.asset.depreciation.make_depreciation_entry", - args: { - "asset_name": frm.doc.name, - "date": row.schedule_date - }, - callback: function(r) { - frappe.model.sync(r.message); - frm.refresh(); - } - }) - } - }, - - 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; - - var 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: { - "asset": frm.doc.name, - "item_code": frm.doc.item_code, - "gross_purchase_amount": frm.doc.gross_purchase_amount, - "company": frm.doc.company, - "posting_date": frm.doc.purchase_date - }, - method: "erpnext.accounts.doctype.asset.asset.make_purchase_invoice", - callback: function(r) { - var doclist = frappe.model.sync(r.message); - frappe.set_route("Form", doclist[0].doctype, doclist[0].name); - } - }) -} - -erpnext.asset.make_sales_invoice = function(frm) { - frappe.call({ - args: { - "asset": frm.doc.name, - "item_code": frm.doc.item_code, - "company": frm.doc.company - }, - method: "erpnext.accounts.doctype.asset.asset.make_sales_invoice", - callback: function(r) { - var doclist = frappe.model.sync(r.message); - frappe.set_route("Form", doclist[0].doctype, doclist[0].name); - } - }) -} - -erpnext.asset.scrap_asset = function(frm) { - frappe.confirm(__("Do you really want to scrap this asset?"), function () { - frappe.call({ - args: { - "asset_name": frm.doc.name - }, - method: "erpnext.accounts.doctype.asset.depreciation.scrap_asset", - callback: function(r) { - cur_frm.reload_doc(); - } - }) - }) -} - -erpnext.asset.restore_asset = function(frm) { - frappe.confirm(__("Do you really want to restore this scrapped asset?"), function () { - frappe.call({ - args: { - "asset_name": frm.doc.name - }, - method: "erpnext.accounts.doctype.asset.depreciation.restore_asset", - callback: function(r) { - cur_frm.reload_doc(); - } - }) - }) -} - -erpnext.asset.transfer_asset = function(frm) { - var dialog = new frappe.ui.Dialog({ - title: __("Transfer Asset"), - fields: [ - { - "label": __("Target Warehouse"), - "fieldname": "target_warehouse", - "fieldtype": "Link", - "options": "Warehouse", - "get_query": function () { - return { - filters: [ - ["Warehouse", "company", "in", ["", cstr(frm.doc.company)]], - ["Warehouse", "is_group", "=", 0] - ] - } - }, - "reqd": 1 - }, - { - "label": __("Date"), - "fieldname": "transfer_date", - "fieldtype": "Datetime", - "reqd": 1, - "default": frappe.datetime.now_datetime() - } - ] - }); - - dialog.set_primary_action(__("Transfer"), function() { - var args = dialog.get_values(); - if(!args) return; - dialog.hide(); - return frappe.call({ - type: "GET", - method: "erpnext.accounts.doctype.asset.asset.transfer_asset", - args: { - args: { - "asset": frm.doc.name, - "transaction_date": args.transfer_date, - "source_warehouse": frm.doc.warehouse, - "target_warehouse": args.target_warehouse, - "company": frm.doc.company - } - }, - freeze: true, - callback: function(r) { - cur_frm.reload_doc(); - } - }) - }); - dialog.show(); -} \ No newline at end of file diff --git a/erpnext/accounts/doctype/asset/asset.json b/erpnext/accounts/doctype/asset/asset.json index 469daa05ae5..727645516dc 100644 --- a/erpnext/accounts/doctype/asset/asset.json +++ b/erpnext/accounts/doctype/asset/asset.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 1, "autoname": "field:asset_name", @@ -12,6 +13,7 @@ "editable_grid": 0, "fields": [ { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,6 +43,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -71,6 +74,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -101,6 +105,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -131,6 +136,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -148,7 +154,7 @@ "label": "Status", "length": 0, "no_copy": 1, - "options": "Draft\nSubmitted\nPartially Depreciated\nFully Depreciated\nSold\nScrapped", + "options": "Draft\nSubmitted\nPartially Depreciated\nFully Depreciated\nSold\nScrapped\nIn Repair\nOut of Order", "permlevel": 0, "precision": "", "print_hide": 0, @@ -162,6 +168,102 @@ "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "asset_owner", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Asset Owner", + "length": 0, + "no_copy": 0, + "options": "Company\nSupplier\nCustomer", + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.asset_owner == \"Supplier\"", + "fieldname": "supplier", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Supplier", + "length": 0, + "no_copy": 0, + "options": "Supplier", + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.asset_owner == \"Customer\"", + "fieldname": "customer", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Customer", + "length": 0, + "no_copy": 0, + "options": "Customer", + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, "allow_on_submit": 1, "bold": 0, "collapsible": 0, @@ -191,6 +293,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -219,6 +322,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -249,6 +353,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -279,12 +384,13 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "is_existing_asset", - "fieldtype": "Check", + "fieldname": "department", + "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -292,9 +398,10 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Is Existing Asset", + "label": "Department", "length": 0, "no_copy": 0, + "options": "Department", "permlevel": 0, "precision": "", "print_hide": 0, @@ -308,6 +415,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -337,36 +445,7 @@ "unique": 0 }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "supplier", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Supplier", - "length": 0, - "no_copy": 0, - "options": "Supplier", - "permlevel": 0, - "precision": "", - "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, - "set_only_once": 0, - "unique": 0 - }, - { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -397,6 +476,37 @@ "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "is_existing_asset", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Is Existing Asset", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -426,6 +536,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -456,6 +567,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -484,6 +596,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -514,6 +627,36 @@ "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_18", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -545,6 +688,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -576,42 +720,13 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "value_after_depreciation", - "fieldtype": "Currency", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 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, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_11", - "fieldtype": "Column Break", + "fieldname": "section_break_20", + "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -634,6 +749,68 @@ "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "calculate_depreciation", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Calculate Depreciation", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "depends_on": "calculate_depreciation", + "fieldname": "section_break_23", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Depreciation", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -666,6 +843,38 @@ "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "value_after_depreciation", + "fieldtype": "Currency", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 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, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -695,6 +904,36 @@ "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_24", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -725,6 +964,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -754,6 +994,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -784,10 +1025,12 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, + "depends_on": "calculate_depreciation", "fieldname": "section_break_14", "fieldtype": "Section Break", "hidden": 0, @@ -813,6 +1056,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -843,6 +1087,68 @@ "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_31", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Maintenance", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "description": "Check if Asset requires Preventive Maintenance or Calibration", + "fieldname": "maintenance_required", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Maintenance Required", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -872,18 +1178,18 @@ "unique": 0 } ], + "has_web_view": 0, "hide_heading": 0, "hide_toolbar": 0, "idx": 72, "image_field": "image", "image_view": 0, "in_create": 0, - "in_dialog": 0, "is_submittable": 1, "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-02-17 16:26:19.111939", + "modified": "2017-10-28 19:59:17.040684", "modified_by": "Administrator", "module": "Accounts", "name": "Asset", diff --git a/erpnext/accounts/doctype/asset/asset.py b/erpnext/accounts/doctype/asset/asset.py index dd1e4916803..942a59e1357 100644 --- a/erpnext/accounts/doctype/asset/asset.py +++ b/erpnext/accounts/doctype/asset/asset.py @@ -1,260 +1,10 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt from __future__ import unicode_literals import frappe -from frappe import _ -from frappe.utils import flt, add_months, cint, nowdate, getdate from frappe.model.document import Document -from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import get_fixed_asset_account -from erpnext.accounts.doctype.asset.depreciation \ - import get_disposal_account_and_cost_center, get_depreciation_accounts class Asset(Document): - def validate(self): - self.status = self.get_status() - self.validate_item() - self.set_missing_values() - self.validate_asset_values() - self.make_depreciation_schedule() - self.set_accumulated_depreciation() - if self.get("schedules"): - self.validate_expected_value_after_useful_life() - # Validate depreciation related accounts - get_depreciation_accounts(self) - - def on_submit(self): - self.set_status() - - def on_cancel(self): - self.validate_cancellation() - self.delete_depreciation_entries() - self.set_status() - - def validate_item(self): - item = frappe.db.get_value("Item", self.item_code, - ["is_fixed_asset", "is_stock_item", "disabled"], as_dict=1) - if not item: - frappe.throw(_("Item {0} does not exist").format(self.item_code)) - elif item.disabled: - frappe.throw(_("Item {0} has been disabled").format(self.item_code)) - elif not item.is_fixed_asset: - frappe.throw(_("Item {0} must be a Fixed Asset Item").format(self.item_code)) - elif item.is_stock_item: - frappe.throw(_("Item {0} must be a non-stock item").format(self.item_code)) - - def set_missing_values(self): - if self.item_code: - item_details = get_item_details(self.item_code) - 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)) - - def validate_asset_values(self): - 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: - self.opening_accumulated_depreciation = 0 - self.number_of_depreciations_booked = 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.opening_accumulated_depreciation: - if not self.number_of_depreciations_booked: - frappe.throw(_("Please set Number of Depreciations Booked")) - else: - self.number_of_depreciations_booked = 0 - - if cint(self.number_of_depreciations_booked) > cint(self.total_number_of_depreciations): - frappe.throw(_("Number of Depreciations Booked cannot be greater than Total Number of Depreciations")) - - if self.next_depreciation_date and getdate(self.next_depreciation_date) < getdate(nowdate()): - frappe.msgprint(_("Next Depreciation Date is entered as past date"), title=_('Warning'), indicator='red') - - if self.next_depreciation_date and getdate(self.next_depreciation_date) < getdate(self.purchase_date): - frappe.throw(_("Next Depreciation Date cannot be before Purchase Date")) - - if (flt(self.value_after_depreciation) > flt(self.expected_value_after_useful_life) - and not self.next_depreciation_date): - frappe.throw(_("Please set Next Depreciation Date")) - - def make_depreciation_schedule(self): - if self.depreciation_method != 'Manual': - self.schedules = [] - - if not self.get("schedules") and self.next_depreciation_date: - value_after_depreciation = flt(self.value_after_depreciation) - - number_of_pending_depreciations = cint(self.total_number_of_depreciations) - \ - cint(self.number_of_depreciations_booked) - if number_of_pending_depreciations: - for n in xrange(number_of_pending_depreciations): - schedule_date = add_months(self.next_depreciation_date, - n * cint(self.frequency_of_depreciation)) - - depreciation_amount = self.get_depreciation_amount(value_after_depreciation) - value_after_depreciation -= flt(depreciation_amount) - - self.append("schedules", { - "schedule_date": schedule_date, - "depreciation_amount": depreciation_amount - }) - - def set_accumulated_depreciation(self): - accumulated_depreciation = flt(self.opening_accumulated_depreciation) - value_after_depreciation = flt(self.value_after_depreciation) - for i, d in enumerate(self.get("schedules")): - depreciation_amount = flt(d.depreciation_amount, d.precision("depreciation_amount")) - value_after_depreciation -= flt(depreciation_amount) - - if i==len(self.get("schedules"))-1 and self.depreciation_method == "Straight Line": - depreciation_amount += flt(value_after_depreciation - flt(self.expected_value_after_useful_life), - d.precision("depreciation_amount")) - - d.depreciation_amount = depreciation_amount - accumulated_depreciation += d.depreciation_amount - d.accumulated_depreciation_amount = flt(accumulated_depreciation, d.precision("accumulated_depreciation_amount")) - - def get_depreciation_amount(self, depreciable_value): - 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)) - else: - factor = 200.0 / self.total_number_of_depreciations - depreciation_amount = flt(depreciable_value * factor / 100, 0) - - value_after_depreciation = flt(depreciable_value) - depreciation_amount - if value_after_depreciation < flt(self.expected_value_after_useful_life): - depreciation_amount = flt(depreciable_value) - flt(self.expected_value_after_useful_life) - - return depreciation_amount - - def validate_expected_value_after_useful_life(self): - accumulated_depreciation_after_full_schedule = \ - max([d.accumulated_depreciation_amount for d in self.get("schedules")]) - - asset_value_after_full_schedule = flt(flt(self.gross_purchase_amount) - - flt(accumulated_depreciation_after_full_schedule), - self.precision('expected_value_after_useful_life')) - - 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"): - frappe.throw(_("Asset cannot be cancelled, as it is already {0}").format(self.status)) - - if self.purchase_invoice: - frappe.throw(_("Please cancel Purchase Invoice {0} first").format(self.purchase_invoice)) - - def delete_depreciation_entries(self): - 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) - - self.db_set("value_after_depreciation", - (flt(self.gross_purchase_amount) - flt(self.opening_accumulated_depreciation))) - - def set_status(self, status=None): - '''Get and update status''' - if not status: - status = self.get_status() - self.db_set("status", status) - - def get_status(self): - '''Returns status based on whether it is draft, submitted, scrapped or depreciated''' - if self.docstatus == 0: - status = "Draft" - elif self.docstatus == 1: - status = "Submitted" - if self.journal_entry_for_scrap: - status = "Scrapped" - elif flt(self.value_after_depreciation) <= flt(self.expected_value_after_useful_life): - status = "Fully Depreciated" - elif flt(self.value_after_depreciation) < flt(self.gross_purchase_amount): - status = 'Partially Depreciated' - elif self.docstatus == 2: - status = "Cancelled" - - return status - -@frappe.whitelist() -def make_purchase_invoice(asset, item_code, gross_purchase_amount, company, posting_date): - pi = frappe.new_doc("Purchase Invoice") - pi.company = company - pi.currency = frappe.db.get_value("Company", company, "default_currency") - pi.set_posting_time = 1 - pi.posting_date = posting_date - pi.append("items", { - "item_code": item_code, - "is_fixed_asset": 1, - "asset": asset, - "expense_account": get_fixed_asset_account(asset), - "qty": 1, - "price_list_rate": gross_purchase_amount, - "rate": gross_purchase_amount - }) - pi.set_missing_values() - return pi - -@frappe.whitelist() -def make_sales_invoice(asset, item_code, company): - si = frappe.new_doc("Sales Invoice") - si.company = company - si.currency = frappe.db.get_value("Company", company, "default_currency") - disposal_account, depreciation_cost_center = get_disposal_account_and_cost_center(company) - si.append("items", { - "item_code": item_code, - "is_fixed_asset": 1, - "asset": asset, - "income_account": disposal_account, - "cost_center": depreciation_cost_center, - "qty": 1 - }) - si.set_missing_values() - return si - -@frappe.whitelist() -def transfer_asset(args): - import json - args = json.loads(args) - movement_entry = frappe.new_doc("Asset Movement") - movement_entry.update(args) - movement_entry.insert() - movement_entry.submit() - - frappe.db.commit() - - frappe.msgprint(_("Asset Movement record {0} created").format("{0}".format(movement_entry.name))) - -@frappe.whitelist() -def get_item_details(item_code): - asset_category = frappe.db.get_value("Item", item_code, "asset_category") - - if not asset_category: - frappe.throw(_("Please enter Asset Category in Item {0}").format(item_code)) - - ret = frappe.db.get_value("Asset Category", asset_category, - ["depreciation_method", "total_number_of_depreciations", "frequency_of_depreciation"], as_dict=1) - - ret.update({ - "asset_category": asset_category - }) - - return ret + pass diff --git a/erpnext/accounts/doctype/asset/test_asset.js b/erpnext/accounts/doctype/asset/test_asset.js new file mode 100644 index 00000000000..6119e382174 --- /dev/null +++ b/erpnext/accounts/doctype/asset/test_asset.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Asset", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Asset + () => frappe.tests.make('Asset', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/erpnext/accounts/doctype/asset/test_asset.py b/erpnext/accounts/doctype/asset/test_asset.py index fd66d1fb679..22baae36df8 100644 --- a/erpnext/accounts/doctype/asset/test_asset.py +++ b/erpnext/accounts/doctype/asset/test_asset.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt from __future__ import unicode_literals import frappe import unittest from frappe.utils import cstr, nowdate, getdate, flt -from erpnext.accounts.doctype.asset.depreciation import post_depreciation_entries, scrap_asset, restore_asset -from erpnext.accounts.doctype.asset.asset import make_sales_invoice, make_purchase_invoice +from erpnext.assets.doctype.asset.depreciation import post_depreciation_entries, scrap_asset, restore_asset +from erpnext.assets.doctype.asset.asset import make_sales_invoice, make_purchase_invoice class TestAsset(unittest.TestCase): def setUp(self): @@ -340,4 +340,4 @@ def set_depreciation_settings_in_company(): company.save() # Enable booking asset depreciation entry automatically - frappe.db.set_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically", 1) \ No newline at end of file + frappe.db.set_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically", 1) diff --git a/erpnext/accounts/doctype/asset_category/asset_category.js b/erpnext/accounts/doctype/asset_category/asset_category.js index aafe8a69a0e..f3bb8026338 100644 --- a/erpnext/accounts/doctype/asset_category/asset_category.js +++ b/erpnext/accounts/doctype/asset_category/asset_category.js @@ -1,44 +1,8 @@ -// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors // For license information, please see license.txt frappe.ui.form.on('Asset Category', { - onload: function(frm) { - frm.add_fetch('company_name', 'accumulated_depreciation_account', 'accumulated_depreciation_account'); - frm.add_fetch('company_name', 'depreciation_expense_account', 'accumulated_depreciation_account'); - - frm.set_query('fixed_asset_account', 'accounts', function(doc, cdt, cdn) { - var d = locals[cdt][cdn]; - return { - "filters": { - "account_type": "Fixed Asset", - "root_type": "Asset", - "is_group": 0, - "company": d.company_name - } - }; - }); - - frm.set_query('accumulated_depreciation_account', 'accounts', function(doc, cdt, cdn) { - var d = locals[cdt][cdn]; - return { - "filters": { - "root_type": "Asset", - "is_group": 0, - "company": d.company_name - } - }; - }); - - frm.set_query('depreciation_expense_account', 'accounts', function(doc, cdt, cdn) { - var d = locals[cdt][cdn]; - return { - "filters": { - "root_type": "Expense", - "is_group": 0, - "company": d.company_name - } - }; - }); + refresh: function(frm) { } -}); \ No newline at end of file +}); diff --git a/erpnext/accounts/doctype/asset_category/asset_category.json b/erpnext/accounts/doctype/asset_category/asset_category.json index 74762d790ca..d34ec5ce3f4 100644 --- a/erpnext/accounts/doctype/asset_category/asset_category.json +++ b/erpnext/accounts/doctype/asset_category/asset_category.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 1, "autoname": "field:asset_category_name", @@ -13,6 +14,7 @@ "engine": "InnoDB", "fields": [ { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -24,7 +26,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 0, + "in_list_view": 1, "in_standard_filter": 0, "label": "Asset Category Name", "length": 0, @@ -42,6 +44,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -54,7 +57,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 0, + "in_list_view": 1, "in_standard_filter": 1, "label": "Depreciation Method", "length": 0, @@ -73,6 +76,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -101,6 +105,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -112,7 +117,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 0, + "in_list_view": 1, "in_standard_filter": 0, "label": "Total Number of Depreciations", "length": 0, @@ -130,6 +135,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -141,7 +147,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 0, + "in_list_view": 1, "in_standard_filter": 0, "label": "Frequency of Depreciation (Months)", "length": 0, @@ -159,6 +165,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -188,6 +195,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -218,17 +226,17 @@ "unique": 0 } ], + "has_web_view": 0, "hide_heading": 0, "hide_toolbar": 0, "idx": 0, "image_view": 0, "in_create": 0, - "in_dialog": 0, "is_submittable": 0, "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-02-17 16:09:52.955332", + "modified": "2017-10-28 19:59:31.819567", "modified_by": "Administrator", "module": "Accounts", "name": "Asset Category", diff --git a/erpnext/accounts/doctype/asset_category/asset_category.py b/erpnext/accounts/doctype/asset_category/asset_category.py index 5279c37ea84..dc454abe547 100644 --- a/erpnext/accounts/doctype/asset_category/asset_category.py +++ b/erpnext/accounts/doctype/asset_category/asset_category.py @@ -1,15 +1,10 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt from __future__ import unicode_literals import frappe -from frappe import _ -from frappe.utils import cint from frappe.model.document import Document class AssetCategory(Document): - def validate(self): - for field in ("total_number_of_depreciations", "frequency_of_depreciation"): - if cint(self.get(field))<1: - frappe.throw(_("{0} must be greater than 0").format(self.meta.get_label(field)), frappe.MandatoryError) \ No newline at end of file + pass diff --git a/erpnext/accounts/doctype/asset_category/test_asset_category.js b/erpnext/accounts/doctype/asset_category/test_asset_category.js new file mode 100644 index 00000000000..7e343b7519e --- /dev/null +++ b/erpnext/accounts/doctype/asset_category/test_asset_category.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Asset Category", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Asset Category + () => frappe.tests.make('Asset Category', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/erpnext/accounts/doctype/asset_category/test_asset_category.py b/erpnext/accounts/doctype/asset_category/test_asset_category.py index b32f9b50202..4d5169a0a6b 100644 --- a/erpnext/accounts/doctype/asset_category/test_asset_category.py +++ b/erpnext/accounts/doctype/asset_category/test_asset_category.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt from __future__ import unicode_literals @@ -7,23 +7,4 @@ import frappe import unittest class TestAssetCategory(unittest.TestCase): - def test_mandatory_fields(self): - asset_category = frappe.new_doc("Asset Category") - asset_category.asset_category_name = "Computers" - - self.assertRaises(frappe.MandatoryError, asset_category.insert) - - asset_category.total_number_of_depreciations = 3 - asset_category.frequency_of_depreciation = 3 - asset_category.append("accounts", { - "company_name": "_Test Company", - "fixed_asset_account": "_Test Fixed Asset - _TC", - "accumulated_depreciation_account": "_Test Accumulated Depreciations - _TC", - "depreciation_expense_account": "_Test Depreciations - _TC" - }) - - try: - asset_category.insert() - except frappe.DuplicateEntryError: - pass - \ No newline at end of file + pass diff --git a/erpnext/accounts/doctype/asset_movement/asset_movement.js b/erpnext/accounts/doctype/asset_movement/asset_movement.js index 70c4080d1c8..f2d82beaa28 100644 --- a/erpnext/accounts/doctype/asset_movement/asset_movement.js +++ b/erpnext/accounts/doctype/asset_movement/asset_movement.js @@ -1,18 +1,8 @@ -// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors // For license information, please see license.txt frappe.ui.form.on('Asset Movement', { - onload: function(frm) { - frm.add_fetch("asset", "warehouse", "source_warehouse"); - - frm.set_query("target_warehouse", function() { - return { - filters: [ - ["Warehouse", "company", "in", ["", cstr(frm.doc.company)]], - ["Warehouse", "is_group", "=", 0] - ] - } - }) + refresh: function(frm) { } }); diff --git a/erpnext/accounts/doctype/asset_movement/asset_movement.json b/erpnext/accounts/doctype/asset_movement/asset_movement.json index a1189f50351..7d7c12730ac 100644 --- a/erpnext/accounts/doctype/asset_movement/asset_movement.json +++ b/erpnext/accounts/doctype/asset_movement/asset_movement.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 0, "autoname": "AM-.#####", @@ -12,6 +13,7 @@ "editable_grid": 0, "fields": [ { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -23,7 +25,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 1, - "in_list_view": 0, + "in_list_view": 1, "in_standard_filter": 1, "label": "Asset", "length": 0, @@ -42,6 +44,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -53,7 +56,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 0, + "in_list_view": 1, "in_standard_filter": 0, "label": "Transaction Date", "length": 0, @@ -71,6 +74,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -82,7 +86,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 0, + "in_list_view": 1, "in_standard_filter": 1, "label": "Company", "length": 0, @@ -101,6 +105,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -129,6 +134,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -159,6 +165,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -170,7 +177,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 0, + "in_list_view": 1, "in_standard_filter": 1, "label": "Target Warehouse", "length": 0, @@ -189,6 +196,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -218,17 +226,17 @@ "unique": 0 } ], + "has_web_view": 0, "hide_heading": 0, "hide_toolbar": 0, "idx": 0, "image_view": 0, "in_create": 0, - "in_dialog": 0, "is_submittable": 1, "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-02-17 16:09:32.069344", + "modified": "2017-10-28 20:01:49.372952", "modified_by": "Administrator", "module": "Accounts", "name": "Asset Movement", diff --git a/erpnext/accounts/doctype/asset_movement/asset_movement.py b/erpnext/accounts/doctype/asset_movement/asset_movement.py index 574c49992b4..5acd4f1e82d 100644 --- a/erpnext/accounts/doctype/asset_movement/asset_movement.py +++ b/erpnext/accounts/doctype/asset_movement/asset_movement.py @@ -1,48 +1,10 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt from __future__ import unicode_literals import frappe -from frappe import _ from frappe.model.document import Document class AssetMovement(Document): - def validate(self): - self.validate_asset() - self.validate_warehouses() - - def validate_asset(self): - status, company = frappe.db.get_value("Asset", self.asset, ["status", "company"]) - if status in ("Draft", "Scrapped", "Sold"): - frappe.throw(_("{0} asset cannot be transferred").format(status)) - - if company != self.company: - frappe.throw(_("Asset {0} does not belong to company {1}").format(self.asset, self.company)) - - def validate_warehouses(self): - if not self.source_warehouse: - self.source_warehouse = frappe.db.get_value("Asset", self.asset, "warehouse") - - if self.source_warehouse == self.target_warehouse: - frappe.throw(_("Source and Target Warehouse cannot be same")) - - def on_submit(self): - self.set_latest_warehouse_in_asset() - - def on_cancel(self): - self.set_latest_warehouse_in_asset() - - def set_latest_warehouse_in_asset(self): - latest_movement_entry = frappe.db.sql("""select target_warehouse from `tabAsset Movement` - where asset=%s and docstatus=1 and company=%s - order by transaction_date desc limit 1""", (self.asset, self.company)) - - if latest_movement_entry: - warehouse = latest_movement_entry[0][0] - else: - warehouse = frappe.db.sql("""select source_warehouse from `tabAsset Movement` - where asset=%s and docstatus=2 and company=%s - order by transaction_date asc limit 1""", (self.asset, self.company))[0][0] - - frappe.db.set_value("Asset", self.asset, "warehouse", warehouse) \ No newline at end of file + pass diff --git a/erpnext/accounts/doctype/asset_movement/test_asset_movement.js b/erpnext/accounts/doctype/asset_movement/test_asset_movement.js new file mode 100644 index 00000000000..b9515763c42 --- /dev/null +++ b/erpnext/accounts/doctype/asset_movement/test_asset_movement.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Asset Movement", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Asset Movement + () => frappe.tests.make('Asset Movement', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/erpnext/accounts/doctype/asset_movement/test_asset_movement.py b/erpnext/accounts/doctype/asset_movement/test_asset_movement.py index 9880efc37f8..6f750a4c502 100644 --- a/erpnext/accounts/doctype/asset_movement/test_asset_movement.py +++ b/erpnext/accounts/doctype/asset_movement/test_asset_movement.py @@ -1,51 +1,10 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt from __future__ import unicode_literals import frappe -from frappe.utils import now import unittest -from erpnext.accounts.doctype.asset.test_asset import create_asset - class TestAssetMovement(unittest.TestCase): - def test_movement(self): - asset = create_asset() - - if asset.docstatus == 0: - asset.submit() - - movement1 = create_asset_movement(asset, target_warehouse="_Test Warehouse 1 - _TC") - self.assertEqual(frappe.db.get_value("Asset", asset.name, "warehouse"), "_Test Warehouse 1 - _TC") - - movement2 = create_asset_movement(asset, target_warehouse="_Test Warehouse 2 - _TC") - self.assertEqual(frappe.db.get_value("Asset", asset.name, "warehouse"), "_Test Warehouse 2 - _TC") - - movement1.cancel() - self.assertEqual(frappe.db.get_value("Asset", asset.name, "warehouse"), "_Test Warehouse 2 - _TC") - - movement2.cancel() - self.assertEqual(frappe.db.get_value("Asset", asset.name, "warehouse"), "_Test Warehouse - _TC") - - asset.load_from_db() - asset.cancel() - frappe.delete_doc("Asset", asset.name) - - -def create_asset_movement(asset, target_warehouse, transaction_date=None): - if not transaction_date: - transaction_date = now() - - movement = frappe.new_doc("Asset Movement") - movement.update({ - "asset": asset.name, - "transaction_date": transaction_date, - "target_warehouse": target_warehouse, - "company": asset.company - }) - - movement.insert() - movement.submit() - - return movement + pass diff --git a/erpnext/accounts/doctype/depreciation_schedule/depreciation_schedule.json b/erpnext/accounts/doctype/depreciation_schedule/depreciation_schedule.json index 1fadf5eb4f6..29dcdfb04b6 100644 --- a/erpnext/accounts/doctype/depreciation_schedule/depreciation_schedule.json +++ b/erpnext/accounts/doctype/depreciation_schedule/depreciation_schedule.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 1, "autoname": "", @@ -13,6 +14,7 @@ "engine": "InnoDB", "fields": [ { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -23,7 +25,9 @@ "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Schedule Date", "length": 0, "no_copy": 1, @@ -40,6 +44,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -50,7 +55,9 @@ "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Depreciation Amount", "length": 0, "no_copy": 1, @@ -68,6 +75,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -78,7 +86,9 @@ "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "length": 0, "no_copy": 0, "permlevel": 0, @@ -94,6 +104,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -104,7 +115,9 @@ "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Accumulated Depreciation Amount", "length": 0, "no_copy": 1, @@ -122,6 +135,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -133,7 +147,9 @@ "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Journal Entry", "length": 0, "no_copy": 1, @@ -151,6 +167,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 1, "bold": 0, "collapsible": 0, @@ -162,7 +179,9 @@ "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Make Depreciation Entry", "length": 0, "no_copy": 0, @@ -179,17 +198,17 @@ "unique": 0 } ], + "has_web_view": 0, "hide_heading": 0, "hide_toolbar": 0, "idx": 0, "image_view": 0, "in_create": 0, - "in_dialog": 0, "is_submittable": 0, "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2016-11-18 16:42:19.543657", + "modified": "2017-10-28 20:02:11.376361", "modified_by": "Administrator", "module": "Accounts", "name": "Depreciation Schedule", @@ -199,7 +218,9 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", + "track_changes": 0, "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/depreciation_schedule/depreciation_schedule.py b/erpnext/accounts/doctype/depreciation_schedule/depreciation_schedule.py index 957d6d119f8..54fba3f68c1 100644 --- a/erpnext/accounts/doctype/depreciation_schedule/depreciation_schedule.py +++ b/erpnext/accounts/doctype/depreciation_schedule/depreciation_schedule.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt from __future__ import unicode_literals diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index ccaae496704..82d8de541d9 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -298,7 +298,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte var row = locals[cdt][cdn]; if(row.asset) { frappe.call({ - method: erpnext.accounts.doctype.asset.depreciation.get_disposal_account_and_cost_center, + method: erpnext.assets.doctype.asset.depreciation.get_disposal_account_and_cost_center, args: { "company": frm.doc.company }, diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index ee2b5542fbf..8edeb99ae02 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -15,7 +15,7 @@ from erpnext.controllers.selling_controller import SellingController from erpnext.accounts.utils import get_account_currency from erpnext.stock.doctype.delivery_note.delivery_note import update_billed_amount_based_on_so from erpnext.projects.doctype.timesheet.timesheet import get_projectwise_timesheet_data -from erpnext.accounts.doctype.asset.depreciation \ +from erpnext.assets.doctype.asset.depreciation \ import get_disposal_account_and_cost_center, get_gl_entries_on_asset_disposal from erpnext.stock.doctype.batch.batch import set_batch_nos from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos, get_delivery_note_serial_no diff --git a/erpnext/assets/__init__.py b/erpnext/assets/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/assets/doctype/__init__.py b/erpnext/assets/doctype/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/assets/doctype/asset/__init__.py b/erpnext/assets/doctype/asset/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js new file mode 100644 index 00000000000..e7459259c85 --- /dev/null +++ b/erpnext/assets/doctype/asset/asset.js @@ -0,0 +1,304 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.provide("erpnext.asset"); + +frappe.ui.form.on('Asset', { + onload: function(frm) { + frm.set_query("item_code", function() { + return { + "filters": { + "disabled": 0, + "is_fixed_asset": 1, + "is_stock_item": 0 + } + }; + }); + + frm.set_query("warehouse", function() { + return { + "filters": { + "company": frm.doc.company, + "is_group": 0 + } + }; + }); + }, + + 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 (in_list(["Submitted", "Partially Depreciated", "Fully Depreciated"], frm.doc.status)) { + frm.add_custom_button("Transfer Asset", function() { + erpnext.asset.transfer_asset(frm); + }); + + frm.add_custom_button("Scrap Asset", function() { + erpnext.asset.scrap_asset(frm); + }); + + frm.add_custom_button("Sell Asset", function() { + erpnext.asset.make_sales_invoice(frm); + }); + + } else if (frm.doc.status=='Scrapped') { + frm.add_custom_button("Restore Asset", function() { + erpnext.asset.restore_asset(frm); + }); + } + if (frm.doc.status=='Submitted' && !frm.doc.is_existing_asset && !frm.doc.purchase_invoice) { + frm.add_custom_button(__("Purchase Invoice"), function() { + frm.trigger("make_purchase_invoice"); + }, __("Make")); + } + if (frm.doc.maintenance_required && !frm.doc.maintenance_schedule) { + frm.add_custom_button(__("Asset Maintenance"), function() { + frm.trigger("create_asset_maintenance"); + }, __("Make")); + } + frm.page.set_inner_btn_group_as_primary(__("Make")); + frm.trigger("setup_chart"); + } + }, + + setup_chart: function(frm) { + var x_intervals = [frm.doc.purchase_date]; + var asset_values = [frm.doc.gross_purchase_amount]; + var last_depreciation_date = frm.doc.purchase_date; + + if(frm.doc.opening_accumulated_depreciation) { + last_depreciation_date = frappe.datetime.add_months(frm.doc.next_depreciation_date, + -1*frm.doc.frequency_of_depreciation); + + x_intervals.push(last_depreciation_date); + asset_values.push(flt(frm.doc.gross_purchase_amount) - + flt(frm.doc.opening_accumulated_depreciation)); + } + + $.each(frm.doc.schedules || [], function(i, v) { + x_intervals.push(v.schedule_date); + var asset_value = flt(frm.doc.gross_purchase_amount) - flt(v.accumulated_depreciation_amount); + if(v.journal_entry) { + last_depreciation_date = v.schedule_date; + asset_values.push(asset_value); + } else { + if (in_list(["Scrapped", "Sold"], frm.doc.status)) { + asset_values.push(null); + } else { + asset_values.push(asset_value) + } + } + }); + + if(in_list(["Scrapped", "Sold"], frm.doc.status)) { + x_intervals.push(frm.doc.disposal_date); + asset_values.push(0); + last_depreciation_date = frm.doc.disposal_date; + } + + frm.dashboard.render_graph({ + title: "Asset Value", + data: { + labels: x_intervals, + datasets: [{ + color: 'green', + values: asset_values, + formatted: asset_values.map(d => d.toFixed(2)) + }] + }, + type: 'line' + }); + }, + + + item_code: function(frm) { + if(frm.doc.item_code) { + frappe.call({ + method: "erpnext.assets.doctype.asset.asset.get_item_details", + args: { + item_code: frm.doc.item_code + }, + callback: function(r, rt) { + if(r.message) { + $.each(r.message, function(field, value) { + frm.set_value(field, value); + }) + } + } + }) + } + }, + + is_existing_asset: function(frm) { + frm.toggle_reqd("next_depreciation_date", (!frm.doc.is_existing_asset && frm.doc.calculate_depreciation)); + }, + + 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); + }, + + make_purchase_invoice: function(frm) { + frappe.call({ + args: { + "asset": frm.doc.name, + "item_code": frm.doc.item_code, + "gross_purchase_amount": frm.doc.gross_purchase_amount, + "company": frm.doc.company, + "posting_date": frm.doc.purchase_date + }, + method: "erpnext.assets.doctype.asset.asset.make_purchase_invoice", + callback: function(r) { + var doclist = frappe.model.sync(r.message); + frappe.set_route("Form", doclist[0].doctype, doclist[0].name); + } + }) + }, + + create_asset_maintenance: function(frm) { + frappe.call({ + args: { + "asset": frm.doc.name, + "item_code": frm.doc.item_code, + "item_name": frm.doc.item_name, + "asset_category": frm.doc.asset_category, + "company": frm.doc.company + }, + method: "erpnext.assets.doctype.asset.asset.create_asset_maintenance", + callback: function(r) { + var doclist = frappe.model.sync(r.message); + frappe.set_route("Form", doclist[0].doctype, doclist[0].name); + } + }) + } +}); + +frappe.ui.form.on('Depreciation Schedule', { + make_depreciation_entry: function(frm, cdt, cdn) { + var row = locals[cdt][cdn]; + if (!row.journal_entry) { + frappe.call({ + method: "erpnext.assets.doctype.asset.depreciation.make_depreciation_entry", + args: { + "asset_name": frm.doc.name, + "date": row.schedule_date + }, + callback: function(r) { + frappe.model.sync(r.message); + frm.refresh(); + } + }) + } + }, + + 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; + + var 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.scrap_asset = function(frm) { + frappe.confirm(__("Do you really want to scrap this asset?"), function () { + frappe.call({ + args: { + "asset_name": frm.doc.name + }, + method: "erpnext.assets.doctype.asset.depreciation.scrap_asset", + callback: function(r) { + cur_frm.reload_doc(); + } + }) + }) +}; + +erpnext.asset.restore_asset = function(frm) { + frappe.confirm(__("Do you really want to restore this scrapped asset?"), function () { + frappe.call({ + args: { + "asset_name": frm.doc.name + }, + method: "erpnext.assets.doctype.asset.depreciation.restore_asset", + callback: function(r) { + cur_frm.reload_doc(); + } + }) + }) +}; + +erpnext.asset.transfer_asset = function(frm) { + var dialog = new frappe.ui.Dialog({ + title: __("Transfer Asset"), + fields: [ + { + "label": __("Target Warehouse"), + "fieldname": "target_warehouse", + "fieldtype": "Link", + "options": "Warehouse", + "get_query": function () { + return { + filters: [ + ["Warehouse", "company", "in", ["", cstr(frm.doc.company)]], + ["Warehouse", "is_group", "=", 0] + ] + } + }, + "reqd": 1 + }, + { + "label": __("Date"), + "fieldname": "transfer_date", + "fieldtype": "Datetime", + "reqd": 1, + "default": frappe.datetime.now_datetime() + } + ] + }); + + dialog.set_primary_action(__("Transfer"), function() { + var args = dialog.get_values(); + if(!args) return; + dialog.hide(); + return frappe.call({ + type: "GET", + method: "erpnext.assets.doctype.asset.asset.transfer_asset", + args: { + args: { + "asset": frm.doc.name, + "transaction_date": args.transfer_date, + "source_warehouse": frm.doc.warehouse, + "target_warehouse": args.target_warehouse, + "company": frm.doc.company + } + }, + freeze: true, + callback: function(r) { + cur_frm.reload_doc(); + } + }) + }); + dialog.show(); +}; \ No newline at end of file diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json new file mode 100644 index 00000000000..e0ed56acc54 --- /dev/null +++ b/erpnext/assets/doctype/asset/asset.json @@ -0,0 +1,1228 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 1, + "allow_rename": 1, + "autoname": "field:asset_name", + "beta": 0, + "creation": "2016-03-01 17:01:27.920130", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "Document", + "editable_grid": 0, + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "asset_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Asset Name", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "item_code", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 1, + "label": "Item Code", + "length": 0, + "no_copy": 0, + "options": "Item", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "item_name", + "fieldtype": "Read Only", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Item Name", + "length": 0, + "no_copy": 0, + "options": "item_code.item_name", + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "asset_category", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 1, + "in_list_view": 0, + "in_standard_filter": 1, + "label": "Asset Category", + "length": 0, + "no_copy": 0, + "options": "Asset Category", + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "Draft", + "fieldname": "status", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Status", + "length": 0, + "no_copy": 1, + "options": "Draft\nSubmitted\nPartially Depreciated\nFully Depreciated\nSold\nScrapped\nIn Repair\nOut of Order", + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "asset_owner", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Asset Owner", + "length": 0, + "no_copy": 0, + "options": "Company\nSupplier\nCustomer", + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.asset_owner == \"Supplier\"", + "fieldname": "supplier", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Supplier", + "length": 0, + "no_copy": 0, + "options": "Supplier", + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.asset_owner == \"Customer\"", + "fieldname": "customer", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Customer", + "length": 0, + "no_copy": 0, + "options": "Customer", + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "image", + "fieldtype": "Attach Image", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Image", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_3", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "company", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Company", + "length": 0, + "no_copy": 0, + "options": "Company", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 1, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 1, + "label": "Warehouse", + "length": 0, + "no_copy": 0, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "department", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Department", + "length": 0, + "no_copy": 0, + "options": "Department", + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "purchase_date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Purchase Date", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "purchase_invoice", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Purchase Invoice", + "length": 0, + "no_copy": 1, + "options": "Purchase Invoice", + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "is_existing_asset", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Is Existing Asset", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "disposal_date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Disposal Date", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "journal_entry_for_scrap", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Journal Entry for Scrap", + "length": 0, + "no_copy": 1, + "options": "Journal Entry", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_5", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "gross_purchase_amount", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Gross Purchase Amount", + "length": 0, + "no_copy": 0, + "options": "Company:company:default_currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_18", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "description": "", + "fieldname": "expected_value_after_useful_life", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Expected Value After Useful Life", + "length": 0, + "no_copy": 0, + "options": "Company:company:default_currency", + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "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_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Opening Accumulated Depreciation", + "length": 0, + "no_copy": 1, + "options": "Company:company:default_currency", + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_20", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "calculate_depreciation", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Calculate Depreciation", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "depends_on": "calculate_depreciation", + "fieldname": "section_break_23", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Depreciation", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "", + "depends_on": "", + "fieldname": "depreciation_method", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Depreciation Method", + "length": 0, + "no_copy": 0, + "options": "\nStraight Line\nDouble Declining Balance\nManual", + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "value_after_depreciation", + "fieldtype": "Currency", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 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, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "total_number_of_depreciations", + "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Total Number of Depreciations", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_24", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:(doc.is_existing_asset && doc.opening_accumulated_depreciation)", + "fieldname": "number_of_depreciations_booked", + "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Number of Depreciations Booked", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "frequency_of_depreciation", + "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Frequency of Depreciation (Months)", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "fieldname": "next_depreciation_date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Next Depreciation Date", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "calculate_depreciation", + "fieldname": "section_break_14", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Depreciation Schedule", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "schedules", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Depreciation Schedules", + "length": 0, + "no_copy": 1, + "options": "Depreciation Schedule", + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_31", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Maintenance", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "description": "Check if Asset requires Preventive Maintenance or Calibration", + "fieldname": "maintenance_required", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Maintenance Required", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "amended_from", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Amended From", + "length": 0, + "no_copy": 1, + "options": "Asset", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 72, + "image_field": "image", + "image_view": 0, + "in_create": 0, + "is_submittable": 1, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "modified": "2017-11-21 04:45:24.039059", + "modified_by": "Administrator", + "module": "Assets", + "name": "Asset", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 1, + "apply_user_permissions": 0, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 1, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts User", + "set_user_permissions": 0, + "share": 1, + "submit": 1, + "write": 1 + } + ], + "quick_entry": 0, + "read_only": 0, + "read_only_onload": 1, + "show_name_in_global_search": 1, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 0, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py new file mode 100644 index 00000000000..97cb8769301 --- /dev/null +++ b/erpnext/assets/doctype/asset/asset.py @@ -0,0 +1,271 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe import _ +from frappe.utils import flt, add_months, cint, nowdate, getdate +from frappe.model.document import Document +from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import get_fixed_asset_account +from erpnext.assets.doctype.asset.depreciation \ + import get_disposal_account_and_cost_center, get_depreciation_accounts + +class Asset(Document): + def validate(self): + self.status = self.get_status() + self.validate_item() + self.set_missing_values() + self.validate_asset_values() + self.make_depreciation_schedule() + self.set_accumulated_depreciation() + if self.get("schedules"): + self.validate_expected_value_after_useful_life() + # Validate depreciation related accounts + get_depreciation_accounts(self) + + def on_submit(self): + self.set_status() + + def on_cancel(self): + self.validate_cancellation() + self.delete_depreciation_entries() + self.set_status() + + def validate_item(self): + item = frappe.db.get_value("Item", self.item_code, + ["is_fixed_asset", "is_stock_item", "disabled"], as_dict=1) + if not item: + frappe.throw(_("Item {0} does not exist").format(self.item_code)) + elif item.disabled: + frappe.throw(_("Item {0} has been disabled").format(self.item_code)) + elif not item.is_fixed_asset: + frappe.throw(_("Item {0} must be a Fixed Asset Item").format(self.item_code)) + elif item.is_stock_item: + frappe.throw(_("Item {0} must be a non-stock item").format(self.item_code)) + + def set_missing_values(self): + if self.item_code: + item_details = get_item_details(self.item_code) + 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)) + + def validate_asset_values(self): + 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 self.calculate_depreciation: + self.opening_accumulated_depreciation = 0 + self.number_of_depreciations_booked = 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.opening_accumulated_depreciation: + if not self.number_of_depreciations_booked: + frappe.throw(_("Please set Number of Depreciations Booked")) + else: + self.number_of_depreciations_booked = 0 + + if cint(self.number_of_depreciations_booked) > cint(self.total_number_of_depreciations): + frappe.throw(_("Number of Depreciations Booked cannot be greater than Total Number of Depreciations")) + + if self.next_depreciation_date and getdate(self.next_depreciation_date) < getdate(nowdate()): + frappe.msgprint(_("Next Depreciation Date is entered as past date"), title=_('Warning'), indicator='red') + + if self.next_depreciation_date and getdate(self.next_depreciation_date) < getdate(self.purchase_date): + frappe.throw(_("Next Depreciation Date cannot be before Purchase Date")) + + if (flt(self.value_after_depreciation) > flt(self.expected_value_after_useful_life) + and not self.next_depreciation_date and self.calculate_depreciation): + frappe.throw(_("Please set Next Depreciation Date")) + + def make_depreciation_schedule(self): + if self.depreciation_method != 'Manual': + self.schedules = [] + + if not self.get("schedules") and self.next_depreciation_date: + value_after_depreciation = flt(self.value_after_depreciation) + + number_of_pending_depreciations = cint(self.total_number_of_depreciations) - \ + cint(self.number_of_depreciations_booked) + if number_of_pending_depreciations: + for n in xrange(number_of_pending_depreciations): + schedule_date = add_months(self.next_depreciation_date, + n * cint(self.frequency_of_depreciation)) + + depreciation_amount = self.get_depreciation_amount(value_after_depreciation) + value_after_depreciation -= flt(depreciation_amount) + + self.append("schedules", { + "schedule_date": schedule_date, + "depreciation_amount": depreciation_amount + }) + + def set_accumulated_depreciation(self): + accumulated_depreciation = flt(self.opening_accumulated_depreciation) + value_after_depreciation = flt(self.value_after_depreciation) + for i, d in enumerate(self.get("schedules")): + depreciation_amount = flt(d.depreciation_amount, d.precision("depreciation_amount")) + value_after_depreciation -= flt(depreciation_amount) + + if i==len(self.get("schedules"))-1 and self.depreciation_method == "Straight Line": + depreciation_amount += flt(value_after_depreciation - flt(self.expected_value_after_useful_life), + d.precision("depreciation_amount")) + + d.depreciation_amount = depreciation_amount + accumulated_depreciation += d.depreciation_amount + d.accumulated_depreciation_amount = flt(accumulated_depreciation, d.precision("accumulated_depreciation_amount")) + + def get_depreciation_amount(self, depreciable_value): + 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)) + else: + factor = 200.0 / self.total_number_of_depreciations + depreciation_amount = flt(depreciable_value * factor / 100, 0) + + value_after_depreciation = flt(depreciable_value) - depreciation_amount + if value_after_depreciation < flt(self.expected_value_after_useful_life): + depreciation_amount = flt(depreciable_value) - flt(self.expected_value_after_useful_life) + + return depreciation_amount + + def validate_expected_value_after_useful_life(self): + accumulated_depreciation_after_full_schedule = \ + max([d.accumulated_depreciation_amount for d in self.get("schedules")]) + + asset_value_after_full_schedule = flt(flt(self.gross_purchase_amount) - + flt(accumulated_depreciation_after_full_schedule), + self.precision('expected_value_after_useful_life')) + + 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"): + frappe.throw(_("Asset cannot be cancelled, as it is already {0}").format(self.status)) + + if self.purchase_invoice: + frappe.throw(_("Please cancel Purchase Invoice {0} first").format(self.purchase_invoice)) + + def delete_depreciation_entries(self): + 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) + + self.db_set("value_after_depreciation", + (flt(self.gross_purchase_amount) - flt(self.opening_accumulated_depreciation))) + + def set_status(self, status=None): + '''Get and update status''' + if not status: + status = self.get_status() + self.db_set("status", status) + + def get_status(self): + '''Returns status based on whether it is draft, submitted, scrapped or depreciated''' + if self.docstatus == 0: + status = "Draft" + elif self.docstatus == 1: + status = "Submitted" + if self.journal_entry_for_scrap: + status = "Scrapped" + elif flt(self.value_after_depreciation) <= flt(self.expected_value_after_useful_life): + status = "Fully Depreciated" + elif flt(self.value_after_depreciation) < flt(self.gross_purchase_amount): + status = 'Partially Depreciated' + elif self.docstatus == 2: + status = "Cancelled" + return status + +@frappe.whitelist() +def make_purchase_invoice(asset, item_code, gross_purchase_amount, company, posting_date): + pi = frappe.new_doc("Purchase Invoice") + pi.company = company + pi.currency = frappe.db.get_value("Company", company, "default_currency") + pi.set_posting_time = 1 + pi.posting_date = posting_date + pi.append("items", { + "item_code": item_code, + "is_fixed_asset": 1, + "asset": asset, + "expense_account": get_fixed_asset_account(asset), + "qty": 1, + "price_list_rate": gross_purchase_amount, + "rate": gross_purchase_amount + }) + pi.set_missing_values() + return pi + +@frappe.whitelist() +def make_sales_invoice(asset, item_code, company): + si = frappe.new_doc("Sales Invoice") + si.company = company + si.currency = frappe.db.get_value("Company", company, "default_currency") + disposal_account, depreciation_cost_center = get_disposal_account_and_cost_center(company) + si.append("items", { + "item_code": item_code, + "is_fixed_asset": 1, + "asset": asset, + "income_account": disposal_account, + "cost_center": depreciation_cost_center, + "qty": 1 + }) + si.set_missing_values() + return si + +@frappe.whitelist() +def create_asset_maintenance(asset, item_code, item_name, asset_category, company): + asset_maintenance = frappe.new_doc("Asset Maintenance") + asset_maintenance.update({ + "asset_name": asset, + "company": company, + "item_code": item_code, + "item_name": item_name, + "asset_category": asset_category + }) + return asset_maintenance + +@frappe.whitelist() +def transfer_asset(args): + import json + args = json.loads(args) + movement_entry = frappe.new_doc("Asset Movement") + movement_entry.update(args) + movement_entry.insert() + movement_entry.submit() + + frappe.db.commit() + + frappe.msgprint(_("Asset Movement record {0} created").format("{0}".format(movement_entry.name))) + +@frappe.whitelist() +def get_item_details(item_code): + asset_category = frappe.db.get_value("Item", item_code, "asset_category") + + if not asset_category: + frappe.throw(_("Please enter Asset Category in Item {0}").format(item_code)) + + ret = frappe.db.get_value("Asset Category", asset_category, + ["depreciation_method", "total_number_of_depreciations", "frequency_of_depreciation"], as_dict=1) + + ret.update({ + "asset_category": asset_category + }) + + return ret diff --git a/erpnext/assets/doctype/asset/asset_dashboard.py b/erpnext/assets/doctype/asset/asset_dashboard.py new file mode 100644 index 00000000000..94dad1b311e --- /dev/null +++ b/erpnext/assets/doctype/asset/asset_dashboard.py @@ -0,0 +1,14 @@ +def get_data(): + return { + 'fieldname': 'asset_name', + 'transactions': [ + { + 'label': ['Maintenance'], + 'items': ['Asset Maintenance', 'Asset Maintenance Log'] + }, + { + 'label': ['Repair'], + 'items': ['Asset Repair'] + } + ] + } \ No newline at end of file diff --git a/erpnext/accounts/doctype/asset/asset_list.js b/erpnext/assets/doctype/asset/asset_list.js similarity index 100% rename from erpnext/accounts/doctype/asset/asset_list.js rename to erpnext/assets/doctype/asset/asset_list.js diff --git a/erpnext/accounts/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py similarity index 100% rename from erpnext/accounts/doctype/asset/depreciation.py rename to erpnext/assets/doctype/asset/depreciation.py diff --git a/erpnext/assets/doctype/asset/test_asset.js b/erpnext/assets/doctype/asset/test_asset.js new file mode 100644 index 00000000000..6119e382174 --- /dev/null +++ b/erpnext/assets/doctype/asset/test_asset.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Asset", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Asset + () => frappe.tests.make('Asset', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py new file mode 100644 index 00000000000..9c3ed80b728 --- /dev/null +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -0,0 +1,343 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe +import unittest +from frappe.utils import cstr, nowdate, getdate, flt +from erpnext.assets.doctype.asset.depreciation import post_depreciation_entries, scrap_asset, restore_asset +from erpnext.assets.doctype.asset.asset import make_sales_invoice, make_purchase_invoice + +class TestAsset(unittest.TestCase): + def setUp(self): + set_depreciation_settings_in_company() + create_asset() + frappe.db.sql("delete from `tabTax Rule`") + + def test_purchase_asset(self): + asset = frappe.get_doc("Asset", "Macbook Pro 1") + asset.submit() + + pi = make_purchase_invoice(asset.name, asset.item_code, asset.gross_purchase_amount, + asset.company, asset.purchase_date) + pi.supplier = "_Test Supplier" + pi.insert() + pi.submit() + + asset.load_from_db() + self.assertEqual(asset.supplier, "_Test Supplier") + self.assertEqual(asset.purchase_date, getdate("2015-01-01")) + self.assertEqual(asset.purchase_invoice, pi.name) + + expected_gle = ( + ("_Test Fixed Asset - _TC", 100000.0, 0.0), + ("Creditors - _TC", 0.0, 100000.0) + ) + + gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry` + where voucher_type='Purchase Invoice' and voucher_no = %s + order by account""", pi.name) + + self.assertEqual(gle, expected_gle) + + pi.cancel() + + asset.load_from_db() + self.assertEqual(asset.supplier, None) + self.assertEqual(asset.purchase_invoice, None) + + self.assertFalse(frappe.db.get_value("GL Entry", + {"voucher_type": "Purchase Invoice", "voucher_no": pi.name})) + + + def test_schedule_for_straight_line_method(self): + asset = frappe.get_doc("Asset", "Macbook Pro 1") + + self.assertEqual(asset.status, "Draft") + + expected_schedules = [ + ["2020-12-31", 30000, 30000], + ["2021-03-31", 30000, 60000], + ["2021-06-30", 30000, 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_schedule_for_straight_line_method_for_existing_asset(self): + asset = frappe.get_doc("Asset", "Macbook Pro 1") + asset.is_existing_asset = 1 + asset.number_of_depreciations_booked = 1 + asset.opening_accumulated_depreciation = 40000 + asset.save() + + self.assertEqual(asset.status, "Draft") + + expected_schedules = [ + ["2020-12-31", 25000, 65000], + ["2021-03-31", 25000, 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_schedule_for_double_declining_method(self): + asset = frappe.get_doc("Asset", "Macbook Pro 1") + asset.depreciation_method = "Double Declining Balance" + asset.save() + + expected_schedules = [ + ["2020-12-31", 66667, 66667], + ["2021-03-31", 22222, 88889], + ["2021-06-30", 1111, 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_schedule_for_double_declining_method_for_existing_asset(self): + asset = frappe.get_doc("Asset", "Macbook Pro 1") + asset.depreciation_method = "Double Declining Balance" + asset.is_existing_asset = 1 + asset.number_of_depreciations_booked = 1 + asset.opening_accumulated_depreciation = 50000 + asset.save() + + expected_schedules = [ + ["2020-12-31", 33333, 83333], + ["2021-03-31", 6667, 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_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") + asset.submit() + asset.load_from_db() + self.assertEqual(asset.status, "Submitted") + + frappe.db.set_value("Company", "_Test Company", "series_for_depreciation_entry", "DEPR-") + + post_depreciation_entries(date="2021-01-01") + asset.load_from_db() + + self.assertEqual(asset.status, "Partially Depreciated") + + # check depreciation entry series + self.assertEqual(asset.get("schedules")[0].journal_entry[:4], "DEPR") + + expected_gle = ( + ("_Test Accumulated Depreciations - _TC", 0.0, 30000.0), + ("_Test Depreciations - _TC", 30000.0, 0.0) + ) + + gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry` + where against_voucher_type='Asset' and against_voucher = %s + order by account""", asset.name) + + self.assertEqual(gle, expected_gle) + self.assertEqual(asset.get("value_after_depreciation"), 70000) + + def test_depreciation_entry_cancellation(self): + asset = frappe.get_doc("Asset", "Macbook Pro 1") + asset.submit() + post_depreciation_entries(date="2021-01-01") + + asset.load_from_db() + + # cancel depreciation entry + depr_entry = asset.get("schedules")[0].journal_entry + self.assertTrue(depr_entry) + frappe.get_doc("Journal Entry", depr_entry).cancel() + + asset.load_from_db() + depr_entry = asset.get("schedules")[0].journal_entry + self.assertFalse(depr_entry) + + + def test_scrap_asset(self): + asset = frappe.get_doc("Asset", "Macbook Pro 1") + asset.submit() + post_depreciation_entries(date="2021-01-01") + + scrap_asset("Macbook Pro 1") + + asset.load_from_db() + self.assertEqual(asset.status, "Scrapped") + self.assertTrue(asset.journal_entry_for_scrap) + + expected_gle = ( + ("_Test Accumulated Depreciations - _TC", 30000.0, 0.0), + ("_Test Fixed Asset - _TC", 0.0, 100000.0), + ("_Test Gain/Loss on Asset Disposal - _TC", 70000.0, 0.0) + ) + + gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry` + where voucher_type='Journal Entry' and voucher_no = %s + order by account""", asset.journal_entry_for_scrap) + + self.assertEqual(gle, expected_gle) + + restore_asset("Macbook Pro 1") + + asset.load_from_db() + self.assertFalse(asset.journal_entry_for_scrap) + self.assertEqual(asset.status, "Partially Depreciated") + + def test_asset_sale(self): + frappe.get_doc("Asset", "Macbook Pro 1").submit() + post_depreciation_entries(date="2021-01-01") + + si = make_sales_invoice(asset="Macbook Pro 1", item_code="Macbook Pro", company="_Test Company") + si.customer = "_Test Customer" + si.due_date = nowdate() + si.get("items")[0].rate = 25000 + si.insert() + si.submit() + + self.assertEqual(frappe.db.get_value("Asset", "Macbook Pro 1", "status"), "Sold") + + expected_gle = ( + ("_Test Accumulated Depreciations - _TC", 30000.0, 0.0), + ("_Test Fixed Asset - _TC", 0.0, 100000.0), + ("_Test Gain/Loss on Asset Disposal - _TC", 45000.0, 0.0), + ("Debtors - _TC", 25000.0, 0.0) + ) + + gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry` + where voucher_type='Sales Invoice' and voucher_no = %s + order by account""", si.name) + + self.assertEqual(gle, expected_gle) + + si.cancel() + + self.assertEqual(frappe.db.get_value("Asset", "Macbook Pro 1", "status"), "Partially Depreciated") + + def test_asset_expected_value_after_useful_life(self): + asset = frappe.get_doc("Asset", "Macbook Pro 1") + asset.depreciation_method = "Straight Line" + asset.is_existing_asset = 1 + asset.total_number_of_depreciations = 400 + asset.gross_purchase_amount = 16866177.00 + asset.expected_value_after_useful_life = 500000 + asset.save() + + accumulated_depreciation_after_full_schedule = \ + max([d.accumulated_depreciation_amount for d in asset.get("schedules")]) + + asset_value_after_full_schedule = (flt(asset.gross_purchase_amount) - + flt(accumulated_depreciation_after_full_schedule)) + + self.assertTrue(asset.expected_value_after_useful_life >= asset_value_after_full_schedule) + + def tearDown(self): + asset = frappe.get_doc("Asset", "Macbook Pro 1") + + if asset.docstatus == 1 and asset.status not in ("Scrapped", "Sold", "Draft", "Cancelled"): + asset.cancel() + + self.assertEqual(frappe.db.get_value("Asset", "Macbook Pro 1", "status"), "Cancelled") + + frappe.delete_doc("Asset", "Macbook Pro 1") + +def create_asset(): + if not frappe.db.exists("Asset Category", "Computers"): + create_asset_category() + + if not frappe.db.exists("Item", "Macbook Pro"): + create_fixed_asset_item() + + asset = frappe.get_doc({ + "doctype": "Asset", + "asset_name": "Macbook Pro 1", + "asset_category": "Computers", + "item_code": "Macbook Pro", + "company": "_Test Company", + "purchase_date": "2015-01-01", + "next_depreciation_date": "2020-12-31", + "gross_purchase_amount": 100000, + "expected_value_after_useful_life": 10000, + "warehouse": "_Test Warehouse - _TC" + }) + try: + asset.save() + except frappe.DuplicateEntryError: + pass + + return asset + +def create_asset_category(): + asset_category = frappe.new_doc("Asset Category") + asset_category.asset_category_name = "Computers" + asset_category.total_number_of_depreciations = 3 + asset_category.frequency_of_depreciation = 3 + asset_category.append("accounts", { + "company_name": "_Test Company", + "fixed_asset_account": "_Test Fixed Asset - _TC", + "accumulated_depreciation_account": "_Test Accumulated Depreciations - _TC", + "depreciation_expense_account": "_Test Depreciations - _TC" + }) + asset_category.insert() + +def create_fixed_asset_item(): + try: + frappe.get_doc({ + "doctype": "Item", + "item_code": "Macbook Pro", + "item_name": "Macbook Pro", + "description": "Macbook Pro Retina Display", + "asset_category": "Computers", + "item_group": "All Item Groups", + "stock_uom": "Nos", + "is_stock_item": 0, + "is_fixed_asset": 1 + }).insert() + except frappe.DuplicateEntryError: + pass + +def set_depreciation_settings_in_company(): + company = frappe.get_doc("Company", "_Test Company") + company.accumulated_depreciation_account = "_Test Accumulated Depreciations - _TC" + company.depreciation_expense_account = "_Test Depreciations - _TC" + company.disposal_account = "_Test Gain/Loss on Asset Disposal - _TC" + company.depreciation_cost_center = "_Test Cost Center - _TC" + company.save() + + # Enable booking asset depreciation entry automatically + frappe.db.set_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically", 1) \ No newline at end of file diff --git a/erpnext/assets/doctype/asset_category/__init__.py b/erpnext/assets/doctype/asset_category/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/assets/doctype/asset_category/asset_category.js b/erpnext/assets/doctype/asset_category/asset_category.js new file mode 100644 index 00000000000..aafe8a69a0e --- /dev/null +++ b/erpnext/assets/doctype/asset_category/asset_category.js @@ -0,0 +1,44 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Asset Category', { + onload: function(frm) { + frm.add_fetch('company_name', 'accumulated_depreciation_account', 'accumulated_depreciation_account'); + frm.add_fetch('company_name', 'depreciation_expense_account', 'accumulated_depreciation_account'); + + frm.set_query('fixed_asset_account', 'accounts', function(doc, cdt, cdn) { + var d = locals[cdt][cdn]; + return { + "filters": { + "account_type": "Fixed Asset", + "root_type": "Asset", + "is_group": 0, + "company": d.company_name + } + }; + }); + + frm.set_query('accumulated_depreciation_account', 'accounts', function(doc, cdt, cdn) { + var d = locals[cdt][cdn]; + return { + "filters": { + "root_type": "Asset", + "is_group": 0, + "company": d.company_name + } + }; + }); + + frm.set_query('depreciation_expense_account', 'accounts', function(doc, cdt, cdn) { + var d = locals[cdt][cdn]; + return { + "filters": { + "root_type": "Expense", + "is_group": 0, + "company": d.company_name + } + }; + }); + + } +}); \ No newline at end of file diff --git a/erpnext/assets/doctype/asset_category/asset_category.json b/erpnext/assets/doctype/asset_category/asset_category.json new file mode 100644 index 00000000000..39b39783833 --- /dev/null +++ b/erpnext/assets/doctype/asset_category/asset_category.json @@ -0,0 +1,295 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 1, + "allow_rename": 1, + "autoname": "field:asset_category_name", + "beta": 0, + "creation": "2016-03-01 17:41:39.778765", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "Document", + "editable_grid": 0, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "asset_category_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Asset Category Name", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "Straight Line", + "fieldname": "depreciation_method", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Depreciation Method", + "length": 0, + "no_copy": 0, + "options": "\nStraight Line\nDouble Declining Balance", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_3", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "total_number_of_depreciations", + "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Total Number of Depreciations", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "frequency_of_depreciation", + "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Frequency of Depreciation (Months)", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_2", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Accounts", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "accounts", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Accounts", + "length": 0, + "no_copy": 0, + "options": "Asset Category Account", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "modified": "2017-10-19 16:08:02.114363", + "modified_by": "Administrator", + "module": "Assets", + "name": "Asset Category", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 1, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts User", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + }, + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 1, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + } + ], + "quick_entry": 0, + "read_only": 0, + "read_only_onload": 0, + "show_name_in_global_search": 1, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 0, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/assets/doctype/asset_category/asset_category.py b/erpnext/assets/doctype/asset_category/asset_category.py new file mode 100644 index 00000000000..5279c37ea84 --- /dev/null +++ b/erpnext/assets/doctype/asset_category/asset_category.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe import _ +from frappe.utils import cint +from frappe.model.document import Document + +class AssetCategory(Document): + def validate(self): + for field in ("total_number_of_depreciations", "frequency_of_depreciation"): + if cint(self.get(field))<1: + frappe.throw(_("{0} must be greater than 0").format(self.meta.get_label(field)), frappe.MandatoryError) \ No newline at end of file diff --git a/erpnext/assets/doctype/asset_category/test_asset_category.js b/erpnext/assets/doctype/asset_category/test_asset_category.js new file mode 100644 index 00000000000..7e343b7519e --- /dev/null +++ b/erpnext/assets/doctype/asset_category/test_asset_category.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Asset Category", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Asset Category + () => frappe.tests.make('Asset Category', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/erpnext/assets/doctype/asset_category/test_asset_category.py b/erpnext/assets/doctype/asset_category/test_asset_category.py new file mode 100644 index 00000000000..b32f9b50202 --- /dev/null +++ b/erpnext/assets/doctype/asset_category/test_asset_category.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe +import unittest + +class TestAssetCategory(unittest.TestCase): + def test_mandatory_fields(self): + asset_category = frappe.new_doc("Asset Category") + asset_category.asset_category_name = "Computers" + + self.assertRaises(frappe.MandatoryError, asset_category.insert) + + asset_category.total_number_of_depreciations = 3 + asset_category.frequency_of_depreciation = 3 + asset_category.append("accounts", { + "company_name": "_Test Company", + "fixed_asset_account": "_Test Fixed Asset - _TC", + "accumulated_depreciation_account": "_Test Accumulated Depreciations - _TC", + "depreciation_expense_account": "_Test Depreciations - _TC" + }) + + try: + asset_category.insert() + except frappe.DuplicateEntryError: + pass + \ No newline at end of file diff --git a/erpnext/assets/doctype/asset_maintenance/__init__.py b/erpnext/assets/doctype/asset_maintenance/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js new file mode 100644 index 00000000000..6a6e72f5469 --- /dev/null +++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.js @@ -0,0 +1,105 @@ +// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Asset Maintenance', { + setup: (frm) => { + frm.fields_dict["asset_maintenance_tasks"].grid.get_field("assign_to").get_query = function(){ + return { + filters: { + parent: frm.doc.maintenance_team + } + }; + }, + frm.set_indicator_formatter('maintenance_status', + function(doc) { + let indicator = 'blue'; + if (doc.maintenance_status == 'Overdue') { + indicator = 'orange'; + } + if (doc.maintenance_status == 'Cancelled') { + indicator = 'red'; + } + return indicator; + } + ); + }, + refresh: (frm) => { + if(!frm.is_new()) { + frm.trigger('make_dashboard'); + } + }, + make_dashboard: (frm) => { + if(!frm.is_new()) { + frappe.call({ + method: 'erpnext.assets.doctype.asset_maintenance.asset_maintenance.get_maintenance_log', + args: {asset_name: frm.doc.asset_name}, + callback: (r) => { + if(!r.message) { + return; + } + var section = frm.dashboard.add_section(`
+
+### Asset Maintenance Team
+Create Asset Maintenance Team, select team members and their role.
+
+
+
+### Asset Maintenance
+For each asset create a Asset Maintenance record listing all the associated maintenance tasks, maintenance type (Preventive Maintenance or Calibration), periodicity, assign to and start and end date of maintenance. Based on start date and periodicity the next due date is auto-calculated and a ToDo is created for the Assignee.
+
+
+### Asset Maintenance Log
+For each task in Asset Maintenance create a Asset Maintenance Log which will have status, completion date and actions performed. Based on completion date here, next due date is calculated automatically.
+
+
+### Asset Repair
+You can also maintain the records of Repair/Failures of your asset which are not listed in Asset Maintenance.
+
\ No newline at end of file
diff --git a/erpnext/docs/user/manual/en/accounts/managing-fixed-assets.md b/erpnext/docs/user/manual/en/asset/assets.md
similarity index 86%
rename from erpnext/docs/user/manual/en/accounts/managing-fixed-assets.md
rename to erpnext/docs/user/manual/en/asset/assets.md
index 45bd2278e5e..6932c59dcc5 100644
--- a/erpnext/docs/user/manual/en/accounts/managing-fixed-assets.md
+++ b/erpnext/docs/user/manual/en/asset/assets.md
@@ -6,7 +6,7 @@ In ERPNext, you can maintain fixed asset records like Computers, Furnitures, Car
Based on the type of assets, create Asset Category. For example, all your desktops and laptops can be part of an Asset Category named "Computers". Here you can set default depreciation method, periodicity and depreciation related accounts, which will be applicable to all the assets under the category.
-
+
> **Note:** You can also set default depreciation related Accounts and Cost Centers in Company master.
@@ -14,13 +14,13 @@ Based on the type of assets, create Asset Category. For example, all your deskto
Asset master is the heart of fixed asset management feature. All the transactions related to Asset like purchasing, sales, depreciation, scrapping will be managed from the Asset master.
-
+
Explanation of the fields:
1. Item Code: An Item for the Asset must be a non-stock item, with "Is Asset" field checked.
-
+
2. Asset Category: The category of assets it belongs to.
3. 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.
@@ -42,24 +42,24 @@ Explanation of the fields:
The system automatically creates a schedule for depreciation based on depreciation method and other related inputs in the Asset record.
-
+
On the scheduled date, system creates depreciation entry by creating a Journal Entry and the same Journal Entry is updated in the depreciation table for reference. Next Depreciation Date and Current Value are also updated on submission of depreciation entry.
-
+
In the depreciation entry, the "Accumulated Depreciation Account" is credited and "Depreciation Expense Account" is debited. The related accounts can be set in the Asset Category or Company.
For better visibility, net value of the asset on different depreciation dates are shown in a line graph.
-
+
## Purchase an Asset
For purchasing a new asset, create and submit the asset record with all the depreciation settings. Then create a Purchase Invoice via "Make Purchase Invoice" button. On clicking the button, system will load a new Purchase Invoice form with pre-loaded items table. It will also set proper fixed asset account (defined in the Asset Category) in the Expense Account field. You need to select Supplier and other necessary details and submit the Purchase Invoice.
-
+
On submission of the invoice, the "Fixed Asset Account" will be debited and payable account will be credited. It also updates purchase date, supplier and Purchase Invoice no. in the Asset master.
@@ -73,23 +73,23 @@ To sell an asset, open the asset record and create a Sales Invoice by clicking o
- "Accumulated Depreciation Account" will be debited by the total depreciated amount till now.
- "Gain/Loss Account on Asset Disposal" will be credited/debited based on gain/loss amount. The Gain/Loss account can be set in Company record.
-
+
## Scrap an Asset
You can scrap an asset anytime using the "Scrap Asset" button in the Asset record. The "Gain/Loss Account on Asset Disposal" mentioned in the Company is debited by the Current Value (After Depreciation) of the asset. After scrapping, you can also restore the asset using "Restore Asset" button.
-
+
## Asset Movement
The movement of the assets (from one warehouse to another) is also tracked via Asset Movement form.
-
+
There is also a dedicated button "Transfer Asset" inside the Asset form to track the Asset Movement.
-
+
{next}
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index d9294283776..b4afea77ecd 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -214,7 +214,7 @@ scheduler_events = {
"erpnext.accounts.doctype.fiscal_year.fiscal_year.auto_create_fiscal_year",
"erpnext.hr.doctype.employee.employee.send_birthday_reminders",
"erpnext.projects.doctype.task.task.set_tasks_as_overdue",
- "erpnext.accounts.doctype.asset.depreciation.post_depreciation_entries",
+ "erpnext.assets.doctype.asset.depreciation.post_depreciation_entries",
"erpnext.hr.doctype.daily_work_summary_settings.daily_work_summary_settings.send_summary",
"erpnext.stock.doctype.serial_no.serial_no.update_maintenance_status",
"erpnext.buying.doctype.supplier_scorecard.supplier_scorecard.refresh_scorecards",
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json
index d1de7e335e5..079ec687936 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json
+++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json
@@ -101,7 +101,7 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
- "reqd": 1,
+ "reqd": 0,
"search_index": 1,
"set_only_once": 0,
"unique": 0
@@ -653,7 +653,7 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
- "reqd": 1,
+ "reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@@ -685,7 +685,7 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
- "reqd": 1,
+ "reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@@ -764,7 +764,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-06-13 14:29:01.615516",
+ "modified": "2017-10-17 07:57:01.723090",
"modified_by": "Administrator",
"module": "Maintenance",
"name": "Maintenance Schedule",
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.js b/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.js
new file mode 100644
index 00000000000..e0f05b1abbd
--- /dev/null
+++ b/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Maintenance Schedule", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Maintenance Schedule
+ () => frappe.tests.make('Maintenance Schedule', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/maintenance/doctype/maintenance_schedule_item/maintenance_schedule_item.json b/erpnext/maintenance/doctype/maintenance_schedule_item/maintenance_schedule_item.json
index c6aac146352..2f159e9a4d9 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule_item/maintenance_schedule_item.json
+++ b/erpnext/maintenance/doctype/maintenance_schedule_item/maintenance_schedule_item.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "hash",
@@ -13,6 +14,7 @@
"engine": "InnoDB",
"fields": [
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -44,6 +46,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -62,6 +65,7 @@
"no_copy": 0,
"oldfieldname": "item_name",
"oldfieldtype": "Data",
+ "options": "item_code.item_name",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@@ -74,6 +78,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -85,13 +90,14 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
- "in_list_view": 1,
+ "in_list_view": 0,
"in_standard_filter": 0,
"label": "Description",
"length": 0,
"no_copy": 0,
"oldfieldname": "description",
"oldfieldtype": "Data",
+ "options": "item_code.description",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@@ -106,6 +112,7 @@
"width": "300px"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -134,6 +141,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -164,6 +172,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -194,6 +203,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -225,6 +235,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -249,12 +260,13 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
- "reqd": 1,
+ "reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -280,12 +292,13 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
- "reqd": 1,
+ "reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -314,6 +327,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -344,6 +358,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -377,17 +392,17 @@
"width": "150px"
}
],
+ "has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 1,
"image_view": 0,
"in_create": 0,
- "in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2017-02-17 17:06:21.448695",
+ "modified": "2017-10-17 08:37:28.964789",
"modified_by": "Administrator",
"module": "Maintenance",
"name": "Maintenance Schedule Item",
diff --git a/erpnext/modules.txt b/erpnext/modules.txt
index 79ded14573f..beb1df56a9f 100644
--- a/erpnext/modules.txt
+++ b/erpnext/modules.txt
@@ -17,4 +17,5 @@ Schools
Regional
Healthcare
Restaurant
-ERPNext Integrations
\ No newline at end of file
+ERPNext Integrations
+Assets
\ No newline at end of file
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index bc63f4a794e..5d3c31f58de 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -465,3 +465,4 @@ erpnext.patches.v9_2.delete_healthcare_domain_default_items
erpnext.patches.v9_1.create_issue_opportunity_type
erpnext.patches.v9_2.rename_translated_domains_in_en
erpnext.patches.v9_0.set_shipping_type_for_existing_shipping_rules
+erpnext.patches.v9_0.update_asset_module_doctypes
diff --git a/erpnext/patches/v9_0/update_asset_module_doctypes.py b/erpnext/patches/v9_0/update_asset_module_doctypes.py
new file mode 100644
index 00000000000..66eb287de3f
--- /dev/null
+++ b/erpnext/patches/v9_0/update_asset_module_doctypes.py
@@ -0,0 +1,12 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doc('assets', 'doctype', 'asset_category')
+ frappe.db.set_value("DocType", "Asset Category", "module", "Assets")
+ frappe.db.set_value("DocType", "Asset", "module", "Assets")
+ frappe.db.set_value("DocType", "Asset Movement", "module", "Assets")
+ frappe.db.set_value("DocType", "Depreciation Schedule", "module", "Assets")
\ No newline at end of file