Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

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