diff --git a/soong_workflow/models/soong_workflow_log.py b/soong_workflow/models/soong_workflow_log.py index 4ace3e958..cfc27d325 100644 --- a/soong_workflow/models/soong_workflow_log.py +++ b/soong_workflow/models/soong_workflow_log.py @@ -24,6 +24,7 @@ class SoongWorkflowLog(models.Model): node_btn_id = fields.Many2one(comodel_name="soong.workflow.node.button", string="动作名称") node_btn_name = fields.Selection([('0', ' '), ('1', '退回'), ('2', '加签'), ('3', '串'), ('4', '并'), ('5', '董事长'), ('6', '承办')], store=True, string='节点功能', default='0') done_by = fields.Many2one(comodel_name="res.users", string="审批人") + done_by_display = fields.Char(string="审批人显示(流程委托)") add_sign_by = fields.Many2one(comodel_name="res.users", string="加签发起人") lase_click_date = fields.Datetime(string="操作时间") approval_state = fields.Selection([('0', '待办'), ('1', '办理中'), ('2', '已办结'), ('3', '结束')], string='状态', default='0') @@ -34,10 +35,10 @@ class SoongWorkflowLog(models.Model): is_active_operate = fields.Boolean(string="归档操作") display_field = fields.Char(string="显示字段", compute="_compute_display_field") - @api.depends("lase_click_date", "done_by") + @api.depends("lase_click_date", "done_by", "done_by_display") def _compute_display_field(self): for record in self: - user_name = record.done_by.name or "" + user_name = record.done_by_display or (record.done_by.name or "") if record.lase_click_date: lase_click_date = record.lase_click_date.strftime("%Y-%m-%d") else: @@ -77,6 +78,7 @@ class SoongWorkflowLog2(models.Model): msg_id = fields.Char(string="Msg_id") sequence = fields.Integer(string="序号", default=10) done_by = fields.Many2one(comodel_name="res.users", string="审批人") + done_by_display = fields.Char(string="审批人显示(流程委托)") name = fields.Char(string="节点名称", compute="_compute_name", store=True) approval_state = fields.Selection([('0', '待办理'), ('1', '办理中'), ('2', '已办结')], string='状态', default='0') document_ids = fields.Many2many('ir.attachment', string="附件") diff --git a/soong_workflow/models/soong_workflow_record.py b/soong_workflow/models/soong_workflow_record.py index 64ec39b84..0b79db7dd 100644 --- a/soong_workflow/models/soong_workflow_record.py +++ b/soong_workflow/models/soong_workflow_record.py @@ -183,14 +183,16 @@ class SoongWorkflowRecord(models.Model): if hasattr(target, 'log_ids'): for log in target.log_ids: if log.approval_state in ('0', '1') and log.done_by and log.done_by.name: - if log.done_by.name not in names: - names.append(log.done_by.name) + _name = log.done_by_display or log.done_by.name + if _name not in names: + names.append(_name) # 从log_ids2中获取待办/办理中的审批人 if hasattr(target, 'log_ids2'): for log2 in target.log_ids2: if log2.approval_state in ('0', '1') and log2.done_by and log2.done_by.name: - if log2.done_by.name not in names: - names.append(log2.done_by.name) + _name = log2.done_by_display or log2.done_by.name + if _name not in names: + names.append(_name) record.pending_users = ','.join(names) except Exception as e: _logger.warning(f"Failed to compute pending_users for record {record.id}: {e}") diff --git a/soong_workflow/wizard/soong_workflow_comment_wizard.py b/soong_workflow/wizard/soong_workflow_comment_wizard.py index 857be13b2..6ccef7bb0 100644 --- a/soong_workflow/wizard/soong_workflow_comment_wizard.py +++ b/soong_workflow/wizard/soong_workflow_comment_wizard.py @@ -240,6 +240,27 @@ class SoongWorkflowCommentWizard(models.TransientModel): # ]) # self.employee_ids1 = employee_user_role_ids + def _get_entrust_substitution(self, model_name): + """返回 {委托人 user_id: 被委托人 hr.employee} 映射。 + 仅包含对当前模型(或在"全部流程"中)生效且在有效期内的流程委托(soong.workflow.entrust)。 + """ + substitution = {} + entrust_all = self.env['ir.model'].sudo().search([('model', '=', 'entrust.all')], limit=1) + model = self.env['ir.model'].sudo().search([('model', '=', model_name)], limit=1) + if not model and not entrust_all: + return substitution + entrusts = self.env['soong.workflow.entrust'].sudo().search([('is_enable', '=', True)]) + for ent in entrusts: + model_ids = ent.model_ids.ids + # 命中"全部流程"(entrust.all) 或 当前业务模型 + in_scope = (entrust_all and entrust_all.id in model_ids) or (model and model.id in model_ids) + if in_scope and ent.entrust_user_id and ent.entrust_user_id2: + delegatee = self.env['hr.employee'].sudo().search( + [('user_id', '=', ent.entrust_user_id2.id)], limit=1) + if delegatee: + substitution[ent.entrust_user_id.id] = delegatee + return substitution + @api.onchange('trans_link_id') def onchange_trans_employee_ids(self): for record in self: @@ -510,6 +531,8 @@ class SoongWorkflowCommentWizard(models.TransientModel): record_has_stamps = hasattr(record_id, 'type_stamp_ids') and bool(record_id.type_stamp_ids) is_transfer_to_stamp = self.trans_link_id and self.trans_link_id.name == '印章管理员' is_stamp_reviewer = bool(current_node_log and getattr(current_node_log, 'stamp_id', False)) + # 流程委托:当前模型(或"全部流程")且在有效期内的 {委托人 user_id: 被委托人 hr.employee} + entrust_substitution = self._get_entrust_substitution(self.res_model) if self.node_btn_name == '转交' else {} if is_transfer_to_stamp and record_has_stamps: # 场景1:转交到印章管理员节点,按章分组建待办(章间并审、章内串审) @@ -562,9 +585,22 @@ class SoongWorkflowCommentWizard(models.TransientModel): # 检查是否为并审模式(印章节点的人提交时也走并审,实现章间并审) elif is_stamp_reviewer or self.approval_concatenation == 'bing': # 并审模式 expected_employees = self.employee_ids + # 流程委托:把选中的委托人解析为实际审批人(被委托人) + delegation_targets = [] + for selected_employee in expected_employees: + actual_employee = selected_employee + is_delegated = False + if selected_employee.user_id and selected_employee.user_id.id in entrust_substitution: + actual_employee = entrust_substitution[selected_employee.user_id.id] + is_delegated = True + delegation_targets.append((selected_employee, actual_employee, is_delegated)) + effective_employees = self.env['hr.employee'] + for selected_employee, actual_employee, is_delegated in delegation_targets: + if actual_employee: + effective_employees |= actual_employee if record_id.log_ids2: log_employee_ids = record_id.log_ids2.mapped('done_by.employee_id.id') - self.employee_ids = expected_employees.filtered(lambda emp: emp.id not in log_employee_ids) + effective_employees = effective_employees.filtered(lambda emp: emp.id not in log_employee_ids) # 查找下一个节点 if self.trans_link_id: @@ -583,7 +619,10 @@ class SoongWorkflowCommentWizard(models.TransientModel): all_completed = len(completed_logs) == 0 next_node_log_records = self.env["soong.workflow.log"] if all_completed: - for employee in self.employee_ids: + for employee in effective_employees: + is_delegated = any(employee.id == actual_employee.id + for selected_employee, actual_employee, is_delegated in delegation_targets + if is_delegated) # 检查该员工在下一节点是否已有记录 next_node_employee_log = self.sudo().env["soong.workflow.log"].search([ ("model", "=", self.res_model), @@ -602,6 +641,7 @@ class SoongWorkflowCommentWizard(models.TransientModel): "node_id": next_node_id.id, "workflow_id": self.node_btn_id.workflow_id.id, "done_by": employee.user_id.id, + "done_by_display": f"{employee.name}(委托人)" if is_delegated else False, "node_btn_name": "4", "approval_state": "0", # 待审批 }) @@ -609,17 +649,22 @@ class SoongWorkflowCommentWizard(models.TransientModel): workflow_record_id = self.env['soong.workflow.record'].sudo().search([('res_id', '=', record_id.id), ('res_model', '=', record_id._name) ]) - workflow_record_id.users_ids = [(4, employee.user_id.id) for employee in self.employee_ids if employee.user_id] - workflow_record_id.employee_ids = self.employee_ids.ids + # 被委托人(实际经办) + 委托人(原选中人) 都可见 + visible_uids = [emp.user_id.id for emp in effective_employees if emp.user_id] + for selected_employee, actual_employee, is_delegated in delegation_targets: + if is_delegated and selected_employee.user_id and selected_employee.user_id.id not in visible_uids: + visible_uids.append(selected_employee.user_id.id) + workflow_record_id.users_ids = [(4, uid) for uid in visible_uids] + workflow_record_id.employee_ids = effective_employees.ids workflow_record_id.approve_state = "pending" # 待审批 related_record = self.env[self.res_model].browse(self.res_id) if hasattr(related_record, 'self_users_ids'): - user_ids = [employee.user_id.id for employee in self.employee_ids if employee.user_id] + user_ids = [emp.user_id.id for emp in effective_employees if emp.user_id] related_record.self_users_ids = [(6, 0, user_ids)] if user_ids else [(5,)] if not self.trans_link_id.name: raise UserError('无转交节点') record_id.write({'state': self.trans_link_id.name}) - for employee in self.employee_ids: + for employee in effective_employees: action_id = self.env['ir.actions.act_window'].search([('res_model', '=', self.res_model)])[0] target_url = f'https://oa.thtzjt.com/web#id={record_id.id}&cids=2&active_id={action_id.id}&model={record_id._name}&view_type=form' url = self.sudo().env["wecom.apps"].generate_oauth_login_url(target_url, employee.user_id.id) @@ -646,15 +691,25 @@ class SoongWorkflowCommentWizard(models.TransientModel): ('name', 'ilike', self.trans_link_id.name), ('workflow_id', '=', record_id.workflow_id.id) ]) - for employee_id in self.employee_ids: - # 创建下一节点的审批记录 + # 流程委托:把选中的委托人解析为实际审批人(被委托人),双方都可见 + delegation_targets = [] + for selected_employee in self.employee_ids: + actual_employee = selected_employee + is_delegated = False + if selected_employee.user_id and selected_employee.user_id.id in entrust_substitution: + actual_employee = entrust_substitution[selected_employee.user_id.id] + is_delegated = True + delegation_targets.append((selected_employee, actual_employee, is_delegated)) + for selected_employee, actual_employee, is_delegated in delegation_targets: + # 创建下一节点的审批记录(done_by 落库为被委托人) self.sudo().env["soong.workflow.log"].create({ "code": self.code, "model": self.res_model, "res_id": self.res_id, "node_id": next_node_id.id, "workflow_id": self.node_btn_id.workflow_id.id, - "done_by": employee_id.user_id.id if self.employee_ids else query_user_id, + "done_by": actual_employee.user_id.id if actual_employee.user_id else query_user_id, + "done_by_display": f"{actual_employee.name}(委托人)" if is_delegated else False, "node_btn_name": "3", "approval_state": "1", # 待审批 }) @@ -662,15 +717,20 @@ class SoongWorkflowCommentWizard(models.TransientModel): # 更新业务记录状态 related_record = self.env[self.res_model].browse(self.res_id) if hasattr(related_record, 'self_users_ids'): - user_ids = [employee.user_id.id for employee in self.employee_ids if employee.user_id] + user_ids = [actual_employee.user_id.id for selected_employee, actual_employee, is_delegated in delegation_targets if actual_employee.user_id] related_record.self_users_ids = [(6, 0, user_ids)] if user_ids else [(5,)] record_id.write({'state': self.trans_link_id.name}) workflow_record_id = self.env['soong.workflow.record'].sudo().search([('res_id', '=', record_id.id), ('res_model', '=', record_id._name) ]) - workflow_record_id.users_ids = [(4, employee.user_id.id) for employee in self.employee_ids if - employee.user_id] - workflow_record_id.employee_ids = self.employee_ids.ids + # 被委托人(实际经办) + 委托人(原选中人) 都可见 + visible_uids = [actual_employee.user_id.id for selected_employee, actual_employee, is_delegated in delegation_targets if actual_employee.user_id] + for selected_employee, actual_employee, is_delegated in delegation_targets: + if is_delegated and selected_employee.user_id and selected_employee.user_id.id not in visible_uids: + visible_uids.append(selected_employee.user_id.id) + + workflow_record_id.users_ids = [(4, uid) for uid in visible_uids] + workflow_record_id.employee_ids = [actual_employee.id for selected_employee, actual_employee, is_delegated in delegation_targets if actual_employee] workflow_record_id.approve_state = "pending" # 待审批 for employee in self.circulated_employee_ids: