Merge pull request #16411 from adityahase/dashboard
feat: Accounting Dashboard
diff --git a/erpnext/accounts/dashboard_chart_source/__init__.py b/erpnext/accounts/dashboard_chart_source/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/dashboard_chart_source/__init__.py
diff --git a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/__init__.py b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/__init__.py
diff --git a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.js b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.js
new file mode 100644
index 0000000..eebd2db
--- /dev/null
+++ b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.js
@@ -0,0 +1,45 @@
+frappe.dashboard_chart_sources["Account Balance Timeline"] = {
+ method_path: "erpnext.accounts.dashboard_chart_source.account_balance_timeline.account_balance_timeline.get",
+ filters: [
+ {
+ fieldname: "company",
+ label: __("Company"),
+ fieldtype: "Link",
+ options: "Company",
+ default: frappe.defaults.get_user_default("Company"),
+ reqd: 1
+ },
+ {
+ fieldname: "account",
+ label: __("Account"),
+ fieldtype: "Link",
+ options: "Account",
+ reqd: 1
+ },
+ {
+ fieldname: "timespan",
+ label: __("Period"),
+ fieldtype: "Select",
+ options: [
+ {value: "Last Year", label: __("Last Year")},
+ {value: "Last Quarter", label: __("Last Quarter")},
+ {value: "Last Month", label: __("Last Month")},
+ {value: "Last Week", label: __("Last Week")}
+ ],
+ reqd: 1
+ },
+ {
+ fieldname: "timegrain",
+ label: __("Periodicity"),
+ fieldtype: "Select",
+ options: [
+ {value: "Quarterly", label: __("Quarterly")},
+ {value: "Monthly", label: __("Monthly")},
+ {value: "Weekly", label: __("Weekly")},
+ {value: "Daily", label: __("Daily")}
+ ],
+ reqd: 1
+ },
+ ],
+ is_time_series: true
+};
\ No newline at end of file
diff --git a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.json b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.json
new file mode 100644
index 0000000..b7ea601
--- /dev/null
+++ b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.json
@@ -0,0 +1,13 @@
+{
+ "config": "{\n \"method_path\": \"erpnext.accounts.dashboard_chart_source.account_balance_timeline.account_balance_timeline.get\",\n\t\"filters\": [\n\t\t{\n\t\t\t\"fieldname\": \"company\",\n\t\t\t\"label\": \"Company\",\n\t\t\t\"fieldtype\": \"Link\",\n\t\t\t\"options\": \"Company\",\n\t\t\t\"reqd\": 1\n\t\t},\n\t\t{\n\t\t\t\"fieldname\": \"account\",\n\t\t\t\"label\": \"Account\",\n\t\t\t\"fieldtype\": \"Link\",\n\t\t\t\"options\": \"Account\",\n\t\t\t\"reqd\": 1\n\t\t},\n\t\t{\n\t\t\t\"fieldname\": \"timespan\",\n\t\t\t\"label\": \"Period\",\n\t\t\t\"fieldtype\": \"Select\",\n\t\t\t\"options\": [\n\t\t\t\t{\"value\": \"Last Year\", \"label\": \"Last Year\"},\n\t\t\t\t{\"value\": \"Last Quarter\", \"label\": \"Last Quarter\"},\n\t\t\t\t{\"value\": \"Last Month\", \"label\": \"Last Month\"},\n\t\t\t\t{\"value\": \"Last Week\", \"label\": \"Last Week\"}\n\t\t\t],\n\t\t\t\"reqd\": 1\n\t\t},\n\t\t{\n\t\t\t\"fieldname\": \"timegrain\",\n\t\t\t\"label\": \"Periodicity\",\n\t\t\t\"fieldtype\": \"Select\",\n\t\t\t\"options\": [\n\t\t\t\t{\"value\": \"Quarterly\", \"label\": \"Quarterly\"},\n\t\t\t\t{\"value\": \"Monthly\", \"label\": \"Monthly\"},\n\t\t\t\t{\"value\": \"Weekly\", \"label\": \"Weekly\"},\n\t\t\t\t{\"value\": \"Daily\", \"label\": \"Daily\"}\n\t\t\t],\n\t\t\t\"reqd\": 1\n\t\t}\n\t],\n\t\"is_time_series\": true\n}\n",
+ "creation": "2019-02-06 07:57:10.377718",
+ "docstatus": 0,
+ "doctype": "Dashboard Chart Source",
+ "idx": 0,
+ "modified": "2019-03-15 16:14:26.505986",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Account Balance Timeline",
+ "owner": "Administrator",
+ "source_name": "Account Balance Timeline"
+}
\ No newline at end of file
diff --git a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py
new file mode 100644
index 0000000..f98a236
--- /dev/null
+++ b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py
@@ -0,0 +1,100 @@
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+from itertools import groupby
+from operator import itemgetter
+import frappe
+from frappe.core.page.dashboard.dashboard import cache_source
+from frappe.utils import add_to_date, date_diff, getdate, nowdate
+from erpnext.accounts.report.general_ledger.general_ledger import execute
+
+@frappe.whitelist()
+@cache_source
+def get(filters=None):
+ timespan = filters.get("timespan")
+ timegrain = filters.get("timegrain")
+ account = filters.get("account")
+ company = filters.get("company")
+
+ from_date = get_from_date_from_timespan(timespan)
+ to_date = nowdate()
+ filters = frappe._dict({
+ "company": company,
+ "from_date": from_date,
+ "to_date": to_date,
+ "account": account,
+ "group_by": "Group by Voucher (Consolidated)"
+ })
+ report_results = execute(filters=filters)[1]
+
+ interesting_fields = ["posting_date", "balance"]
+
+ _results = []
+ for row in report_results[1:-2]:
+ _results.append([row[key] for key in interesting_fields])
+
+ _results = add_opening_balance(from_date, _results, report_results[0])
+ grouped_results = groupby(_results, key=itemgetter(0))
+ results = [list(values)[-1] for key, values in grouped_results]
+ results = add_missing_dates(results, from_date, to_date)
+ results = granulate_results(results, from_date, to_date, timegrain)
+
+ return {
+ "labels": [result[0] for result in results],
+ "datasets": [{
+ "name": account,
+ "values": [result[1] for result in results]
+ }]
+ }
+
+def get_from_date_from_timespan(timespan):
+ days = months = years = 0
+ if "Last Week" == timespan:
+ days = -7
+ if "Last Month" == timespan:
+ months = -1
+ elif "Last Quarter" == timespan:
+ months = -3
+ elif "Last Year" == timespan:
+ years = -1
+ return add_to_date(None, years=years, months=months, days=days,
+ as_string=True, as_datetime=True)
+
+
+def add_opening_balance(from_date, _results, opening):
+ if not _results or (_results[0][0] != getdate(from_date)):
+ _results.insert(0, [from_date, opening.balance])
+ return _results
+
+def add_missing_dates(incomplete_results, from_date, to_date):
+ day_count = date_diff(to_date, from_date)
+
+ results_dict = dict(incomplete_results)
+ last_balance = incomplete_results[0][1]
+ results = []
+ for date in (add_to_date(getdate(from_date), days=n) for n in range(day_count + 1)):
+ if date in results_dict:
+ last_balance = results_dict[date]
+ results.append([date, last_balance])
+ return results
+
+def get_dates_from_timegrain(from_date, to_date, timegrain):
+ days = months = years = 0
+ if "Daily" == timegrain:
+ days = 1
+ elif "Weekly" == timegrain:
+ days = 7
+ elif "Monthly" == timegrain:
+ months = 1
+ elif "Quarterly" == timegrain:
+ months = 3
+
+ dates = [from_date]
+ while dates[-1] <= to_date:
+ dates.append(add_to_date(dates[-1], years=years, months=months, days=days))
+ return dates
+
+def granulate_results(incomplete_results, from_date, to_date, timegrain):
+ dates = set(get_dates_from_timegrain(getdate(from_date), getdate(to_date), timegrain))
+ return list(filter(lambda x: x[0] in dates,incomplete_results))