123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- # -*- coding: utf-8 -*-
- import json
- from odoo import http
- from odoo.http import request
- from odoo.utils import util
- from .base import BaseController
- import _ast
- import re
- import csv
- import logging
- _logger = logging.getLogger(__name__)
- try: # Python 3
- import configparser
- from threading import current_thread
- from xmlrpc.client import Fault, ServerProxy, MININT, MAXINT
- PY2 = False
- except ImportError: # Python 2
- import ConfigParser as configparser
- from threading import currentThread as current_thread
- from xmlrpclib import Fault, ServerProxy, MININT, MAXINT
- PY2 = True
- DOMAIN_OPERATORS = frozenset('!|&')
- _term_re = re.compile(
- '([\w._]+)\s*' '(=(?:like|ilike|\?)|[<>]=?|!?=(?!=)'
- '|(?<= )(?:like|ilike|in|not like|not ilike|not in|child_of))' '\s*(.*)')
- # Simplified ast.literal_eval which does not parse operators
- def _convert(node, _consts={'None': None, 'True': True, 'False': False}):
- if isinstance(node, _ast.Str):
- return node.s
- if isinstance(node, _ast.Num):
- return node.n
- if isinstance(node, _ast.Tuple):
- return tuple(map(_convert, node.elts))
- if isinstance(node, _ast.List):
- return list(map(_convert, node.elts))
- if isinstance(node, _ast.Dict):
- return dict([(_convert(k), _convert(v))
- for (k, v) in zip(node.keys, node.values)])
- if hasattr(node, 'value') and str(node.value) in _consts:
- return node.value # Python 3.4+
- if isinstance(node, _ast.Name) and node.id in _consts:
- return _consts[node.id] # Python <= 3.3
- raise ValueError('malformed or disallowed expression')
- if PY2:
- int_types = int, long
- class _DictWriter(csv.DictWriter):
- """Unicode CSV Writer, which encodes output to UTF-8."""
- def writeheader(self):
- # Method 'writeheader' does not exist in Python 2.6
- header = dict(zip(self.fieldnames, self.fieldnames))
- self.writerow(header)
- def _dict_to_list(self, rowdict):
- rowlst = csv.DictWriter._dict_to_list(self, rowdict)
- return [cell.encode('utf-8') if hasattr(cell, 'encode') else cell
- for cell in rowlst]
- else: # Python 3
- basestring = str
- int_types = int
- _DictWriter = csv.DictWriter
- def literal_eval(expression, _octal_digits=frozenset('01234567')):
- node = compile(expression, '<unknown>', 'eval', _ast.PyCF_ONLY_AST)
- if expression[:1] == '0' and expression[1:2] in _octal_digits:
- raise SyntaxError('unsupported octal notation')
- value = _convert(node.body)
- if isinstance(value, int_types) and not MININT <= value <= MAXINT:
- raise ValueError('overflow, int exceeds XML-RPC limits')
- return value
- def searchargs(params, kwargs=None, context=None):
- """Compute the 'search' parameters."""
- if not params:
- return []
- domain = params[0]
- if not isinstance(domain, list):
- return params
- for (idx, term) in enumerate(domain):
- if isinstance(term, basestring) and term not in DOMAIN_OPERATORS:
- m = _term_re.match(term.strip())
- if not m:
- raise ValueError('Cannot parse term %r' % term)
- (field, operator, value) = m.groups()
- try:
- value = literal_eval(value)
- except Exception:
- # Interpret the value as a string
- pass
- domain[idx] = (field, operator, value)
- return domain
- class Bill(http.Controller, BaseController):
- @http.route(['/api/query_menus'], auth='public', methods=['POST'], csrf=False)
- def query_menus(self, **kwargs):
- is_car = True # 出车通知
- rp = {'result': [False, is_car, False, False, False, False, False, False, False, False, False, False, False,
- False, False, False, False, False, False, False, False, False, False, False, False, False,
- False, False, False, False, False, False, False, False, False, False, False, False, False,
- False, False, False, False, False, False, False, False, False, False, False, False, False]}
- return self.res_ok(rp)
- @http.route(['/api/loads/<string:model>/<string:ids>'], auth='public', methods=['POST'],
- csrf=False)
- def loads(self, model=None, ids=None, **kwargs): # 需要传递过来参数token
- if not model:
- return self.res_err(600, u'缺少参数:缺少 要查询的档案model')
- if not ids:
- return self.res_err(600, '缺少参数:缺少单据ID')
- ids = filter(lambda x: x, ids.split(','))
- if not ids:
- return self.res_err(600, u'缺少参数:缺少有效单据ID')
- if len(ids) > 1:
- return self.res_err(603, u'单据ID只允许一个')
- # print 'model:', model, ', valid ids:', ids
- ids = int(ids[0])
- try:
- param_dic = self._get_params()
- env = request.env(user=1)
- field = param_dic.get('fields', "[]")
- fields = eval(field) if util.is_string(field) else field
- detail_list = param_dic.get('detail_list', "[]")
- detail_list = eval(detail_list) if util.is_string(detail_list) else detail_list
- is_check_cache = param_dic.get('is_check_cache', False)
- cache_field = param_dic.get('cache_field', 'write_date')
- cache_value = param_dic.get('cache_value', '')
- except Exception as e:
- field = param_dic.get('fields', "[]")
- ex = e.name if hasattr(e, 'name') else str(e)
- return self.res_err(-1, ex + u'. fields:{},type:{}'.format(field, type(field)))
- warning_list = []
- try:
- bill = env[model].browse(ids)
- # print 'bill:', bill
- if not bill:
- warning_list.append('单据No.{}已删除'.format(ids))
- rp = {'result': {}, 'warning': warning_list}
- # print 'no bill, result:', rp
- return self.res_ok(rp)
- if is_check_cache and cache_field and cache_value: # 验证缓存是否为最新
- data = bill[cache_field]
- if data == cache_value:
- rp = {'result': {}, 'warning': warning_list, 'is_same': True}
- return self.res_ok(rp)
- model_fields = env[model].fields_get()
- result = {}
- Bill._get_and_set_field_value(bill, fields, model_fields, result, warning_list)
- for detail_info in detail_list:
- if 'detail_field' not in detail_info or 'fields' not in detail_info:
- # print 'invalid detail info:', detail_info
- continue
- f_detail = detail_info['detail_field']
- f_list = detail_info['fields']
- if f_detail not in bill:
- # print 'no details:', f_detail
- warning_list.append('no details:{}'.format(f_detail))
- continue
- detail = bill[f_detail]
- # print 'detail:', detail, 'model:', detail._name
- detail_model_fields = env[detail._name].fields_get()
- # print 'detail model info:', detail_model_fields
- v_detail_list = []
- for d in detail:
- v_detail = {}
- Bill._get_and_set_field_value(d, f_list, detail_model_fields, v_detail, warning_list)
- v_detail_list.append(v_detail)
- result[f_detail] = v_detail_list
- except Exception as e:
- return self.res_err(-1, e.name if hasattr(e, 'name') else str(e))
- rp = {'result': result, 'warning': warning_list}
- # print '===>query:model:', model, '\n result:\n', rp
- return self.res_ok(rp)
- @staticmethod
- def _get_and_set_field_value(bill_or_detail, need_fields, model_fields, result, warning_list):
- for f in need_fields:
- if f not in model_fields:
- warning_list.append('没有字段:' + f)
- continue
- if model_fields[f]['type'] == 'many2one':
- # print '===>many2one value type:', type(bill[f])
- if bill_or_detail[f]:
- # print 'field:', f, ',value:', bill[f]
- result[f] = {'id': bill_or_detail[f]['id'], 'name': bill_or_detail[f]['name']}
- else:
- result[f] = {'id': 0, 'name': ''}
- else:
- result[f] = bill_or_detail[f]
- return
- @http.route(['/api/query/<string:model>',
- '/api/query/<string:model>/<string:ids>'], auth='public', methods=['POST'],
- csrf=False)
- def query(self, model=None, ids=None, **kwargs): # 需要传递过来参数token
- try:
- param_dic = self._get_params()
- if not model:
- return self.res_err(600, u'缺少参数:缺少 要查询的档案model')
- env = request.env(user=1)
- f = param_dic.get('filter', "[]")
- domain = eval(f) if util.is_string(f) else f
- field = param_dic.get('fields', "[]")
- fields = eval(field) if util.is_string(field) else field
- offset = int(param_dic.get('page', '1')) - 1
- limit = int(param_dic.get('per_page', '30'))
- order = param_dic.get('order', 'id')
- except Exception as e:
- field = param_dic.get('fields', "[]")
- f = param_dic.get('filter', "[]")
- ex = e.name if hasattr(e, 'name') else str(e)
- return self.res_err(-1, ex + u'. fields:{},type:{}; filter:{},type:{}'.format(field, type(field), f,
- type(f)))
- domain = searchargs(domain)
- if ids:
- ids = list(map(int, ids.split(',')))
- domain += [('id', 'in', ids)]
- try:
- count = env[model].search_count(domain)
- result = env[model].search_read(domain, fields, offset * limit, limit, order)
- model_fields = env[model].fields_get()
- for r in result:
- for f in r.keys():
- if model_fields[f]['type'] == 'many2one':
- if r[f]:
- r[f] = {'id': r[f][0], 'display_name': r[f][1]}
- else:
- r[f] = ''
- if ids and result and len(ids) == 1:
- result = result[0]
- except Exception as e:
- return self.res_err(-1, e.name if hasattr(e, 'name') else str(e))
- rp = {'result': result, 'total': count, 'page': offset + 1, 'per_page': limit}
- return self.res_ok(rp)
- def _get_params(self):
- try:
- encrypt_type = request.params.get('encrypt_type', 'raw')
- if encrypt_type == 'raw':
- if request.httprequest.data:
- dic = json.loads(request.httprequest.data)
- return dic
- else:
- combined_multi_dict = request.httprequest.values
- return dict([(key, str(v)) for key, v in combined_multi_dict.items()])
- else:
- _logger.info(u'>>> ===error===未处理的请求类型')
- return None
- except Exception as e:
- _logger.info(u'>>> ===error===获取参数出错:' + e.name if hasattr(e, 'name') else str(e))
- return None
- @http.route('/api/create/<string:model>',
- auth='none', type='http', csrf=False, methods=['POST'])
- def create_objects(self, model=None, **kw):
- param_dic = self._get_params()
- if not model:
- return self.res_err(600, u'缺少参数:缺少 要查询的档案model')
- env = request.env(user=1)
- bill = param_dic.get('bill', '')
- try:
- bill_dic = eval(bill) if util.is_string(bill) else bill
- if u"detail_field" in bill_dic:
- f = bill_dic.pop(u"detail_field")
- if f in bill_dic:
- detail_values = bill_dic[f]
- if util.is_string(detail_values):
- bill_dic[f] = eval(detail_values)
- result = env[model].create(bill_dic).id
- except Exception as e:
- return self.res_err(-1, e.name if hasattr(e, 'name') else str(e))
- return self.res_ok({'id': result})
- @http.route('/api/update/<string:model>/<string:ids>',
- auth='none', type='http', csrf=False, methods=['POST'])
- def update_objects(self, model=None, ids=None, **kw): # 只支持对单个单据进行修改
- param_dic = self._get_params()
- if not model:
- return self.res_err(600, u'缺少参数:缺少 要查询的档案model')
- env = request.env(user=1)
- ids = list(map(int, ids.split(',')))
- bill = param_dic.get('bill', '')
- try:
- new_value_dic = eval(bill) if util.is_string(bill) else bill
- if u"detail_field" in new_value_dic:
- f = new_value_dic.pop(u"detail_field")
- if f in new_value_dic:
- detail_values = new_value_dic[f]
- if util.is_string(detail_values):
- new_value_dic[f] = eval(detail_values)
- result = env[model].browse(ids).write(new_value_dic)
- except Exception as e:
- return self.res_err(-1, e.name if hasattr(e, 'name') else str(e))
- rp = {'result': result}
- return self.res_ok(rp)
- @http.route(['/api/delete/<string:model>/<string:ids>',
- ], auth='none', type='http', csrf=False, methods=['POST'])
- def unlink_objects(self, model=None, ids=None, **kw):
- # param_dic = self._get_params()
- if not model:
- return self.res_err(600, u'缺少参数:缺少 要查询的档案model')
- env = request.env(user=1)
- ids = list(map(int, ids.split(',')))
- try:
- result = env[model].browse(ids).unlink()
- except Exception as e:
- return self.res_err(-1, e.name if hasattr(e, 'name') else str(e))
- rp = {'result': result}
- return self.res_ok(rp)
- @http.route(['/api/call/<string:model>/<string:method>',
- ], auth='none', type='http', csrf=False, methods=['POST', 'GET'])
- def call_method(self, model=None, method=None, **kw):
- param_dic = self._get_params()
- if not model:
- return self.res_err(600, u'缺少参数:缺少 要查询的档案model')
- env = request.env(user=1)
- p = param_dic.get('param', '')
- param = eval(p) if util.is_string(p) else p
- try:
- result = eval('env[model].' + method)(param)
- except Exception as e:
- return self.res_err(-1, e.name if hasattr(e, 'name') else str(e))
- response = {'result': result}
- return self.res_ok(response)
|