# -*- 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, '', '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//'], 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/', '/api/query//'], 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/', 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//', 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//', ], 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//', ], 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)