diff --git a/app_user_admin/__init__.py b/app_user_admin/__init__.py new file mode 100644 index 000000000..8de8fe724 --- /dev/null +++ b/app_user_admin/__init__.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- + +from . import models +from . import controllers +from . import wizard +from .hooks import pre_init_hook +from .hooks import post_init_hook +from .hooks import uninstall_hook diff --git a/app_user_admin/__manifest__.py b/app_user_admin/__manifest__.py new file mode 100644 index 000000000..71a59ee82 --- /dev/null +++ b/app_user_admin/__manifest__.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- + +# Copyright 2014 ABF OSIELL + +# Created on 2022-09-01 +# author: 欧度智能,https://www.odooai.cn +# email: 300883@qq.com +# resource of odooai +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +# Odoo16在线用户手册(长期更新) +# https://www.odooai.cn/documentation/16.0/zh_CN/index.html + +# Odoo16在线开发者手册(长期更新) +# https://www.odooai.cn/documentation/16.0/zh_CN/developer.html + +# Odoo13在线用户手册(长期更新) +# https://www.odooai.cn/documentation/user/13.0/zh_CN/index.html + +# Odoo13在线开发者手册(长期更新) +# https://www.odooai.cn/documentation/13.0/index.html + +# Odoo10在线中文用户手册(长期更新) +# https://www.odooai.cn/documentation/user/10.0/zh_CN/index.html + +# Odoo10离线中文用户手册下载 +# https://www.odooai.cn/odoo10_user_manual_document_offline/ +# Odoo10离线开发手册下载-含python教程,jquery参考,Jinja2模板,PostgresSQL参考(odoo开发必备) +# https://www.odooai.cn/odoo10_developer_document_offline/ + +############################################################################## +# Copyright (C) 2009-TODAY odooAi.cn Ltd. https://www.odooai.cn +# Author: Ivan Deng,300883@qq.com +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# See . +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +############################################################################## +# todo: 这个有点复杂了,只处理成角色有哪些用户即可 + +{ + 'name': "Easy User Admin,User Role manager. 用户角色/用户权限快速管理", + 'version': '17.0.24.12.23', + 'author': 'odooai.cn', + 'category': 'Base', + 'website': 'https://www.odooai.cn', + 'live_test_url': 'https://demo.odooapp.cn', + 'license': 'OPL-1', + 'sequence': 2, + 'price': 38.00, + 'currency': 'EUR', + 'images': ['static/description/banner.png'], + 'depends': [ + 'web', + ], + 'summary': ''' + Easy setup user role base on multi security groups. + User role packed with access rule, Validity time period. + Quick assign access right to every user.Mass setup user access right. + Quick set role access. + ''', + 'description': ''' + Base on oca base_user_role. author,ABF OSIELL, Odoo Community Association (OCA) + 1. Easy setup user role base on multi security groups. + 2. User role packed with access rule, Validity time period. + 3. Quick assign access right to every user.Mass setup user access right. + 4. The Roles is the base rule of user. Also you can set detail in Access Rights page + 5. Easy import groups access from user to roles. + 11. Multi-language Support. Multi-Company Support. + 12. Support Odoo 18,17,16,15,14,13,12, Enterprise and Community and odoo.sh Edition. + 13. Full Open Source. + ========== + 1. + 2. + 11. 多语言支持,多公司支持 + 12. Odoo 18,17,16,15,14,13,12, 企业版,社区版,在线SaaS.sh版,等全版本支持 + 13. 代码完全开源 + ''', + 'data': [ + "security/ir.model.access.csv", + "data/ir_cron_data.xml", + "data/ir_module_category_data.xml", + "wizard/wizard_user2role_views.xml", + "views/res_users_role_views.xml", + "views/res_users_views.xml", + "views/res_groups_views.xml", + ], + 'demo': [], + # 'pre_init_hook': 'pre_init_hook', + # 'post_init_hook': 'post_init_hook', + # 'uninstall_hook': 'uninstall_hook', + 'installable': True, + 'application': True, + 'auto_install': False, +} diff --git a/app_user_admin/controllers/__init__.py b/app_user_admin/controllers/__init__.py new file mode 100644 index 000000000..221005dc7 --- /dev/null +++ b/app_user_admin/controllers/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +# from . import main \ No newline at end of file diff --git a/app_user_admin/controllers/main.py b/app_user_admin/controllers/main.py new file mode 100644 index 000000000..8bdffa5a5 --- /dev/null +++ b/app_user_admin/controllers/main.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +from odoo import http +from odoo.http import request +from odoo.exceptions import AccessDenied, UserError +from odoo.tools.translate import _ +from odoo.addons.portal.controllers.portal import CustomerPortal + +# class appCustomerPortal(CustomerPortal): + +# @http.route('/my/webclient/locale/', type='http', auth="none") +# def index(self, **kw): +# return "Hello, world" + +# @http.route('/default/default/objects/', auth='public') +# def list(self, **kw): +# return http.request.render('default.listing', { +# 'root': '/default/default', +# 'objects': http.request.env['default.default'].search([]), +# }) + +# @http.route('/default/default/objects//', auth='public') +# def object(self, obj, **kw): +# return http.request.render('default.object', { +# 'object': obj +# }) diff --git a/app_user_admin/data/ir_cron_data.xml b/app_user_admin/data/ir_cron_data.xml new file mode 100644 index 000000000..10737312f --- /dev/null +++ b/app_user_admin/data/ir_cron_data.xml @@ -0,0 +1,15 @@ + + + + + Update user roles + 3 + hours + True + + code + model.cron_update_users() + + diff --git a/app_user_admin/data/ir_module_category_data.xml b/app_user_admin/data/ir_module_category_data.xml new file mode 100644 index 000000000..210493784 --- /dev/null +++ b/app_user_admin/data/ir_module_category_data.xml @@ -0,0 +1,15 @@ + + + + + + User roles + + diff --git a/app_user_admin/hooks.py b/app_user_admin/hooks.py new file mode 100644 index 000000000..b1901857a --- /dev/null +++ b/app_user_admin/hooks.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- + +# Created on 2018-10-12 +# author: 欧度智能,https://www.odooai.cn +# email: 300883@qq.com +# resource of odooai +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +# Odoo在线中文用户手册(长期更新) +# https://www.odooai.cn/documentation/user/10.0/zh_CN/index.html + +# Odoo10离线中文用户手册下载 +# https://www.odooai.cn/odoo10_user_manual_document_offline/ +# Odoo10离线开发手册下载-含python教程,jquery参考,Jinja2模板,PostgresSQL参考(odoo开发必备) +# https://www.odooai.cn/odoo10_developer_document_offline/ +# description: + +from odoo import api, SUPERUSER_ID, _ + + +def pre_init_hook(env): + pass + +def post_init_hook(env): + pass + +def uninstall_hook(env): + pass diff --git a/app_user_admin/i18n/README.txt b/app_user_admin/i18n/README.txt new file mode 100644 index 000000000..222b84cd9 --- /dev/null +++ b/app_user_admin/i18n/README.txt @@ -0,0 +1,2 @@ +Please follow this tutorial for more guides: +https://www.odoo.com/documentation/master/developer/misc/i18n/translations.html \ No newline at end of file diff --git a/app_user_admin/i18n/zh_CN.po b/app_user_admin/i18n/zh_CN.po new file mode 100644 index 000000000..68f8fdd31 --- /dev/null +++ b/app_user_admin/i18n/zh_CN.po @@ -0,0 +1,379 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * app_user_admin +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0+e-20230721\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-09-04 16:44+0000\n" +"PO-Revision-Date: 2023-09-04 16:44+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_groups__role_count +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__role_count +msgid "# Roles" +msgstr "# 角色" + +#. module: app_user_admin +#: model_terms:ir.ui.view,arch_db:app_user_admin.view_res_users_form_inherit +msgid "" +"The Roles is the base rule of user. Also you can set detail in " +"Access Rights page" +msgstr "角色是用户的基本规则。您也可以在访问权限页面中设置详细信息" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__model_access +msgid "Access Controls" +msgstr "访问控制" + +#. module: app_user_admin +#: model:ir.model,name:app_user_admin.model_res_groups +msgid "Access Groups" +msgstr "用户权限组" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__menu_access +msgid "Access Menu" +msgstr "访问菜单" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__model_access_ids +#: model_terms:ir.ui.view,arch_db:app_user_admin.view_res_users_role_form +msgid "Access Rights" +msgstr "访问权限" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role_line__active +msgid "Active" +msgstr "积极" + +#. module: app_user_admin +#: model_terms:ir.ui.view,arch_db:app_user_admin.view_res_users_role_form +msgid "Add a line" +msgstr "添加一行" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__category_id +msgid "Application" +msgstr "应用" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__group_category_id +msgid "Associated category" +msgstr "关联类别" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__group_id +msgid "Associated group" +msgstr "关联组" + +#. module: app_user_admin +#: model:ir.model.fields,help:app_user_admin.field_res_users_role__group_category_id +msgid "Associated group's category" +msgstr "关联权限组的类别" + +#. module: app_user_admin +#: model_terms:ir.ui.view,arch_db:app_user_admin.app_wizard_user2role_form_view +msgid "Cancel" +msgstr "取消" + +#. module: app_user_admin +#: model:ir.model,name:app_user_admin.model_wizard_user2role +msgid "Clone User Group to Role Wizard" +msgstr "克隆用户权限组至角色" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__color +msgid "Color Index" +msgstr "颜色索引指数" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__comment +msgid "Comment" +msgstr "评论" + +#. module: app_user_admin +#: model_terms:ir.ui.view,arch_db:app_user_admin.app_wizard_user2role_form_view +msgid "Confirm" +msgstr "确定" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__create_uid +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role_line__create_uid +#: model:ir.model.fields,field_description:app_user_admin.field_wizard_user2role__create_uid +msgid "Created by" +msgstr "创建者" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__create_date +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role_line__create_date +#: model:ir.model.fields,field_description:app_user_admin.field_wizard_user2role__create_date +msgid "Created on" +msgstr "创建于" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__display_name +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role_line__display_name +#: model:ir.model.fields,field_description:app_user_admin.field_wizard_user2role__display_name +msgid "Display Name" +msgstr "显示名称" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role_line__is_enabled +msgid "Enabled" +msgstr "启用" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role_line__date_from +msgid "From" +msgstr "从" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__full_name +msgid "Group Name" +msgstr "权限组名称" + +#. module: app_user_admin +#: model:ir.model.fields,help:app_user_admin.field_res_users_role__share +msgid "Group created to set access rights for sharing data with some users." +msgstr "为设置与某些用户共享数据的访问权限而创建的组。" + +#. module: app_user_admin +#: model_terms:ir.ui.view,arch_db:app_user_admin.view_res_users_role_form +msgid "Groups Setup" +msgstr "权限组设置" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__id +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role_line__id +#: model:ir.model.fields,field_description:app_user_admin.field_wizard_user2role__id +msgid "ID" +msgstr "" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_wizard_user2role__user_id +msgid "Import From User" +msgstr "从用户导入" + +#. module: app_user_admin +#: model_terms:ir.ui.view,arch_db:app_user_admin.view_res_users_role_form +msgid "Import Groups" +msgstr "导入权限组" + +#. module: app_user_admin +#: model:ir.actions.act_window,name:app_user_admin.action_wizard_user2role +msgid "Import User Groups to Role" +msgstr "导入用户权限组至角色" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__implied_ids +msgid "Inherits" +msgstr "继承" + +#. module: app_user_admin +#: model_terms:ir.ui.view,arch_db:app_user_admin.view_res_users_role_form +msgid "Internal Notes" +msgstr "内部说明" + +#. module: app_user_admin +#: model:ir.model.fields,help:app_user_admin.field_res_groups__parent_ids +#: model:ir.model.fields,help:app_user_admin.field_res_users_role__parent_ids +msgid "" +"Inverse relation for the Inherits field. The groups from which this group is" +" inheriting" +msgstr "“继承”字段的反比关系。此组从中继承的组" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role____last_update +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role_line____last_update +#: model:ir.model.fields,field_description:app_user_admin.field_wizard_user2role____last_update +msgid "Last Modified on" +msgstr "上次修改时间" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__write_uid +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role_line__write_uid +#: model:ir.model.fields,field_description:app_user_admin.field_wizard_user2role__write_uid +msgid "Last Updated by" +msgstr "最后更新者" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__write_date +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role_line__write_date +#: model:ir.model.fields,field_description:app_user_admin.field_wizard_user2role__write_date +msgid "Last Updated on" +msgstr "最后更新于" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__model_access_count +msgid "Model Access Count" +msgstr "模型访问计数" + +#. module: app_user_admin +#: model_terms:ir.ui.view,arch_db:app_user_admin.view_res_users_role_form +msgid "Multi Add line" +msgstr "批量添加" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__name +msgid "Name" +msgstr "名字" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_groups__trans_parent_ids +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__trans_parent_ids +msgid "Parent Groups" +msgstr "上级组" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_groups__parent_ids +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__parent_ids +msgid "Parents" +msgstr "上级" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__rule_ids +#: model_terms:ir.ui.view,arch_db:app_user_admin.view_res_users_role_form +msgid "Record Rules" +msgstr "记录规则" + +#. module: app_user_admin +#: model:ir.model.fields,help:app_user_admin.field_res_groups__role_id +#: model:ir.model.fields,help:app_user_admin.field_res_users_role__role_id +msgid "Relation for the groups that represents a role" +msgstr "表示角色与权限组的关系" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_groups__role_id +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__role_id +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role_line__role_id +msgid "Role" +msgstr "角色" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users__role_line_ids +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__line_ids +msgid "Role lines" +msgstr "角色明细" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_groups__role_ids +#: model:ir.model.fields,field_description:app_user_admin.field_res_users__role_ids +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__role_ids +#: model_terms:ir.ui.view,arch_db:app_user_admin.res_groups_view_form +#: model_terms:ir.ui.view,arch_db:app_user_admin.view_res_users_form_inherit +#: model_terms:ir.ui.view,arch_db:app_user_admin.view_res_users_role_search +msgid "Roles" +msgstr "角色" + +#. module: app_user_admin +#: model:ir.actions.act_window,name:app_user_admin.action_res_users_role_tree +#: model:ir.ui.menu,name:app_user_admin.menu_action_res_users_role_tree +msgid "Roles Management" +msgstr "角色管理" + +#. module: app_user_admin +#: model:ir.model.constraint,message:app_user_admin.constraint_res_users_role_line_user_role_uniq +msgid "Roles can be assigned to a user only once at a time" +msgstr "一次只能为用户分配一次角色" + +#. module: app_user_admin +#: model:ir.model.fields,help:app_user_admin.field_res_groups__role_ids +#: model:ir.model.fields,help:app_user_admin.field_res_users_role__role_ids +msgid "Roles in which the group is involved" +msgstr "权限组所在的角色" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__rule_groups +msgid "Rules" +msgstr "规则" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__rules_count +msgid "Rules Count" +msgstr "规则计数" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__share +msgid "Share Group" +msgstr "共享组" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role_line__date_to +msgid "To" +msgstr "至" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_wizard_user2role__role_id +msgid "To Role" +msgstr "" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__trans_implied_ids +msgid "Transitively inherits" +msgstr "可传递继承" + +#. module: app_user_admin +#: model:ir.actions.server,name:app_user_admin.cron_update_users_ir_actions_server +#: model:ir.cron,cron_name:app_user_admin.cron_update_users +msgid "Update user roles" +msgstr "更新用户角色" + +#. module: app_user_admin +#: model:ir.model,name:app_user_admin.model_res_users +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role_line__user_id +msgid "User" +msgstr "用户" + +#. module: app_user_admin +#: model:ir.model,name:app_user_admin.model_res_users_role +msgid "User role" +msgstr "用户角色" + +#. module: app_user_admin +#: model:ir.module.category,name:app_user_admin.ir_module_category_role +msgid "User roles" +msgstr "用户角色" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__users +msgid "Users" +msgstr "用户" + +#. module: app_user_admin +#: model_terms:ir.ui.view,arch_db:app_user_admin.view_res_users_role_form +msgid "Users Add to Role" +msgstr "用户添加到角色" + +#. module: app_user_admin +#: model:ir.model,name:app_user_admin.model_res_users_role_line +msgid "Users associated to a role" +msgstr "与角色关联的用户" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__user_ids +msgid "Users list" +msgstr "用户列表" + +#. module: app_user_admin +#: model:ir.model.fields,help:app_user_admin.field_res_users_role__implied_ids +msgid "Users of this group automatically inherit those groups" +msgstr "此组的用户会自动继承这些组" + +#. module: app_user_admin +#: model:ir.model.fields,field_description:app_user_admin.field_res_groups__view_access +#: model:ir.model.fields,field_description:app_user_admin.field_res_users_role__view_access +msgid "Views" +msgstr "视图" + +#. module: app_user_admin +#: model_terms:ir.ui.view,arch_db:app_user_admin.view_res_users_form_inherit +msgid "You can set multi user role in Roles Management" +msgstr "您可以在角色管理中设置多用户角色" diff --git a/app_user_admin/models/__init__.py b/app_user_admin/models/__init__.py new file mode 100644 index 000000000..85ebfa5b7 --- /dev/null +++ b/app_user_admin/models/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- + +from . import res_users_role +from . import res_users_role_line +from . import res_users +from . import res_groups diff --git a/app_user_admin/models/res_groups.py b/app_user_admin/models/res_groups.py new file mode 100644 index 000000000..ef4d51363 --- /dev/null +++ b/app_user_admin/models/res_groups.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- + +from odoo import api, fields, models + + +class ResGroups(models.Model): + _inherit = "res.groups" + + view_access = fields.Many2many( + groups="base.group_system", + ) + + # The inverse field of the field group_id on the res.users.role model + # This field should be used a One2one relation as a role can only be + # represented by one group. It's declared as a One2many field as the + # inverse field on the res.users.role it's declared as a Many2one + role_id = fields.One2many( + comodel_name="res.users.role", + inverse_name="group_id", + help="Relation for the groups that represents a role", + ) + + role_ids = fields.Many2many( + comodel_name="res.users.role", + relation="res_groups_implied_roles_rel", + string="Roles", + compute="_compute_role_ids", + help="Roles in which the group is involved", + ) + + parent_ids = fields.Many2many( + "res.groups", + "res_groups_implied_rel", + "hid", + "gid", + string="Parents", + help="Inverse relation for the Inherits field. " + "The groups from which this group is inheriting", + ) + + trans_parent_ids = fields.Many2many( + comodel_name="res.groups", + string="Parent Groups", + compute="_compute_trans_parent_ids", + recursive=True, + ) + + role_count = fields.Integer("# Roles", compute="_compute_role_count") + + def _compute_role_count(self): + for group in self: + group.role_count = len(group.role_ids) + + @api.depends("parent_ids.trans_parent_ids") + def _compute_trans_parent_ids(self): + for group in self: + group.trans_parent_ids = ( + group.parent_ids | group.parent_ids.trans_parent_ids + ) + + def _compute_role_ids(self): + for group in self: + if group.trans_parent_ids: + group.role_ids = group.trans_parent_ids.role_id + else: + group.role_ids = group.role_id + + def action_view_roles(self): + self.ensure_one() + action = self.env["ir.actions.act_window"]._for_xml_id( + "app_user_admin.action_res_users_role_tree" + ) + action["context"] = {} + if len(self.role_ids) > 1: + action["domain"] = [("id", "in", self.role_ids.ids)] + elif self.role_ids: + form_view = [ + (self.env.ref("app_user_admin.view_res_users_role_form").id, "form") + ] + if "views" in action: + action["views"] = form_view + [ + (state, view) for state, view in action["views"] if view != "form" + ] + else: + action["views"] = form_view + action["res_id"] = self.role_ids.id + else: + action = {"type": "ir.actions.act_window_close"} + return action diff --git a/app_user_admin/models/res_users.py b/app_user_admin/models/res_users.py new file mode 100644 index 000000000..9518b552e --- /dev/null +++ b/app_user_admin/models/res_users.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- + +from odoo import api, fields, models + + +class ResUsers(models.Model): + _inherit = "res.users" + + role_line_ids = fields.One2many( + comodel_name="res.users.role.line", + inverse_name="user_id", + string="Role lines", + default=lambda self: self._default_role_lines(), + ) + role_ids = fields.One2many( + comodel_name="res.users.role", + string="Roles", + compute="_compute_role_ids", + compute_sudo=True, + ) + + @api.model + def _default_role_lines(self): + default_user = self.env.ref("base.default_user", raise_if_not_found=False) + default_values = [] + if default_user: + for role_line in default_user.with_context(active_test=False).role_line_ids: + default_values.append( + { + "role_id": role_line.role_id.id, + "date_from": role_line.date_from, + "date_to": role_line.date_to, + "is_enabled": role_line.is_enabled, + } + ) + return default_values + + @api.depends("role_line_ids.role_id") + def _compute_role_ids(self): + for user in self: + user.role_ids = user.role_line_ids.mapped("role_id") + + @api.model_create_multi + def create(self, vals_list): + new_records = super(ResUsers, self).create(vals_list) + new_records.set_groups_from_roles() + return new_records + + def write(self, vals): + res = super(ResUsers, self).write(vals) + self.sudo().set_groups_from_roles() + return res + + def _get_enabled_roles(self): + return self.role_line_ids.filtered(lambda rec: rec.is_enabled) + + def set_groups_from_roles(self, force=False): + """Set (replace) the groups following the roles defined on users. + If no role is defined on the user, its groups are let untouched unless + the `force` parameter is `True`. + """ + role_groups = {} + # We obtain all the groups associated to each role first, so that + # it is faster to compare later with each user's groups. + for role in self.mapped("role_line_ids.role_id"): + role_groups[role] = list( + set( + role.group_id.ids + + role.implied_ids.ids + + role.trans_implied_ids.ids + ) + ) + for user in self: + if not user.role_line_ids and not force: + continue + group_ids = [] + for role_line in user._get_enabled_roles(): + role = role_line.role_id + group_ids += role_groups[role] + group_ids = list(set(group_ids)) # Remove duplicates IDs + groups_to_add = list(set(group_ids) - set(user.groups_id.ids)) + groups_to_remove = list(set(user.groups_id.ids) - set(group_ids)) + to_add = [(4, gr) for gr in groups_to_add] + to_remove = [(3, gr) for gr in groups_to_remove] + groups = to_remove + to_add + if groups: + vals = {"groups_id": groups} + super(ResUsers, user).write(vals) + return True diff --git a/app_user_admin/models/res_users_role.py b/app_user_admin/models/res_users_role.py new file mode 100644 index 000000000..a5a1a5b5d --- /dev/null +++ b/app_user_admin/models/res_users_role.py @@ -0,0 +1,124 @@ +# -*- coding: utf-8 -*- + +import logging + +from odoo import SUPERUSER_ID, api, fields, models + +_logger = logging.getLogger(__name__) + + +class ResUsersRole(models.Model): + _name = "res.users.role" + _inherits = {"res.groups": "group_id"} + _description = "User role" + + group_id = fields.Many2one( + comodel_name="res.groups", + required=True, + ondelete="cascade", + readonly=True, + string="Associated group", + ) + line_ids = fields.One2many( + comodel_name="res.users.role.line", inverse_name="role_id", string="Role lines" + ) + user_ids = fields.One2many( + comodel_name="res.users", string="Users list", compute="_compute_user_ids" + ) + rule_ids = fields.Many2many( + comodel_name="ir.rule", + compute="_compute_rule_ids", + string="Record Rules", + required=False, + ) + rules_count = fields.Integer(compute="_compute_rule_ids") + model_access_ids = fields.Many2many( + comodel_name="ir.model.access", + compute="_compute_model_access_ids", + string="Access Rights", + required=False, + ) + model_access_count = fields.Integer(compute="_compute_model_access_ids") + group_category_id = fields.Many2one( + related="group_id.category_id", + default=lambda cls: cls.env.ref("app_user_admin.ir_module_category_role").id, + string="Associated category", + help="Associated group's category", + readonly=False, + ) + + @api.depends("line_ids.user_id") + def _compute_user_ids(self): + for role in self.sudo() if self._bypass_rules() else self: + role.user_ids = role.line_ids.mapped("user_id") + + @api.depends("implied_ids", "implied_ids.model_access") + def _compute_model_access_ids(self): + for rec in self: + rec.model_access_ids = rec.implied_ids.model_access.ids + rec.model_access_count = len(rec.model_access_ids) + + @api.depends("implied_ids", "implied_ids.rule_groups") + def _compute_rule_ids(self): + for rec in self: + rec.rule_ids = rec.implied_ids.rule_groups.ids + rec.rules_count = len(rec.rule_ids) + + @api.model + def _bypass_rules(self): + # Run methods as super user to avoid problems by "Administrator/Access Right" + return self._name == "res.users.role" and self.env.user.has_group( + "base.group_erp_manager" + ) + + @api.model_create_multi + def create(self, vals_list): + model = (self.sudo() if self._bypass_rules() else self).browse() + new_records = super(ResUsersRole, model).create(vals_list) + new_records.update_users() + return new_records + + def read(self, fields=None, load="_classic_read"): + recs = self.sudo() if self._bypass_rules() else self + return super(ResUsersRole, recs).read(fields, load) + + def write(self, vals): + recs = self.sudo() if self._bypass_rules() else self + # Workaround to solve issue with broken code in odoo that clear the + # cache during the write: see odoo/addons/base/models/res_users.py#L226 + groups_vals = {} + for field in recs.group_id._fields: + if field in vals: + groups_vals[field] = vals.pop(field) + if groups_vals: + recs.group_id.write(groups_vals) + res = super(ResUsersRole, recs).write(vals) + recs.update_users() + return res + + def unlink(self): + users = self.mapped("user_ids") + res = super(ResUsersRole, self).unlink() + users.set_groups_from_roles(force=True) + return res + + def update_users(self): + """Update all the users concerned by the roles identified by `ids`.""" + users = self.mapped("user_ids") + users.set_groups_from_roles() + return True + + @api.model + def cron_update_users(self): + logging.info("Update user roles") + self.search([]).update_users() + + def show_rule_ids(self): + action = self.env["ir.actions.actions"]._for_xml_id("base.action_rule") + action["domain"] = [("id", "in", self.rule_ids.ids)] + return action + + def show_model_access_ids(self): + action = self.env["ir.actions.actions"]._for_xml_id("base.ir_access_act") + action["domain"] = [("id", "in", self.model_access_ids.ids)] + return action diff --git a/app_user_admin/models/res_users_role_line.py b/app_user_admin/models/res_users_role_line.py new file mode 100644 index 000000000..b065f2f0e --- /dev/null +++ b/app_user_admin/models/res_users_role_line.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- + +import datetime +import logging + +from odoo import SUPERUSER_ID, api, fields, models + +_logger = logging.getLogger(__name__) + + +class ResUsersRoleLine(models.Model): + _name = "res.users.role.line" + _description = "Users associated to a role" + + active = fields.Boolean(related="user_id.active") + role_id = fields.Many2one( + comodel_name="res.users.role", required=True, string="Role", ondelete="cascade" + ) + user_id = fields.Many2one( + comodel_name="res.users", + required=True, + string="User", + domain=[("id", "!=", SUPERUSER_ID)], + ondelete="cascade", + ) + date_from = fields.Date("From") + date_to = fields.Date("To") + is_enabled = fields.Boolean("Enabled", compute="_compute_is_enabled") + _sql_constraints = [ + ( + "user_role_uniq", + "unique (user_id,role_id)", + "Roles can be assigned to a user only once at a time", + ) + ] + + @api.depends("date_from", "date_to") + def _compute_is_enabled(self): + today = datetime.date.today() + for role_line in self: + role_line.is_enabled = True + if role_line.date_from: + date_from = role_line.date_from + if date_from > today: + role_line.is_enabled = False + if role_line.date_to: + date_to = role_line.date_to + if today > date_to: + role_line.is_enabled = False + + def unlink(self): + users = self.mapped("user_id") + res = super(ResUsersRoleLine, self).unlink() + users.set_groups_from_roles(force=True) + return res diff --git a/app_user_admin/report/__init__.py b/app_user_admin/report/__init__.py new file mode 100644 index 000000000..633f86615 --- /dev/null +++ b/app_user_admin/report/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- + diff --git a/app_user_admin/security/ir.model.access.csv b/app_user_admin/security/ir.model.access.csv new file mode 100644 index 000000000..3df15dc5f --- /dev/null +++ b/app_user_admin/security/ir.model.access.csv @@ -0,0 +1,4 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_res_users_role,access_res_users_role,model_res_users_role,"base.group_erp_manager",1,1,1,1 +access_res_users_role_line,access_res_users_role_line,model_res_users_role_line,"base.group_erp_manager",1,1,1,1 +access_wizard_user2role,access_wizard_user2role,model_wizard_user2role,"base.group_erp_manager",1,1,1,1 diff --git a/app_user_admin/static/description/banner.png b/app_user_admin/static/description/banner.png new file mode 100644 index 000000000..c91898c20 Binary files /dev/null and b/app_user_admin/static/description/banner.png differ diff --git a/app_user_admin/static/description/banner1.png b/app_user_admin/static/description/banner1.png new file mode 100644 index 000000000..ee2cc268c Binary files /dev/null and b/app_user_admin/static/description/banner1.png differ diff --git a/app_user_admin/static/description/demo1.jpg b/app_user_admin/static/description/demo1.jpg new file mode 100644 index 000000000..bc4f2826f Binary files /dev/null and b/app_user_admin/static/description/demo1.jpg differ diff --git a/app_user_admin/static/description/demo2.jpg b/app_user_admin/static/description/demo2.jpg new file mode 100644 index 000000000..cce629c64 Binary files /dev/null and b/app_user_admin/static/description/demo2.jpg differ diff --git a/app_user_admin/static/description/demo3.jpg b/app_user_admin/static/description/demo3.jpg new file mode 100644 index 000000000..d4c1a2180 Binary files /dev/null and b/app_user_admin/static/description/demo3.jpg differ diff --git a/app_user_admin/static/description/demo4.jpg b/app_user_admin/static/description/demo4.jpg new file mode 100644 index 000000000..c287a3599 Binary files /dev/null and b/app_user_admin/static/description/demo4.jpg differ diff --git a/app_user_admin/static/description/demo41.jpg b/app_user_admin/static/description/demo41.jpg new file mode 100644 index 000000000..05c20f8eb Binary files /dev/null and b/app_user_admin/static/description/demo41.jpg differ diff --git a/app_user_admin/static/description/demo5.jpg b/app_user_admin/static/description/demo5.jpg new file mode 100644 index 000000000..20a21cbf5 Binary files /dev/null and b/app_user_admin/static/description/demo5.jpg differ diff --git a/app_user_admin/static/description/icon.png b/app_user_admin/static/description/icon.png new file mode 100644 index 000000000..0dcbec343 Binary files /dev/null and b/app_user_admin/static/description/icon.png differ diff --git a/app_user_admin/static/description/index.html b/app_user_admin/static/description/index.html new file mode 100644 index 000000000..f415760e8 --- /dev/null +++ b/app_user_admin/static/description/index.html @@ -0,0 +1,151 @@ +
+
+
+

