# -*- coding:utf-8 -*-
# 项目: jdg-core-base
# Copyright 2018 JDG <www.yunside.com>
# Created by bjccdsrlcr (longjie.jiang@yunside.com) @ 11/1/19
# -*- coding: utf-8 -*-

import logging
import os
from odoo import fields, models, api
from odoo import api,exceptions
from odoo.exceptions import ValidationError
from core.middleware.trust_rpc import get_trust_rpc
import simplejson
from odoo.tools import config
import re
from tpl_engine import TPL_Engine
from odoo.tools.safe_eval import safe_eval
from odoo.addons.base.ir.ir_model import make_compute
from odoo.fields import Field, Default, resolve_mro
from odoo.tools import float_precision, float_repr, float_round, frozendict, \
                       html_sanitize, human_size, pg_varchar, ustr, OrderedSet
from collections import OrderedDict, defaultdict
from functools import partial
_logger = logging.getLogger(__name__)


class IrModelFieldsInherit(models.Model):
    _inherit = 'ir.model.fields'

    default = fields.Char(string=u'default')


class JDTableDataSource(models.Model):
    _name = 'jd.table.datasource'
    _description = u'报表数据源'

    number = fields.Char(u'编码', index=True, required=True, copy=False)
    data_node_id = fields.Many2one('jd.data.node', string=u'数据节点', required=True)
    # 只有报表数据源需要生成向导，元数据只需要可执行sql
    type = fields.Selection([('report', u'报表数据源'),
                             ('metadata', u'元数据')], string=u'数据源类型', default='report', required=True)
    name = fields.Char(u'名称', index=True, required=True)
    sql = fields.Text(u'SQL')
    params = fields.One2many('jd.table.params', 'datasource_id', string=u'参数')
    report_ids = fields.One2many('jd.table.report', 'datasource_id',
                                 string=u'报表', ondelete='restrict')
    search_model = fields.Many2one('ir.model', string=u'过滤器模型', ondelete='cascade')
    search_view = fields.Many2one('ir.ui.view', string=u'过滤器视图', ondelete='cascade')

    connect_success = fields.Boolean(string=u'是否连接成功', default=False, readonly=True)
    connect_success_text = fields.Text(string=u'连接成功', readonly=True)
    onchange_method_line_ids = fields.One2many('jd.table.datasource.onchange.method.line', 'parent_id',
                                               string=u'Onchange方法列表')
    reset_view = fields.Boolean(string=u'是否重置视图', default=False)

    form_view_code = fields.Text(string=u'form视图代码', readonly=True)
    
    _sql_constraints = [
        ('number_uniq', 'unique (number)', u'编号不能重复！')
    ]

    @api.multi
    def copy(self, default=None):
        if default is None:
            default = {}
        default['number'] = self.number + 'bak'

        return super(JDTableDataSource, self).copy(default=default)

    # @api.model_cr
    # def _register_hook(self):
    #     """
    #     服务启动并将所有的module加载入registry后，会调用该方法。
    #     :return:
    #     """
    #     sql = '''
    #           select count(*) from ir_model where model = 'jd.table.datasource'
    #           '''
    #     self.env.cr.execute(sql)
    #     count = self.env.cr.fetchone()
    #     if count > 0:
    #         recs = self.search([('search_model', '!=', False)])
    #         for rec in recs:
    #             rec.add_method()
    #             if rec.type == 'report':
    #                 #如果有wizard表单视图，则取表单视图
    #                 if rec.form_view_code:
    #                     rec.search_view.update({
    #                         'arch_base': rec.form_view_code
    #                     })

    def contain_chinese(self, string):
        """
        检查整个字符串是否包含中文
        :param string: 需要检查的字符串
        :return: bool
        """
        RE = re.compile(u'[\u4e00-\u9fa5]', re.UNICODE)
        match = re.search(RE, string)
        if match is None:
            return False
        else:
            return True
    
    @api.multi
    @api.constrains('number')
    def check_number(self):
        """
        编码不能包含中文
        :return: 
        """
        for item in self:
            if item.contain_chinese(item.number):
                raise ValidationError(u'编码不能包含中文')

    @api.multi
    def test_connect(self):
        """
        测试数据节点是否可成功连接
        :return:
        """
        for item in self:
            des_data_node_id = item.data_node_id.id
            try:
                remote_odoo = get_trust_rpc(des_data_node_id)
                if remote_odoo:
                    item.connect_success = True
                    item.connect_success_text = u'恭喜您，该数据源可用。本次测试时间：%s' % fields.Datetime.now()
            except Exception as e:
                _logger.error(e)
                raise ValidationError('%s' % e)
    
    @api.multi
    def add_onchange_method(self):
        """
        增加onchange方法
        :return: 
        """
        return {
            'name': '增加onchange方法',
            'type': 'ir.actions.act_window',
            'model': 'ir.actions.act_window',
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': 'jd.rpt.wizard.onchange.method',
            'target': 'new',
            'view_id': False,
            'context': {}
        }

    @api.multi
    def edit_xml(self):
        """
        编辑向导格式
        :return:
        """
        self.ensure_one()
        return {
            'name': '编辑向导视图',
            'type': 'ir.actions.act_window',
            'model': 'ir.actions.act_window',
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': 'jd.rpt.wizard.edit.xml',
            'target': 'new',
            'view_id': False,
            'context': {}
        }
    
    @api.multi
    def create_external_id(self):
        """
        格式化本条记录的同时，创建一条外部id
        :return: 
        """
        self.ensure_one()
        item = self[0]

        self.env['ir.model.data'].create({
            'name': 'sql_%s' % item.number,
            'model': 'jd.table.datasource',
            'module': config.get('external_module_name', 'jd_report'),
            'res_id': self.search([('number', '=', item.number)], limit=1).id,
        })
    @api.multi
    def generate_xml(self):
        """
        基于当前记录自动生成data.xml文件
        :return:
        """
        for item in self:
            tpl_engine = TPL_Engine()
            external_module_name = config.get('external_module_name', 'jd_report')
            des_path = config.get('des_path', '.')
            des_path = des_path + '/' + item.number
            is_exist = os.path.exists(des_path)
            if not is_exist:
                os.makedirs(des_path)
            # 写入表头
            data = {'number': item.number,
                    'name': item.name,
                    'data_node_id': item.data_node_id.id,
                    'reset_view': item.reset_view,
                    'form_view_code': item.form_view_code or "",
                    'type': item.type,
                    'sql': item.sql,
                    'search_model': item.search_model.id,
                    'search_view': item.search_view.id}
            sql_str = tpl_engine.render('tpl_sql.xml', data)
            # matcher = re.search('<field name="sql">([\S\s]*)<\/field>', sql_str)
            # sql_content = ""
            # if matcher:
            #     sql_content = matcher.group(1)
            #     sql_content = sql_content.replace("<", "&lt;")
            #     sql_content = sql_content.replace(">", "&gt;")
            # sql_str = re.sub('<field name="sql">[\S\s]*<\/field>', '<field name="sql">%s</field>' % sql_content, sql_str)
            # sql_str = sql_str.replace("<=", "&lt;=")
            # sql_str = sql_str.replace(">=", "&gt;=")
            sql_filename = '%s/%s_sql.xml' % (des_path, item.number)
            with open(sql_filename, mode='w+') as f:
                f.write(sql_str)
            external_rec = self.env['ir.model.data'].search([('name', '=', 'sql_%s' % item.number), ('module', '=', config.get('external_module_name', 'jd_report'))])
            if external_rec:
                external_rec.unlink()
            self.env['ir.model.data'].create({
                'name': 'sql_%s' % item.number,
                'model': 'jd.table.datasource',
                'module': config.get('external_module_name', 'jd_report'),
                'res_id': item.id,
            })
            # 写入参数明细
            data_list = []
            for index, param in enumerate(item.params):
                vals = {
                    'external_module_name': external_module_name,
                    'index': index,
                    'external_id': 'sql_%s' % item.number,
                    'datasource_number': item.number,
                    'param': param.param,
                    'name': param.name,
                    'domain': param.domain or "",
                    'default_val': param.default_val or "",
                    'ttype': param.ttype or "",
                    'relation': param.relation or "",
                    # 数据源用外部ID 不能用数据库ID
                    'data_source': param.data_source.id or "",
                    'compute': param.compute or "",
                    'depends': param.depends or "",
                    'selection': param.selection or "",
                    'required': param.required or "",
                    'readonly': param.readonly or "",
                    'store': param.store or ""
                }
                # 如果有填写元数据数据源
                if param.data_source:
                    data_source_external_id = param.data_source.get_external_id()
                    vals.update({
                        'data_source': data_source_external_id[param.data_source.id]
                    })
                data_list.append(vals)
                if self.env['ir.model.data'].search([('name', '=', 'sql_params_%s_%d' % (item.number, index)), ('module', '=', config.get('external_module_name', 'jd_report'))]):
                    self.env['ir.model.data'].search([('name', '=', 'sql_params_%s_%d' % (item.number, index)),
                                                      ('module', '=', config.get('external_module_name', 'jd_report'))]).unlink()
                self.env['ir.model.data'].create({
                    'name': 'sql_params_%s_%d' % (item.number, index),
                    'model': 'jd.table.params',
                    'module': config.get('external_module_name', 'jd_report'),
                    'res_id': param.id,
                })
            data_dic = {'data': data_list}
            sql_param_str = tpl_engine.render('tpl_sql_param.xml', data_dic)
            sql_param_filename = '%s/%s_sql_param.xml' % (des_path, item.number)
            with open(sql_param_filename, mode='w') as f:
                f.write(sql_param_str)
            # 写入方法明细
            data_method_list = []
            for index, methods in enumerate(item.onchange_method_line_ids):
                data_method_list.append({
                    'external_module_name': external_module_name,
                    'index': index,
                    'external_id': 'sql_%s' % item.number,
                    'datasource_number': item.number,
                    'method_code': methods.method_code
                })
                if self.env['ir.model.data'].search([('name', '=', 'sql_methods_%s_%d' % (item.number, index)), ('module', '=', config.get('external_module_name', 'jd_report'))]):
                    self.env['ir.model.data'].search([('name', '=', 'sql_methods_%s_%d' % (item.number, index)),
                                                      ('module', '=', config.get('external_module_name', 'jd_report'))]).unlink()
                self.env['ir.model.data'].create({
                    'name': 'sql_methods_%s_%d' % (item.number, index),
                    'model': 'jd.table.datasource.onchange.method.line',
                    'module': config.get('external_module_name', 'jd_report'),
                    'res_id': methods.id,
                })
            data_method_dic = {'data': data_method_list}
            sql_method_str = tpl_engine.render('tpl_sql_method.xml', data_method_dic)
            sql_method_filename = '%s/%s_sql_method.xml' % (des_path, item.number)
            with open(sql_method_filename, mode='w') as f:
                f.write(sql_method_str)

    # @api.multi
    # def unlink(self):
    #     '''
    #     删除对应的菜单
    #     :return:
    #     '''
    #     search_model = None
    #     search_view = None
    #     for record in self:
    #         if record.params and len(record.params) > 0:
    #             record.params.unlink()
    #         if record.search_model and record.search_model.id:
    #             search_model = record.search_model
    #         if record.search_view and record.search_view.id:
    #             search_view = record.search_view
    #         if record.report_ids and len(record.report_ids) > 0:
    #             raise exceptions.ValidationError(u'有报表引用该数据源，不能删除。')
    #
    #     result = super(JDTableDataSource, self).unlink()
    #     if search_view:
    #         search_view.unlink()
    #     if search_model:
    #         search_model.unlink()
    #     # for record in self:
    #     #     sql = "drop table x_report_search_%d" % record.id
    #     #     self.env.cr.execute(sql)
    #     return result

    def action_edit_sql(self):
        '''
        打开SQL编辑器
        :return:
        '''
        return {
            'type': 'ir.actions.act_url',
            'url': '/v1/jd_report/sql_editor?id='+str(self.id),
            'target': 'new',
        }

    @api.model
    def create(self, vals):
        res = super(JDTableDataSource, self).create(vals)
        if res.type == 'report':
            # 下面几个方法，必须按顺序执行
            res.reset_filter_view()
            res.create_or_update_filter_model()
            res.create_or_update_filter_view()
        return res

    @api.multi
    def write(self, vals):
        res = super(JDTableDataSource, self).write(vals)
        # if self[0].type == 'report':
        #     if 'onchange_method_line_ids' in vals:
                # self[0].add_method()
                ##下面几个方法，必须按顺序执行
                # self[0].reset_filter_view()
                # self[0].create_or_update_filter_model()
                # self[0].create_or_update_filter_view()
        return res

    def create_local_data(self, relation, data_source):
        """
        对于非当前节点的many2one参数，临时创建该模型
        并向模型中填充数据源的数据
        :return:
        """
        cr = self.env.cr
        sql = data_source.sql
        remote_odoo = get_trust_rpc(data_source.data_node_id.id)
        data_list = remote_odoo.env['report.execute.sql'].execute_sql(sql)
        sql = '''
        select count(*) from ir_model where model = %s 
        '''
        cr.execute(sql, ('x_' + relation,))
        count = cr.dictfetchone()
        # 本地无该模型，则新建该模型
        if count['count'] == 0:
            model_val = {
                'name': '生产线',
                'model': 'x_' + relation,
                'transient': False,
            }
            model = self.env['ir.model'].sudo().create(model_val)
            field_val = {
                'name': 'x_name',
                'ttype': 'char',
                'model_id': model.id,
            }
            self.env['ir.model.fields'].sudo().create(field_val)
            for data in data_list:
                model.create({
                    'name': data['name']
                })
        else:
            model = self.env['x_'+relation].sudo()
            for data in data_list:
                if model.search([('x_name', '=', data['name'])]):
                    continue
                else:
                    model.create({
                        'id': data['id'],
                        'x_name': data['name']
                    })

    def create_selection_data(self, data_source):
        """
        对于非当前节点的many2one参数，从远程获取(id, name)填充到selection/multi_selection字段中。
        :return:
        """
        sql = data_source.sql
        remote_odoo = get_trust_rpc(data_source.data_node_id.id, env=self.env)
        # 执行sql前的判断， 1. 判断if语句 2. 判断空值
        # 判断sql中是否存在if语句
        # 查找所有的[if][end if]语句块。 取出判断条件为真的语句进行拼接
        import re
        pattern = re.compile(r'\[if.*?\[end if\]')
        result = pattern.findall(sql)
        for r in result:
            matcher = re.search(r'\[if(.*)then\]', r)
            try:
                if eval(matcher.group(1)):
                    matcher = re.search(r'then\](.*)\[end if\]', r)
                    sql = sql.replace(r, matcher.group(1), 1)
                else:
                    sql = sql.replace(r, " ", 1)
            except Exception as e:
                raise e
        data_list = remote_odoo.env['report.execute.sql'].execute_sql(sql)
        # 组装成tuple的形式
        selection = []
        for data in data_list:
            if 'id' in data and 'name' in data:
                selection.append((str(data['id']), str(data['name'])))
        if len(selection) == 0:
            return "[('false', '')]"
        else:
            return str(selection)

    def get_domain(self, domain, relation):
        """
        分析domain为[] 还是函数
        :return:
        """
        if domain:
            domain = str(domain)
            if domain.startswith('['):
                return domain
            else:
                # 如果存在.在domain中，则去查对应模型的该方法 #todo
                if '.' in domain:
                    domain = domain.split('.')[1]
                    if hasattr(self.search_model, domain):
                        domain = getattr(self.search_model, domain)
                    else:
                        domain = ""
                else:
                    if hasattr(self, domain):
                        domain = getattr(self, domain)()
                    else:
                        domain = ""
            return domain
        else:
            return ""

    @api.multi
    def create_or_update_filter_model(self):
        try:
            model = self.env['ir.model']
            if self.search_model and self.search_model.id:
                search_model = self.search_model
            else:
                model_val = {
                    'name': self.name + "-" + u'查询',
                    'model': 'x_report.search_' + str(self.id),
                    'transient': True,
                }
                search_model = model.create(model_val)
                #self.write({'search_model': search_model.id})#会死循环，用SQL代替
                sql = "update jd_table_datasource set search_model=%s where id=%s"
                self.env.cr.execute(sql, (search_model.id, self.id))
            model_field = self.env['ir.model.fields']
            if search_model.field_id:
                for param in self.params:
                    old_field = None
                    for f in search_model.field_id:
                        params_name = f.name
                        if params_name == 'x_' + param.param[1:]:  # 首字母是@,需要去掉
                            old_field = f
                            break
                    field_val = {
                        'name': 'x_' + param.param[1:],
                        'field_description': param.name,
                        'ttype': param.ttype,
                        'relation': param.relation or "",
                        'relation_table': param.relation_table or "",
                        'column1': param.column1 or "",
                        'column2': param.column2 or "",
                        'model_id': search_model.id,
                        'domain': self.get_domain(param.domain, param.relation),
                        'depends': param.depends or "",
                        'compute': param.compute or "",
                        # 'selection': param.selection or "[('false', '')]",
                        'default': param.default_val or "",
                        'required': param.required,
                        'readonly': param.readonly,
                        'store': param.store,
                    }
                    if param.ttype in ('selection', 'multi_selection'):
                        if param.data_source:
                            field_val.update({
                                'selection': self.create_selection_data(param.data_source)
                            })
                        else:
                            field_val.update({
                                'selection': param.selection or "[('false', '')]"
                            })
                    if old_field and old_field.id:
                        old_field.write(field_val)
                    else:
                        model_field.create(field_val)
                remove_field_ids = []
                for f in search_model.field_id:
                    if f.name.startswith('x_'):
                        remove = True
                        for p in self.params:
                            if 'x_'+p.param[1:] == f.name:
                                remove = False
                        if remove:
                            remove_field_ids.append(f.id)

                model_field.browse(remove_field_ids).unlink()
            self.add_method()
        except Exception as e:
            import  traceback
            def traceback_info(_logger=_logger):
                stack_info = traceback.extract_stack()
                not_found_code = True
                for stack_info_item in stack_info:
                    python_path = stack_info_item[0]
                    if (python_path.find('hd_') != -1 or python_path.find('gateway') != -1
                        or python_path.find('jdg_app') != -1) and python_path.find(
                        'error_code') == -1 and python_path.find(
                        'api') == -1:
                        traceback_str = u'\n抛错文件：' + str(stack_info_item[0])
                        traceback_str += u'\n抛错行数：' + str(stack_info_item[1]) + u', 抛错方法：' + str(stack_info_item[2])
                        traceback_str += u'\n抛错代码：' + str(stack_info_item[3])
                        _logger.error(traceback_str)
                        not_found_code = False
                if not_found_code:
                    traceback.print_exc()
            _logger.error(e)
            traceback_info(_logger)
            raise e

    def reset_filter_view(self):
        '''
        重置过滤试图，避免出现"视图中还有使用的字段错误"，不能修改过滤条件字段。
        :return:
        '''

        if self.search_view and self.search_view.id:
            form_tmpl = u'''<?xml version="1.0"?>
                       <form string="%(form_name)s">
                               <group>
                                   %(fields)s
                               </group>
                               <footer>
                                   <button context="{'wizard_id': active_id}" string="确定" name="action_for_report_search" type="object" class="btn-primary"/>
                                   <button string="取消" class="btn-default" special="cancel"/>
                               </footer>
                       </form>'''
            form_xml = form_tmpl % {'form_name': 'tmp', 'fields': ''}
            self.search_view.write({'arch_base': form_xml})

    @api.one
    def create_or_update_filter_view(self):
        '''
        创建或是更新ir_ui_view
        :param values:
        :return:
        '''

        view_val = {
            'name': '',
            'type': 'form',
            'model': self.search_model.model,
            'priority': 100,
            'active': True,
            'mode': 'primary',
            'arch_base': ''
        }
        form_tmpl = u'''<?xml version="1.0"?>
            <form string="%(form_name)s">
                    <group col="4">
                        %(fields)s
                    </group>
                    <footer>
                        <button context="{'wizard_id': active_id}" string="确定" name="action_for_report_search" type="object" class="btn-primary"/>
                        <button string="取消" class="btn-default" special="cancel"/>
                    </footer>
            </form>'''
        field_tmpl = u'<field name="%s"/>'
        field_xml_list = []
        if self.search_model and self.search_model.id and self.search_model.field_id:
            for field in self.search_model.field_id:
                if field.name.startswith("x_"):
                    field_xml_list.append(field_tmpl % field.name)
        # if not field_xml_list:
        #     return
        fields_xml = "\r\n".join(field_xml_list)
        form_val = {
            'form_name': self.search_model.name,
            'fields': fields_xml
        }
        form_xml = form_tmpl % form_val
        view_val.update({
            'arch_base': form_xml,
            'name': self.search_model.name + "_report_search_view",
        })
        view_model = self.env['ir.ui.view']
        self.form_view_code = form_xml
        if self.search_view and self.search_view.id:
            self.search_view.write(view_val)
        else:
            search_view = view_model.create(view_val)
            # self.write({'search_model': search_model.id})#会死循环，用SQL代替
            sql = "update jd_table_datasource set search_view=%s where id=%s"
            self.env.cr.execute(sql, (search_view.id, self.id))

    @api.multi
    def get_onchange_method(self):
        self.ensure_one()
        item = self[0]
        methods = []
        method_names = []
        import re
        for line in item.onchange_method_line_ids:
            methods.append(line.method_code)
            search_obj = re.search(r'def (.*)\(self\)', line.method_code)
            if search_obj:
                method_names.append(search_obj.group(1))
        return {'methods': methods, 'method_names': method_names}

    # def make_function(self, text):
    #     """ Return a compute function from its code body and dependencies. """
    #     func = lambda self: safe_eval(text, SAFE_EVAL_BASE, {'self': self}, mode="exec")
    #     # deps = [arg.strip() for arg in deps.split(",")] if deps else []
    #     return func

    def add_method(self):
        ModelClass = type(self.env[self.search_model.model])
        for method in self.get_onchange_method()['methods']:
            try:
                exec(method)
            except Exception as e:
                _logger.error(e)
                _logger.error('method 【%s】 is illegal' % method)
        for method_name in self.get_onchange_method()['method_names']:
            setattr(ModelClass, method_name, eval(method_name))


