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

from odoo import models, fields, api, exceptions
from odoo.exceptions import ValidationError
from odoo import SUPERUSER_ID
import logging

_logger = logging.getLogger(__name__)


class WizardAccessConfig(models.TransientModel):
    _name = 'wizard.jd.access.controls.config'
    _description = u'权限生成器'

    menu_ids = fields.Many2many('jd.ir.ui.menu.config',
                                'rel_jd_base_wizard_jd_access_controls_menu_config',
                                'left_id',
                                'right_id', string=u'菜单')
    group_id = fields.Many2one('res.groups', string=u'群组（功能包）', required=True, ondelete='cascade')
    note = fields.Text(string=u'菜单对应模型', compute=u'get_note', store=True)

    @api.multi
    @api.onchange('group_id')
    def on_group_id_change(self):
        """
        群组发生变化时带出已有的菜单项
        :return:
        """
        for record in self:
            if record.group_id:
                exist_menu_ids = record.group_id.menu_ids.ids
                record.menu_ids = [(6, 0, exist_menu_ids)]

    @api.model
    def create(self, vals):
        menu_ids = vals.get('menu_ids')
        new_menu_ids = []
        if any(m[0] == 6 for m in menu_ids):
            for m in menu_ids:
                if m[0] == 6:
                    new_menu_ids = m[2]
        else:
            for m in menu_ids:
                if m[0] != 6:
                    new_menu_ids.append(m[1])
        vals.update({
            'menu_ids': [(6, 0, new_menu_ids)]
        })
        return super(WizardAccessConfig, self).create(vals)

    @api.multi
    @api.depends('menu_ids')
    def get_note(self):
        """
        :return:
        """
        for record in self:
            if record.menu_ids:
                sql = '''
                SELECT a.res_model AS model_name, 
                       a.name AS menu_name
                       FROM ir_act_window a
                WHERE a.id IN (SELECT SUBSTRING(m.action, '\d+')::INTEGER AS id 
                                      FROM ir_ui_menu m 
                               WHERE m.action IS NOT NULL
                               AND m.id in %s)
                '''
                menu_ids = []
                for m in record.menu_ids:
                    menu_ids.append(m.menu_id.id)
                self.env.cr.execute(sql, (tuple(menu_ids),))
                rs = self.env.cr.dictfetchall()
                message = u"已选择的菜单详情如下：\r\n"
                for r in rs:
                    message += u'菜单名：%s,对应的模型为【%s】\r\n' % (r['menu_name'], r['model_name'])
                record.note = message

    @api.multi
    def get_score(self, perm_read, perm_write, perm_create, perm_unlink, perm_audit, perm_unaudit):
        count_read, count_write, count_create, count_unlink, count_audit, count_unaudit = 0, 0, 0, 0, 0, 0
        if perm_read:
            count_read += 1
        if perm_write:
            count_write += 1
        if perm_create:
            count_create += 1
        if perm_unlink:
            count_unlink += 1
        if perm_audit:
            count_audit += 1
        if perm_unaudit:
            count_unaudit += 1
        return {
            'count_read': count_create,
            'count_write': count_write,
            'count_create': count_create,
            'count_unlink': count_unlink,
            'count_audit': count_audit,
            'count_unaudit': count_unaudit,
        }

    @api.multi
    def get_temp_perm(self, count_read, count_write, count_create, count_unlink, count_audit, count_unaudit):
        temp_perm_read, temp_perm_write, temp_perm_create, temp_perm_unlink, temp_perm_audit, temp_perm_unaudit \
            = False, False, False, False, False, False
        if count_read > 0:
            temp_perm_read = True
        if count_write:
            temp_perm_write = True
        if count_create:
            temp_perm_create = True
        if count_unlink:
            temp_perm_unlink = True
        if count_audit:
            temp_perm_audit = True
        if count_unaudit:
            temp_perm_unaudit = True
        return {
            'temp_perm_read': temp_perm_read,
            'temp_perm_write': temp_perm_write,
            'temp_perm_create': temp_perm_create,
            'temp_perm_unlink': temp_perm_unlink,
            'temp_perm_audit': temp_perm_audit,
            'temp_perm_unaudit': temp_perm_unaudit,
        }

    @api.multi
    def get_final_perm(self, temp_ma_list, after_perm_read, after_perm_write, after_perm_create, after_perm_unlink,
                       after_perm_audit, after_perm_unaudit):
        """
        :return:
        """
        count_read, count_write, count_create, count_unlink, count_audit, count_unaudit = 1, 0, 0, 0, 0, 0
        for temp in temp_ma_list:
            count = self.get_score(temp.perm_read, temp.perm_write, temp.perm_create, temp.perm_unlink,
                                   temp.perm_audit, temp.perm_unaudit)
            count_read += count['count_read']
            count_write += count['count_write']
            count_create += count['count_create']
            count_unlink += count['count_unlink']
            count_audit += count['count_audit']
            count_unaudit += count['count_unaudit']
        before_temp_perm = self.get_temp_perm(count_read, count_write, count_create, count_unlink, count_audit,
                                              count_unaudit)
        temp_perm_read = before_temp_perm['temp_perm_read']
        temp_perm_write = before_temp_perm['temp_perm_write']
        temp_perm_create = before_temp_perm['temp_perm_create']
        temp_perm_unlink = before_temp_perm['temp_perm_unlink']
        temp_perm_audit = before_temp_perm['temp_perm_audit']
        temp_perm_unaudit = before_temp_perm['temp_perm_unaudit']
        score = self.get_score(temp_perm_read | after_perm_read,
                               temp_perm_write | after_perm_write,
                               temp_perm_create | after_perm_create,
                               temp_perm_unlink | after_perm_unlink,
                               temp_perm_audit | after_perm_audit,
                               temp_perm_unaudit | after_perm_unaudit)
        count_read += score['count_read']
        count_write += score['count_write']
        count_create += score['count_create']
        count_unlink += score['count_unlink']
        count_audit += score['count_audit']
        count_unaudit += score['count_unaudit']
        after_temp_perm = self.get_temp_perm(count_read, count_write, count_create, count_unlink, count_audit,
                                             count_unaudit)
        return {
            'before_temp_perm': before_temp_perm,
            'after_temp_perm': after_temp_perm
        }

    @api.multi
    def get_menu_ids(self, act_window_ids):
        """
        根据model_id查询对应的menu_ids
        :param model_id:
        :return:
        """
        sql = '''
            SELECT id,action,name
            FROM ir_ui_menu
            WHERE substring(action, '\d+')::INTEGER IN %s
        '''
        self.env.cr.execute(sql, (tuple(act_window_ids),))
        rs = self.env.cr.dictfetchall()
        menu_ids = [r['id'] for r in rs]
        return menu_ids

    @api.multi
    def get_model(self, model_id):
        """
        :param model_id:
        :return:
        """
        sql = '''
              SELECT id, model FROM ir_model WHERE id = %s
        '''
        self.env.cr.execute(sql, (model_id,))
        res_model = self.env.cr.dictfetchone()['model']
        return res_model

    @api.multi
    def get_act_ids(self, model_name):
        """
        :param model_name:
        :return:
        """
        sql = '''
               SELECT id FROM ir_act_window WHERE res_model = %s
        '''
        self.env.cr.execute(sql, (model_name,))
        return [r['id'] for r in self.env.cr.dictfetchall()]

    @api.multi
    def unlink_acl(self, unlink_ids):
        if unlink_ids:
            unlink_sql = '''
                            delete from ir_model_access where id in %s
                        '''
            self.env.cr.execute(unlink_sql, (tuple(unlink_ids),))

    @api.multi
    def create_acl(self, model, dict, group_id):
        sql_insert = '''
        DO $$
        DECLARE
          v_access_id INT;
        BEGIN
          -- 查找当前群组是否已有 指定模型的访问权
          SELECT ma.id
          INTO v_access_id
          FROM ir_model_access ma
          WHERE ma.group_id = %(group_id)s
                AND ma.model_id = %(model_id)s
          ORDER BY ma.id DESC
          LIMIT 1;
        
          IF v_access_id IS NOT NULL
          THEN
            UPDATE ir_model_access ma
            SET
              active       = TRUE,
              perm_read    = %(perm_read)s,
              perm_write   = %(perm_write)s,
              perm_unlink  = %(perm_unlink)s,
              perm_create  = %(perm_create)s,
              perm_audit   = %(perm_audit)s,
              perm_unaudit = %(perm_unaudit)s,
              perm_export  = %(perm_export)s
            WHERE ma.id = v_access_id;
          ELSE
        
            INSERT INTO ir_model_access
            (name, model_id, group_id, active, perm_read,
             perm_write, perm_unlink, perm_create, perm_audit, perm_unaudit, perm_export)
            VALUES
              (%(name)s, %(model_id)s, %(group_id)s, TRUE, %(perm_read)s,
               %(perm_write)s, %(perm_unlink)s, %(perm_create)s, %(perm_audit)s, %(perm_unaudit)s, %(perm_export)s);
          END IF;
        END;
        $$
        '''
        params = {
            'name': model.name,
            'model_id': model.id,
            'group_id': group_id,
            'perm_read': dict.get('temp_perm_read', False),
            'perm_write': dict.get('temp_perm_write', False),
            'perm_unlink': dict.get('temp_perm_unlink', False),
            'perm_create': dict.get('temp_perm_create', False),
            'perm_audit': dict.get('temp_perm_audit', False),
            'perm_unaudit': dict.get('temp_perm_unaudit', False),
            'perm_export': dict.get('temp_perm_export', False),
        }
        cr = self.env.cr
        cr.execute(sql_insert, params)

        sql_search = '''
        SELECT ma.id AS access_id
          FROM ir_model_access ma
          WHERE ma.group_id = %(group_id)s
                AND ma.model_id = %(model_id)s
          ORDER BY ma.id DESC
          LIMIT 1;
        '''
        params = {
            'group_id': group_id,
            'model_id': model.id
        }
        cr.execute(sql_search, params)
        rec = cr.dictfetchone()
        if rec and rec.get('access_id'):
            access_id = rec.get('access_id')
        else:
            access_id = None
        return access_id

    @api.multi
    def create_model_acl_by_menu_ids(self, group_id, menu_config_ids):
        """
         menu_config_ids 为选择的所有菜单项的记录集
        :param group_id:
        :param menu_config_ids:
        :param model_id:
        :return:
        """
        cr = self.env.cr

        # 1、根据关联菜单项配置，插入菜单直接关联模型的权限
        sql = """
        DO $$
        DECLARE
          rec          RECORD;
          count_access INT;
        BEGIN
          -- 根据关联菜单项配置，插入菜单直接关联模型的权限
          FOR rec IN (
            SELECT
              coalesce(mu.model_name, '无名称') AS model_name,
              mu.model_id                    AS model_id,
              CASE WHEN
                TRUE = ANY (mu.perm_read)
                THEN TRUE
              ELSE FALSE
              END                            AS perm_read,
              CASE WHEN
                TRUE = ANY (mu.perm_write)
                THEN TRUE
              ELSE FALSE
              END                            AS perm_write,
              CASE WHEN
                TRUE = ANY (mu.perm_create)
                THEN TRUE
              ELSE FALSE
              END                            AS perm_create,
              CASE WHEN
                TRUE = ANY (mu.perm_unlink)
                THEN TRUE
              ELSE FALSE
              END                            AS perm_unlink,
              CASE WHEN
                TRUE = ANY (mu.perm_audit)
                THEN TRUE
              ELSE FALSE
              END                            AS perm_audit,
              CASE WHEN
                TRUE = ANY (mu.perm_unaudit)
                THEN TRUE
              ELSE FALSE
              END                            AS perm_unaudit
            FROM
              (
                SELECT
                  DISTINCT ON (md.model_id)
                  md.model_id                         AS model_id,
                  md.model_name                       AS model_name,
                  array_agg(DISTINCT mc.perm_read)    AS perm_read,
                  array_agg(DISTINCT mc.perm_write)   AS perm_write,
                  array_agg(DISTINCT mc.perm_create)  AS perm_create,
                  array_agg(DISTINCT mc.perm_unlink)  AS perm_unlink,
                  array_agg(DISTINCT mc.perm_audit)   AS perm_audit,
                  array_agg(DISTINCT mc.perm_unaudit) AS perm_unaudit
                FROM res_groups rg
                  INNER JOIN jd_menu_config_base_res_group rel ON rel.left_id = rg.id
                  INNER JOIN jd_ir_ui_menu_config mc ON mc.id = rel.right_id
                  INNER JOIN ir_ui_menu mu ON mu.id = mc.menu_id
                  INNER JOIN
                  (
                    -- 计算每个菜单关联的模型
                    SELECT
                      mu.id   AS menu_id,
                      md.id   AS model_id,
                      md.name AS model_name
                    FROM ir_ui_menu mu
                      INNER JOIN (SELECT
                                    id,
                                    res_model
                                  FROM ir_act_window) act ON act.id = substring(mu.action, '\d+') :: INTEGER
                      INNER JOIN (SELECT
                                    id,
                                    model,
                                    name
                                  FROM ir_model) md ON md.model = act.res_model
                    WHERE mu.action IS NOT NULL
                  ) md ON md.menu_id = mu.id
                WHERE rg.id = %(group_id)s
                GROUP BY md.model_id, md.model_name
                ORDER BY md.model_id
              ) mu
          ) LOOP
            -- 查找当前群组是否已有此模型的访问权
            SELECT count(1)
            INTO count_access
            FROM ir_model_access ma
            WHERE ma.group_id = %(group_id)s
                  AND ma.model_id = rec.model_id;

            IF count_access > 0
            THEN
              UPDATE ir_model_access ma
              SET
                active       = TRUE,
                name         = rec.model_name,
                perm_read    = coalesce(rec.perm_read, perm_read),
                perm_write   = coalesce(rec.perm_write, perm_write),
                perm_create  = coalesce(rec.perm_create, perm_create),
                perm_unlink  = coalesce(rec.perm_unlink, perm_unlink),
                perm_audit   = coalesce(rec.perm_audit, perm_audit),
                perm_unaudit = coalesce(rec.perm_unaudit, perm_unaudit)
              WHERE ma.group_id = %(group_id)s
                    AND ma.model_id = rec.model_id;
            ELSE
              INSERT INTO ir_model_access
              (name, model_id, group_id, active, perm_read,
               perm_write, perm_unlink, perm_create, perm_audit, perm_unaudit)
              VALUES
                (rec.model_name, rec.model_id, %(group_id)s, TRUE, rec.perm_read,
                 rec.perm_write, rec.perm_unlink, rec.perm_create, rec.perm_audit, rec.perm_unaudit);
            END IF;
          END LOOP;
        END;
        $$
        """
        params = {
            'group_id': group_id
        }
        cr.execute(sql, params)

        # 2、根据关联菜单项配置，插入菜单模型涉及到的 many2one、many2many、one2many 模型的 读 权限
        sql = """
        DO $$
        DECLARE
          rec          RECORD;
          count_access INT;
        BEGIN
          -- 根据关联菜单项配置，插入菜单模型涉及到的 many2one、many2many、one2many 模型的 读 权限
          FOR rec IN (
            SELECT DISTINCT
              md.model_id AS model_id,
              mf.relation AS relation,
              md.name     AS model_name
            FROM ir_model_fields mf
              INNER JOIN (
                           SELECT
                             md.id    AS model_id,
                             md.model AS model,
                             md.name  AS name
                           FROM ir_model md
                         ) md ON md.model = mf.relation
            WHERE mf.model_id = ANY (array(SELECT
                                             DISTINCT md.model_id AS model_id
                                           FROM res_groups rg
                                             INNER JOIN jd_menu_config_base_res_group rel ON rel.left_id = rg.id
                                             INNER JOIN jd_ir_ui_menu_config mc ON mc.id = rel.right_id
                                             INNER JOIN ir_ui_menu mu ON mu.id = mc.menu_id
                                             INNER JOIN (
                                                          -- 计算每个菜单关联的模型
                                                          SELECT
                                                            mu.id   AS menu_id,
                                                            md.id   AS model_id,
                                                            md.name AS model_name
                                                          FROM ir_ui_menu mu
                                                            INNER JOIN (SELECT
                                                                          id,
                                                                          res_model
                                                                        FROM ir_act_window) act
                                                              ON act.id = substring(mu.action, '\d+') :: INTEGER
                                                            INNER JOIN (SELECT
                                                                          id,
                                                                          model,
                                                                          name
                                                                        FROM ir_model) md ON md.model = act.res_model
                                                          WHERE mu.action IS NOT NULL
                                                        ) md ON md.menu_id = mu.id
                                           WHERE rg.id = %(group_id)s
                                           ORDER BY md.model_id))
                  AND mf.ttype IN ('many2one', 'many2many', 'one2many')
                  AND left(mf.model, 2) <> 'ir'
                  AND left(mf.model, 3) <> 'web'
                  AND left(mf.model, 4) <> 'mail'
                  AND left(mf.model, 4) <> 'base'
                  AND left(mf.model, 6) <> 'report'
                  AND left(mf.model, 7) <> 'resource'
                  AND left(mf.model, 8) <> 'calendar'
                  AND left(mf.model, 8) <> 'workflow'
                  AND left(mf.model, 9) <> 'fetchmail'
          ) LOOP
            -- 查找当前群组是否已有此模型的访问权
            SELECT count(1)
            INTO count_access
            FROM ir_model_access ma
            WHERE ma.group_id = %(group_id)s
                  AND ma.model_id = rec.model_id;

            IF count_access > 0
            THEN
              UPDATE ir_model_access ma
              SET
                active       = TRUE,
                name         = rec.model_name,
                perm_read    = TRUE,
                perm_write   = coalesce(perm_write, FALSE),
                perm_create  = coalesce(perm_create, FALSE),
                perm_unlink  = coalesce(perm_unlink, FALSE),
                perm_audit   = coalesce(perm_audit, FALSE),
                perm_unaudit = coalesce(perm_unaudit, FALSE)
              WHERE ma.group_id = %(group_id)s
                    AND ma.model_id = rec.model_id;
            ELSE
              INSERT INTO ir_model_access
              (name, model_id, group_id, active, perm_read,
               perm_write, perm_unlink, perm_create, perm_audit, perm_unaudit)
              VALUES
                (rec.model_name, rec.model_id, %(group_id)s, TRUE, TRUE,
                 FALSE, FALSE, FALSE, FALSE, FALSE);
            END IF;
          END LOOP;
        END;
        $$
        """
        cr.execute(sql, params)

        # 3、给关联菜单项配置涉及到的 one2many 模型赋权，权限项与表头模型的访问权一致
        sql = """
        SELECT DISTINCT
          md.model_id       AS relation_model_id,
          mf.relation       AS relation,
          md.name           AS model_name,
          mf.model          AS model,
          mf.model_id       AS model_id,
          mf.relation_field AS relation_field
        FROM ir_model_fields mf
          INNER JOIN (
                       SELECT
                         md.id    AS model_id,
                         md.model AS model,
                         md.name  AS name
                       FROM ir_model md
                     ) md ON md.model = mf.relation
        WHERE mf.model_id = ANY (array(SELECT
                                         DISTINCT md.model_id AS model_id
                                       FROM res_groups rg
                                         INNER JOIN jd_menu_config_base_res_group rel ON rel.left_id = rg.id
                                         INNER JOIN jd_ir_ui_menu_config mc ON mc.id = rel.right_id
                                         INNER JOIN ir_ui_menu mu ON mu.id = mc.menu_id
                                         INNER JOIN (
                                                      -- 计算每个菜单关联的模型
                                                      SELECT
                                                        mu.id   AS menu_id,
                                                        md.id   AS model_id,
                                                        md.name AS model_name
                                                      FROM ir_ui_menu mu
                                                        INNER JOIN (SELECT
                                                                      id,
                                                                      res_model
                                                                    FROM ir_act_window) act
                                                          ON act.id = substring(mu.action, '\d+') :: INTEGER
                                                        INNER JOIN (SELECT
                                                                      id,
                                                                      model,
                                                                      name
                                                                    FROM ir_model) md ON md.model = act.res_model
                                                      WHERE mu.action IS NOT NULL
                                                    ) md ON md.menu_id = mu.id
                                       WHERE rg.id = %(group_id)s
                                       ORDER BY md.model_id))
              AND mf.ttype IN ('one2many')
              AND left(mf.model, 2) <> 'ir'
              AND left(mf.model, 3) <> 'web'
              AND left(mf.model, 4) <> 'mail'
              AND left(mf.model, 4) <> 'base'
              AND left(mf.model, 6) <> 'report'
              AND left(mf.model, 7) <> 'resource'
              AND left(mf.model, 8) <> 'calendar'
              AND left(mf.model, 8) <> 'workflow'
              AND left(mf.model, 9) <> 'fetchmail'
              AND mf.relation_field IS NOT NULL
              AND mf.relation <> mf.model
        """
        cr.execute(sql, params)
        recs = cr.dictfetchall()
        if recs:
            for rec in recs:
                relation_model_id = rec.get('relation_model_id')  # 关联模型ID
                relation = rec.get('relation')  # 关联模型
                model_name = rec.get('model_name')  # 关联模型名称
                model = rec.get('model')  # 表头模型
                model_id = rec.get('model_id')  # 表头模型ID
                relation_field = rec.get('relation_field')  # 关联字段

                try:
                    ondelete = self.env[relation]._fields[relation_field].ondelete
                except Exception as e:
                    ondelete = 'set null'
                # 根据 关联字段的 ondelete 属性判断，如果是 cascade，则one2many字段强关联与表头的权限一致，否则只有读权限
                # 由于第2步已经给所有 one2many 字段模型的 读 权限，故此处只需要处理强关联的权限
                if ondelete == 'cascade':
                    sql = """
                    DO $$
                    DECLARE
                      v_relation_access_id INT;
                      v_perm_write         BOOLEAN;
                      v_perm_create        BOOLEAN;
                      v_perm_unlink        BOOLEAN;
                      v_perm_audit         BOOLEAN;
                      v_perm_unaudit       BOOLEAN;
                    BEGIN
                      -- 查找当前群组中，表头模型的访问权
                      SELECT DISTINCT ON (ma.model_id)
                        coalesce(ma.perm_write, FALSE),
                        coalesce(ma.perm_create, FALSE),
                        coalesce(ma.perm_unlink, FALSE),
                        coalesce(ma.perm_audit, FALSE),
                        coalesce(ma.perm_unaudit, FALSE)
                      INTO
                        v_perm_write,
                        v_perm_create,
                        v_perm_unlink,
                        v_perm_audit,
                        v_perm_unaudit
                      FROM ir_model_access ma
                      WHERE ma.group_id = %(group_id)s
                            AND ma.model_id = %(model_id)s
                      ORDER BY ma.model_id, ma.id DESC;

                      -- 查找当前群组是否已有 one2many 字段关联模型的访问权
                      SELECT ma.id
                      INTO v_relation_access_id
                      FROM ir_model_access ma
                      WHERE ma.group_id = %(group_id)s
                            AND ma.model_id = %(relation_model_id)s
                      ORDER BY ma.id DESC
                      LIMIT 1;

                      IF v_relation_access_id IS NOT NULL
                      -- 如果有关联模型的访问权，且权限项为 FALSE 时，则更新为与表头模型一致的访问权
                      THEN
                        UPDATE ir_model_access ma
                        SET
                          active       = TRUE,
                          perm_read    = TRUE,
                          perm_write   = (CASE
                                          WHEN perm_write = TRUE
                                            THEN perm_write
                                          ELSE v_perm_write END),
                          perm_create  = (CASE
                                          WHEN perm_create = TRUE
                                            THEN perm_create
                                          ELSE v_perm_create END),
                          perm_unlink  = (CASE
                                          WHEN perm_unlink = TRUE
                                            THEN perm_unlink
                                          ELSE v_perm_unlink END),
                          perm_audit   = (CASE
                                          WHEN perm_audit = TRUE
                                            THEN perm_audit
                                          ELSE v_perm_audit END),
                          perm_unaudit = (CASE
                                          WHEN perm_unaudit = TRUE
                                            THEN perm_unaudit
                                          ELSE v_perm_unaudit END)
                        WHERE ma.id = v_relation_access_id;
                      ELSE

                        INSERT INTO ir_model_access
                        (name, model_id, group_id, active, perm_read,
                         perm_write, perm_unlink, perm_create, perm_audit, perm_unaudit)
                        VALUES
                          (%(model_name)s, %(relation_model_id)s, %(group_id)s, TRUE, TRUE,
                           v_perm_write, v_perm_create, v_perm_unlink, v_perm_audit, v_perm_unaudit);
                      END IF;
                    END;
                    $$;
                    """
                    params_access = {
                        'group_id': group_id,
                        'model_id': model_id,
                        'model_name': model_name,
                        'relation_model_id': relation_model_id
                    }
                    cr.execute(sql, params_access)
                self.env['wizard.jd.access.controls.config'].create_model_acl_by_model(group_id, relation)

        # 4、给关联菜单项配置涉及到的 reference 模型赋予 读 权限
        sql = """
        SELECT DISTINCT
          mf.model    AS model,
          mf.model_id AS model_id
        FROM ir_model_fields mf
        WHERE mf.model_id = ANY (array(SELECT
                                         DISTINCT md.model_id AS model_id
                                       FROM res_groups rg
                                         INNER JOIN jd_menu_config_base_res_group rel ON rel.left_id = rg.id
                                         INNER JOIN jd_ir_ui_menu_config mc ON mc.id = rel.right_id
                                         INNER JOIN ir_ui_menu mu ON mu.id = mc.menu_id
                                         INNER JOIN (
                                                      -- 计算每个菜单关联的模型
                                                      SELECT
                                                        mu.id   AS menu_id,
                                                        md.id   AS model_id,
                                                        md.name AS model_name
                                                      FROM ir_ui_menu mu
                                                        INNER JOIN (SELECT
                                                                      id,
                                                                      res_model
                                                                    FROM ir_act_window) act
                                                          ON act.id = substring(mu.action, '\d+') :: INTEGER
                                                        INNER JOIN (SELECT
                                                                      id,
                                                                      model,
                                                                      name
                                                                    FROM ir_model) md ON md.model = act.res_model
                                                      WHERE mu.action IS NOT NULL
                                                    ) md ON md.menu_id = mu.id
                                       WHERE rg.id = %(group_id)s
                                       ORDER BY md.model_id))
              AND mf.ttype IN ('reference')
              AND left(mf.model, 2) <> 'ir'
              AND left(mf.model, 3) <> 'web'
              AND left(mf.model, 4) <> 'mail'
              AND left(mf.model, 4) <> 'base'
              AND left(mf.model, 6) <> 'report'
              AND left(mf.model, 7) <> 'resource'
              AND left(mf.model, 8) <> 'calendar'
              AND left(mf.model, 8) <> 'workflow'
              AND left(mf.model, 9) <> 'fetchmail'
        """
        cr.execute(sql, params)
        recs = cr.dictfetchall()
        if recs:
            for rec in recs:
                model = rec.get('model')  # 表头模型
                model_id = rec.get('model_id')  # 表头模型ID
                # 获取 reference 字段详细关联的 模型
                model_list = self.env[model]._reference_models()
                if len(model_list) > 20:
                    continue
                    # raise ValidationError(u'生成访问权时发现模型【%s】包含reference字段，'
                    #                       u'且该字段未指定具体的模型范围，请联系开发人员检查。'
                    #
                for item in model_list:
                    relation_model = item[0]
                    sql = """
                    DO $$
                    DECLARE
                      v_relation_model_name VARCHAR;
                      v_relation_model_id   INT;
                      v_relation_access_id  INT;
                    BEGIN
                      SELECT
                        md.id,
                        md.name
                      INTO
                        v_relation_model_id,
                        v_relation_model_name
                      FROM ir_model md
                      WHERE md.model = %(relation_model)s;

                      -- 查找当前群组是否已有 指定模型的访问权
                      SELECT ma.id
                      INTO v_relation_access_id
                      FROM ir_model_access ma
                      WHERE ma.group_id = %(group_id)s
                            AND ma.model_id = v_relation_model_id
                      ORDER BY ma.id DESC
                      LIMIT 1;

                      IF v_relation_access_id IS NOT NULL
                      -- 如果有关联模型的访问权，且权限项为 FALSE 时，则更新为与表头模型一致的访问权
                      THEN
                        UPDATE ir_model_access ma
                        SET
                          active    = TRUE,
                          perm_read = TRUE
                        WHERE ma.id = v_relation_access_id;
                      ELSE

                        INSERT INTO ir_model_access
                        (name, model_id, group_id, active, perm_read,
                         perm_write, perm_unlink, perm_create, perm_audit, perm_unaudit)
                        VALUES
                          (v_relation_model_name, v_relation_model_id, %(group_id)s, TRUE, TRUE,
                           FALSE, FALSE, FALSE, FALSE, FALSE);
                      END IF;
                    END;
                    $$;
                    """
                    params_access = {
                        'group_id': group_id,
                        'relation_model': relation_model
                    }
                    cr.execute(sql, params_access)

        # 5、如果是瞬态模型，说明是报表，需指定菜单；如果有inherits属性，则添加代理继承的所有模型访问权
        sql = """
        SELECT
          mu.model_id AS model_id,
          mu.model    AS model,
          mu.menu_ids AS menu_ids,
          CASE WHEN
            TRUE = ANY (mu.perm_read)
            THEN TRUE
          ELSE FALSE
          END         AS perm_read,
          CASE WHEN
            TRUE = ANY (mu.perm_write)
            THEN TRUE
          ELSE FALSE
          END         AS perm_write,
          CASE WHEN
            TRUE = ANY (mu.perm_create)
            THEN TRUE
          ELSE FALSE
          END         AS perm_create,
          CASE WHEN
            TRUE = ANY (mu.perm_unlink)
            THEN TRUE
          ELSE FALSE
          END         AS perm_unlink,
          CASE WHEN
            TRUE = ANY (mu.perm_audit)
            THEN TRUE
          ELSE FALSE
          END         AS perm_audit,
          CASE WHEN
            TRUE = ANY (mu.perm_unaudit)
            THEN TRUE
          ELSE FALSE
          END         AS perm_unaudit,
          CASE WHEN
            TRUE = ANY (mu.perm_confirm)
            THEN TRUE
          ELSE FALSE
          END         AS perm_confirm,
          CASE WHEN
            TRUE = ANY (mu.perm_cancel)
            THEN TRUE
          ELSE FALSE
          END         AS perm_cancel
        FROM
          (
            SELECT
              DISTINCT ON (md.model_id)
              md.model_id                         AS model_id,
              md.model                            AS model,
              array_agg(DISTINCT mu.id)           AS menu_ids,
              array_agg(DISTINCT mc.perm_read)    AS perm_read,
              array_agg(DISTINCT mc.perm_write)   AS perm_write,
              array_agg(DISTINCT mc.perm_create)  AS perm_create,
              array_agg(DISTINCT mc.perm_unlink)  AS perm_unlink,
              array_agg(DISTINCT mc.perm_audit)   AS perm_audit,
              array_agg(DISTINCT mc.perm_unaudit) AS perm_unaudit,
              array_agg(DISTINCT mc.perm_confirm) AS perm_confirm,
              array_agg(DISTINCT mc.perm_cancel)  AS perm_cancel
            FROM res_groups rg
              INNER JOIN jd_menu_config_base_res_group rel ON rel.left_id = rg.id
              INNER JOIN jd_ir_ui_menu_config mc ON mc.id = rel.right_id
              INNER JOIN ir_ui_menu mu ON mu.id = mc.menu_id
              INNER JOIN
              (
                -- 计算每个菜单关联的模型
                SELECT
                  mu.id    AS menu_id,
                  md.id    AS model_id,
                  md.name  AS model_name,
                  md.model AS model
                FROM ir_ui_menu mu
                  INNER JOIN (SELECT
                                id,
                                res_model
                              FROM ir_act_window) act ON act.id = substring(mu.action, '\d+') :: INTEGER
                  INNER JOIN (SELECT
                                id,
                                model,
                                name
                              FROM ir_model) md ON md.model = act.res_model
                WHERE mu.action IS NOT NULL
              ) md ON md.menu_id = mu.id
            WHERE rg.id = %(group_id)s
            GROUP BY md.model_id, md.model
            ORDER BY md.model_id
          ) mu
        """
        params = {
            'group_id': group_id
        }
        cr.execute(sql, params)
        recs = cr.dictfetchall()
        if recs:
            for rec in recs:
                dict = {
                    'temp_perm_read': rec.get('perm_read', False),
                    'temp_perm_write': rec.get('perm_write', False),
                    'temp_perm_create': rec.get('perm_create', False),
                    'temp_perm_unlink': rec.get('perm_unlink', False),
                    'temp_perm_audit': rec.get('perm_audit', False),
                    'temp_perm_unaudit': rec.get('perm_unaudit', False),
                }
                model_id = rec.get('model_id')
                model_name = rec.get('model')
                menu_ids = rec.get('menu_ids', [])
                # 判断模型的is_transient()方法。如果为真,说明是瞬态模型， 同时添加menu_access
                if self.env[model_name].is_transient() and menu_ids:
                    #     group_rec = self.env['res.groups'].sudo().browse(group_id)
                    #     for menu_id in menu_ids:
                    #         group_rec.menu_access = [(4, menu_id)]
                    sql = '''
                    DO
                    $$
                    DECLARE
                      rec     RECORD;
                      v_count INT :=0;
                    BEGIN
                      FOR rec IN (
                        SELECT mn AS menu_id
                        FROM unnest(%(menu_ids)s) AS mn
                      ) LOOP
                        v_count := 0;
                        SELECT count(1)
                        INTO v_count
                        FROM ir_ui_menu_group_rel rel
                        WHERE rel.gid = %(group_id)s
                              AND rel.menu_id = rec.menu_id;
                        IF v_count = 0
                        THEN
                          INSERT INTO ir_ui_menu_group_rel (gid, menu_id) VALUES (%(group_id)s, rec.menu_id);
                        END IF;
                      END LOOP;
                    END;
                    $$
                    '''
                    params_group = {
                        'group_id': group_id,
                        'menu_ids': menu_ids
                    }
                    cr.execute(sql, params_group)
                # 判断该模型是否有inherits属性。如有则添加代理继承的所有模型访问权
                if self.env[model_name]._inherits.iteritems():
                    for k, v in self.env[model_name]._inherits.iteritems():
                        model = self.env['ir.model'].search([('model', '=', k)], limit=1)
                        self.env['wizard.jd.access.controls.config'].create_acl(model=model,
                                                                                dict=dict,
                                                                                group_id=group_id)
                perm_confirm = rec.get('perm_confirm', False)
                perm_cancel = rec.get('perm_cancel', False)
                if perm_confirm or perm_cancel:
                    sql = '''
                    DO $$
                    DECLARE
                      v_access_id INT;
                    BEGIN
                      -- 查找当前群组是否已有 指定模型的按钮访问权
                      SELECT ba.id
                      INTO v_access_id
                      FROM jd_button_access ba
                      WHERE ba.group_id = %(group_id)s
                            AND ba.model_id = %(model_id)s
                      ORDER BY ba.id DESC
                      LIMIT 1;

                      IF v_access_id IS NOT NULL
                      THEN
                        UPDATE jd_button_access ba
                        SET
                          perm_confirm  = (CASE
                                          WHEN perm_unlink = TRUE
                                            THEN perm_unlink
                                          ELSE %(perm_confirm)s END),
                          perm_cancel  = (CASE
                                          WHEN perm_unlink = TRUE
                                            THEN perm_unlink
                                          ELSE %(perm_cancel)s END)
                        WHERE ba.id = v_access_id;
                      ELSE
                        INSERT INTO jd_button_access
                        (model_id, group_id, perm_confirm, perm_cancel)
                        VALUES
                          (%(model_id)s, %(group_id)s, %(perm_confirm)s, %(perm_cancel)s);
                      END IF;
                    END;
                    $$
                    '''
                    params_access = {
                        'model_id': model_id,
                        'group_id': group_id,
                        'perm_confirm': perm_confirm,
                        'perm_cancel': perm_cancel
                    }
                    cr.execute(sql, params_access)
        sql = '''
        SELECT array_agg(ma.id) AS access_ids
        FROM ir_model_access ma
        WHERE ma.group_id = %(group_id)s
        '''
        params = {
            'group_id': group_id
        }
        cr.execute(sql, params)
        rec = cr.dictfetchone()
        access_ids = rec.get('access_ids')
        return access_ids

    @api.multi
    def create_model_acl_by_model(self, group_id, model, perm_read=None, perm_write=None, perm_create=None,
                                  perm_unlink=None, perm_audit=None, perm_unaudit=None, perm_export=None):
        """
        :param group_id:
        :param model_id:
        :return:
        """
        cr = self.env.cr
        # 1、插入指定模型涉及到的 many2one、many2many、one2many 模型的 读 权限
        sql = """
        DO $$
        DECLARE
          rec          RECORD;
          count_access INT;
        BEGIN
          -- 插入指定模型涉及到的 many2one、many2many、one2many 模型的 读 权限
          FOR rec IN (
            SELECT DISTINCT
              md.model_id AS model_id,
              mf.relation AS relation,
              md.name     AS model_name
            FROM ir_model_fields mf
              INNER JOIN (
                           SELECT
                             md.id    AS model_id,
                             md.model AS model,
                             md.name  AS name
                           FROM ir_model md
                         ) md ON md.model = mf.relation
            WHERE mf.model = %(model)s
                  AND mf.ttype IN ('many2one', 'many2many', 'one2many')
                  AND left(mf.model, 2) <> 'ir'
                  AND left(mf.model, 3) <> 'web'
                  AND left(mf.model, 4) <> 'mail'
                  AND left(mf.model, 4) <> 'base'
                  AND left(mf.model, 6) <> 'report'
                  AND left(mf.model, 7) <> 'resource'
                  AND left(mf.model, 8) <> 'calendar'
                  AND left(mf.model, 8) <> 'workflow'
                  AND left(mf.model, 9) <> 'fetchmail'
          ) LOOP
            -- 查找当前群组是否已有此模型的访问权
            SELECT count(1)
            INTO count_access
            FROM ir_model_access ma
            WHERE ma.group_id = %(group_id)s
                  AND ma.model_id = rec.model_id;
        
            IF count_access > 0
            THEN
              UPDATE ir_model_access ma
              SET
                active       = TRUE,
                name         = rec.model_name,
                perm_read    = TRUE,
                perm_write   = coalesce(perm_write, FALSE),
                perm_create  = coalesce(perm_create, FALSE),
                perm_unlink  = coalesce(perm_unlink, FALSE),
                perm_audit   = coalesce(perm_audit, FALSE),
                perm_unaudit = coalesce(perm_unaudit, FALSE),
                perm_export = coalesce(perm_export, FALSE)
              WHERE ma.group_id = %(group_id)s
                    AND ma.model_id = rec.model_id;
            ELSE
              INSERT INTO ir_model_access
              (name, model_id, group_id, active, perm_read,
               perm_write, perm_unlink, perm_create, perm_audit, perm_unaudit, perm_export)
              VALUES
                (rec.model_name, rec.model_id, %(group_id)s, TRUE, TRUE,
                 FALSE, FALSE, FALSE, FALSE, FALSE, FALSE);
            END IF;
          END LOOP;
        END;
        $$
        """
        params = {
            'group_id': group_id,
            'model': model
        }
        cr.execute(sql, params)

        # 2、涉及到的 one2many 模型赋权，权限项与表头模型的访问权一致
        sql = '''
        SELECT DISTINCT
          md.model_id       AS relation_model_id,
          mf.relation       AS relation,
          md.name           AS model_name,
          mf.model          AS model,
          mf.model_id       AS model_id,
          mf.relation_field AS relation_field
        FROM ir_model_fields mf
          INNER JOIN (
                       SELECT
                         md.id    AS model_id,
                         md.model AS model,
                         md.name  AS name
                       FROM ir_model md
                     ) md ON md.model = mf.relation
        WHERE mf.model = %(model)s
              AND mf.ttype IN ('one2many')
              AND left(mf.model, 2) <> 'ir'
              AND left(mf.model, 3) <> 'web'
              AND left(mf.model, 4) <> 'mail'
              AND left(mf.model, 4) <> 'base'
              AND left(mf.model, 6) <> 'report'
              AND left(mf.model, 7) <> 'resource'
              AND left(mf.model, 8) <> 'calendar'
              AND left(mf.model, 8) <> 'workflow'
              AND left(mf.model, 9) <> 'fetchmail'
              AND mf.relation_field IS NOT NULL
              AND mf.relation <> mf.model
        '''
        cr.execute(sql, params)
        recs = cr.dictfetchall()
        if recs:
            for rec in recs:
                relation_model_id = rec.get('relation_model_id')  # 关联模型ID
                relation = rec.get('relation')  # 关联模型
                model_name = rec.get('model_name')  # 关联模型名称
                model = rec.get('model')  # 表头模型
                model_id = rec.get('model_id')  # 表头模型ID
                relation_field = rec.get('relation_field')  # 关联字段

                try:
                    ondelete = self.env[relation]._fields[relation_field].ondelete
                except Exception as e:
                    ondelete = 'set null'
                # 根据 关联字段的 ondelete 属性判断，如果是 cascade，则one2many字段强关联与表头的权限一致，否则只有读权限
                # 由于第2步已经给所有 one2many 字段模型的 读 权限，故此处只需要处理强关联的权限
                if ondelete == 'cascade':
                    sql = """
                    DO $$
                    DECLARE
                      v_relation_access_id INT;
                      v_perm_write         BOOLEAN;
                      v_perm_create        BOOLEAN;
                      v_perm_unlink        BOOLEAN;
                      v_perm_audit         BOOLEAN;
                      v_perm_unaudit       BOOLEAN;
                      v_perm_export        BOOLEAN;
                    BEGIN
                      -- 查找当前群组中，表头模型的访问权
                      SELECT DISTINCT ON (ma.model_id)
                        coalesce(ma.perm_write, FALSE),
                        coalesce(ma.perm_create, FALSE),
                        coalesce(ma.perm_unlink, FALSE),
                        coalesce(ma.perm_audit, FALSE),
                        coalesce(ma.perm_unaudit, FALSE),
                        coalesce(ma.perm_export, FALSE)
                      INTO
                        v_perm_write,
                        v_perm_create,
                        v_perm_unlink,
                        v_perm_audit,
                        v_perm_unaudit,
                        v_perm_export
                      FROM ir_model_access ma
                      WHERE ma.group_id = %(group_id)s
                            AND ma.model_id = %(model_id)s
                      ORDER BY ma.model_id, ma.id DESC;

                      -- 查找当前群组是否已有 one2many 字段关联模型的访问权
                      SELECT ma.id
                      INTO v_relation_access_id
                      FROM ir_model_access ma
                      WHERE ma.group_id = %(group_id)s
                            AND ma.model_id = %(relation_model_id)s
                      ORDER BY ma.id DESC
                      LIMIT 1;

                      IF v_relation_access_id IS NOT NULL
                      -- 如果有关联模型的访问权，且权限项为 FALSE 时，则更新为与表头模型一致的访问权
                      THEN
                        UPDATE ir_model_access ma
                        SET
                          active       = TRUE,
                          perm_read    = TRUE,
                          perm_write   = (CASE
                                          WHEN perm_write = TRUE
                                            THEN perm_write
                                          ELSE v_perm_write END),
                          perm_create  = (CASE
                                          WHEN perm_create = TRUE
                                            THEN perm_create
                                          ELSE v_perm_create END),
                          perm_unlink  = (CASE
                                          WHEN perm_unlink = TRUE
                                            THEN perm_unlink
                                          ELSE v_perm_unlink END),
                          perm_audit   = (CASE
                                          WHEN perm_audit = TRUE
                                            THEN perm_audit
                                          ELSE v_perm_audit END),
                          perm_unaudit = (CASE
                                          WHEN perm_unaudit = TRUE
                                            THEN perm_unaudit
                                          ELSE v_perm_unaudit END),
                          perm_export = (CASE
                                          WHEN perm_export = TRUE
                                            THEN perm_export
                                          ELSE v_perm_export END)
                        WHERE ma.id = v_relation_access_id;
                      ELSE

                        INSERT INTO ir_model_access
                        (name, model_id, group_id, active, perm_read,
                         perm_write, perm_unlink, perm_create, perm_audit, perm_unaudit, perm_export)
                        VALUES
                          (%(model_name)s, %(relation_model_id)s, %(group_id)s, TRUE, TRUE,
                           v_perm_write, v_perm_create, v_perm_unlink, v_perm_audit, v_perm_unaudit, v_perm_export);
                      END IF;
                    END;
                    $$;
                    """
                    params_access = {
                        'group_id': group_id,
                        'model_id': model_id,
                        'model_name': model_name,
                        'relation_model_id': relation_model_id
                    }
                    cr.execute(sql, params_access)

        # 4、给涉及到的 reference 模型赋予 读 权限
        sql = """
        SELECT DISTINCT
          mf.model    AS model,
          mf.model_id AS model_id
        FROM ir_model_fields mf
        WHERE mf.model = %(model)s
              AND mf.ttype IN ('reference')
              AND left(mf.model, 2) <> 'ir'
              AND left(mf.model, 3) <> 'web'
              AND left(mf.model, 4) <> 'mail'
              AND left(mf.model, 4) <> 'base'
              AND left(mf.model, 6) <> 'report'
              AND left(mf.model, 7) <> 'resource'
              AND left(mf.model, 8) <> 'calendar'
              AND left(mf.model, 8) <> 'workflow'
              AND left(mf.model, 9) <> 'fetchmail'
        """
        cr.execute(sql, params)
        recs = cr.dictfetchall()
        if recs:
            for rec in recs:
                model = rec.get('model')  # 表头模型
                model_id = rec.get('model_id')  # 表头模型ID
                # 获取 reference 字段详细关联的 模型
                model_list = self.env[model]._reference_models()
                if len(model_list) > 20:
                    continue
                    # raise ValidationError(u'生成访问权时发现模型【%s】包含reference字段，'
                    #                       u'且该字段未指定具体的模型范围，请联系开发人员检查。'
                    #
                for item in model_list:
                    relation_model = item[0]
                    sql = """
                    DO $$
                    DECLARE
                      v_relation_model_name VARCHAR;
                      v_relation_model_id   INT;
                      v_relation_access_id  INT;
                    BEGIN
                      SELECT
                        md.id,
                        md.name
                      INTO
                        v_relation_model_id,
                        v_relation_model_name
                      FROM ir_model md
                      WHERE md.model = %(relation_model)s;

                      -- 查找当前群组是否已有 指定模型的访问权
                      SELECT ma.id
                      INTO v_relation_access_id
                      FROM ir_model_access ma
                      WHERE ma.group_id = %(group_id)s
                            AND ma.model_id = v_relation_model_id
                      ORDER BY ma.id DESC
                      LIMIT 1;

                      IF v_relation_access_id IS NOT NULL
                      -- 如果有关联模型的访问权，且权限项为 FALSE 时，则更新为与表头模型一致的访问权
                      THEN
                        UPDATE ir_model_access ma
                        SET
                          active    = TRUE,
                          perm_read = TRUE
                        WHERE ma.id = v_relation_access_id;
                      ELSE

                        INSERT INTO ir_model_access
                        (name, model_id, group_id, active, perm_read,
                         perm_write, perm_unlink, perm_create, perm_audit, perm_unaudit, perm_export)
                        VALUES
                          (v_relation_model_name, v_relation_model_id, %(group_id)s, TRUE, TRUE,
                           FALSE, FALSE, FALSE, FALSE, FALSE, FALSE);
                      END IF;
                    END;
                    $$;
                    """
                    params_access = {
                        'group_id': group_id,
                        'relation_model': relation_model
                    }
                    cr.execute(sql, params_access)
        sql = '''
        SELECT array_agg(ma.id) AS access_ids
        FROM ir_model_access ma
        WHERE ma.group_id = %(group_id)s
        '''
        cr.execute(sql, params)
        rec = cr.dictfetchone()
        access_ids = rec.get('access_ids')
        return access_ids

    @api.multi
    def do_confirm(self):
        """
        :return:
        """
        for record in self:
            # 判断选择的菜单与原有菜单是否一致。
            new_ids = record.menu_ids.ids
            old_ids = record.group_id.menu_ids.ids
            cr = self.env.cr
            if not self.is_same_list(old_ids, new_ids):
                # 删除所有关联菜单配置、新增新的菜单配置
                delete_menu_sql = '''
                delete from jd_menu_config_base_res_group where right_id in %s
                '''
                if old_ids:
                    cr.execute(delete_menu_sql, (tuple(old_ids),))
                insert_menu_sql = '''
                insert into jd_menu_config_base_res_group(left_id, right_id) values
                '''
                line_sql = ''
                for m in new_ids:
                    # 最后一个元素以分号结尾
                    if m == new_ids[-1]:
                        line_sql += "(%s, %s);" % (record.group_id.id, m)
                    else:
                        line_sql += "(%s, %s)," % (record.group_id.id, m)
                if line_sql:
                    cr.execute(insert_menu_sql + line_sql)
                delete_acl_sql = '''
                delete from ir_model_access where group_id = %s
                '''
                self.env.cr.execute(delete_acl_sql, (record.group_id.id,))
                delete_bcl_sql = '''
                delete from jd_button_access where group_id = %s
                '''
                self.env.cr.execute(delete_bcl_sql, (record.group_id.id,))
                if record.menu_ids:
                    acl_list = self.create_model_acl_by_menu_ids(record.group_id.id, record.menu_ids)
                    self.remove_duplicate(acl_list)
            # 不存在差异直接pass
            else:
                _logger.info('new_ids == old_ids no action')
            # 清除res.groups的cache
            # 使得使用sql更改res.groups的acl时可以马上生效，不用重启。
            # 参考res.groups的write方法 _bj
            self.env['ir.model.access'].call_cache_clearing_methods()
            return {
                'type': 'ir.actions.act_window',
                'model': 'ir.actions.act_window',
                'name': u'群组',
                'res_model': 'res.groups',
                'view_type': 'form',
                'view_mode': 'form',
                'res_id': record.group_id.id,
            }

    def remove_duplicate(self, acl_list):
        """
        去除重复项
        传入acl数组，将重复的进行合并处理。
        :return:
        """
        acl_ids = acl_list
        sql = '''
            select id, model_id from ir_model_access where id in %s
            '''
        self.env.cr.execute(sql, (tuple(acl_ids),))
        model_ids = [{'id': r['id'], 'model_id': r['model_id']} for r in self.env.cr.dictfetchall()]
        dic = {}
        duplicate_ids = []
        for m in model_ids:
            if str(m['model_id']) in dic.keys():
                dic[str(m['model_id'])] += 1
                duplicate_ids.append((m['model_id'], m['id']))
            else:
                dic[str(m['model_id'])] = 1
                duplicate_ids.append((m['model_id'], m['id']))
        # 找到所有出现次数大于2的记录。对记录进行合并处理。
        over_model_ids = [k for k, v in dic.iteritems() if v > 1]
        final = []
        for over in over_model_ids:
            tmp_ids = []
            for dul in duplicate_ids:
                if dul[0] == int(over):
                    tmp_ids.append((dul[0], dul[1]))
            final.append(tmp_ids)
        unlink_ids = []
        # 合并重复值
        for i in final:
            tmp_perm_read, tmp_perm_write, tmp_perm_create, tmp_perm_unlink, tmp_perm_audit, tmp_perm_unaudit, tmp_perm_export\
                = True, False, False, False, False, False, False
            model_id, group_id = None, None
            for j in i:
                model_id = j[0]
                tmp_rec = self.env['ir.model.access'].browse(j[1])
                group_id = tmp_rec.group_id.id
                tmp_perm_read = tmp_perm_read | tmp_rec.perm_read
                tmp_perm_write = tmp_perm_write | tmp_rec.perm_write
                tmp_perm_create = tmp_perm_create | tmp_rec.perm_create
                tmp_perm_unlink = tmp_perm_unlink | tmp_rec.perm_unlink
                tmp_perm_audit = tmp_perm_audit | tmp_rec.perm_audit
                tmp_perm_unaudit = tmp_perm_unaudit | tmp_rec.perm_unaudit
                tmp_perm_export = tmp_perm_export | tmp_rec.perm_export
                unlink_ids.append(tmp_rec.id)
            dic = {
                'temp_perm_read': tmp_perm_read,
                'temp_perm_write': tmp_perm_write,
                'temp_perm_create': tmp_perm_create,
                'temp_perm_unlink': tmp_perm_unlink,
                'temp_perm_audit': tmp_perm_audit,
                'temp_perm_unaudit': tmp_perm_unaudit,
                'temp_perm_export': tmp_perm_export,
            }
            model_rec = self.env['ir.model'].browse(model_id)
            self.create_acl(model=model_rec,
                            dict=dic,
                            group_id=group_id)
        self.unlink_acl(unlink_ids=unlink_ids)

    def is_same_list(self, old_ids, new_ids):
        """
        判断两个列表是否完全一致
        :param old_ids:
        :param new_ids:
        :return:
        """
        old_ids = set(old_ids)
        new_ids = set(new_ids)
        if len(list(new_ids - old_ids)) == 0 and len(list(old_ids - new_ids)) == 0:
            return True
        else:
            return False

    def is_same_dict(self, dic1, dic2):
        """
        判断两个相同键的字典是否一致
        :param old_ids:
        :param new_ids:
        :return:
        """
        flag = 0
        for i in dic1:
            for j in dic2:
                if i == j and dic1[i] == dic2[j]:
                    flag += 1
                else:
                    flag = flag
        if flag == 6:
            return True
        else:
            return False
