bill_no_login.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  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 _ast
  8. import re
  9. import csv
  10. import logging
  11. _logger = logging.getLogger(__name__)
  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 Bill(http.Controller, BaseController):
  89. @http.route(['/api/query_menus'], auth='public', methods=['POST'], csrf=False)
  90. def query_menus(self, **kwargs):
  91. is_car = True # 出车通知
  92. rp = {'result': [False, is_car, False, False, False, False, False, False, False, False, False, False, False,
  93. False, False, False, False, False, False, False, False, False, False, False, False, False,
  94. False, False, False, False, False, False, False, False, False, False, False, False, False,
  95. False, False, False, False, False, False, False, False, False, False, False, False, False]}
  96. return self.res_ok(rp)
  97. @http.route(['/api/loads/<string:model>/<string:ids>'], auth='public', methods=['POST'],
  98. csrf=False)
  99. def loads(self, model=None, ids=None, **kwargs): # 需要传递过来参数token
  100. if not model:
  101. return self.res_err(600, u'缺少参数:缺少 要查询的档案model')
  102. if not ids:
  103. return self.res_err(600, '缺少参数:缺少单据ID')
  104. ids = filter(lambda x: x, ids.split(','))
  105. if not ids:
  106. return self.res_err(600, u'缺少参数:缺少有效单据ID')
  107. if len(ids) > 1:
  108. return self.res_err(603, u'单据ID只允许一个')
  109. # print 'model:', model, ', valid ids:', ids
  110. ids = int(ids[0])
  111. try:
  112. param_dic = self._get_params()
  113. env = request.env(user=1)
  114. field = param_dic.get('fields', "[]")
  115. fields = eval(field) if util.is_string(field) else field
  116. detail_list = param_dic.get('detail_list', "[]")
  117. detail_list = eval(detail_list) if util.is_string(detail_list) else detail_list
  118. is_check_cache = param_dic.get('is_check_cache', False)
  119. cache_field = param_dic.get('cache_field', 'write_date')
  120. cache_value = param_dic.get('cache_value', '')
  121. except Exception as e:
  122. field = param_dic.get('fields', "[]")
  123. ex = e.name if hasattr(e, 'name') else str(e)
  124. return self.res_err(-1, ex + u'. fields:{},type:{}'.format(field, type(field)))
  125. warning_list = []
  126. try:
  127. bill = env[model].browse(ids)
  128. # print 'bill:', bill
  129. if not bill:
  130. warning_list.append('单据No.{}已删除'.format(ids))
  131. rp = {'result': {}, 'warning': warning_list}
  132. # print 'no bill, result:', rp
  133. return self.res_ok(rp)
  134. if is_check_cache and cache_field and cache_value: # 验证缓存是否为最新
  135. data = bill[cache_field]
  136. if data == cache_value:
  137. rp = {'result': {}, 'warning': warning_list, 'is_same': True}
  138. return self.res_ok(rp)
  139. model_fields = env[model].fields_get()
  140. result = {}
  141. Bill._get_and_set_field_value(bill, fields, model_fields, result, warning_list)
  142. for detail_info in detail_list:
  143. if 'detail_field' not in detail_info or 'fields' not in detail_info:
  144. # print 'invalid detail info:', detail_info
  145. continue
  146. f_detail = detail_info['detail_field']
  147. f_list = detail_info['fields']
  148. if f_detail not in bill:
  149. # print 'no details:', f_detail
  150. warning_list.append('no details:{}'.format(f_detail))
  151. continue
  152. detail = bill[f_detail]
  153. # print 'detail:', detail, 'model:', detail._name
  154. detail_model_fields = env[detail._name].fields_get()
  155. # print 'detail model info:', detail_model_fields
  156. v_detail_list = []
  157. for d in detail:
  158. v_detail = {}
  159. Bill._get_and_set_field_value(d, f_list, detail_model_fields, v_detail, warning_list)
  160. v_detail_list.append(v_detail)
  161. result[f_detail] = v_detail_list
  162. except Exception as e:
  163. return self.res_err(-1, e.name if hasattr(e, 'name') else str(e))
  164. rp = {'result': result, 'warning': warning_list}
  165. # print '===>query:model:', model, '\n result:\n', rp
  166. return self.res_ok(rp)
  167. @staticmethod
  168. def _get_and_set_field_value(bill_or_detail, need_fields, model_fields, result, warning_list):
  169. for f in need_fields:
  170. if f not in model_fields:
  171. warning_list.append('没有字段:' + f)
  172. continue
  173. if model_fields[f]['type'] == 'many2one':
  174. # print '===>many2one value type:', type(bill[f])
  175. if bill_or_detail[f]:
  176. # print 'field:', f, ',value:', bill[f]
  177. result[f] = {'id': bill_or_detail[f]['id'], 'name': bill_or_detail[f]['name']}
  178. else:
  179. result[f] = {'id': 0, 'name': ''}
  180. else:
  181. result[f] = bill_or_detail[f]
  182. return
  183. @http.route(['/api/query/<string:model>',
  184. '/api/query/<string:model>/<string:ids>'], auth='public', methods=['POST'],
  185. csrf=False)
  186. def query(self, model=None, ids=None, **kwargs): # 需要传递过来参数token
  187. try:
  188. param_dic = self._get_params()
  189. if not model:
  190. return self.res_err(600, u'缺少参数:缺少 要查询的档案model')
  191. env = request.env(user=1)
  192. f = param_dic.get('filter', "[]")
  193. domain = eval(f) if util.is_string(f) else f
  194. field = param_dic.get('fields', "[]")
  195. fields = eval(field) if util.is_string(field) else field
  196. offset = int(param_dic.get('page', '1')) - 1
  197. limit = int(param_dic.get('per_page', '30'))
  198. order = param_dic.get('order', 'id')
  199. except Exception as e:
  200. field = param_dic.get('fields', "[]")
  201. f = param_dic.get('filter', "[]")
  202. ex = e.name if hasattr(e, 'name') else str(e)
  203. return self.res_err(-1, ex + u'. fields:{},type:{}; filter:{},type:{}'.format(field, type(field), f,
  204. type(f)))
  205. domain = searchargs(domain)
  206. if ids:
  207. ids = list(map(int, ids.split(',')))
  208. domain += [('id', 'in', ids)]
  209. try:
  210. count = env[model].search_count(domain)
  211. result = env[model].search_read(domain, fields, offset * limit, limit, order)
  212. model_fields = env[model].fields_get()
  213. for r in result:
  214. for f in r.keys():
  215. if model_fields[f]['type'] == 'many2one':
  216. if r[f]:
  217. r[f] = {'id': r[f][0], 'display_name': r[f][1]}
  218. else:
  219. r[f] = ''
  220. if ids and result and len(ids) == 1:
  221. result = result[0]
  222. except Exception as e:
  223. return self.res_err(-1, e.name if hasattr(e, 'name') else str(e))
  224. rp = {'result': result, 'total': count, 'page': offset + 1, 'per_page': limit}
  225. return self.res_ok(rp)
  226. def _get_params(self):
  227. try:
  228. encrypt_type = request.params.get('encrypt_type', 'raw')
  229. if encrypt_type == 'raw':
  230. if request.httprequest.data:
  231. dic = json.loads(request.httprequest.data)
  232. return dic
  233. else:
  234. combined_multi_dict = request.httprequest.values
  235. return dict([(key, str(v)) for key, v in combined_multi_dict.items()])
  236. else:
  237. _logger.info(u'>>> ===error===未处理的请求类型')
  238. return None
  239. except Exception as e:
  240. _logger.info(u'>>> ===error===获取参数出错:' + e.name if hasattr(e, 'name') else str(e))
  241. return None
  242. @http.route('/api/create/<string:model>',
  243. auth='none', type='http', csrf=False, methods=['POST'])
  244. def create_objects(self, model=None, **kw):
  245. param_dic = self._get_params()
  246. if not model:
  247. return self.res_err(600, u'缺少参数:缺少 要查询的档案model')
  248. env = request.env(user=1)
  249. bill = param_dic.get('bill', '')
  250. try:
  251. bill_dic = eval(bill) if util.is_string(bill) else bill
  252. if u"detail_field" in bill_dic:
  253. f = bill_dic.pop(u"detail_field")
  254. if f in bill_dic:
  255. detail_values = bill_dic[f]
  256. if util.is_string(detail_values):
  257. bill_dic[f] = eval(detail_values)
  258. result = env[model].create(bill_dic).id
  259. except Exception as e:
  260. return self.res_err(-1, e.name if hasattr(e, 'name') else str(e))
  261. return self.res_ok({'id': result})
  262. @http.route('/api/update/<string:model>/<string:ids>',
  263. auth='none', type='http', csrf=False, methods=['POST'])
  264. def update_objects(self, model=None, ids=None, **kw): # 只支持对单个单据进行修改
  265. param_dic = self._get_params()
  266. if not model:
  267. return self.res_err(600, u'缺少参数:缺少 要查询的档案model')
  268. env = request.env(user=1)
  269. ids = list(map(int, ids.split(',')))
  270. bill = param_dic.get('bill', '')
  271. try:
  272. new_value_dic = eval(bill) if util.is_string(bill) else bill
  273. if u"detail_field" in new_value_dic:
  274. f = new_value_dic.pop(u"detail_field")
  275. if f in new_value_dic:
  276. detail_values = new_value_dic[f]
  277. if util.is_string(detail_values):
  278. new_value_dic[f] = eval(detail_values)
  279. result = env[model].browse(ids).write(new_value_dic)
  280. except Exception as e:
  281. return self.res_err(-1, e.name if hasattr(e, 'name') else str(e))
  282. rp = {'result': result}
  283. return self.res_ok(rp)
  284. @http.route(['/api/delete/<string:model>/<string:ids>',
  285. ], auth='none', type='http', csrf=False, methods=['POST'])
  286. def unlink_objects(self, model=None, ids=None, **kw):
  287. # param_dic = self._get_params()
  288. if not model:
  289. return self.res_err(600, u'缺少参数:缺少 要查询的档案model')
  290. env = request.env(user=1)
  291. ids = list(map(int, ids.split(',')))
  292. try:
  293. result = env[model].browse(ids).unlink()
  294. except Exception as e:
  295. return self.res_err(-1, e.name if hasattr(e, 'name') else str(e))
  296. rp = {'result': result}
  297. return self.res_ok(rp)
  298. @http.route(['/api/call/<string:model>/<string:method>',
  299. ], auth='none', type='http', csrf=False, methods=['POST', 'GET'])
  300. def call_method(self, model=None, method=None, **kw):
  301. param_dic = self._get_params()
  302. if not model:
  303. return self.res_err(600, u'缺少参数:缺少 要查询的档案model')
  304. env = request.env(user=1)
  305. p = param_dic.get('param', '')
  306. param = eval(p) if util.is_string(p) else p
  307. try:
  308. result = eval('env[model].' + method)(param)
  309. except Exception as e:
  310. return self.res_err(-1, e.name if hasattr(e, 'name') else str(e))
  311. response = {'result': result}
  312. return self.res_ok(response)