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.
 
 
 
 
 
 

420 rindas
12 KiB

  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. # get doclist of given doctype
  135. doclist.setdefault(f[0], webnotes.model.doctype.get(f[0]))
  136. tname = ('`tab' + f[0] + '`')
  137. if not tname in webnotes.local.reportview_tables:
  138. webnotes.local.reportview_tables.append(tname)
  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. fieldtype = doclist[f[0]].get({"doctype": "DocField",
  146. "fieldname": f[1]})[0].fieldtype
  147. if fieldtype in ["Float", "Int", "Currency", "Percent"]:
  148. conditions.append('ifnull(' + tname + '.' + f[1] + ", 0) " + f[2] \
  149. + " " + cstr(flt(f[3])))
  150. else:
  151. f[3] = "'" + f[3].replace("'", "\\'") + "'"
  152. conditions.append('ifnull(' + tname + '.' + f[1] + ", '') " + f[2] + \
  153. " " + cstr(f[3]))
  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