Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

reportview.py 13 KiB

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