seitime-frappe/frappe/utils/dashboard.py
Gavin D'souza 3446026555 chore: Update header: license.txt => LICENSE
The license.txt file has been replaced with LICENSE for quite a while
now. INAL but it didn't seem accurate to say "hey, checkout license.txt
although there's no such file". Apart from this, there were
inconsistencies in the headers altogether...this change brings
consistency.
2021-09-03 12:02:59 +05:30

114 lines
3.6 KiB
Python

# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
# License: MIT. See LICENSE
import frappe
from frappe import _
from functools import wraps
from frappe.utils import add_to_date, cint, get_link_to_form
from frappe.modules.import_file import import_file_by_path
import os
from os.path import join
def cache_source(function):
@wraps(function)
def wrapper(*args, **kwargs):
if kwargs.get("chart_name"):
chart = frappe.get_doc('Dashboard Chart', kwargs.get("chart_name"))
else:
chart = kwargs.get("chart")
no_cache = kwargs.get("no_cache")
if no_cache:
return function(chart = chart, no_cache = no_cache)
chart_name = frappe.parse_json(chart).name
cache_key = "chart-data:{}".format(chart_name)
if int(kwargs.get("refresh") or 0):
results = generate_and_cache_results(kwargs, function, cache_key, chart)
else:
cached_results = frappe.cache().get_value(cache_key)
if cached_results:
results = frappe.parse_json(frappe.safe_decode(cached_results))
else:
results = generate_and_cache_results(kwargs, function, cache_key, chart)
return results
return wrapper
def generate_and_cache_results(args, function, cache_key, chart):
try:
args = frappe._dict(args)
results = function(
chart_name = args.chart_name,
filters = args.filters or None,
from_date = args.from_date or None,
to_date = args.to_date or None,
time_interval = args.time_interval or None,
timespan = args.timespan or None,
heatmap_year = args.heatmap_year or None
)
except TypeError as e:
if str(e) == "'NoneType' object is not iterable":
# Probably because of invalid link filter
#
# Note: Do not try to find the right way of doing this because
# it results in an inelegant & inefficient solution
# ref: https://github.com/frappe/frappe/pull/9403
frappe.throw(_('Please check the filter values set for Dashboard Chart: {}').format(
get_link_to_form(chart.doctype, chart.name)), title=_('Invalid Filter Value'))
return
else:
raise
frappe.db.set_value("Dashboard Chart", args.chart_name, "last_synced_on", frappe.utils.now(), update_modified = False)
return results
def get_dashboards_with_link(docname, doctype):
dashboards = []
links = []
if doctype == 'Dashboard Chart':
links = frappe.get_all('Dashboard Chart Link',
fields = ['parent'],
filters = {
'chart': docname
})
elif doctype == 'Number Card':
links = frappe.get_all('Number Card Link',
fields = ['parent'],
filters = {
'card': docname
})
dashboards = [link.parent for link in links]
return dashboards
def sync_dashboards(app=None):
"""Import, overwrite fixtures from `[app]/fixtures`"""
if not cint(frappe.db.get_single_value('System Settings', 'setup_complete')):
return
if app:
apps = [app]
else:
apps = frappe.get_installed_apps()
for app_name in apps:
print("Updating Dashboard for {app}".format(app=app_name))
for module_name in frappe.local.app_modules.get(app_name) or []:
frappe.flags.in_import = True
make_records_in_module(app_name, module_name)
frappe.flags.in_import = False
def make_records_in_module(app, module):
dashboards_path = frappe.get_module_path(module, "{module}_dashboard".format(module=module))
charts_path = frappe.get_module_path(module, "dashboard chart")
cards_path = frappe.get_module_path(module, "number card")
paths = [dashboards_path, charts_path, cards_path]
for path in paths:
make_records(path)
def make_records(path, filters=None):
if os.path.isdir(path):
for fname in os.listdir(path):
if os.path.isdir(join(path, fname)):
if fname == '__pycache__':
continue
import_file_by_path("{path}/{fname}/{fname}.json".format(path=path, fname=fname))