You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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