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

13 лет назад
13 лет назад
13 лет назад
12 лет назад
12 лет назад
12 лет назад
12 лет назад
12 лет назад
12 лет назад
12 лет назад
12 лет назад
13 лет назад
12 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
11 лет назад
12 лет назад
13 лет назад
13 лет назад
12 лет назад
12 лет назад
13 лет назад
12 лет назад
13 лет назад
13 лет назад
13 лет назад
12 лет назад
12 лет назад
13 лет назад
12 лет назад
13 лет назад
12 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
12 лет назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  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