diff --git a/soong_workflow/__manifest__.py b/soong_workflow/__manifest__.py index 05ce54166..646266375 100644 --- a/soong_workflow/__manifest__.py +++ b/soong_workflow/__manifest__.py @@ -22,7 +22,6 @@ "views/soong_workflow_record.xml", "views/soong_approval_group.xml", 'wizard/approval_notice_wizard_views.xml', - 'wizard/soong_transmitted_wizard_views.xml', "wizard/soong_workflow_comment_wizard_view.xml", "templates/soong_workflow_templates.xml", ], diff --git a/soong_workflow/models/soong_workflow.py b/soong_workflow/models/soong_workflow.py index 9e8652b10..e10a7f865 100644 --- a/soong_workflow/models/soong_workflow.py +++ b/soong_workflow/models/soong_workflow.py @@ -49,7 +49,8 @@ class SoongWorkflow(models.Model): link_ids = fields.One2many(comodel_name="soong.workflow.link", inverse_name="workflow_id", string="Links") remove_default_btn_until_end = fields.Boolean(string="是否覆盖表头按钮状态", default=False) - current_stage_highlight_color = fields.Char(default="rgb(0, 255, 255)",help="The color to highlight the current stage on flow",) + current_stage_highlight_color = fields.Char(default="rgb(0, 255, 255)", + help="The color to highlight the current stage on flow", ) start_time = fields.Datetime(string="生效日期", copy=False, default=fields.Datetime.now) end_time = fields.Datetime(string="失效日期", copy=False) is_enable = fields.Boolean(string="是否启用", default="False", compute="compute_is_enable", store=True) @@ -106,15 +107,18 @@ class SoongWorkflow(models.Model): @api.depends('start_time', 'end_time') def compute_is_enable(self): - # 逻辑调整修改时间的时候判断有无要启用的,只准一个不能冲突 - for rec in self: - if rec.start_time and rec.end_time: - if rec.start_time < datetime.datetime.now() and rec.end_time > datetime.datetime.now(): - rec.is_enable = True + is_enable_ids = self.search([('model_id', '=', self.model_id.id), ('is_enable', '=', True)]) + if len(is_enable_ids) <= 1: + for rec in self: + if rec.start_time and rec.end_time: + if rec.start_time < datetime.datetime.now() and rec.end_time > datetime.datetime.now(): + rec.is_enable = True + else: + rec.is_enable = False else: rec.is_enable = False - else: - rec.is_enable = False + else: + raise UserError('工作流一个模型只能启用一个') @api.constrains("node_ids") def validate_nodes(self): @@ -150,16 +154,17 @@ class SoongWorkflow(models.Model): if not val["node_ids"]: val["node_ids"] = [ (0, 0, { - "name": _("开始"), - "sequence": 1, - "node_name": "start", - "flow_start": True, - },), + "name": _("开始"), + "sequence": 1, + "node_name": "start", + "flow_start": True, + "button_ids": '' + },), (0, 0, { - "name": _("结束"), - "sequence": 99, - "node_name": "end", - "flow_end": True, + "name": _("结束"), + "sequence": 99, + "node_name": "end", + "flow_end": True, },), ] return super().create(values) diff --git a/soong_workflow/models/soong_workflow_mixin.py b/soong_workflow/models/soong_workflow_mixin.py index eb1d71d0b..ef18b2111 100644 --- a/soong_workflow/models/soong_workflow_mixin.py +++ b/soong_workflow/models/soong_workflow_mixin.py @@ -112,7 +112,7 @@ class SoongWorkflowMixin(models.AbstractModel): def _add_comment(self, logs, btn_rec): wizard = self.env.ref("soong_workflow.view_soong_workflow_comment_wizard") return { - "name": _("Comment"), + "name": _("评论"), "type": "ir.actions.act_window", "view_mode": "form", "res_model": "soong.workflow.comment.wizard", @@ -162,6 +162,7 @@ class SoongWorkflowMixin(models.AbstractModel): cx.update({"active_id": self.id, "active_ids": self.ids}) wkf_btn_obj = self.env["soong.workflow.node.button"] btn_rec = wkf_btn_obj.search([("btn_key", "=", cx.get("btn_key", False))]) + # 优化弹窗 if btn_rec: log_obj = self._create_update_logs(btn_rec) if btn_rec.has_comment: @@ -242,37 +243,9 @@ class SoongWorkflowMixin(models.AbstractModel): res = self._update_fields_view(view_type, res) # res = self._add_state_tree_view(view_type, res) res = self._add_soong_workflow_log(view_type, res, params) - # todo 后许可拓展退回层级 - res = self._add_return_button(view_type, res) - # 转交 如果一条链路直接跳转,如果多条链路选择跳转 - # res = self._add_transmitted_button(view_type, res) - return res - - # 收回逻辑 - def _add_return_button(self, view_type, res): - model = self._name - wkf_obj = self.env["soong.workflow"] - wkf_rec = wkf_obj.search([("model_id", "=", model), ('is_enable', '=', True)]) - - if not wkf_rec.is_enable_return_button: - return res - - arch = etree.fromstring(res["arch"]) - if view_type == "form": - header_el = arch.xpath("//form/header") - header_el = header_el[0] if header_el else False - if header_el: - button = etree.Element("button", { - "name": "action_return", - "type": "object", - "string": "收回", - "class": "btn-primary", # 按钮的样式 - # "icon": "fa-undo", # 按钮图标 (如果需要) - }) - header_el.append(button) - res["arch"] = etree.tostring(arch, encoding="unicode").replace("\t", "") return res + # 收回 def action_return(self): # 收回目前只支持指定用户和指定角色 for record in self: @@ -309,56 +282,35 @@ class SoongWorkflowMixin(models.AbstractModel): # 当前单据状态所在的位置 record_number = key.split('_')[1] for key, values in result_dict.items(): - if self.env.user.id in values: - # 当前用户所在节点 - user_number = key.split('_')[1] - user_key = key + if values != [False]: + if self.env.user.id in values: + # 当前用户所在节点 + user_number = key.split('_')[1] + user_key = key + else: + raise UserError('请配置节点的人员') number = int(record_number) - int(user_number) if number == 1: self.write({'state': user_key.split('_')[0]}) else: raise UserError('不可收回') - - - - - - - # for button in header_el.iter("button"): - # btn_invisible = "state != 'end'" - # if "invisible" in button.attrib: - # btn_invisible = btn_invisible + " or " + button.attrib["invisible"] - # button.set("invisible", btn_invisible) - # 转交 - def _add_transmitted_button(self, view_type, res): - model = self._name - wkf_obj = self.env["soong.workflow"] - wkf_rec = wkf_obj.search([("model_id", "=", model), ('is_enable', '=', True)]) - - if not wkf_rec.is_enable_transmitted_button: - return res - - arch = etree.fromstring(res["arch"]) - if view_type == "form": - header_el = arch.xpath("//form/header") - header_el = header_el[0] if header_el else False - if header_el: - button = etree.Element("button", { - "name": "action_transmitted", - "type": "object", - "string": "转交", - "class": "btn-primary", # 按钮的样式 - }) - header_el.append(button) - res["arch"] = etree.tostring(arch, encoding="unicode").replace("\t", "") - return res - def action_transmitted(self): + # 当前节点对应的链路 + node_ids = self.workflow_id.node_ids.search([('node_name', '=', self.state)]) # 判断链路是一个就跳转 - # 是多个就弹窗选择 - pass + if len(node_ids.out_link_ids) == 1: + state_next = node_ids.out_link_ids.name.split('-> ')[-1] + self.write({'state': state_next}) + # 多个节点弹窗选择并发送消息提醒 + elif len(node_ids.out_link_ids) > 1: + state_list = [] + for node in node_ids.out_link_ids: + state_list.append(node.name.split('-> ')[-1]) + # 传入每个节点的对应人员 + else: + raise UserError('节点链路配置错误') def _remove_default_header(self, view_type, res): """ diff --git a/soong_workflow/models/soong_workflow_node.py b/soong_workflow/models/soong_workflow_node.py index 40df51c27..c2db941b3 100644 --- a/soong_workflow/models/soong_workflow_node.py +++ b/soong_workflow/models/soong_workflow_node.py @@ -58,76 +58,49 @@ class SoongWorkflowNode(models.Model): ), ] - sequence = fields.Integer( - string="Sequence", default=10, help="Arrange node by defining sequence." - ) - name = fields.Char( - string="Name", translate=True, help="Enter string name of the node." - ) - node_name = fields.Char( - string="Technical Name", - help="Generated technical name which used by backend code.", - ) - workflow_id = fields.Many2one( - comodel_name="soong.workflow", - string="Workflow Ref.", - ondelete="cascade", - required=True, - ) - model_id = fields.Many2one( - "ir.model", - string="Model Ref.", - domain="[('state','=','base')]", - related="workflow_id.model_id", - required=True, - ) - flow_start = fields.Boolean( - string="Flow Start", help="Check it if this node is the starting node." - ) - flow_end = fields.Boolean( - string="Flow End", help="Check it if this node is the ending node." - ) - is_visible = fields.Boolean( - string="Appear in Statusbar", - default=True, - help="Control visiability of the node/state in view.", - ) - out_link_ids = fields.One2many( - comodel_name="soong.workflow.link", - inverse_name="node_from", - string="Outgoing Transitions", - ) - in_link_ids = fields.One2many( - comodel_name="soong.workflow.link", - inverse_name="node_to", - string="Incoming Transitions", - ) - - field_ids = fields.One2many( - comodel_name="soong.workflow.node.field", - inverse_name="node_id", - string="Fields", - ) - button_ids = fields.One2many( - comodel_name="soong.workflow.node.button", - inverse_name="node_id", - string="Buttons", - ) - + sequence = fields.Integer(string="Sequence", default=10, help="Arrange node by defining sequence.") + name = fields.Char(string="Name", translate=True, help="Enter string name of the node.") + node_name = fields.Char(string="Technical Name",help="Generated technical name which used by backend code.",) + workflow_id = fields.Many2one(comodel_name="soong.workflow",string="Workflow Ref.",ondelete="cascade",required=True,) + model_id = fields.Many2one("ir.model",string="Model Ref.",domain="[('state','=','base')]",related="workflow_id.model_id",required=True,) + flow_start = fields.Boolean(string="Flow Start", help="Check it if this node is the starting node.") + flow_end = fields.Boolean(string="Flow End", help="Check it if this node is the ending node.") + is_visible = fields.Boolean(string="Appear in Statusbar",default=True,help="Control visiability of the node/state in view.",) + out_link_ids = fields.One2many(comodel_name="soong.workflow.link",inverse_name="node_from",string="Outgoing Transitions",) + in_link_ids = fields.One2many(comodel_name="soong.workflow.link",inverse_name="node_to",string="Incoming Transitions",) + field_ids = fields.One2many(comodel_name="soong.workflow.node.field",inverse_name="node_id",string="Fields",) + button_ids = fields.One2many(comodel_name="soong.workflow.node.button",inverse_name="node_id",string="Buttons",) diagram_position = fields.Char(readonly=True, string="Diagram Position") bg_color = fields.Char(default=DEFAULT_BG_COLOR, string="Background Color") label_color = fields.Char(default=DEFAULT_LABEL_COLOR, string="Label Color") - # Custom colors - use_custom_colors = fields.Boolean( - help="Select colors from the palette manually", string="Use Custom Colors" - ) - res_bg_color = fields.Char( - compute="_compute_custom_colors", readonly=True, string="Backgroung Color" - ) - res_label_color = fields.Char( - compute="_compute_custom_colors", readonly=True, string="Label Color" - ) + use_custom_colors = fields.Boolean(help="Select colors from the palette manually", string="Use Custom Colors") + res_bg_color = fields.Char(compute="_compute_custom_colors", readonly=True, string="Backgroung Color") + res_label_color = fields.Char(compute="_compute_custom_colors", readonly=True, string="Label Color") + + @api.model_create_multi + def create(self, values): + for val in values: + if val['node_name'] != 'end': + if not val["button_ids"]: + val["button_ids"] = [ + (0, 0, { + "name": _("转交"), + "workflow_id": val['workflow_id'], + "sequence": 1, + "action_type": "code", + "code": "obj.action_transmitted()", + "has_comment": True, + },), + (0, 0, { + "name": _("收回"), + "workflow_id": val['workflow_id'], + "sequence": 2, + "action_type": "code", + "code": "obj.action_return()", + },) + ] + return super().create(values) @api.depends("bg_color", "label_color", "use_custom_colors", "flow_start", "flow_end") def _compute_custom_colors(self): @@ -210,7 +183,7 @@ class SoongWorkflowNodeButton(models.Model): string="Icon", help="Enter icon name like: fa-print, it's recommended to use FontAwesome Icons.", ) - has_comment = fields.Boolean(string="Comment", default=False) + has_comment = fields.Boolean(string="评论", default=False) btn_key = fields.Char(string="Button Key", default=_generate_key) btn_hide = fields.Boolean( string="Hide Button if Condition isn't fulfilled", diff --git a/soong_workflow/security/ir.model.access.csv b/soong_workflow/security/ir.model.access.csv index bd24009db..ceb16fda0 100644 --- a/soong_workflow/security/ir.model.access.csv +++ b/soong_workflow/security/ir.model.access.csv @@ -23,6 +23,4 @@ access_soong_approval_group,soong_approval_group,model_soong_approval_group,soon access_soong_approval_notice_wizard,soong_approval_notice_wizard,model_soong_approval_notice_wizard,base.group_user,1,1,1,1 access_soong_workflow_log_user,soong_workflow_log_user,model_soong_workflow_log,soong_workflow.group_soong_workflow_user,1,1,1,1 -access_soong_workflow_comment_wizard_user,soong_workflow_comment_wizard_user,model_soong_workflow_comment_wizard,soong_workflow.group_soong_workflow_user,1,1,1,1 - -access_soong_approval_transmitted_wizard,soong_approval_transmitted_wizard,model_soong_approval_transmitted_wizard,soong_workflow.group_soong_workflow_user,1,1,1,1 \ No newline at end of file +access_soong_workflow_comment_wizard_user,soong_workflow_comment_wizard_user,model_soong_workflow_comment_wizard,soong_workflow.group_soong_workflow_user,1,1,1,1 \ No newline at end of file diff --git a/soong_workflow/views/soong_workflow_views.xml b/soong_workflow/views/soong_workflow_views.xml index 502a5ee36..26677356f 100644 --- a/soong_workflow/views/soong_workflow_views.xml +++ b/soong_workflow/views/soong_workflow_views.xml @@ -27,6 +27,7 @@ + diff --git a/soong_workflow/wizard/__init__.py b/soong_workflow/wizard/__init__.py index b8d44c6f0..e66025961 100644 --- a/soong_workflow/wizard/__init__.py +++ b/soong_workflow/wizard/__init__.py @@ -3,7 +3,6 @@ from . import approval_notice_wizard -from . import soong_transmitted_wizard from . import soong_workflow_comment_wizard diff --git a/soong_workflow/wizard/soong_transmitted_wizard.py b/soong_workflow/wizard/soong_transmitted_wizard.py deleted file mode 100644 index 3fa508c64..000000000 --- a/soong_workflow/wizard/soong_transmitted_wizard.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- -from odoo import api, fields, models, tools, _ -from datetime import datetime, date, time, timedelta -from odoo.tools.safe_eval import safe_eval -from odoo.exceptions import ValidationError, UserError -import logging - -_logger = logging.getLogger(__name__) - - -class SoongApprovalTransmittedWizard(models.TransientModel): - _name = 'soong.approval.transmitted.wizard' - _description = """ 转交弹窗 """ - - name = fields.Char(string='名称') - - def confirm(self): - pass \ No newline at end of file diff --git a/soong_workflow/wizard/soong_transmitted_wizard_views.xml b/soong_workflow/wizard/soong_transmitted_wizard_views.xml deleted file mode 100644 index 162ea4ab4..000000000 --- a/soong_workflow/wizard/soong_transmitted_wizard_views.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - 一键转交 - soong.approval.transmitted.wizard - -
- - - - -
-
-
-
-
-
\ No newline at end of file diff --git a/soong_workflow/wizard/soong_workflow_comment_wizard.py b/soong_workflow/wizard/soong_workflow_comment_wizard.py index c667f15c2..cfd79764b 100644 --- a/soong_workflow/wizard/soong_workflow_comment_wizard.py +++ b/soong_workflow/wizard/soong_workflow_comment_wizard.py @@ -12,13 +12,16 @@ class SoongWorkflowCommentWizard(models.TransientModel): res_id = fields.Integer() log_ids = fields.Many2many(comodel_name="soong.workflow.log") node_btn_id = fields.Many2one(comodel_name="soong.workflow.node.button") + button_type = fields.Selection([('trans', '转交'), ('other', '其他')], string="按钮类型", default='other') comment_note_id = fields.Many2one('soong.note', required=True, string="意见") comment_type = fields.Selection(related="comment_note_id.type", string="意见类型") comment_return_type = fields.Char(related="comment_note_id.return_type", string="退回类型") + state_list = fields.Char(string="状态列表") + employee_ids = fields.Many2many('hr.employee', string="提醒经办人") + notice_message = fields.Char(string="消息通知") def add_comment(self): self.ensure_one() cx = self.env.context.copy() or {} - self.log_ids.write({"comment": self.comment}) return self.node_btn_id.with_context(cx).run() diff --git a/yuthon_hr_employee/models/yuthon_hr_department.py b/yuthon_hr_employee/models/yuthon_hr_department.py index a9606bd1e..a34c73e9c 100644 --- a/yuthon_hr_employee/models/yuthon_hr_department.py +++ b/yuthon_hr_employee/models/yuthon_hr_department.py @@ -4,7 +4,7 @@ from odoo import api, fields, models class YuthonHrDepartment(models.Model): _inherit = "hr.department" - _order = 'department_code' + _order = 'department_code asc' department_phone = fields.Char(string="部门电话") department_fax = fields.Char(string="部门传真") diff --git a/yuthon_hr_employee/models/yuthon_hr_employee.py b/yuthon_hr_employee/models/yuthon_hr_employee.py index 08f98aae4..da037c3e2 100644 --- a/yuthon_hr_employee/models/yuthon_hr_employee.py +++ b/yuthon_hr_employee/models/yuthon_hr_employee.py @@ -20,7 +20,7 @@ class YuthonHrEmployee(models.Model): 对原模型数据的隐藏,字段的开发和添加 """ _inherit = "hr.employee" - _order = 'number' + _order = 'number asc' # odoo里是这样做的,一个用户可以多个公司绑定多个员工,每个员工都有自己的部门和岗位 @@ -28,7 +28,6 @@ class YuthonHrEmployee(models.Model): user_number = fields.Char(string="员工编号", default=lambda self: self.env['ir.sequence'].next_by_code('employee_code')) use_user_type = fields.Selection([('formal', '正式职工'), ('labor', '劳务协议'), ('part_time', '兼职协议'), ('employment', '兼职用工')], string="用工形式") - job_lv_id = fields.Many2one('yuthon.job.lv', string="最新职级") # 个人信息 user_salary = fields.Float(string="基本工资") diff --git a/yuthon_work_brand/__manifest__.py b/yuthon_work_brand/__manifest__.py index cd076bf01..3d42a0977 100644 --- a/yuthon_work_brand/__manifest__.py +++ b/yuthon_work_brand/__manifest__.py @@ -9,6 +9,7 @@ """, 'depends': ['base', 'board', + 'spreadsheet_dashboard', 'yuthon_notice', 'soong_workflow', 'yuthon_issue', diff --git a/yuthon_work_brand/views/hr_menus.xml b/yuthon_work_brand/views/hr_menus.xml index 99055b491..596d19861 100644 --- a/yuthon_work_brand/views/hr_menus.xml +++ b/yuthon_work_brand/views/hr_menus.xml @@ -1,21 +1,21 @@ - - False - + + + - - False - + + + - - False - + + + - - False - + + + - + + parent="holiday_manage_menu_root_board" action="yuthon_hr_attendance.holiday_manage_type_action" sequence="1"/> + parent="holiday_manage_menu_root_board" action="yuthon_hr_attendance.holiday_balance_action" sequence="3"/> diff --git a/yuthon_work_brand/views/work_menus.xml b/yuthon_work_brand/views/work_menus.xml index 854d4eaed..1ef7fdbd1 100644 --- a/yuthon_work_brand/views/work_menus.xml +++ b/yuthon_work_brand/views/work_menus.xml @@ -1,21 +1,21 @@ - - False - + + + - - False - + + + - - False - + + + - - False - + + + False @@ -91,76 +91,76 @@ sequence="5"/> + name="议题库" + parent="spreadsheet_dashboard.spreadsheet_dashboard_menu_root" + sequence="7"/> + parent="tianhe_issue_library_menu_root_board" + name="全部" + action="yuthon_issue.issue_library_action" + sequence="1"/> + parent="tianhe_issue_library_menu_root_board" + name="待上会" + action="yuthon_issue.issue_library_action_will" + sequence="5"/> + parent="tianhe_issue_library_menu_root_board" + name="已上会" + action="yuthon_issue.issue_library_action_done" + sequence="10"/> + parent="tianhe_issue_library_menu_root_board" + name="子部门议题库" + sequence="3"/> + parent="tianhe_other_issue_library_menu_board" + name="全部" + action="yuthon_issue.issue_library_action2" + sequence="1"/> + parent="tianhe_other_issue_library_menu_board" + name="待上会" + action="yuthon_issue.issue_library_action_will2" + sequence="3"/> + parent="tianhe_other_issue_library_menu_board" + name="已上会" + action="yuthon_issue.issue_library_action_done2" + sequence="5"/> + parent="tianhe_issue_library_menu_root_board" + name="议题审批" + action="yuthon_issue.issue_library_action" + sequence="9"/> + parent="issue_approval_menu_board" + name="党总支议题审批" + action="yuthon_issue.issue_approval_party_action" + sequence="1"/> + parent="issue_approval_menu_board" + name="领导班子议题审批" + action="yuthon_issue.issue_approval_class_action" + sequence="3"/> + parent="issue_approval_menu_board" + name="董事会议题审批" + action="yuthon_issue.issue_approval_boss_action" + sequence="5"/> + name="会议室" + parent="spreadsheet_dashboard.spreadsheet_dashboard_menu_root" + sequence="9"/> + name="预定" + action="room.room_booking_action" + parent="room_menu_root_board" + sequence="1"/> + name="房间" + action="room.room_room_action" + parent="room_menu_root_board" + sequence="2"/> \ No newline at end of file