選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 
 
 

329 行
8.7 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. """build query for doclistview and return results"""
  23. import webnotes, json
  24. tables = None
  25. doctypes = {}
  26. roles = []
  27. @webnotes.whitelist()
  28. def get(arg=None):
  29. """
  30. build query
  31. gets doctype, subject, filters
  32. limit_start, limit_page_length
  33. """
  34. data = webnotes.form_dict
  35. global tables
  36. if 'query' in data:
  37. return run_custom_query(data)
  38. filters = json.loads(data['filters'])
  39. fields = json.loads(data['fields'])
  40. tables = get_tables()
  41. load_doctypes()
  42. remove_user_tags(fields)
  43. # conditions
  44. conditions = build_conditions(filters)
  45. # query dict
  46. data['tables'] = ', '.join(tables)
  47. data['conditions'] = ' and '.join(conditions)
  48. data['fields'] = ', '.join(fields)
  49. if not data.get('order_by'):
  50. data['order_by'] = tables[0] + '.modified desc'
  51. if len(tables) > 1:
  52. data['group_by'] = "group by " + tables[0] + ".name"
  53. else:
  54. data['group_by'] = ''
  55. check_sort_by_table(data.get('order_by'), tables)
  56. add_limit(data)
  57. query = """select %(fields)s from %(tables)s where %(conditions)s
  58. %(group_by)s order by %(order_by)s %(limit)s""" % data
  59. return webnotes.conn.sql(query, as_dict=1)
  60. def check_sort_by_table(sort_by, tables):
  61. """check atleast 1 column selected from the sort by table """
  62. tbl = sort_by.split('.')[0]
  63. if tbl not in tables:
  64. if tbl.startswith('`'):
  65. tbl = tbl[4:-1]
  66. webnotes.msgprint("Please select atleast 1 column from '%s' to sort"\
  67. % tbl, raise_exception=1)
  68. def run_custom_query(data):
  69. """run custom query"""
  70. query = data['query']
  71. if '%(key)s' in query:
  72. query = query.replace('%(key)s', 'name')
  73. return webnotes.conn.sql(query, as_dict=1, debug=1)
  74. def load_doctypes():
  75. """load all doctypes and roles"""
  76. global doctypes, roles
  77. import webnotes.model.doctype
  78. roles = webnotes.get_roles()
  79. for t in tables:
  80. if t.startswith('`'):
  81. doctype = t[4:-1]
  82. if not doctype in webnotes.user.can_get_report:
  83. webnotes.response['403'] = 1
  84. raise webnotes.PermissionError
  85. doctypes[doctype] = webnotes.model.doctype.get(doctype)
  86. def remove_user_tags(fields):
  87. """remove column _user_tags if not in table"""
  88. for fld in fields:
  89. if '_user_tags' in fld:
  90. if not '_user_tags' in get_table_columns(webnotes.form_dict['doctype']):
  91. del fields[fields.index(fld)]
  92. break
  93. def add_limit(data):
  94. if 'limit_page_length' in data:
  95. data['limit'] = 'limit %(limit_start)s, %(limit_page_length)s' % data
  96. else:
  97. data['limit'] = ''
  98. def build_conditions(filters):
  99. """build conditions"""
  100. data = webnotes.form_dict
  101. # docstatus condition
  102. docstatus = json.loads(data['docstatus'])
  103. if docstatus:
  104. conditions = [tables[0] + '.docstatus in (' + ','.join(docstatus) + ')']
  105. else:
  106. # default condition
  107. conditions = [tables[0] + '.docstatus < 2']
  108. # make conditions from filters
  109. build_filter_conditions(data, filters, conditions)
  110. # join parent, child tables
  111. for tname in tables[1:]:
  112. conditions.append(tname + '.parent = ' + tables[0] + '.name')
  113. # match conditions
  114. build_match_conditions(data, conditions)
  115. return conditions
  116. def build_filter_conditions(data, filters, conditions):
  117. """build conditions from user filters"""
  118. for f in filters:
  119. tname = ('`tab' + f[0] + '`')
  120. if not tname in tables:
  121. tables.append(tname)
  122. # prepare in condition
  123. if f[2]=='in':
  124. opts = ["'" + t.strip().replace("'", "\'") + "'" for t in f[3].split(',')]
  125. f[3] = "(" + ', '.join(opts) + ")"
  126. else:
  127. f[3] = "'" + f[3].replace("'", "\'") + "'"
  128. conditions.append(tname + '.' + f[1] + " " + f[2] + " " + f[3])
  129. def build_match_conditions(data, conditions):
  130. """add match conditions if applicable"""
  131. match_conditions = []
  132. match = True
  133. for d in doctypes[data['doctype']]:
  134. if d.doctype == 'DocPerm':
  135. if d.role in roles:
  136. if d.match: # role applicable
  137. for v in webnotes.user.defaults.get(d.match, ['**No Match**']):
  138. match_conditions.append('`tab%s`.%s="%s"' % (data['doctype'], d.match,v))
  139. else:
  140. match = False
  141. if match_conditions and match:
  142. conditions.append('('+ ' or '.join(match_conditions) +')')
  143. def get_tables():
  144. """extract tables from fields"""
  145. data = webnotes.form_dict
  146. tables = ['`tab' + data['doctype'] + '`']
  147. # add tables from fields
  148. for f in json.loads(data['fields']):
  149. table_name = f.split('.')[0]
  150. if table_name.lower().startswith('group_concat('):
  151. table_name = table_name[13:]
  152. # check if ifnull function is used
  153. if table_name.lower().startswith('ifnull('):
  154. table_name = table_name[7:]
  155. if not table_name[0]=='`':
  156. table_name = '`' + table_name + '`'
  157. if not table_name in tables:
  158. tables.append(table_name)
  159. return tables
  160. @webnotes.whitelist()
  161. def save_report():
  162. """save report"""
  163. from webnotes.model.doc import Document
  164. data = webnotes.form_dict
  165. if webnotes.conn.exists('Report', data['name']):
  166. d = Document('Report', data['name'])
  167. else:
  168. d = Document('Report')
  169. d.name = data['name']
  170. d.ref_doctype = data['doctype']
  171. d.json = data['json']
  172. d.save()
  173. webnotes.msgprint("%s saved." % d.name)
  174. return d.name
  175. @webnotes.whitelist()
  176. def export_query():
  177. """export from report builder"""
  178. # TODO: validate use is allowed to export
  179. verify_export_allowed()
  180. ret = get()
  181. columns = [x[0] for x in webnotes.conn.get_description()]
  182. data = [['Sr'] + get_labels(columns),]
  183. # flatten dict
  184. cnt = 1
  185. for row in ret:
  186. flat = [cnt,]
  187. for c in columns:
  188. flat.append(row.get(c))
  189. data.append(flat)
  190. cnt += 1
  191. # convert to csv
  192. from cStringIO import StringIO
  193. import csv
  194. f = StringIO()
  195. writer = csv.writer(f)
  196. for r in data:
  197. for i in xrange(len(r)):
  198. if type(r[i]) is unicode:
  199. r[i] = r[i].encode('utf-8')
  200. writer.writerow(r)
  201. f.seek(0)
  202. webnotes.response['result'] = f.read()
  203. webnotes.response['type'] = 'csv'
  204. webnotes.response['doctype'] = [t[4:-1] for t in tables][0]
  205. def verify_export_allowed():
  206. """throw exception if user is not allowed to export"""
  207. global roles
  208. roles = webnotes.get_roles()
  209. if not ('Administrator' in roles or 'System Manager' in roles or 'Report Manager' in roles):
  210. raise webnotes.PermissionError
  211. def get_labels(columns):
  212. """get column labels based on column names"""
  213. label_dict = {}
  214. for doctype in doctypes:
  215. for d in doctypes[doctype]:
  216. if d.doctype=='DocField' and d.fieldname:
  217. label_dict[d.fieldname] = d.label
  218. return map(lambda x: label_dict.get(x, x.title()), columns)
  219. @webnotes.whitelist()
  220. def delete_items():
  221. """delete selected items"""
  222. import json
  223. from webnotes.model import delete_doc
  224. from webnotes.model.code import get_obj
  225. il = json.loads(webnotes.form_dict.get('items'))
  226. doctype = webnotes.form_dict.get('doctype')
  227. for d in il:
  228. dt_obj = get_obj(doctype, d)
  229. if hasattr(dt_obj, 'on_trash'):
  230. dt_obj.on_trash()
  231. delete_doc(doctype, d)
  232. @webnotes.whitelist()
  233. def get_stats():
  234. """get tag info"""
  235. import json
  236. tags = json.loads(webnotes.form_dict.get('stats'))
  237. doctype = webnotes.form_dict['doctype']
  238. stats = {}
  239. columns = get_table_columns(doctype)
  240. for tag in tags:
  241. if not tag in columns: continue
  242. tagcount = webnotes.conn.sql("""select %(tag)s, count(*)
  243. from `tab%(doctype)s`
  244. where ifnull(%(tag)s, '')!=''
  245. group by %(tag)s;""" % locals(), as_list=1)
  246. if tag=='_user_tags':
  247. stats[tag] = scrub_user_tags(tagcount)
  248. else:
  249. stats[tag] = tagcount
  250. return stats
  251. def scrub_user_tags(tagcount):
  252. """rebuild tag list for tags"""
  253. rdict = {}
  254. tagdict = dict(tagcount)
  255. for t in tagdict:
  256. alltags = t.split(',')
  257. for tag in alltags:
  258. if tag:
  259. if not tag in rdict:
  260. rdict[tag] = 0
  261. rdict[tag] += tagdict[t]
  262. rlist = []
  263. for tag in rdict:
  264. rlist.append([tag, rdict[tag]])
  265. return rlist
  266. def get_table_columns(table):
  267. res = webnotes.conn.sql("DESC `tab%s`" % table, as_dict=1)
  268. if res: return [r['Field'] for r in res]