Easy User Admin, User Role manager.

+

Quick assign access right to every user.Mass setup user access right.

+
+

Latest update: v17.24.12.23

+
+
+ Key features: +
    +
  • + + 1. Easy setup user role base on multi security groups. +
  • +
  • + + 2. User role packed with access rule, Validity time period. +
  • +
  • + + 3. Quick assign access right to every user.Mass setup user access right. +
  • +
  • + + 4. The Roles is the base rule of user. Also you can set detail in Access Rights page +
  • +
  • + + 5. Easy import groups access from user to roles. +
  • +
  • + + 11. Multi-language Support. Multi-Company Support. +
  • +
  • + + 12. Support Odoo 18,17,16,15,14,13,12, Enterprise and Community and odoo.sh Edition. +
  • +
  • + + 13. Full Open Source. +
  • +
+
+
+
+
+
+
+ +
+
+

1. Easy setup user role base on multi security groups.

+

+
+ +
+
+
+ +
+
+

2. User role packed with access rule, Validity time period.

+

+
+ +
+
+
+ +
+
+

3. Quick assign access right to every user.Mass setup user access right.

+

+
+ +
+
+
+ +
+
+

4. The Roles is the base rule of user. Also you can set detail in Access Rights page

+

+
+ +
+
+ +
+
+
+ +
+
+

