No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

reportview.py 12 KiB

hace 13 años
hace 13 años
hace 13 años
hace 13 años
hace 13 años
hace 13 años
hace 13 años
hace 12 años
hace 13 años
hace 13 años
hace 13 años
hace 13 años
hace 12 años
hace 13 años
hace 12 años
hace 13 años
hace 13 años
hace 13 años
hace 13 años
hace 13 años
hace 13 años
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  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. if not isinstance(f, (list, tuple)):
  137. webnotes.throw("Filter must be a tuple or list (in a list)")
  138. if len(f) != 4:
  139. webnotes.throw("Filter must have 4 values (doctype, fieldname, condition, value): " + str(f))
  140. tname = ('`tab' + f[0] + '`')
  141. if not tname in webnotes.local.reportview_tables:
  142. webnotes.local.reportview_tables.append(tname)
  143. if not hasattr(webnotes.local, "reportview_doctypes") \
  144. or not webnotes.local.reportview_doctypes.has_key(tname):
  145. load_doctypes()
  146. # prepare in condition
  147. if f[2] in ['in', 'not in']:
  148. opts = ["'" + t.strip().replace("'", "\\'") + "'" for t in f[3].split(',')]
  149. f[3] = "(" + ', '.join(opts) + ")"
  150. conditions.append('ifnull(' + tname + '.' + f[1] + ", '') " + f[2] + " " + f[3])
  151. else:
  152. df = webnotes.local.reportview_doctypes[f[0]].get({"doctype": "DocField",
  153. "fieldname": f[1]})
  154. if f[2] == "like" or (isinstance(f[3], basestring) and
  155. (not df or df[0].fieldtype not in ["Float", "Int", "Currency", "Percent"])):
  156. value, default_val = ("'" + f[3].replace("'", "\\'") + "'"), '""'
  157. else:
  158. value, default_val = flt(f[3]), 0
  159. conditions.append('ifnull({tname}.{fname}, {default_val}) {operator} {value}'.format(
  160. tname=tname, fname=f[1], default_val=default_val, operator=f[2],
  161. value=value))
  162. def build_match_conditions(doctype, fields=None, as_condition=True):
  163. """add match conditions if applicable"""
  164. import webnotes.permissions
  165. match_filters = {}
  166. match_conditions = []
  167. or_conditions = []
  168. if not getattr(webnotes.local, "reportview_tables", None):
  169. webnotes.local.reportview_tables = get_tables(doctype, fields)
  170. load_doctypes()
  171. # is restricted
  172. restricted = webnotes.permissions.get_user_perms(webnotes.local.reportview_doctypes[doctype]).restricted
  173. # get restrictions
  174. restrictions = webnotes.defaults.get_restrictions()
  175. if restricted:
  176. or_conditions.append('`tab{doctype}`.`owner`="{user}"'.format(doctype=doctype,
  177. user=webnotes.local.session.user))
  178. match_filters["owner"] = webnotes.session.user
  179. if restrictions:
  180. fields_to_check = webnotes.local.reportview_doctypes[doctype].get_restricted_fields(restrictions.keys())
  181. if doctype in restrictions:
  182. fields_to_check.append(webnotes._dict({"fieldname":"name", "options":doctype}))
  183. # check in links
  184. for df in fields_to_check:
  185. if as_condition:
  186. match_conditions.append('`tab{doctype}`.{fieldname} in ({values})'.format(doctype=doctype,
  187. fieldname=df.fieldname,
  188. values=", ".join([('"'+v.replace('"', '\"')+'"') \
  189. for v in restrictions[df.options]])))
  190. else:
  191. match_filters.setdefault(df.fieldname, [])
  192. match_filters[df.fieldname]= restrictions[df.options]
  193. if as_condition:
  194. conditions = " and ".join(match_conditions)
  195. doctype_conditions = get_permission_query_conditions(doctype)
  196. if doctype_conditions:
  197. conditions += ' and ' + doctype_conditions if conditions else doctype_conditions
  198. if or_conditions:
  199. if conditions:
  200. conditions = '({conditions}) or {or_conditions}'.format(conditions=conditions,
  201. or_conditions = ' or '.join(or_conditions))
  202. else:
  203. conditions = " or ".join(or_conditions)
  204. return conditions
  205. else:
  206. return match_filters
  207. def get_permission_query_conditions(doctype):
  208. condition_methods = webnotes.get_hooks("permission_query_conditions:" + doctype)
  209. if condition_methods:
  210. conditions = []
  211. for method in condition_methods:
  212. c = webnotes.get_attr(method)()
  213. if c:
  214. conditions.append(c)
  215. return " and ".join(conditions) if conditions else None
  216. def get_tables(doctype, fields):
  217. """extract tables from fields"""
  218. tables = ['`tab' + doctype + '`']
  219. # add tables from fields
  220. if fields:
  221. for f in fields:
  222. if "." not in f: continue
  223. table_name = f.split('.')[0]
  224. if table_name.lower().startswith('group_concat('):
  225. table_name = table_name[13:]
  226. if table_name.lower().startswith('ifnull('):
  227. table_name = table_name[7:]
  228. if not table_name[0]=='`':
  229. table_name = '`' + table_name + '`'
  230. if not table_name in tables:
  231. tables.append(table_name)
  232. return tables
  233. @webnotes.whitelist()
  234. def save_report():
  235. """save report"""
  236. from webnotes.model.doc import Document
  237. data = webnotes.local.form_dict
  238. if webnotes.conn.exists('Report', data['name']):
  239. d = Document('Report', data['name'])
  240. else:
  241. d = Document('Report')
  242. d.report_name = data['name']
  243. d.ref_doctype = data['doctype']
  244. d.report_type = "Report Builder"
  245. d.json = data['json']
  246. webnotes.bean([d]).save()
  247. webnotes.msgprint("%s saved." % d.name)
  248. return d.name
  249. @webnotes.whitelist()
  250. def export_query():
  251. """export from report builder"""
  252. form_params = get_form_params()
  253. webnotes.permissions.can_export(form_params.doctype, raise_exception=True)
  254. ret = execute(**form_params)
  255. columns = [x[0] for x in webnotes.conn.get_description()]
  256. data = [['Sr'] + get_labels(columns),]
  257. # flatten dict
  258. cnt = 1
  259. for row in ret:
  260. flat = [cnt,]
  261. for c in columns:
  262. flat.append(row.get(c))
  263. data.append(flat)
  264. cnt += 1
  265. # convert to csv
  266. from cStringIO import StringIO
  267. import csv
  268. f = StringIO()
  269. writer = csv.writer(f)
  270. for r in data:
  271. # encode only unicode type strings and not int, floats etc.
  272. writer.writerow(map(lambda v: isinstance(v, unicode) and v.encode('utf-8') or v, r))
  273. f.seek(0)
  274. webnotes.response['result'] = unicode(f.read(), 'utf-8')
  275. webnotes.response['type'] = 'csv'
  276. webnotes.response['doctype'] = [t[4:-1] for t in webnotes.local.reportview_tables][0]
  277. def get_labels(columns):
  278. """get column labels based on column names"""
  279. label_dict = {}
  280. for doctype in webnotes.local.reportview_doctypes:
  281. for d in webnotes.local.reportview_doctypes[doctype]:
  282. if d.doctype=='DocField' and d.fieldname:
  283. label_dict[d.fieldname] = d.label
  284. return map(lambda x: label_dict.get(x, x.title()), columns)
  285. @webnotes.whitelist()
  286. def delete_items():
  287. """delete selected items"""
  288. import json
  289. from webnotes.model.code import get_obj
  290. il = json.loads(webnotes.form_dict.get('items'))
  291. doctype = webnotes.form_dict.get('doctype')
  292. for d in il:
  293. try:
  294. dt_obj = get_obj(doctype, d)
  295. if hasattr(dt_obj, 'on_trash'):
  296. dt_obj.on_trash()
  297. webnotes.delete_doc(doctype, d)
  298. except Exception, e:
  299. webnotes.errprint(webnotes.get_traceback())
  300. pass
  301. @webnotes.whitelist()
  302. def get_stats(stats, doctype):
  303. """get tag info"""
  304. import json
  305. tags = json.loads(stats)
  306. stats = {}
  307. columns = get_table_columns(doctype)
  308. for tag in tags:
  309. if not tag in columns: continue
  310. tagcount = execute(doctype, fields=[tag, "count(*)"],
  311. filters=["ifnull(%s,'')!=''" % tag], group_by=tag, as_list=True)
  312. if tag=='_user_tags':
  313. stats[tag] = scrub_user_tags(tagcount)
  314. else:
  315. stats[tag] = tagcount
  316. return stats
  317. def scrub_user_tags(tagcount):
  318. """rebuild tag list for tags"""
  319. rdict = {}
  320. tagdict = dict(tagcount)
  321. for t in tagdict:
  322. alltags = t.split(',')
  323. for tag in alltags:
  324. if tag:
  325. if not tag in rdict:
  326. rdict[tag] = 0
  327. rdict[tag] += tagdict[t]
  328. rlist = []
  329. for tag in rdict:
  330. rlist.append([tag, rdict[tag]])
  331. return rlist
  332. def get_table_columns(table):
  333. res = webnotes.conn.sql("DESC `tab%s`" % table, as_dict=1)
  334. if res: return [r['Field'] for r in res]
  335. # used in building query in queries.py
  336. def get_match_cond(doctype, searchfield = 'name'):
  337. cond = build_match_conditions(doctype)
  338. if cond:
  339. cond = ' and ' + cond
  340. else:
  341. cond = ''
  342. return cond