From 8990697fee02a5680ecfe2de4ffe5dd6f6904e36 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Tue, 12 May 2020 17:38:34 +0530 Subject: [PATCH] feat: fixed asset register based on fiscal year *asset value chart --- erpnext/assets/dashboard_fixtures.py | 105 ++++++++++++++++-- erpnext/assets/desk_page/assets/assets.json | 13 ++- .../fixed_asset_register.js | 70 +++++++++--- .../fixed_asset_register.py | 62 +++++++---- 4 files changed, 199 insertions(+), 51 deletions(-) diff --git a/erpnext/assets/dashboard_fixtures.py b/erpnext/assets/dashboard_fixtures.py index 93a06544f0..84e67cf648 100644 --- a/erpnext/assets/dashboard_fixtures.py +++ b/erpnext/assets/dashboard_fixtures.py @@ -3,12 +3,13 @@ import frappe import json - +from frappe.utils import nowdate, add_months def get_data(): return frappe._dict({ "dashboards": get_dashboards(), - "charts": get_charts() + "charts": get_charts(), + "number_cards": get_number_cards(), }) def get_dashboards(): @@ -16,22 +17,63 @@ def get_dashboards(): "name": "Asset", "dashboard_name": "Asset", "charts": [ - { "chart": "Category-wise Asset Value" }, - { "chart": "Location-wise Asset Value" }, + { "chart": "Asset Value Analytics", "width": "Full" }, + { "chart": "Category-wise Asset Value", "width": "Half" }, + { "chart": "Location-wise Asset Value", "width": "Half" }, ] }] def get_charts(): + company = get_company_for_dashboards() + fiscal_year = get_fiscal_year() + return [ + { + "name": "Asset Value Analytics", + "chart_name": "Asset Value Analytics", + "chart_type": "Report", + "report_name": "Fixed Asset Register", + "is_custom": 1, + "group_by_type": "Count", + "number_of_groups": 0, + "is_public": 0, + "timespan": "Last Year", + "time_interval": "Yearly", + "timeseries": 0, + "filters_json": json.dumps({ + "company": company, + "status": "In Location", + "filter_based_on": "Fiscal Year", + "from_fiscal_year": fiscal_year, + "to_fiscal_year": fiscal_year, + "period_start_date": add_months(nowdate(), -12), + "period_end_date": nowdate(), + "date_based_on": "Purchase Date", + "group_by": "--Select a group--" + }), + "type": "Bar", + "custom_options": json.dumps({ + "type": "bar", + "barOptions": { "stacked": 1 }, + "axisOptions": { "shortenYAxisNumbers": 1 }, + "tooltipOptions": {} + }), + "doctype": "Dashboard Chart", + "y_axis": [] + }, { "name": "Category-wise Asset Value", "chart_name": "Category-wise Asset Value", "chart_type": "Report", - "report_name": "Fixed Asset Report", - "is_custom": 1, + "report_name": "Fixed Asset Register", "x_field": "asset_category", "timeseries": 0, - "filters_json": json.dumps("""{"status":"In Location","group_by":"Asset Category","is_existing_asset":0}"""), + "filters_json": json.dumps({ + "company": company, + "status":"In Location", + "group_by":"Asset Category", + "is_existing_asset":0 + }), "type": "Donut", "doctype": "Dashboard Chart", "y_axis": [ @@ -53,11 +95,15 @@ def get_charts(): "name": "Location-wise Asset Value", "chart_name": "Location-wise Asset Value", "chart_type": "Report", - "report_name": "Fixed Asset Report", - "is_custom": 1, + "report_name": "Fixed Asset Register", "x_field": "location", "timeseries": 0, - "filters_json": json.dumps("""{"status":"In Location","group_by":"Location","is_existing_asset":0}"""), + "filters_json": json.dumps({ + "company": company, + "status":"In Location", + "group_by":"Location", + "is_existing_asset":0 + }), "type": "Donut", "doctype": "Dashboard Chart", "y_axis": [ @@ -74,4 +120,41 @@ def get_charts(): "height": 300, "axisOptions": {"shortenYAxisNumbers": 1} }) - }] + } + ] + +def get_number_cards(): + return [ + { + "name": "Asset Value", + "label": "Asset Value", + "function": "Sum", + "aggregate_function_based_on": "value_after_depreciation", + "document_type": "Asset", + "is_public": 1, + "show_percentage_stats": 1, + "stats_time_interval": "Monthly", + "filters_json": "[]", + "doctype": "Number Card", + } + ] + +def get_company_for_dashboards(): + company = frappe.defaults.get_defaults().company + if company: + return company + else: + company_list = frappe.get_list("Company") + if company_list: + return company_list[0].name + return None + +def get_fiscal_year(): + fiscal_year = frappe.defaults.get_defaults().fiscal_year + if fiscal_year: + return fiscal_year + else: + fiscal_year_list = frappe.get_list("Fiscal Year") + if fiscal_year_list: + return fiscal_year_list[0].name + return None \ No newline at end of file diff --git a/erpnext/assets/desk_page/assets/assets.json b/erpnext/assets/desk_page/assets/assets.json index 13709e370b..429a8a897c 100644 --- a/erpnext/assets/desk_page/assets/assets.json +++ b/erpnext/assets/desk_page/assets/assets.json @@ -17,7 +17,12 @@ } ], "category": "Modules", - "charts": [], + "charts": [ + { + "chart_name": "Asset Value Analytics", + "label": "Asset Value Analytics" + } + ], "creation": "2020-03-02 15:43:27.634865", "developer_mode_only": 0, "disable_user_customization": 0, @@ -27,7 +32,7 @@ "idx": 0, "is_standard": 1, "label": "Assets", - "modified": "2020-05-08 16:07:04.671296", + "modified": "2020-05-12 17:35:14.770662", "modified_by": "Administrator", "module": "Assets", "name": "Assets", @@ -42,8 +47,8 @@ "type": "DocType" }, { - "label": "Asset Movement", - "link_to": "Asset Movement", + "label": "Asset Category", + "link_to": "Asset Category", "type": "DocType" }, { diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js index e886a35e5d..a08851743c 100644 --- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js +++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js @@ -21,14 +21,61 @@ frappe.query_reports["Fixed Asset Register"] = { reqd: 1 }, { - fieldname:"purchase_date", - label: __("Purchase Date"), - fieldtype: "Date" + "fieldname":"filter_based_on", + "label": __("Period Based On"), + "fieldtype": "Select", + "options": ["Fiscal Year", "Date Range"], + "default": ["Fiscal Year"], + "reqd": 1, + on_change: function() { + let filter_based_on = frappe.query_report.get_filter_value('filter_based_on'); + frappe.query_report.toggle_filter_display('from_fiscal_year', filter_based_on === 'Date Range'); + frappe.query_report.toggle_filter_display('to_fiscal_year', filter_based_on === 'Date Range'); + frappe.query_report.toggle_filter_display('from_date', filter_based_on === 'Fiscal Year'); + frappe.query_report.toggle_filter_display('to_date', filter_based_on === 'Fiscal Year'); + + frappe.query_report.refresh(); + } }, { - fieldname:"available_for_use_date", - label: __("Available For Use Date"), - fieldtype: "Date" + "fieldname":"from_date", + "label": __("Start Date"), + "fieldtype": "Date", + "default": frappe.datetime.nowdate(), + "hidden": 1, + "reqd": 1 + }, + { + "fieldname":"to_date", + "label": __("End Date"), + "fieldtype": "Date", + "default": frappe.datetime.add_months(frappe.datetime.nowdate(), 12), + "hidden": 1, + "reqd": 1 + }, + { + "fieldname":"from_fiscal_year", + "label": __("Start Year"), + "fieldtype": "Link", + "options": "Fiscal Year", + "default": frappe.defaults.get_user_default("fiscal_year"), + "reqd": 1 + }, + { + "fieldname":"to_fiscal_year", + "label": __("End Year"), + "fieldtype": "Link", + "options": "Fiscal Year", + "default": frappe.defaults.get_user_default("fiscal_year"), + "reqd": 1 + }, + { + "fieldname":"date_based_on", + "label": __("Date Based On"), + "fieldtype": "Select", + "options": ["Purchase Date", "Available For Use Date"], + "default": "Purchase Date", + "reqd": 1 }, { fieldname:"asset_category", @@ -48,18 +95,13 @@ frappe.query_reports["Fixed Asset Register"] = { fieldtype: "Link", options: "Cost Center" }, - { - fieldname:"finance_book", - label: __("Finance Book"), - fieldtype: "Link", - options: "Finance Book" - }, { fieldname:"group_by", label: __("Group By"), fieldtype: "Select", - options: " \nAsset Category\nLocation", - default: '', + options: ["--Select a group--", "Asset Category", "Location"], + default: "--Select a group--", + reqd: 1 }, { fieldname:"is_existing_asset", diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py index 0b4b334326..23714e6f66 100644 --- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py +++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py @@ -4,26 +4,33 @@ from __future__ import unicode_literals import frappe from frappe import _ -from frappe.utils import cstr, today, flt +from frappe.utils import cstr, today, flt, add_years, formatdate, getdate +from erpnext.accounts.report.financial_statements import get_period_list, get_fiscal_year_data, validate_fiscal_year def execute(filters=None): filters = frappe._dict(filters or {}) columns = get_columns(filters) data = get_data(filters) - chart = prepare_chart_data(data) if not filters.get("group_by") else {} + chart = prepare_chart_data(data, filters) if filters.get("group_by") not in ("Asset Category", "Location") else {} return columns, data, None, chart def get_conditions(filters): conditions = { 'docstatus': 1 } status = filters.status + date_field = frappe.scrub(filters.date_based_on or "Purchase Date") if filters.get('company'): conditions["company"] = filters.company - if filters.get('purchase_date'): - conditions["purchase_date"] = ('<=', filters.get('purchase_date')) - if filters.get('available_for_use_date'): - conditions["available_for_use_date"] = ('<=', filters.get('available_for_use_date')) + if filters.filter_based_on == "Date Range": + conditions[date_field] = ["between", [filters.from_date, filters.to_date]] + if filters.filter_based_on == "Fiscal Year": + fiscal_year = get_fiscal_year_data(filters.from_fiscal_year, filters.to_fiscal_year) + validate_fiscal_year(fiscal_year, filters.from_fiscal_year, filters.to_fiscal_year) + year_start_date = getdate(fiscal_year.year_start_date) + year_end_date = getdate(fiscal_year.year_end_date) + + conditions[date_field] = ["between", [year_start_date, year_end_date]] if filters.get('is_existing_asset'): conditions["is_existing_asset"] = filters.get('is_existing_asset') if filters.get('asset_category'): @@ -49,16 +56,17 @@ def get_data(filters): pi_supplier_map = get_purchase_invoice_supplier_map() conditions = get_conditions(filters) - group_by = frappe.scrub(filters.get("group_by") or "") - if group_by: - if group_by == "asset_category": - fields = ["asset_category", "gross_purchase_amount", "opening_accumulated_depreciation"] - else: - fields = ["location", "gross_purchase_amount", "opening_accumulated_depreciation"] + group_by = frappe.scrub(filters.get("group_by")) + if group_by == "asset_category": + fields = ["asset_category", "gross_purchase_amount", "opening_accumulated_depreciation"] assets_record = frappe.db.get_all("Asset", filters=conditions, fields=fields, group_by=group_by) - print(assets_record) + + elif group_by == "location": + fields = ["location", "gross_purchase_amount", "opening_accumulated_depreciation"] + assets_record = frappe.db.get_all("Asset", filters=conditions, fields=fields, group_by=group_by) + else: fields = ["name as asset_id", "asset_name", "status", "department", "cost_center", "purchase_receipt", "asset_category", "purchase_date", "gross_purchase_amount", "location", @@ -89,19 +97,29 @@ def get_data(filters): return data -def prepare_chart_data(data): - labels, asset_values, depreciated_amounts = [], [], [] +def prepare_chart_data(data, filters): + labels_values_map = {} + date_field = frappe.scrub(filters.date_based_on) + + period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year, + filters.from_date, filters.to_date, filters.filter_based_on, "Monthly", company=filters.company) + + for d in period_list: + labels_values_map.setdefault(d.get('label'), frappe._dict({'asset_value': 0, 'depreciated_amount': 0})) + for d in data: - labels.append(d.get("asset_id")) - asset_values.append(d.get("asset_value")) - depreciated_amounts.append(d.get("depreciated_amount")) + date = d.get(date_field) + belongs_to_month = formatdate(date, "MMM YYYY") + + labels_values_map[belongs_to_month].asset_value += d.get("asset_value") + labels_values_map[belongs_to_month].depreciated_amount += d.get("depreciated_amount") return { "data" : { - "labels": labels, + "labels": labels_values_map.keys(), "datasets": [ - { 'name': _('Asset Value'), 'values': asset_values }, - { 'name': _('Depreciatied Amount'), 'values': depreciated_amounts} + { 'name': _('Asset Value'), 'values': [d.get("asset_value") for d in labels_values_map.values()] }, + { 'name': _('Depreciatied Amount'), 'values': [d.get("depreciated_amount") for d in labels_values_map.values()] } ] }, "type": "bar", @@ -144,7 +162,7 @@ def get_purchase_invoice_supplier_map(): AND pi.is_return=0''')) def get_columns(filters): - if filters.get("group_by"): + if filters.get("group_by") in ["Asset Category", "Location"]: return [ { "label": _("{}").format(filters.get("group_by")),