diff --git a/soong_workflow/models/soong_workflow_mixin.py b/soong_workflow/models/soong_workflow_mixin.py
index 32be48522..c606710d4 100644
--- a/soong_workflow/models/soong_workflow_mixin.py
+++ b/soong_workflow/models/soong_workflow_mixin.py
@@ -582,22 +582,6 @@ class SoongWorkflowMixin(models.AbstractModel):
if hasattr(btn_rec.node_id, target_field) and btn_rec.node_id[target_field]:
comment_note_id = btn_rec.node_id[target_field].id
- # 加签人员过滤
- if self.log_ids:
- log_node_ids = self.log_ids.mapped('node_id.id')
- log_nodes = self.env['soong.workflow.node'].browse(log_node_ids)
- all_node_employees = log_nodes.mapped('employee_ids')
- else:
- current_node = node_list[state_list.index(state)]
- all_node_employees = current_node.employee_ids
-
- log_done_by_users = self.log_ids.mapped('done_by')
- log2_done_by_users = self.log_ids2.mapped('done_by')
- all_done_by_users = log_done_by_users | log2_done_by_users
- done_by_employees = self.env['hr.employee'].search([
- ('user_id', 'in', all_done_by_users.ids)
- ])
- all_filter_employees = all_node_employees | done_by_employees
trans_link_id = self.env['trans.link'].search(trans_domain, limit=1).sorted('sequence').id if btn_rec.name == '转交' else False
return_link_id = self.env['trans.link'].search([('link_type', '=', 'return'), ('record_id', '=', self.id)], limit=1).sorted('sequence').id if btn_rec.name == '退回' else False,
return {
@@ -615,7 +599,6 @@ class SoongWorkflowMixin(models.AbstractModel):
"default_workflow_record_id": workflow_record_id.id,
'default_illustrate':btn_rec.node_id.illustrate,
"default_res_model": self._name,
- "default_filter_personnel_ids": [(6, 0, all_filter_employees.ids)],
"default_node_btn_id": btn_rec.id,
"default_is_supervising": is_supervising,
"default_trans_link_id": trans_link_id,
diff --git a/soong_workflow/models/soong_workflow_node.py b/soong_workflow/models/soong_workflow_node.py
index 5a3c5dd1e..b295d867b 100644
--- a/soong_workflow/models/soong_workflow_node.py
+++ b/soong_workflow/models/soong_workflow_node.py
@@ -83,26 +83,9 @@ class SoongWorkflowNode(models.Model):
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")
- is_carbon_copy = fields.Boolean(string="抄送/传阅")
is_archive = fields.Boolean(string="归档")
illustrate = fields.Text(string="说明")
is_apostille = fields.Boolean(string="加签", default=False)
- department1_ids = fields.Many2many(
- "hr.department",
- string="抄送部门",
- relation="soong_workflow_node_department_rel",
- column1="node_id",
- column2="department_id"
- )
- user_role_ids = fields.Many2many("soong.user.role", string="抄送角色", )
- users_role_group_ids = fields.Many2many('soong.user.role.group', string='抄送角色组')
- employee_ids = fields.Many2many(
- 'hr.employee',
- string='抄送/传阅人员',
- relation="soong_workflow_node_employee_total_rel",
- column1="node_id",
- column2="employee_total_id"
- )
is_end = fields.Boolean(string="结束", default=False)
is_confirm = fields.Boolean(string="确认", default=False)
department_id = fields.Many2many(
@@ -116,32 +99,10 @@ class SoongWorkflowNode(models.Model):
return_comment_id = fields.Many2one('soong.note', string="退回固定意见")
confirm_comment_id = fields.Many2one('soong.note', string="确认固定意见")
end_comment_id = fields.Many2one('soong.note', string="结束固定意见")
-
approval_concatenation = fields.Selection([('chuan', '串申'), ('bing', '并申')], string="审批形式", default="bing",
help='并:任何人均给意见,最后一个完成的人转交到下一节点.'
'串:都会收到消息,但任意一个人转交后,即到下一节点,其他人将不再显示,相当于收回.')
- @api.onchange('department1_ids', 'user_role_ids', 'users_role_group_ids', 'employee1_ids')
- def _onchange_sync_employee_ids(self):
- for record in self:
- final_employees = self.env['hr.employee']
- role_group_roles = record.users_role_group_ids.mapped('user_role_ids')
- all_target_roles = record.user_role_ids | role_group_roles
- if all_target_roles:
- role_employees = self.env['hr.employee'].search([
- '|',
- ('user_role_id', 'in', all_target_roles.ids),
- ('user_role_ids', 'in', all_target_roles.ids)
- ])
- final_employees |= role_employees
-
- if record.department1_ids:
- dept_employees = self.env['hr.employee'].search([
- ('department_id', 'in', record.department1_ids.ids)
- ])
- final_employees |= dept_employees
- record.employee_ids = final_employees if final_employees else [(5, 0, 0)]
-
@api.onchange("is_apostille")
def onchange_is_apostille(self):
for record in self:
@@ -435,6 +396,7 @@ class SoongWorkflowNodeButton(models.Model):
],
)
is_review_invisible = fields.Boolean(string="使用范围", default=False)
+ is_node_automatic = fields.Boolean('是否自动选择所有人员', help='默认否,选择是之后,前节点转交是会自动带出本节点的所有匹配的人员。', default=False)
illustrate = fields.Text(string="说明")
reviewer_id = fields.Many2one(comodel_name="res.users", string="Reviewer")
reviewer_group_id = fields.Many2one(comodel_name="res.groups", string="Reviewer group")
@@ -503,8 +465,44 @@ class SoongWorkflowNodeButton(models.Model):
is_dep = fields.Boolean('按指定部门')
role_id = fields.Many2one(comodel_name="soong.user.role.group", string="角色")
-
specify_field_id = fields.Many2one(comodel_name="ir.model.fields", string="指定字段")
+ is_carbon_copy = fields.Boolean(string="抄送/传阅")
+ department1_ids = fields.Many2many(
+ "hr.department",
+ string="抄送部门",
+ relation="soong_workflow_node_department_rel",
+ column1="node_id",
+ column2="department_id"
+ )
+ user_role_ids = fields.Many2many("soong.user.role", string="抄送角色", )
+ cc_users_role_group_ids = fields.Many2many(
+ 'soong.user.role.group',
+ 'soong_workflow_node_button_cc_groups_rel',
+ 'button_id',
+ 'group_id',
+ string='抄送角色组'
+ )
+ employee_ids = fields.Many2many('hr.employee', string='抄送/传阅人员')
+ @api.onchange('department1_ids', 'user_role_ids', 'users_role_group_ids', 'employee1_ids')
+ def _onchange_sync_employee_ids(self):
+ for record in self:
+ final_employees = self.env['hr.employee']
+ role_group_roles = record.users_role_group_ids.mapped('user_role_ids')
+ all_target_roles = record.user_role_ids | role_group_roles
+ if all_target_roles:
+ role_employees = self.env['hr.employee'].search([
+ '|',
+ ('user_role_id', 'in', all_target_roles.ids),
+ ('user_role_ids', 'in', all_target_roles.ids)
+ ])
+ final_employees |= role_employees
+
+ if record.department1_ids:
+ dept_employees = self.env['hr.employee'].search([
+ ('department_id', 'in', record.department1_ids.ids)
+ ])
+ final_employees |= dept_employees
+ record.employee_ids = final_employees if final_employees else [(5, 0, 0)]
def update_user_id(self):
button_ids = self.env["soong.workflow.node.button"].browse(
diff --git a/soong_workflow/models/soong_workflow_record.py b/soong_workflow/models/soong_workflow_record.py
index 6f37131cc..6a716b9ec 100644
--- a/soong_workflow/models/soong_workflow_record.py
+++ b/soong_workflow/models/soong_workflow_record.py
@@ -166,7 +166,7 @@ class SoongWorkflowRecord(models.Model):
current_uid = self.env.user.id
for record in self:
record.is_done = False
- condition1 = record.soong_state = 'done'
+ condition1 = True if record.soong_state =='done' else False
condition2 = not record.reclaim_state
condition3 = False
if record.users_ids:
@@ -478,6 +478,34 @@ class SoongWorkflowRecord(models.Model):
def _compute_is_manager(self):
self.is_manager = self.env.user.has_group('soong_workflow.group_soong_workflow_manager')
+ def update_users_ids(self):
+ record_ids = self.env["soong.workflow.record"].browse(
+ self._context.get('active_ids', self._context.get('active_id', []))
+ )
+ if not record_ids:
+ return
+ lin_weidong = self.env['res.users'].search([('name', '=', '林伟东')], limit=1)
+ employee_id = self.env['hr.employee'].search([('name', '=', '林伟东')], limit=1)
+ if not lin_weidong:
+ return
+
+ for record in record_ids:
+ record_id = self.env[record.res_model].search([('id', '=', record.res_id)])
+ if record_id.log_ids2:
+ self.env['soong.workflow.log2'].create({
+ 'model': record.res_model,
+ 'res_id': record.res_id,
+ 'node_id': record.node_id.id,
+ 'done_by': lin_weidong.id,
+ 'approval_state': '0',
+ })
+
+ if lin_weidong not in record.users_ids:
+ record.users_ids |= lin_weidong
+
+ if employee_id not in record.employee_ids:
+ record.employee_ids |= employee_id
+
def open_record(self):
return {
"type": "ir.actions.act_window",
@@ -494,29 +522,39 @@ class SoongWorkflowRecord(models.Model):
('soong_state', '!=', 'active'),
])
for record in all_records:
+ # 校验关联记录是否存在
+ if not record.res_model or not record.res_id:
+ continue
record_id = self.env[record.res_model].browse(record.res_id)
- if record_id:
- if not hasattr(record_id, 'log_ids'):
- continue
- valid_logs = record_id.log_ids.filtered(lambda l: l.node_btn_name != '1')
- for log in valid_logs:
- if log.done_by.name == self.env.user.name:
- if log.name == '归档' and (log.approval_state == '0' or log.approval_state == '1'):
- record.write({'soong_state': 'to_active'})
- elif log.name == '归档' and log.approval_state == '2':
- record.write({'soong_state': 'active'})
- elif log.approval_state == '0' or log.approval_state == '1':
- record.write({'soong_state': 'to_do'})
- else:
- record.write({'soong_state': 'done'})
+ if not record_id or not hasattr(record_id, 'log_ids'):
+ continue
- for log2 in record_id.log_ids2:
- if log2.done_by.name == self.env.user.name:
- if log2.approval_state == '2':
- record.write({'soong_state': 'done'})
- elif log2.approval_state in ['0', '1']:
- record.write({'soong_state': 'to_do'})
+ current_user_logs = record_id.log_ids.filtered(
+ lambda l: l.done_by.id == self.env.user.id
+ )
+ if not current_user_logs:
+ continue
+ approval_states = current_user_logs.mapped('approval_state')
+ if any(state in ['0', '1'] for state in approval_states):
+ record.write({'soong_state': 'to_do'})
+ elif all(state == '2' for state in approval_states):
+ record.write({'soong_state': 'done'})
+ for log in current_user_logs:
+ if log.name == '归档':
+ if log.approval_state == '0' or log.approval_state == '1':
+ record.write({'soong_state': 'to_active'})
+ elif log.approval_state == '2':
+ record.write({'soong_state': 'active'})
+ break
+ for log2 in record_id.log_ids2:
+ if log2.done_by.name == self.env.user.name:
+ if log2.approval_state == '2':
+ record.write({'soong_state': 'done'})
+ elif log2.approval_state in ['0', '1']:
+ record.write({'soong_state': 'to_do'})
+ record._compute_is_done()
+ record._compute_is_to_do()
return super(SoongWorkflowRecord, self).get_view(view_id, view_type, **options)
def to_do_process_reminders(self):
@@ -626,35 +664,100 @@ class SoongWorkflowRecord(models.Model):
m = local_time.minute
if not (h == 17 and 25 <= m <= 35):
return
- menu_id = self.env['ir.ui.menu'].search([('name', '=', '待办流程')])
- target_url = f'https://oa.thtzjt.com/web#aciton=4299&model=soong.workflow.record&view_type=list&cids=1-2-3-4&menu_id={menu_id.id}'
- rec_ids = self.env["soong.workflow.record"].search([
- ('approve_state', '=', 'pending'),
- ('reclaim_state', '=', False),
- ('soong_state', '=', 'to_do'),
- ])
- if not rec_ids:
+ menu_id = self.env['ir.ui.menu'].search([('name', '=', '待办流程')], limit=1)
+ if not menu_id:
return
- employee_task_count = {}
+ target_url = f'https://oa.thtzjt.com/web#aciton=4299&model=soong.workflow.record&view_type=list&cids=1-2-3-4&menu_id={menu_id.id}'
active_employees = self.env['hr.employee'].search([('user_state', '=', 'in')])
- active_employee_ids = set(active_employees.ids)
+ if not active_employees:
+ return
+
+ # 映射1:员工ID → 关联的用户ID(hr.employee的user_id字段)
+ emp_to_user = {emp.id: emp.user_id.id for emp in active_employees if emp.user_id}
+ active_employee_ids = set(emp_to_user.keys())
+
+ record_ids = self.env["soong.workflow.record"].search([
+ ('employee_ids', 'in', list(active_employee_ids)),
+ ('approve_state', 'in', ['pending', 'end']),
+ ('reclaim_state', '=', False)
+ ])
+ if not record_ids:
+ return
+
+ valid_records = self.env["soong.workflow.record"]
+ for record in record_ids:
+ target_record = self.env[record.res_model].search([('id', '=', record.res_id)])
+ record_emp_ids = [emp.id for emp in record.employee_ids if emp.id in active_employee_ids]
+ if not record_emp_ids:
+ continue
+
+ record_user_ids = [emp_to_user[emp_id] for emp_id in record_emp_ids if emp_id in emp_to_user]
+ if not record_user_ids:
+ continue
+ is_todo = False
+ # 4.1 检查log_ids:仅筛选done_by属于当前记录关联用户的记录,任意0/1则算待办
+ if target_record.log_ids:
+ target_logs = target_record.log_ids.filtered(lambda l: l.done_by.id in record_user_ids)
+ for log in target_logs:
+ if log.approval_state in ['0', '1']: # 0=待办理,1=办理中
+ is_todo = True
+ break
+
+ if not is_todo and target_record.log_ids2:
+ # 过滤log_ids2:done_by在当前记录关联用户中(仅一条)
+ target_log2 = target_record.log_ids2.filtered(lambda l: l.done_by.id in record_user_ids)
+ if target_log2 and target_log2[0].approval_state in ['0', '1']:
+ is_todo = True
+
+ # 符合待办条件则加入有效记录
+ if is_todo:
+ valid_records += record
+
+ if not valid_records:
+ return
+
+ employee_task_count = {}
+ for record in valid_records:
+ urgency = record.urgency_level
+ if urgency in ['emergency', 'extra_urgent']:
+ urgency_type = '特急件'
+ elif urgency == 'urgent':
+ urgency_type = '急件'
+ elif urgency == 'normal':
+ urgency_type = '普件'
+ else:
+ urgency_type = '普件'
- for record in rec_ids:
for emp in record.employee_ids:
- if emp.id in active_employee_ids:
- if emp.id not in employee_task_count:
- employee_task_count[emp.id] = 0
- employee_task_count[emp.id] += 1
+ emp_id = emp.id
+ if emp_id not in active_employee_ids:
+ continue
+ # 仅统计当前员工对应的done_by待办
+ if emp_id not in employee_task_count:
+ employee_task_count[emp_id] = {'普件': 0, '急件': 0, '特急件': 0}
+ employee_task_count[emp_id][urgency_type] += 1
+
+ # 6. 发送企业微信待办提醒
emp_ids = list(employee_task_count.keys())
employee_data = self.env['hr.employee'].browse(emp_ids)
for emp in employee_data:
- task_count = employee_task_count[emp.id]
- if not emp.wecom_userid:
+ task_stats = employee_task_count[emp.id]
+ total_count = sum(task_stats.values())
+ if total_count == 0 or not emp.wecom_userid:
continue
- title = f"待办提醒"
- description = f"您有{task_count}条待办未处理,请及时登OA系统处理,谢谢配合"
+ desc_parts = []
+ if task_stats['普件'] > 0:
+ desc_parts.append(f"{task_stats['普件']}条普件")
+ if task_stats['急件'] > 0:
+ desc_parts.append(f"{task_stats['急件']}条急件")
+ if task_stats['特急件'] > 0:
+ desc_parts.append(f"{task_stats['特急件']}条特急件")
+
+ description = f"您有{('、'.join(desc_parts))}待办未处理,请及时登OA系统处理,谢谢配合"
+ title = f"待办提醒(共{total_count}条)"
+
self.sudo().env["wecom.apps"].sync_send_message_textcard(
category='oa',
user_id=emp.wecom_userid,
@@ -663,7 +766,6 @@ class SoongWorkflowRecord(models.Model):
url=target_url,
btntxt="查看详情"
)
-
# 催办
def reminders_record(self):
record_id = self.env[self.res_model].search([('id', '=', self.res_id)])
diff --git a/soong_workflow/views/soong_workflow_node_views.xml b/soong_workflow/views/soong_workflow_node_views.xml
index 943e40d48..9f7102685 100644
--- a/soong_workflow/views/soong_workflow_node_views.xml
+++ b/soong_workflow/views/soong_workflow_node_views.xml
@@ -40,15 +40,6 @@
-
-
-
-
-
@@ -212,6 +203,18 @@
+
+
+
+
+
+
+
+
diff --git a/soong_workflow/views/soong_workflow_record.xml b/soong_workflow/views/soong_workflow_record.xml
index 36faffb9d..bcc890629 100644
--- a/soong_workflow/views/soong_workflow_record.xml
+++ b/soong_workflow/views/soong_workflow_record.xml
@@ -549,11 +549,11 @@
code
action = model.append_date()
-
-
-
-
-
-
-
+
+ 一次性
+
+
+ code
+ action = model.update_users_ids()
+
diff --git a/soong_workflow/wizard/soong_workflow_comment_wizard.py b/soong_workflow/wizard/soong_workflow_comment_wizard.py
index 392027df1..295d4dbd5 100644
--- a/soong_workflow/wizard/soong_workflow_comment_wizard.py
+++ b/soong_workflow/wizard/soong_workflow_comment_wizard.py
@@ -45,7 +45,6 @@ class SoongWorkflowCommentWizard(models.TransientModel):
)
employee_trans_domain_ids = fields.Many2many('hr.employee', 'employee_trans_domain_ids_rel', string="传阅人员", store=True)
- filter_personnel_ids = fields.Many2many('hr.employee', 'filter_personnel_rel', 'custom_id', 'employee_id', string="过滤人员", store=True)
employee_ids = fields.Many2many('hr.employee', 'employee_ids_rel', 'custom_id', 'employee_id', string="传阅人员", store=True)
circulated_employee_ids = fields.Many2many('hr.employee', 'circulated_employee_rel', 'custom_id', 'employee_id', help='只可以看不可以评论,看过以后状态自动变为已阅', string="加签人员", store=True)
dep_manager_employee_ids = fields.Many2many('hr.employee', 'dep_manager_employee_rel', 'custom_id', 'employee_id', string="承办", store=True)
@@ -78,7 +77,14 @@ class SoongWorkflowCommentWizard(models.TransientModel):
if len(filtered_employees) == 1:
self.employee_ids = filtered_employees
else:
- self.employee_ids = False
+ domain = [('id', 'in', self.employee_ids1.ids)]
+ if self.is_selection:
+ if self.is_this_company:
+ domain.append(('company_id', '=', self.company_id.id))
+ all_employees = self.env['hr.employee'].search(domain)
+ self.employee_ids = all_employees
+ else:
+ self.employee_ids = False
@api.constrains('employee_ids')
def _check_employee_ids(self):
@@ -189,6 +195,10 @@ class SoongWorkflowCommentWizard(models.TransientModel):
@api.onchange('trans_link_id')
def onchange_trans_employee_ids(self):
for record in self:
+ record.is_selection = False
+ record.is_this_company = True
+ if record.node_btn_id.employee_ids:
+ record.circulated_employee_ids = record.node_btn_id.employee_ids
if not record.trans_link_id:
continue
record_id = self.env[record.res_model].browse(record.res_id) if record.res_model and record.res_id else None
@@ -202,6 +212,35 @@ class SoongWorkflowCommentWizard(models.TransientModel):
record.approval_concatenation = node.approval_concatenation
record.employee_trans_domain_ids = employee_user_role_ids
record.employee_ids1 = employee_user_role_ids
+ workflow_id = link.node_button_id.workflow_id
+ node = workflow_id.node_ids.search([
+ ('name', '=', link.name),
+ ('workflow_id', '=', workflow_id.id)
+ ])
+ button_priority_list = ["分发", "下发", "转交", "结束"]
+ button = False
+ if node.button_ids:
+ for btn_name in button_priority_list:
+ for btn in node.button_ids:
+ if btn.name == btn_name: # 匹配优先级按钮名称
+ is_in_scope = True
+ if not btn.is_review_invisible:
+ button = btn
+ break
+ if btn.is_review_invisible:
+ domain = eval(btn.invisible_expression)
+ model = record_id.env[record_id._name]
+ matched = model.search(domain + [('id', '=', record_id.id)])
+ is_in_scope = bool(matched)
+ if is_in_scope:
+ target_btn = btn
+ button = target_btn
+ break
+ if button:
+ if button.is_automatic_group:
+ record.is_this_company = False
+ if button.is_node_automatic:
+ record.is_selection = True
def _get_approvers_for_link(self, link, record_id=None):
"""
diff --git a/soong_workflow/wizard/soong_workflow_comment_wizard_view.xml b/soong_workflow/wizard/soong_workflow_comment_wizard_view.xml
index dfa68c8ff..fd279274f 100644
--- a/soong_workflow/wizard/soong_workflow_comment_wizard_view.xml
+++ b/soong_workflow/wizard/soong_workflow_comment_wizard_view.xml
@@ -11,7 +11,6 @@
-
@@ -46,7 +45,7 @@
+ domain="[('company_id', '=', company_id)] if is_this_company else []"/>
@@ -63,7 +62,7 @@
+ domain="[('company_id', '=', company_id)]"/>
@@ -77,7 +76,7 @@
+ domain="[('company_id', '=', company_id)]"/>
@@ -126,7 +125,7 @@
context="{'tree_view_ref':'yuthon_hr_employee.view_employee_phone_tree'}"/>
+ domain="[('company_id', '=', company_id)]"/>
@@ -149,7 +148,7 @@
+ domain="[('company_id', '=', company_id)] if is_this_company else []"/>
-
+
@@ -250,7 +250,7 @@
-
+