@@ -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="附件")
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user