class JDTableParams(models.Model):
    _name = 'jd.table.params'
    _description = u'报表参数'

    datasource_id = fields.Many2one('jd.table.datasource', string=u'数据源', index=True, ondelete='cascade')
    param = fields.Char(u'参数', required=True)
    name = fields.Char(u'名称', index=True, required=True)
    domain = fields.Char(u'domain', help=u'domain需为domain表达式格式的或为函数')
    default_val = fields.Char(u'默认值')
    ttype = fields.Selection(selection='_get_field_types', string=u'参数类型', required=True)
    relation = fields.Char(u'relation')
    relation_table = fields.Char(string=u'relation table')
    column1 = fields.Char(string=u'Column 1')
    column2 = fields.Char(string=u"Column 2")
    data_source = fields.Many2one('jd.table.datasource', string=u'数据来源', domain=[('type', '=', 'metadata')])
    compute = fields.Text(string=u'compute函数')
    depends = fields.Char(string=u'depends字段')
    selection = fields.Char(string=u'Selection值')
    required = fields.Boolean(string=u'required')
    readonly = fields.Boolean(string=u'readonly')
    store = fields.Boolean(string=u'store', default=True)


    @api.model
    def create(self, vals):
        res = super(JDTableParams, self).create(vals)
        if res.datasource_id.type == 'report':
            #下面几个方法，必须按顺序执行
            if res.datasource_id.reset_view:
                res.datasource_id.reset_filter_view()
            res.datasource_id.create_or_update_filter_model()
            if res.datasource_id.reset_view:
                res.datasource_id.create_or_update_filter_view()
        return res

    @api.multi
    def write(self, vals):
        res = super(JDTableParams, self).write(vals)
        if self[0].datasource_id.type == 'report':
            # self[0].datasource_id.reset_filter_view()
            self[0].datasource_id.create_or_update_filter_model()
            # if 'param' in vals:
            #     raise ValidationError(u'暂不支持直接修改字段名，请先删除后重新创建一个字段')
                # self[0].datasource_id.reset_filter_view()
                # self[0].datasource_id.create_or_update_filter_model()
                # self[0].datasource_id.create_or_update_filter_view()
        return res

    @api.multi
    def unlink(self):
        """
        删除字段时必须更新视图
        :return:
        """
        for item in self:
            if item.datasource_id.type == 'report':
                item.datasource_id.reset_filter_view()
                item.datasource_id.create_or_update_filter_model()
                item.datasource_id.create_or_update_filter_view()
                # 更新form_view_code
                param = 'x_' + item.param[1:]
                item.datasource_id.form_view_code = re.sub('<field name="%s"\/>' % param, "", item.datasource_id.form_view_code)
                item.datasource_id.search_view.arch_base = re.sub('<field name="%s"\/>' % param, "", item.datasource_id.search_view.arch_base)
        return super(JDTableParams, self).unlink()

    @api.model
    def _get_field_types(self):
        return sorted((key, key) for key in fields.MetaField.by_type)
    
    @api.multi
    def edit_compute_method(self):
        """
        修改compute方法
        :return:
        """
        return {
            'name': '修改compute方法',
            'type': 'ir.actions.act_window',
            'model': 'ir.actions.act_window',
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': 'jd.rpt.wizard.compute.method',
            'target': 'new',
            'view_id': False,
            'context': {'edit': True}
        }


class JdTableOnChangeMethodLine(models.Model):
    _name = 'jd.table.datasource.onchange.method.line'
    _description = u'onchange方法列表'

    parent_id = fields.Many2one('jd.table.datasource', string=u'数据源', index=True, ondelete='cascade')
    method_code = fields.Text(string=u'方法代码')

    @api.model
    def create(self, vals):
        res = super(JdTableOnChangeMethodLine, self).create(vals)
        if res.parent_id.type == 'report':
            res.parent_id.add_method()
        return res

    @api.multi
    def write(self, vals):
        res = super(JdTableOnChangeMethodLine, self).write(vals)
        if self[0].parent_id.type == 'report':
            self[0].parent_id.add_method()
        return res

    @api.multi
    def edit_onchange_method(self):
        """
        修改onchange方法
        :return:
        """
        return {
            'name': '修改onchange方法',
            'type': 'ir.actions.act_window',
            'model': 'ir.actions.act_window',
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': 'jd.rpt.wizard.onchange.method',
            'target': 'new',
            'view_id': False,
            'context': {'edit': True}
        }