5. Easy import groups access from user to roles.

+

+
+ +
+
+
+ +
+
+

Multi-language Support..

+

+
+ +
+
+
+ +
+
+
+

Technical Help & Support

+
+
+
+

+ For any type of technical help & support requests, Feel free to contact us

+ + odoo@china.com +

+ Via QQ: 300883 (App user would not get QQ or any other IM support. Only for odoo project customize.)

+ + 300883@qq.com +
+
+

+ Visit our website for more support.

+ + https://www.odooai.cn +
+
+
+
+

More Powerful addons, Make your odoo very easy to use, easy customize: + odooAi.cn Odoo Addons +

+
+
+ diff --git a/app_user_admin/static/img/icon_odooai.png b/app_user_admin/static/img/icon_odooai.png new file mode 100644 index 000000000..a022f8d0f Binary files /dev/null and b/app_user_admin/static/img/icon_odooai.png differ diff --git a/app_user_admin/static/img/icon_odooapp.png b/app_user_admin/static/img/icon_odooapp.png new file mode 100644 index 000000000..775a12eef Binary files /dev/null and b/app_user_admin/static/img/icon_odooapp.png differ diff --git a/app_user_admin/static/img/logo_odooai.png b/app_user_admin/static/img/logo_odooai.png new file mode 100644 index 000000000..4fb394b22 Binary files /dev/null and b/app_user_admin/static/img/logo_odooai.png differ diff --git a/app_user_admin/static/src/js/odooai.cn b/app_user_admin/static/src/js/odooai.cn new file mode 100644 index 000000000..e69de29bb diff --git a/app_user_admin/static/src/scss/odooai.cn b/app_user_admin/static/src/scss/odooai.cn new file mode 100644 index 000000000..e69de29bb diff --git a/app_user_admin/static/src/xml/odooai.cn b/app_user_admin/static/src/xml/odooai.cn new file mode 100644 index 000000000..e69de29bb diff --git a/app_user_admin/views/res_groups_views.xml b/app_user_admin/views/res_groups_views.xml new file mode 100644 index 000000000..d4c67945c --- /dev/null +++ b/app_user_admin/views/res_groups_views.xml @@ -0,0 +1,23 @@ + + + + app.res.groups.form + res.groups + + + +
+ +
+
+
+
+
diff --git a/app_user_admin/views/res_users_role_views.xml b/app_user_admin/views/res_users_role_views.xml new file mode 100644 index 000000000..47578594e --- /dev/null +++ b/app_user_admin/views/res_users_role_views.xml @@ -0,0 +1,114 @@ + + + + + res.users.role.tree + res.users.role + + + + + + + + + + res.users.role.search + res.users.role + + + + + + + + + + + res.users.role.form + res.users.role + +
+ +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + Roles Management + ir.actions.act_window + res.users.role + + + +
diff --git a/app_user_admin/views/res_users_views.xml b/app_user_admin/views/res_users_views.xml new file mode 100644 index 000000000..c5adc3dcf --- /dev/null +++ b/app_user_admin/views/res_users_views.xml @@ -0,0 +1,43 @@ + + + + + res.users.form.inherit + res.users + + + + + + + + + + + + + + + + + + + + res.users.search.inherit + res.users + + + + + + + + diff --git a/app_user_admin/wizard/__init__.py b/app_user_admin/wizard/__init__.py new file mode 100644 index 000000000..27ede9113 --- /dev/null +++ b/app_user_admin/wizard/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import wizard_user2role diff --git a/app_user_admin/wizard/odooai.cn b/app_user_admin/wizard/odooai.cn new file mode 100644 index 000000000..e69de29bb diff --git a/app_user_admin/wizard/wizard_user2role.py b/app_user_admin/wizard/wizard_user2role.py new file mode 100644 index 000000000..977282c88 --- /dev/null +++ b/app_user_admin/wizard/wizard_user2role.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from odoo import api, fields, models, _ +from odoo.exceptions import UserError +from odoo.osv import expression +from odoo.tools import float_is_zero, float_compare + + +class WizardUser2Role(models.TransientModel): + _name = 'wizard.user2role' + _description = 'Clone User Group to Role Wizard' + + user_id = fields.Many2one('res.users', string='Import From User', required=True) + role_id = fields.Many2one('res.users.role', string='To Role', required=True) + + def confirm(self): + self.ensure_one() + vals = [] + self.role_id.write({ + 'implied_ids': self.user_id.groups_id.ids + }) diff --git a/app_user_admin/wizard/wizard_user2role_views.xml b/app_user_admin/wizard/wizard_user2role_views.xml new file mode 100644 index 000000000..090b5eba0 --- /dev/null +++ b/app_user_admin/wizard/wizard_user2role_views.xml @@ -0,0 +1,30 @@ + + + + wizard.user2role.form + wizard.user2role + +
+ + + + + + +
+
+
+
+
+ + + Import User Groups to Role + wizard.user2role + form + + new + + +
\ No newline at end of file diff --git a/yuthon_wechat/models/hr_attendance_detail.py b/yuthon_wechat/models/hr_attendance_detail.py index 1131f49cd..22b4b1de3 100644 --- a/yuthon_wechat/models/hr_attendance_detail.py +++ b/yuthon_wechat/models/hr_attendance_detail.py @@ -691,6 +691,7 @@ class HrAttendanceDetail(models.Model): "check_in": checkin_time, "is_late_card": checkin_time > will_datetime_start, "is_no_card": True, + "is_abnormal": True, }) return True else: @@ -708,10 +709,10 @@ class HrAttendanceDetail(models.Model): "sch_check_in_time": will_datetime_start, "check_in": min_time, "is_late_card": min_time > will_datetime_start, - "sch_check_out_time": will_datetime_end, "check_out": max_time, "is_early_card": will_datetime_end > max_time, + "is_abnormal": min_time > will_datetime_start or will_datetime_end > max_time, }) return True