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.
 
 
 
 
 
 

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