Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

reportview.py 12 KiB

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