Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

reportview.py 12 KiB

vor 13 Jahren
vor 13 Jahren
vor 13 Jahren
vor 13 Jahren
vor 13 Jahren
vor 13 Jahren
vor 13 Jahren
vor 12 Jahren
vor 13 Jahren
vor 13 Jahren
vor 13 Jahren
vor 13 Jahren
vor 12 Jahren
vor 13 Jahren
vor 12 Jahren
vor 13 Jahren
vor 13 Jahren
vor 13 Jahren
vor 13 Jahren
vor 13 Jahren
vor 13 Jahren
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. from __future__ import unicode_literals
  4. """build query for doclistview and return results"""
  5. import webnotes, json
  6. import webnotes.defaults
  7. @webnotes.whitelist()
  8. def get():
  9. return compress(execute(**get_form_params()))
  10. def get_form_params():
  11. data = webnotes._dict(webnotes.local.form_dict)
  12. del data["cmd"]
  13. if isinstance(data.get("filters"), basestring):
  14. data["filters"] = json.loads(data["filters"])
  15. if isinstance(data.get("fields"), basestring):
  16. data["fields"] = json.loads(data["fields"])
  17. if isinstance(data.get("docstatus"), basestring):
  18. data["docstatus"] = json.loads(data["docstatus"])
  19. return data
  20. def execute(doctype, query=None, filters=None, fields=None, docstatus=None,
  21. group_by=None, order_by=None, limit_start=0, limit_page_length=None,
  22. as_list=False, with_childnames=False, debug=False):
  23. if query:
  24. return run_custom_query(query)
  25. if not filters: filters = []
  26. if not docstatus: docstatus = []
  27. args = prepare_args(doctype, filters, fields, docstatus, group_by, order_by, with_childnames)
  28. args.limit = add_limit(limit_start, limit_page_length)
  29. query = """select %(fields)s from %(tables)s where %(conditions)s
  30. %(group_by)s order by %(order_by)s %(limit)s""" % args
  31. return webnotes.conn.sql(query, as_dict=not as_list, debug=debug)
  32. def prepare_args(doctype, filters, fields, docstatus, group_by, order_by, with_childnames):
  33. webnotes.local.reportview_tables = get_tables(doctype, fields)
  34. load_doctypes()
  35. remove_user_tags(doctype, fields)
  36. conditions = build_conditions(doctype, fields, filters, docstatus)
  37. args = webnotes._dict()
  38. if with_childnames:
  39. for t in webnotes.local.reportview_tables:
  40. if t != "`tab" + doctype + "`":
  41. fields.append(t + ".name as '%s:name'" % t[4:-1])
  42. # query dict
  43. args.tables = ', '.join(webnotes.local.reportview_tables)
  44. args.conditions = ' and '.join(conditions)
  45. args.fields = ', '.join(fields)
  46. args.order_by = order_by or webnotes.local.reportview_tables[0] + '.modified desc'
  47. args.group_by = group_by and (" group by " + group_by) or ""
  48. check_sort_by_table(args.order_by)
  49. return args
  50. def compress(data):
  51. """separate keys and values"""
  52. if not data: return data
  53. values = []
  54. keys = data[0].keys()
  55. for row in data:
  56. new_row = []
  57. for key in keys:
  58. new_row.append(row[key])
  59. values.append(new_row)
  60. return {
  61. "keys": keys,
  62. "values": values
  63. }
  64. def check_sort_by_table(sort_by):
  65. """check atleast 1 column selected from the sort by table """
  66. if "." in sort_by:
  67. tbl = sort_by.split('.')[0]
  68. if tbl not in webnotes.local.reportview_tables:
  69. if tbl.startswith('`'):
  70. tbl = tbl[4:-1]
  71. webnotes.msgprint("Please select atleast 1 column from '%s' to sort"\
  72. % tbl, raise_exception=1)
  73. def run_custom_query(query):
  74. """run custom query"""
  75. if '%(key)s' in query:
  76. query = query.replace('%(key)s', 'name')
  77. return webnotes.conn.sql(query, as_dict=1)
  78. def load_doctypes():
  79. """load all doctypes and roles"""
  80. import webnotes.model.doctype
  81. webnotes.local.reportview_roles = webnotes.get_roles()
  82. if not getattr(webnotes.local, "reportview_doctypes", None):
  83. webnotes.local.reportview_doctypes = {}
  84. for t in webnotes.local.reportview_tables:
  85. if t.startswith('`'):
  86. doctype = t[4:-1]
  87. if not webnotes.has_permission(doctype):
  88. raise webnotes.PermissionError, doctype
  89. webnotes.local.reportview_doctypes[doctype] = webnotes.model.doctype.get(doctype)
  90. def remove_user_tags(doctype, fields):
  91. """remove column _user_tags if not in table"""
  92. columns = get_table_columns(doctype)
  93. del_user_tags = False
  94. del_comments = False
  95. for fld in fields:
  96. if '_user_tags' in fld and not "_user_tags" in columns:
  97. del_user_tags = fld
  98. if '_comments' in fld and not "_comments" in columns:
  99. del_comments = fld
  100. if del_user_tags: del fields[fields.index(del_user_tags)]
  101. if del_comments: del fields[fields.index(del_comments)]
  102. def add_limit(limit_start, limit_page_length):
  103. if limit_page_length:
  104. return 'limit %s, %s' % (limit_start, limit_page_length)
  105. else:
  106. return ''
  107. def build_conditions(doctype, fields, filters, docstatus):
  108. """build conditions"""
  109. if docstatus:
  110. conditions = [webnotes.local.reportview_tables[0] + '.docstatus in (' + ','.join(docstatus) + ')']
  111. else:
  112. # default condition
  113. conditions = [webnotes.local.reportview_tables[0] + '.docstatus < 2']
  114. # make conditions from filters
  115. build_filter_conditions(filters, conditions)
  116. # join parent, child tables
  117. for tname in webnotes.local.reportview_tables[1:]:
  118. conditions.append(tname + '.parent = ' + webnotes.local.reportview_tables[0] + '.name')
  119. # match conditions
  120. match_conditions = build_match_conditions(doctype, fields)
  121. if match_conditions:
  122. conditions.append(match_conditions)
  123. return conditions
  124. def build_filter_conditions(filters, conditions):
  125. """build conditions from user filters"""
  126. from webnotes.utils import cstr, flt
  127. if not getattr(webnotes.local, "reportview_tables", None):
  128. webnotes.local.reportview_tables = []
  129. doclist = {}
  130. for f in filters:
  131. if isinstance(f, basestring):
  132. conditions.append(f)
  133. else:
  134. tname = ('`tab' + f[0] + '`')
  135. if not tname in webnotes.local.reportview_tables:
  136. webnotes.local.reportview_tables.append(tname)
  137. # prepare in condition
  138. if f[2] in ['in', 'not in']:
  139. opts = ["'" + t.strip().replace("'", "\\'") + "'" for t in f[3].split(',')]
  140. f[3] = "(" + ', '.join(opts) + ")"
  141. conditions.append('ifnull(' + tname + '.' + f[1] + ", '') " + f[2] + " " + f[3])
  142. else:
  143. if isinstance(f[3], basestring):
  144. df = webnotes.local.reportview_doctypes[f[0]].get({"doctype": "DocField",
  145. "fieldname": f[1]})
  146. if df and df[0].fieldtype in ["Float", "Int", "Currency", "Percent"]:
  147. val, default_null_val = flt(f[3]), 0
  148. else:
  149. val, default_null_val = ("'" + f[3].replace("'", "\\'") + "'"), ""
  150. else:
  151. val, default_null_val = f[3], 0
  152. conditions.append('ifnull(' + tname + '.' + f[1] + ", '"+ default_null_val +"') " \
  153. + f[2] + " " + cstr(val))
  154. def build_match_conditions(doctype, fields=None, as_condition=True):
  155. """add match conditions if applicable"""
  156. match_filters = {}
  157. match_conditions = []
  158. match = True
  159. if not getattr(webnotes.local, "reportview_tables", None) \
  160. or not getattr(webnotes.local, "reportview_doctypes", None):
  161. webnotes.local.reportview_tables = get_tables(doctype, fields)
  162. load_doctypes()
  163. if not getattr(webnotes.local, "reportview_roles", None):
  164. webnotes.local.reportview_roles = webnotes.get_roles()
  165. for d in webnotes.local.reportview_doctypes[doctype]:
  166. if d.doctype == 'DocPerm' and d.parent == doctype:
  167. if d.role in webnotes.local.reportview_roles:
  168. if d.match: # role applicable
  169. if ':' in d.match:
  170. document_key, default_key = d.match.split(":")
  171. else:
  172. default_key = document_key = d.match
  173. for v in webnotes.defaults.get_user_default_as_list(default_key, \
  174. webnotes.session.user) or ["** No Match **"]:
  175. if as_condition:
  176. match_conditions.append('`tab%s`.%s="%s"' % (doctype,
  177. document_key, v))
  178. else:
  179. if v:
  180. match_filters.setdefault(document_key, [])
  181. if v not in match_filters[document_key]:
  182. match_filters[document_key].append(v)
  183. elif d.read == 1 and d.permlevel == 0:
  184. # don't restrict if another read permission at level 0
  185. # exists without a match restriction
  186. match = False
  187. match_filters = {}
  188. if as_condition:
  189. conditions = ""
  190. if match_conditions and match:
  191. conditions = '('+ ' or '.join(match_conditions) +')'
  192. doctype_conditions = get_doctype_conditions(doctype)
  193. if doctype_conditions:
  194. conditions += ' and ' + doctype_conditions if conditions else doctype_conditions
  195. return conditions
  196. else:
  197. return match_filters
  198. def get_doctype_conditions(doctype):
  199. from webnotes.model.code import load_doctype_module
  200. module = load_doctype_module(doctype)
  201. if module and hasattr(module, 'get_match_conditions'):
  202. return getattr(module, 'get_match_conditions')()
  203. def get_tables(doctype, fields):
  204. """extract tables from fields"""
  205. tables = ['`tab' + doctype + '`']
  206. # add tables from fields
  207. if fields:
  208. for f in fields:
  209. if "." not in f: continue
  210. table_name = f.split('.')[0]
  211. if table_name.lower().startswith('group_concat('):
  212. table_name = table_name[13:]
  213. if table_name.lower().startswith('ifnull('):
  214. table_name = table_name[7:]
  215. if not table_name[0]=='`':
  216. table_name = '`' + table_name + '`'
  217. if not table_name in tables:
  218. tables.append(table_name)
  219. return tables
  220. @webnotes.whitelist()
  221. def save_report():
  222. """save report"""
  223. from webnotes.model.doc import Document
  224. data = webnotes.local.form_dict
  225. if webnotes.conn.exists('Report', data['name']):
  226. d = Document('Report', data['name'])
  227. else:
  228. d = Document('Report')
  229. d.report_name = data['name']
  230. d.ref_doctype = data['doctype']
  231. d.report_type = "Report Builder"
  232. d.json = data['json']
  233. webnotes.bean([d]).save()
  234. webnotes.msgprint("%s saved." % d.name)
  235. return d.name
  236. @webnotes.whitelist()
  237. def export_query():
  238. """export from report builder"""
  239. # TODO: validate use is allowed to export
  240. verify_export_allowed()
  241. ret = execute(**get_form_params())
  242. columns = [x[0] for x in webnotes.conn.get_description()]
  243. data = [['Sr'] + get_labels(columns),]
  244. # flatten dict
  245. cnt = 1
  246. for row in ret:
  247. flat = [cnt,]
  248. for c in columns:
  249. flat.append(row.get(c))
  250. data.append(flat)
  251. cnt += 1
  252. # convert to csv
  253. from cStringIO import StringIO
  254. import csv
  255. f = StringIO()
  256. writer = csv.writer(f)
  257. for r in data:
  258. # encode only unicode type strings and not int, floats etc.
  259. writer.writerow(map(lambda v: isinstance(v, unicode) and v.encode('utf-8') or v, r))
  260. f.seek(0)
  261. webnotes.response['result'] = unicode(f.read(), 'utf-8')
  262. webnotes.response['type'] = 'csv'
  263. webnotes.response['doctype'] = [t[4:-1] for t in webnotes.local.reportview_tables][0]
  264. def verify_export_allowed():
  265. """throw exception if user is not allowed to export"""
  266. webnotes.local.reportview_roles = webnotes.get_roles()
  267. if not ('Administrator' in webnotes.local.reportview_roles or \
  268. 'System Manager' in webnotes.local.reportview_roles or \
  269. 'Report Manager' in webnotes.local.reportview_roles):
  270. raise webnotes.PermissionError
  271. def get_labels(columns):
  272. """get column labels based on column names"""
  273. label_dict = {}
  274. for doctype in webnotes.local.reportview_doctypes:
  275. for d in webnotes.local.reportview_doctypes[doctype]:
  276. if d.doctype=='DocField' and d.fieldname:
  277. label_dict[d.fieldname] = d.label
  278. return map(lambda x: label_dict.get(x, x.title()), columns)
  279. @webnotes.whitelist()
  280. def delete_items():
  281. """delete selected items"""
  282. import json
  283. from webnotes.model import delete_doc
  284. from webnotes.model.code import get_obj
  285. il = json.loads(webnotes.form_dict.get('items'))
  286. doctype = webnotes.form_dict.get('doctype')
  287. for d in il:
  288. try:
  289. dt_obj = get_obj(doctype, d)
  290. if hasattr(dt_obj, 'on_trash'):
  291. dt_obj.on_trash()
  292. delete_doc(doctype, d)
  293. except Exception, e:
  294. webnotes.errprint(webnotes.getTraceback())
  295. pass
  296. @webnotes.whitelist()
  297. def get_stats(stats, doctype):
  298. """get tag info"""
  299. import json
  300. tags = json.loads(stats)
  301. stats = {}
  302. columns = get_table_columns(doctype)
  303. for tag in tags:
  304. if not tag in columns: continue
  305. tagcount = execute(doctype, fields=[tag, "count(*)"],
  306. filters=["ifnull(%s,'')!=''" % tag], group_by=tag, as_list=True)
  307. if tag=='_user_tags':
  308. stats[tag] = scrub_user_tags(tagcount)
  309. else:
  310. stats[tag] = tagcount
  311. return stats
  312. def scrub_user_tags(tagcount):
  313. """rebuild tag list for tags"""
  314. rdict = {}
  315. tagdict = dict(tagcount)
  316. for t in tagdict:
  317. alltags = t.split(',')
  318. for tag in alltags:
  319. if tag:
  320. if not tag in rdict:
  321. rdict[tag] = 0
  322. rdict[tag] += tagdict[t]
  323. rlist = []
  324. for tag in rdict:
  325. rlist.append([tag, rdict[tag]])
  326. return rlist
  327. def get_table_columns(table):
  328. res = webnotes.conn.sql("DESC `tab%s`" % table, as_dict=1)
  329. if res: return [r['Field'] for r in res]
  330. # used in building query in queries.py
  331. def get_match_cond(doctype, searchfield = 'name'):
  332. cond = build_match_conditions(doctype)
  333. if cond:
  334. cond = ' and ' + cond
  335. else:
  336. cond = ''
  337. return cond