Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 
 
 

398 рядки
11 KiB

  1. # Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com)
  2. #
  3. # MIT License (MIT)
  4. #
  5. # Permission is hereby granted, free of charge, to any person obtaining a
  6. # copy of this software and associated documentation files (the "Software"),
  7. # to deal in the Software without restriction, including without limitation
  8. # the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9. # and/or sell copies of the Software, and to permit persons to whom the
  10. # Software is furnished to do so, subject to the following conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be included in
  13. # all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  16. # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  17. # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  18. # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  19. # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
  20. # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. #
  22. from __future__ import unicode_literals
  23. """build query for doclistview and return results"""
  24. import webnotes, json
  25. import webnotes.defaults
  26. tables = None
  27. doctypes = {}
  28. roles = []
  29. @webnotes.whitelist()
  30. def get():
  31. return compress(execute(**get_form_params()))
  32. def get_form_params():
  33. data = webnotes._dict(webnotes.form_dict)
  34. del data["cmd"]
  35. if isinstance(data.get("filters"), basestring):
  36. data["filters"] = json.loads(data["filters"])
  37. if isinstance(data.get("fields"), basestring):
  38. data["fields"] = json.loads(data["fields"])
  39. if isinstance(data.get("docstatus"), basestring):
  40. data["docstatus"] = json.loads(data["docstatus"])
  41. return data
  42. def execute(doctype, query=None, filters=None, fields=None, docstatus=None,
  43. group_by=None, order_by=None, limit_start=0, limit_page_length=None,
  44. as_list=False, debug=False):
  45. if query:
  46. return run_custom_query(query)
  47. if not filters: filters = []
  48. if not docstatus: docstatus = []
  49. args = prepare_args(doctype, filters, fields, docstatus, group_by, order_by)
  50. args.limit = add_limit(limit_start, limit_page_length)
  51. query = """select %(fields)s from %(tables)s where %(conditions)s
  52. %(group_by)s order by %(order_by)s %(limit)s""" % args
  53. return webnotes.conn.sql(query, as_dict=not as_list, debug=debug)
  54. def prepare_args(doctype, filters, fields, docstatus, group_by, order_by):
  55. global tables
  56. tables = get_tables(doctype, fields)
  57. load_doctypes()
  58. remove_user_tags(doctype, fields)
  59. conditions = build_conditions(doctype, fields, filters, docstatus)
  60. args = webnotes._dict()
  61. # query dict
  62. args.tables = ', '.join(tables)
  63. args.conditions = ' and '.join(conditions)
  64. args.fields = ', '.join(fields)
  65. args.order_by = order_by or tables[0] + '.modified desc'
  66. args.group_by = group_by and (" group by " + group_by) or ""
  67. check_sort_by_table(args.order_by)
  68. return args
  69. def compress(data):
  70. """separate keys and values"""
  71. if not data: return data
  72. values = []
  73. keys = data[0].keys()
  74. for row in data:
  75. new_row = []
  76. for key in keys:
  77. new_row.append(row[key])
  78. values.append(new_row)
  79. return {
  80. "keys": keys,
  81. "values": values
  82. }
  83. def check_sort_by_table(sort_by):
  84. """check atleast 1 column selected from the sort by table """
  85. tbl = sort_by.split('.')[0]
  86. if tbl not in tables:
  87. if tbl.startswith('`'):
  88. tbl = tbl[4:-1]
  89. webnotes.msgprint("Please select atleast 1 column from '%s' to sort"\
  90. % tbl, raise_exception=1)
  91. def run_custom_query(query):
  92. """run custom query"""
  93. if '%(key)s' in query:
  94. query = query.replace('%(key)s', 'name')
  95. return webnotes.conn.sql(query, as_dict=1)
  96. def load_doctypes():
  97. """load all doctypes and roles"""
  98. global doctypes, roles
  99. import webnotes.model.doctype
  100. roles = webnotes.get_roles()
  101. for t in tables:
  102. if t.startswith('`'):
  103. doctype = t[4:-1]
  104. if not webnotes.has_permission(doctype):
  105. raise webnotes.PermissionError, doctype
  106. doctypes[doctype] = webnotes.model.doctype.get(doctype)
  107. def remove_user_tags(doctype, fields):
  108. """remove column _user_tags if not in table"""
  109. for fld in fields:
  110. if '_user_tags' in fld:
  111. if not '_user_tags' in get_table_columns(doctype):
  112. del fields[fields.index(fld)]
  113. break
  114. def add_limit(limit_start, limit_page_length):
  115. if limit_page_length:
  116. return 'limit %s, %s' % (limit_start, limit_page_length)
  117. else:
  118. return ''
  119. def build_conditions(doctype, fields, filters, docstatus):
  120. """build conditions"""
  121. if docstatus:
  122. conditions = [tables[0] + '.docstatus in (' + ','.join(docstatus) + ')']
  123. else:
  124. # default condition
  125. conditions = [tables[0] + '.docstatus < 2']
  126. # make conditions from filters
  127. build_filter_conditions(filters, conditions)
  128. # join parent, child tables
  129. for tname in tables[1:]:
  130. conditions.append(tname + '.parent = ' + tables[0] + '.name')
  131. # match conditions
  132. match_conditions = build_match_conditions(doctype, fields)
  133. if match_conditions:
  134. conditions.append(match_conditions)
  135. return conditions
  136. def build_filter_conditions(filters, conditions):
  137. """build conditions from user filters"""
  138. from webnotes.utils import cstr
  139. global tables
  140. if not tables: tables = []
  141. for f in filters:
  142. if isinstance(f, basestring):
  143. conditions.append(f)
  144. else:
  145. tname = ('`tab' + f[0] + '`')
  146. if not tname in tables:
  147. tables.append(tname)
  148. # prepare in condition
  149. if f[2] in ['in', 'not in']:
  150. opts = ["'" + t.strip().replace("'", "\\'") + "'" for t in f[3].split(',')]
  151. f[3] = "(" + ', '.join(opts) + ")"
  152. conditions.append(tname + '.' + f[1] + " " + f[2] + " " + f[3])
  153. else:
  154. if isinstance(f[3], basestring):
  155. f[3] = "'" + f[3].replace("'", "\\'") + "'"
  156. conditions.append(tname + '.' + f[1] + " " + f[2] + " " + f[3])
  157. else:
  158. conditions.append('ifnull(' + tname + '.' + f[1] + ",0) " + f[2] \
  159. + " " + cstr(f[3]))
  160. def build_match_conditions(doctype, fields=None, as_condition=True, match_filters={}):
  161. """add match conditions if applicable"""
  162. global tables, roles
  163. match_conditions = []
  164. match = True
  165. if not tables or not doctypes:
  166. tables = get_tables(doctype, fields)
  167. load_doctypes()
  168. if not roles:
  169. roles = webnotes.get_roles()
  170. for d in doctypes[doctype]:
  171. if d.doctype == 'DocPerm' and d.parent == doctype:
  172. if d.role in roles:
  173. if d.match: # role applicable
  174. if ':' in d.match:
  175. document_key, default_key = d.match.split(":")
  176. else:
  177. default_key = document_key = d.match
  178. for v in webnotes.defaults.get_user_default_as_list(default_key, \
  179. webnotes.session.user) or ["** No Match **"]:
  180. if as_condition:
  181. match_conditions.append('`tab%s`.%s="%s"' % (doctype,
  182. document_key, v))
  183. else:
  184. if v:
  185. match_filters.setdefault(document_key, [])
  186. if v not in match_filters[document_key]:
  187. match_filters[document_key].append(v)
  188. elif d.read == 1 and d.permlevel == 0:
  189. # don't restrict if another read permission at level 0
  190. # exists without a match restriction
  191. match = False
  192. if as_condition:
  193. if match_conditions and match:
  194. return '('+ ' or '.join(match_conditions) +')'
  195. else:
  196. return ""
  197. else:
  198. return match_filters
  199. def get_tables(doctype, fields):
  200. """extract tables from fields"""
  201. tables = ['`tab' + doctype + '`']
  202. # add tables from fields
  203. for f in fields or []:
  204. if "." not in f: continue
  205. table_name = f.split('.')[0]
  206. if table_name.lower().startswith('group_concat('):
  207. table_name = table_name[13:]
  208. if table_name.lower().startswith('ifnull('):
  209. table_name = table_name[7:]
  210. if not table_name[0]=='`':
  211. table_name = '`' + table_name + '`'
  212. if not table_name in tables:
  213. tables.append(table_name)
  214. return tables
  215. @webnotes.whitelist()
  216. def save_report():
  217. """save report"""
  218. from webnotes.model.doc import Document
  219. data = webnotes.form_dict
  220. if webnotes.conn.exists('Report', data['name']):
  221. d = Document('Report', data['name'])
  222. else:
  223. d = Document('Report')
  224. d.report_name = data['name']
  225. d.ref_doctype = data['doctype']
  226. d.report_type = "Report Builder"
  227. d.json = data['json']
  228. webnotes.bean([d]).save()
  229. webnotes.msgprint("%s saved." % d.name)
  230. return d.name
  231. @webnotes.whitelist()
  232. def export_query():
  233. """export from report builder"""
  234. # TODO: validate use is allowed to export
  235. verify_export_allowed()
  236. ret = execute(**get_form_params())
  237. columns = [x[0] for x in webnotes.conn.get_description()]
  238. data = [['Sr'] + get_labels(columns),]
  239. # flatten dict
  240. cnt = 1
  241. for row in ret:
  242. flat = [cnt,]
  243. for c in columns:
  244. flat.append(row.get(c))
  245. data.append(flat)
  246. cnt += 1
  247. # convert to csv
  248. from cStringIO import StringIO
  249. import csv
  250. f = StringIO()
  251. writer = csv.writer(f)
  252. for r in data:
  253. # encode only unicode type strings and not int, floats etc.
  254. writer.writerow(map(lambda v: isinstance(v, unicode) and v.encode('utf-8') or v, r))
  255. f.seek(0)
  256. webnotes.response['result'] = unicode(f.read(), 'utf-8')
  257. webnotes.response['type'] = 'csv'
  258. webnotes.response['doctype'] = [t[4:-1] for t in tables][0]
  259. def verify_export_allowed():
  260. """throw exception if user is not allowed to export"""
  261. global roles
  262. roles = webnotes.get_roles()
  263. if not ('Administrator' in roles or 'System Manager' in roles or 'Report Manager' in roles):
  264. raise webnotes.PermissionError
  265. def get_labels(columns):
  266. """get column labels based on column names"""
  267. label_dict = {}
  268. for doctype in doctypes:
  269. for d in doctypes[doctype]:
  270. if d.doctype=='DocField' and d.fieldname:
  271. label_dict[d.fieldname] = d.label
  272. return map(lambda x: label_dict.get(x, x.title()), columns)
  273. @webnotes.whitelist()
  274. def delete_items():
  275. """delete selected items"""
  276. import json
  277. from webnotes.model import delete_doc
  278. from webnotes.model.code import get_obj
  279. il = json.loads(webnotes.form_dict.get('items'))
  280. doctype = webnotes.form_dict.get('doctype')
  281. for d in il:
  282. try:
  283. dt_obj = get_obj(doctype, d)
  284. if hasattr(dt_obj, 'on_trash'):
  285. dt_obj.on_trash()
  286. delete_doc(doctype, d)
  287. except Exception, e:
  288. webnotes.errprint(webnotes.getTraceback())
  289. pass
  290. @webnotes.whitelist()
  291. def get_stats(stats, doctype):
  292. """get tag info"""
  293. import json
  294. tags = json.loads(stats)
  295. stats = {}
  296. columns = get_table_columns(doctype)
  297. for tag in tags:
  298. if not tag in columns: continue
  299. tagcount = execute(doctype, fields=[tag, "count(*)"],
  300. filters=["ifnull(%s,'')!=''" % tag], group_by=tag, as_list=True)
  301. if tag=='_user_tags':
  302. stats[tag] = scrub_user_tags(tagcount)
  303. else:
  304. stats[tag] = tagcount
  305. return stats
  306. def scrub_user_tags(tagcount):
  307. """rebuild tag list for tags"""
  308. rdict = {}
  309. tagdict = dict(tagcount)
  310. for t in tagdict:
  311. alltags = t.split(',')
  312. for tag in alltags:
  313. if tag:
  314. if not tag in rdict:
  315. rdict[tag] = 0
  316. rdict[tag] += tagdict[t]
  317. rlist = []
  318. for tag in rdict:
  319. rlist.append([tag, rdict[tag]])
  320. return rlist
  321. def get_table_columns(table):
  322. res = webnotes.conn.sql("DESC `tab%s`" % table, as_dict=1)
  323. if res: return [r['Field'] for r in res]