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 12 KiB

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