dropdown.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. # -*- coding: utf-8 -*-
  2. import json
  3. from odoo import http
  4. from odoo.http import request
  5. from odoo.utils import util
  6. from .base import BaseController
  7. import logging
  8. _logger = logging.getLogger(__name__)
  9. import _ast
  10. import re
  11. import csv
  12. try: # Python 3
  13. import configparser
  14. from threading import current_thread
  15. from xmlrpc.client import Fault, ServerProxy, MININT, MAXINT
  16. PY2 = False
  17. except ImportError: # Python 2
  18. import ConfigParser as configparser
  19. from threading import currentThread as current_thread
  20. from xmlrpclib import Fault, ServerProxy, MININT, MAXINT
  21. PY2 = True
  22. DOMAIN_OPERATORS = frozenset('!|&')
  23. _term_re = re.compile(
  24. '([\w._]+)\s*' '(=(?:like|ilike|\?)|[<>]=?|!?=(?!=)'
  25. '|(?<= )(?:like|ilike|in|not like|not ilike|not in|child_of))' '\s*(.*)')
  26. # Simplified ast.literal_eval which does not parse operators
  27. def _convert(node, _consts={'None': None, 'True': True, 'False': False}):
  28. if isinstance(node, _ast.Str):
  29. return node.s
  30. if isinstance(node, _ast.Num):
  31. return node.n
  32. if isinstance(node, _ast.Tuple):
  33. return tuple(map(_convert, node.elts))
  34. if isinstance(node, _ast.List):
  35. return list(map(_convert, node.elts))
  36. if isinstance(node, _ast.Dict):
  37. return dict([(_convert(k), _convert(v))
  38. for (k, v) in zip(node.keys, node.values)])
  39. if hasattr(node, 'value') and str(node.value) in _consts:
  40. return node.value # Python 3.4+
  41. if isinstance(node, _ast.Name) and node.id in _consts:
  42. return _consts[node.id] # Python <= 3.3
  43. raise ValueError('malformed or disallowed expression')
  44. if PY2:
  45. int_types = int, long
  46. class _DictWriter(csv.DictWriter):
  47. """Unicode CSV Writer, which encodes output to UTF-8."""
  48. def writeheader(self):
  49. # Method 'writeheader' does not exist in Python 2.6
  50. header = dict(zip(self.fieldnames, self.fieldnames))
  51. self.writerow(header)
  52. def _dict_to_list(self, rowdict):
  53. rowlst = csv.DictWriter._dict_to_list(self, rowdict)
  54. return [cell.encode('utf-8') if hasattr(cell, 'encode') else cell
  55. for cell in rowlst]
  56. else: # Python 3
  57. basestring = str
  58. int_types = int
  59. _DictWriter = csv.DictWriter
  60. def literal_eval(expression, _octal_digits=frozenset('01234567')):
  61. node = compile(expression, '<unknown>', 'eval', _ast.PyCF_ONLY_AST)
  62. if expression[:1] == '0' and expression[1:2] in _octal_digits:
  63. raise SyntaxError('unsupported octal notation')
  64. value = _convert(node.body)
  65. if isinstance(value, int_types) and not MININT <= value <= MAXINT:
  66. raise ValueError('overflow, int exceeds XML-RPC limits')
  67. return value
  68. def searchargs(params, kwargs=None, context=None):
  69. """Compute the 'search' parameters."""
  70. if not params:
  71. return []
  72. domain = params[0]
  73. if not isinstance(domain, list):
  74. return params
  75. for (idx, term) in enumerate(domain):
  76. if isinstance(term, basestring) and term not in DOMAIN_OPERATORS:
  77. m = _term_re.match(term.strip())
  78. if not m:
  79. raise ValueError('Cannot parse term %r' % term)
  80. (field, operator, value) = m.groups()
  81. try:
  82. value = literal_eval(value)
  83. except Exception:
  84. # Interpret the value as a string
  85. pass
  86. domain[idx] = (field, operator, value)
  87. return domain
  88. class Dropdown(http.Controller, BaseController):
  89. @http.route('/<string:sub_domain>/drop-down', auth='public', methods=['POST'], csrf=False)
  90. def drop_down(self, sub_domain, **kwargs): # 需要传递过来参数token
  91. param_list = self._get_params(
  92. ['token', 'model', 'count_per_page', 'page_index', 'search_field', 'search_value', 'order', 'filter',
  93. 'data_type', 'id_field', 'name_field']) # data_type:用于数据授权:当同一个档案要使用不同数据授权时,通过该字段区分
  94. if not param_list:
  95. return self.res_err(-1, u'未处理的请求类型,请联系开发者')
  96. user_token, model, count_per_page, page_index, search_field, search_value, order, _filter, data_type, id_field, name_field = param_list
  97. if not user_token:
  98. return self.res_err(601, u'无权操作:缺少 token')
  99. if not model:
  100. return self.res_err(600, u'缺少参数:缺少 要查询的档案model')
  101. if not id_field:
  102. id_field = 'id'
  103. else:
  104. search_field = id_field
  105. wx_user, info = self._query_wx_user(user_token)
  106. request.uid = wx_user.user_id.id
  107. if info:
  108. return info
  109. return self._query_dropdown_data(wx_user, model, count_per_page, page_index, search_field, search_value, order,
  110. _filter, data_type, id_field, name_field)
  111. def _get_params(self, param_list):
  112. if not param_list:
  113. return None
  114. param_values = []
  115. try:
  116. encrypt_type = request.params.get('encrypt_type', 'raw')
  117. if encrypt_type == 'raw':
  118. if request.httprequest.data:
  119. dic = json.loads(request.httprequest.data)
  120. for p in param_list:
  121. param_values.append(dic.get(p, None))
  122. else:
  123. for p in param_list:
  124. v = request.httprequest.values[p] if p in request.httprequest.values else None
  125. param_values.append(v)
  126. return param_values
  127. else:
  128. _logger.info(u'>>> ===error===未处理的请求类型')
  129. return None
  130. except Exception as e:
  131. _logger.info(u'>>> ===error===获取参数出错:' + str(e))
  132. return None
  133. def _query_wx_user(self, user_token): # 已保证微信用户与系统用户关联起来
  134. access_token = request.env(user=1)['wxapp.access_token'].search([
  135. ('token', '=', user_token),
  136. ])
  137. if not access_token:
  138. return None, self.res_err(10000, u'微信用户未注册,或登录信息过期')
  139. if not access_token.open_id:
  140. return None, self.res_err(9999, u'用户未登录')
  141. user = request.env(user=1)['wxapp.user'].search([
  142. ('open_id', '=', access_token.open_id),
  143. ])
  144. _logger.info(u'>>> open_id======' + access_token.open_id)
  145. _logger.info(u'>>> wx_user======' + user.name if user else u'无')
  146. if not user or not user.user_id.id or not user.user_id.active:
  147. return None, self.res_err(9999, u'请等待系统管理员授权: 当前微信用户,没有与系统用户关联')
  148. return user, None
  149. def _query_dropdown_data(self, wx_user, model, count_per_page, page_index, search_field, search_value, order,
  150. _filter, data_type, id_field, name_field):
  151. count_per_page = self._get_valid_count_per_page(count_per_page)
  152. page_index = self._get_valid_page_index(page_index)
  153. domain = self._get_domain(search_field, search_value)
  154. # self._add_organization(domain, model, data_type)
  155. # print('filter:', _filter)
  156. _filter = Dropdown._get_valid_filter(_filter)
  157. # print('filter after deal:', _filter)
  158. if _filter:
  159. domain += _filter
  160. # print '===>domain', domain, ',order:', order, ',limit:', count_per_page
  161. if order:
  162. data = request.env(user=wx_user.user_id.id)[model].search(domain, limit=count_per_page,
  163. offset=count_per_page * page_index, order=order)
  164. else:
  165. data = request.env(user=wx_user.user_id.id)[model].search(domain, limit=count_per_page,
  166. offset=count_per_page * page_index)
  167. if id_field == 'id':
  168. _name_list = [{'id': row.id, 'name': row[name_field] if name_field else row.name} for row in
  169. data] if data else []
  170. else:
  171. _name_list = [{'id': row[id_field].id, 'name': row[name_field] if name_field else row[id_field].name} for
  172. row in data if row[id_field]] if data else []
  173. data = {
  174. "_list": _name_list
  175. }
  176. # print 'data:', data
  177. # print 'result:', _name_list
  178. return self.res_ok(data)
  179. @staticmethod
  180. def _get_valid_filter(_filter):
  181. if not _filter:
  182. return None
  183. _filter = eval(_filter) if util.is_string(_filter) else _filter
  184. _filter = searchargs(_filter)
  185. if _filter and util.is_list(_filter):
  186. _need_replace = []
  187. for _tuple in _filter:
  188. if len(_tuple) > 2:
  189. if util.is_string(_tuple[2]):
  190. new_tuple = (_tuple[0], _tuple[1], _tuple[2])
  191. _need_replace.append((_tuple, new_tuple))
  192. else:
  193. new_tuple = (_tuple[0], _tuple[1], None)
  194. _need_replace.append((_tuple, new_tuple))
  195. if _need_replace:
  196. for old, _new in _need_replace:
  197. index = _filter.index(old)
  198. _filter.remove(old)
  199. _filter.insert(index, _new)
  200. return _filter
  201. return None
  202. def _get_valid_count_per_page(self, count_per_page):
  203. if not count_per_page:
  204. return 80
  205. try:
  206. count_per_page = int(count_per_page)
  207. except Exception:
  208. return 80
  209. if count_per_page < 10:
  210. count_per_page = 80
  211. return count_per_page
  212. def _get_valid_page_index(self, page_index):
  213. if not page_index:
  214. return 0
  215. try:
  216. page_index = int(page_index)
  217. except Exception:
  218. return 0
  219. if page_index < 0:
  220. page_index = 0
  221. return page_index
  222. def _get_domain(self, search_field, search_value):
  223. if not search_field or not search_value:
  224. return []
  225. return [(search_field, 'ilike', search_value)]
  226. @http.route('/<string:sub_domain>/drop-down-fault', auth='public', methods=['POST'], csrf=False)
  227. def query_fault(self, sub_domain, **kwargs): # 需要传递过来参数token
  228. param_list = self._get_params(
  229. ['token', 'model', 'count_per_page', 'page_index', 'search_field', 'search_value', 'order', 'filter',
  230. 'data_type', 'id_field', 'name_field']) # data_type:用于数据授权:当同一个档案要使用不同数据授权时,通过该字段区分
  231. if not param_list:
  232. return self.res_err(-1, u'未处理的请求类型,请联系开发者')
  233. # print('all param list:', param_list)
  234. user_token, model, count_per_page, page_index, search_field, search_value, order, _filter, data_type, id_field, name_field = param_list
  235. if not user_token:
  236. return self.res_err(601, u'无权操作:缺少 token')
  237. if not id_field:
  238. id_field = 'id'
  239. else:
  240. search_field = id_field
  241. wx_user, info = self._query_wx_user(user_token)
  242. request.uid = wx_user.user_id.id
  243. if info:
  244. return info
  245. return self._query_dropdown_data_fault(wx_user, count_per_page, page_index, search_field, search_value, _filter)
  246. def _query_dropdown_data_fault(self, wx_user, count_per_page, page_index, search_field, search_value, _filter):
  247. count_per_page = self._get_valid_count_per_page(count_per_page)
  248. page_index = self._get_valid_page_index(page_index)
  249. domain = self._get_domain(search_field, search_value)
  250. # self._add_organization(domain, model, data_type)
  251. _filter = Dropdown._get_valid_filter(_filter)
  252. has_valid_filter = _filter[0][2] if _filter else False
  253. where_exp, where_param = self._get_where_from(domain, _filter, has_valid_filter)
  254. limit_exp = count_per_page
  255. offset_exp = count_per_page * page_index
  256. where_param.append(limit_exp)
  257. where_param.append(offset_exp)
  258. if has_valid_filter:
  259. sql_format = "select f.id,f.name from archives_fault f " \
  260. "left join archives_equipment_fault_rel r on r.fault_id=f.id " \
  261. "{} limit %s offset %s"
  262. sql = sql_format.format(where_exp)
  263. else:
  264. sql_format = "select f.id,f.name from archives_fault f " \
  265. "{} limit %s offset %s"
  266. sql = sql_format.format(where_exp)
  267. # print('sql:', sql)
  268. # print('params:', where_param)
  269. cr = request.env(user=wx_user.user_id.id).cr
  270. cr.execute(sql, where_param)
  271. data = cr.fetchall()
  272. _name_list = [{'id': row[0], 'name': row[1]} for row in data] if data else []
  273. data = {
  274. "_list": _name_list
  275. }
  276. return self.res_ok(data)
  277. def _get_where_from(self, domain, _filter, has_valid_filter):
  278. _param_value_list = []
  279. if domain:
  280. _and_list_domain = []
  281. for field, operator, value in domain:
  282. self._add_condition_and_param(_and_list_domain, _param_value_list, field, operator, value)
  283. domain_condition = ' and '.join(_and_list_domain)
  284. else:
  285. domain_condition = ''
  286. if has_valid_filter:
  287. _filter_condition_list = []
  288. for field, operator, value in _filter:
  289. self._add_condition_and_param(_filter_condition_list, _param_value_list, field, operator, value)
  290. _filter_condition = ' and '.join(_filter_condition_list)
  291. _format = '(({}) or f.is_common=true)' if len(_filter_condition_list) > 1 else '({} or f.is_common=true)'
  292. _filter_condition = _format.format(_filter_condition)
  293. else:
  294. _filter_condition = ''
  295. if domain and has_valid_filter:
  296. condition = '{} and {}'.format(domain_condition, _filter_condition)
  297. else:
  298. condition = domain_condition or _filter_condition
  299. if condition:
  300. condition = 'where {}'.format(condition)
  301. return condition, _param_value_list
  302. @staticmethod
  303. def _add_condition_and_param(condition_list, param_ist, field, operator, value):
  304. # print('field:', field)
  305. # print('operator:', operator)
  306. # print('value:', value)
  307. has_prefix = '.' in field
  308. add_prefix = '' if has_prefix else 'f.'
  309. if operator == 'ilike':
  310. condition_list.append('{}{} ilike %s'.format(add_prefix, field))
  311. param_ist.append('%{}%'.format(value))
  312. return
  313. condition_list.append("{}{} {} %s".format(add_prefix, field, operator))
  314. param_ist.append(value)
  315. return
  316. @http.route('/<string:sub_domain>/drop-down-fault-reason', auth='public', methods=['POST'], csrf=False)
  317. def query_fault_reason(self, sub_domain, **kwargs): # 需要传递过来参数token
  318. param_list = self._get_params(
  319. ['token', 'model', 'count_per_page', 'page_index', 'search_field', 'search_value', 'order', 'filter',
  320. 'data_type', 'id_field', 'name_field']) # data_type:用于数据授权:当同一个档案要使用不同数据授权时,通过该字段区分
  321. if not param_list:
  322. return self.res_err(-1, u'未处理的请求类型,请联系开发者')
  323. # print('all param list:', param_list)
  324. user_token, model, count_per_page, page_index, search_field, search_value, order, _filter, data_type, id_field, name_field = param_list
  325. if not user_token:
  326. return self.res_err(601, u'无权操作:缺少 token')
  327. if not id_field:
  328. id_field = 'id'
  329. else:
  330. search_field = id_field
  331. wx_user, info = self._query_wx_user(user_token)
  332. request.uid = wx_user.user_id.id
  333. if info:
  334. return info
  335. return self._query_dropdown_data_fault_reason(wx_user, count_per_page, page_index, search_field, search_value,
  336. _filter, order)
  337. def _query_dropdown_data_fault_reason(self, wx_user, count_per_page, page_index, search_field, search_value,
  338. _filter, order):
  339. count_per_page = self._get_valid_count_per_page(count_per_page)
  340. page_index = self._get_valid_page_index(page_index)
  341. domain = self._get_domain(search_field, search_value)
  342. # self._add_organization(domain, model, data_type)
  343. _filter = Dropdown._get_valid_filter(_filter)
  344. has_valid_filter = _filter[0][2] if _filter else False
  345. where_exp, where_param = self._get_fault_reason_where_from(domain, _filter, has_valid_filter)
  346. limit_exp = count_per_page
  347. offset_exp = count_per_page * page_index
  348. where_param.append(limit_exp)
  349. where_param.append(offset_exp)
  350. if order:
  351. order = 'order by {}'.format(order)
  352. sql_format = "select id,name from archives_fault_reason " \
  353. "{} {} limit %s offset %s"
  354. sql = sql_format.format(where_exp, order)
  355. # print('sql:', sql)
  356. # print('params:', where_param)
  357. cr = request.env(user=wx_user.user_id.id).cr
  358. cr.execute(sql, where_param)
  359. data = cr.fetchall()
  360. _name_list = [{'id': row[0], 'name': row[1]} for row in data] if data else []
  361. data = {
  362. "_list": _name_list
  363. }
  364. return self.res_ok(data)
  365. def _get_fault_reason_where_from(self, domain, _filter, has_valid_filter):
  366. _param_value_list = []
  367. if domain:
  368. _and_list_domain = []
  369. for field, operator, value in domain:
  370. self._add_condition_and_param_4_fault_reason(_and_list_domain, _param_value_list, field, operator,
  371. value)
  372. domain_condition = ' and '.join(_and_list_domain)
  373. else:
  374. domain_condition = ''
  375. if has_valid_filter:
  376. _filter_condition_list = []
  377. for field, operator, value in _filter:
  378. self._add_condition_and_param_4_fault_reason(_filter_condition_list, _param_value_list, field, operator,
  379. value)
  380. _filter_condition = ' and '.join(_filter_condition_list)
  381. _format = '(({}) or fault_id is null)' if len(_filter_condition_list) > 1 else '({} or fault_id is null)'
  382. _filter_condition = _format.format(_filter_condition)
  383. else:
  384. _filter_condition = ''
  385. if domain and has_valid_filter:
  386. condition = '{} and {}'.format(domain_condition, _filter_condition)
  387. else:
  388. condition = domain_condition or _filter_condition
  389. if condition:
  390. condition = 'where {}'.format(condition)
  391. return condition, _param_value_list
  392. @staticmethod
  393. def _add_condition_and_param_4_fault_reason(condition_list, param_ist, field, operator, value):
  394. # print('field:', field)
  395. # print('operator:', operator)
  396. # print('value:', value)
  397. condition_list.append("{} {} %s".format(field, operator))
  398. if operator == 'ilike':
  399. value = '%{}%'.format(value)
  400. param_ist.append(value)
  401. return