Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

375 linhas
9.8 KiB

  1. # Copyright (c) 2015, Frappe 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 frappe, json
  6. from six.moves import range
  7. import frappe.permissions
  8. import MySQLdb
  9. from frappe.model.db_query import DatabaseQuery
  10. from frappe import _
  11. from six import text_type, string_types, StringIO
  12. @frappe.whitelist()
  13. def get():
  14. args = get_form_params()
  15. data = compress(execute(**args), args = args)
  16. return data
  17. def execute(doctype, *args, **kwargs):
  18. return DatabaseQuery(doctype).execute(*args, **kwargs)
  19. def get_form_params():
  20. """Stringify GET request parameters."""
  21. data = frappe._dict(frappe.local.form_dict)
  22. del data["cmd"]
  23. if "csrf_token" in data:
  24. del data["csrf_token"]
  25. if isinstance(data.get("filters"), string_types):
  26. data["filters"] = json.loads(data["filters"])
  27. if isinstance(data.get("fields"), string_types):
  28. data["fields"] = json.loads(data["fields"])
  29. if isinstance(data.get("docstatus"), string_types):
  30. data["docstatus"] = json.loads(data["docstatus"])
  31. if isinstance(data.get("save_user_settings"), string_types):
  32. data["save_user_settings"] = json.loads(data["save_user_settings"])
  33. else:
  34. data["save_user_settings"] = True
  35. doctype = data["doctype"]
  36. fields = data["fields"]
  37. for field in fields:
  38. key = field.split(" as ")[0]
  39. if "." in key:
  40. parenttype, fieldname = key.split(".")[0][4:-1], key.split(".")[1].strip("`")
  41. else:
  42. parenttype = data.doctype
  43. fieldname = fieldname.strip("`")
  44. df = frappe.get_meta(parenttype).get_field(fieldname)
  45. report_hide = df.report_hide if df else None
  46. # remove the field from the query if the report hide flag is set
  47. if report_hide:
  48. fields.remove(field)
  49. # queries must always be server side
  50. data.query = None
  51. return data
  52. def compress(data, args = {}):
  53. """separate keys and values"""
  54. from frappe.desk.query_report import add_total_row
  55. if not data: return data
  56. values = []
  57. keys = data[0].keys()
  58. for row in data:
  59. new_row = []
  60. for key in keys:
  61. new_row.append(row[key])
  62. values.append(new_row)
  63. if args.get("add_total_row"):
  64. meta = frappe.get_meta(args.doctype)
  65. values = add_total_row(values, keys, meta)
  66. return {
  67. "keys": keys,
  68. "values": values
  69. }
  70. @frappe.whitelist()
  71. def save_report():
  72. """save report"""
  73. data = frappe.local.form_dict
  74. if frappe.db.exists('Report', data['name']):
  75. d = frappe.get_doc('Report', data['name'])
  76. else:
  77. d = frappe.new_doc('Report')
  78. d.report_name = data['name']
  79. d.ref_doctype = data['doctype']
  80. d.report_type = "Report Builder"
  81. d.json = data['json']
  82. frappe.get_doc(d).save()
  83. frappe.msgprint(_("{0} is saved").format(d.name))
  84. return d.name
  85. @frappe.whitelist()
  86. def export_query():
  87. """export from report builder"""
  88. form_params = get_form_params()
  89. form_params["limit_page_length"] = None
  90. form_params["as_list"] = True
  91. doctype = form_params.doctype
  92. add_totals_row = None
  93. file_format_type = form_params["file_format_type"]
  94. del form_params["doctype"]
  95. del form_params["file_format_type"]
  96. if 'add_totals_row' in form_params and form_params['add_totals_row']=='1':
  97. add_totals_row = 1
  98. del form_params["add_totals_row"]
  99. frappe.permissions.can_export(doctype, raise_exception=True)
  100. if 'selected_items' in form_params:
  101. si = json.loads(frappe.form_dict.get('selected_items'))
  102. form_params["filters"] = {"name": ("in", si)}
  103. del form_params["selected_items"]
  104. db_query = DatabaseQuery(doctype)
  105. ret = db_query.execute(**form_params)
  106. if add_totals_row:
  107. ret = append_totals_row(ret)
  108. data = [['Sr'] + get_labels(db_query.fields, doctype)]
  109. for i, row in enumerate(ret):
  110. data.append([i+1] + list(row))
  111. if file_format_type == "CSV":
  112. # convert to csv
  113. import csv
  114. from frappe.utils.xlsxutils import handle_html
  115. f = StringIO()
  116. writer = csv.writer(f)
  117. for r in data:
  118. # encode only unicode type strings and not int, floats etc.
  119. writer.writerow([handle_html(frappe.as_unicode(v)).encode('utf-8') \
  120. if isinstance(v, string_types) else v for v in r])
  121. f.seek(0)
  122. frappe.response['result'] = text_type(f.read(), 'utf-8')
  123. frappe.response['type'] = 'csv'
  124. frappe.response['doctype'] = doctype
  125. elif file_format_type == "Excel":
  126. from frappe.utils.xlsxutils import make_xlsx
  127. xlsx_file = make_xlsx(data, doctype)
  128. frappe.response['filename'] = doctype + '.xlsx'
  129. frappe.response['filecontent'] = xlsx_file.getvalue()
  130. frappe.response['type'] = 'binary'
  131. def append_totals_row(data):
  132. if not data:
  133. return data
  134. data = list(data)
  135. totals = []
  136. totals.extend([""]*len(data[0]))
  137. for row in data:
  138. for i in range(len(row)):
  139. if isinstance(row[i], (float, int)):
  140. totals[i] = (totals[i] or 0) + row[i]
  141. data.append(totals)
  142. return data
  143. def get_labels(fields, doctype):
  144. """get column labels based on column names"""
  145. labels = []
  146. for key in fields:
  147. key = key.split(" as ")[0]
  148. if "." in key:
  149. parenttype, fieldname = key.split(".")[0][4:-1], key.split(".")[1].strip("`")
  150. else:
  151. parenttype = doctype
  152. fieldname = fieldname.strip("`")
  153. df = frappe.get_meta(parenttype).get_field(fieldname)
  154. label = df.label if df else fieldname.title()
  155. if label in labels:
  156. label = doctype + ": " + label
  157. labels.append(label)
  158. return labels
  159. @frappe.whitelist()
  160. def delete_items():
  161. """delete selected items"""
  162. import json
  163. il = json.loads(frappe.form_dict.get('items'))
  164. doctype = frappe.form_dict.get('doctype')
  165. for i, d in enumerate(il):
  166. try:
  167. frappe.delete_doc(doctype, d)
  168. if len(il) >= 5:
  169. frappe.publish_realtime("progress",
  170. dict(progress=[i+1, len(il)], title=_('Deleting {0}').format(doctype)),
  171. user=frappe.session.user)
  172. except Exception:
  173. pass
  174. @frappe.whitelist()
  175. def get_sidebar_stats(stats, doctype, filters=[]):
  176. cat_tags = frappe.db.sql("""select tag.parent as category, tag.tag_name as tag
  177. from `tabTag Doc Category` as docCat
  178. INNER JOIN tabTag as tag on tag.parent = docCat.parent
  179. where docCat.tagdoc=%s
  180. ORDER BY tag.parent asc,tag.idx""",doctype,as_dict=1)
  181. return {"defined_cat":cat_tags, "stats":get_stats(stats, doctype, filters)}
  182. @frappe.whitelist()
  183. def get_stats(stats, doctype, filters=[]):
  184. """get tag info"""
  185. import json
  186. tags = json.loads(stats)
  187. if filters:
  188. filters = json.loads(filters)
  189. stats = {}
  190. try:
  191. columns = frappe.db.get_table_columns(doctype)
  192. except MySQLdb.OperationalError:
  193. # raised when _user_tags column is added on the fly
  194. columns = []
  195. for tag in tags:
  196. if not tag in columns: continue
  197. try:
  198. tagcount = frappe.get_list(doctype, fields=[tag, "count(*)"],
  199. #filters=["ifnull(`%s`,'')!=''" % tag], group_by=tag, as_list=True)
  200. filters = filters + ["ifnull(`%s`,'')!=''" % tag], group_by = tag, as_list = True)
  201. if tag=='_user_tags':
  202. stats[tag] = scrub_user_tags(tagcount)
  203. stats[tag].append([_("No Tags"), frappe.get_list(doctype,
  204. fields=[tag, "count(*)"],
  205. filters=filters +["({0} = ',' or {0} = '' or {0} is null)".format(tag)], as_list=True)[0][1]])
  206. else:
  207. stats[tag] = tagcount
  208. except frappe.SQLError:
  209. # does not work for child tables
  210. pass
  211. except MySQLdb.OperationalError:
  212. # raised when _user_tags column is added on the fly
  213. pass
  214. return stats
  215. @frappe.whitelist()
  216. def get_filter_dashboard_data(stats, doctype, filters=[]):
  217. """get tags info"""
  218. import json
  219. tags = json.loads(stats)
  220. if filters:
  221. filters = json.loads(filters)
  222. stats = {}
  223. columns = frappe.db.get_table_columns(doctype)
  224. for tag in tags:
  225. if not tag["name"] in columns: continue
  226. tagcount = []
  227. if tag["type"] not in ['Date', 'Datetime']:
  228. tagcount = frappe.get_list(doctype,
  229. fields=[tag["name"], "count(*)"],
  230. filters = filters + ["ifnull(`%s`,'')!=''" % tag["name"]],
  231. group_by = tag["name"],
  232. as_list = True)
  233. if tag["type"] not in ['Check','Select','Date','Datetime','Int',
  234. 'Float','Currency','Percent'] and tag['name'] not in ['docstatus']:
  235. stats[tag["name"]] = list(tagcount)
  236. if stats[tag["name"]]:
  237. data =["No Data", frappe.get_list(doctype,
  238. fields=[tag["name"], "count(*)"],
  239. filters=filters + ["({0} = '' or {0} is null)".format(tag["name"])],
  240. as_list=True)[0][1]]
  241. if data and data[1]!=0:
  242. stats[tag["name"]].append(data)
  243. else:
  244. stats[tag["name"]] = tagcount
  245. return stats
  246. def scrub_user_tags(tagcount):
  247. """rebuild tag list for tags"""
  248. rdict = {}
  249. tagdict = dict(tagcount)
  250. for t in tagdict:
  251. if not t:
  252. continue
  253. alltags = t.split(',')
  254. for tag in alltags:
  255. if tag:
  256. if not tag in rdict:
  257. rdict[tag] = 0
  258. rdict[tag] += tagdict[t]
  259. rlist = []
  260. for tag in rdict:
  261. rlist.append([tag, rdict[tag]])
  262. return rlist
  263. # used in building query in queries.py
  264. def get_match_cond(doctype):
  265. cond = DatabaseQuery(doctype).build_match_conditions()
  266. return ((' and ' + cond) if cond else "").replace("%", "%%")
  267. def build_match_conditions(doctype, as_condition=True):
  268. match_conditions = DatabaseQuery(doctype).build_match_conditions(as_condition=as_condition)
  269. if as_condition:
  270. return match_conditions.replace("%", "%%")
  271. else:
  272. return match_conditions
  273. def get_filters_cond(doctype, filters, conditions, ignore_permissions=None, with_match_conditions=False):
  274. if isinstance(filters, string_types):
  275. filters = json.loads(filters)
  276. if filters:
  277. flt = filters
  278. if isinstance(filters, dict):
  279. filters = filters.items()
  280. flt = []
  281. for f in filters:
  282. if isinstance(f[1], string_types) and f[1][0] == '!':
  283. flt.append([doctype, f[0], '!=', f[1][1:]])
  284. elif isinstance(f[1], (list, tuple)) and \
  285. f[1][0] in (">", "<", ">=", "<=", "like", "not like", "in", "not in", "between"):
  286. flt.append([doctype, f[0], f[1][0], f[1][1]])
  287. else:
  288. flt.append([doctype, f[0], '=', f[1]])
  289. query = DatabaseQuery(doctype)
  290. query.filters = flt
  291. query.conditions = conditions
  292. if with_match_conditions:
  293. query.build_match_conditions()
  294. query.build_filter_conditions(flt, conditions, ignore_permissions)
  295. cond = ' and ' + ' and '.join(query.conditions)
  296. else:
  297. cond = ''
  298. return cond