diff --git a/soong_workflow/models/soong_workflow_entrust.py b/soong_workflow/models/soong_workflow_entrust.py
index 8473be4c7..b5a54b41a 100644
--- a/soong_workflow/models/soong_workflow_entrust.py
+++ b/soong_workflow/models/soong_workflow_entrust.py
@@ -40,7 +40,7 @@ class SoongWorkflowEntrust(models.Model):
is_expiration_date = fields.Boolean(string="一直有效", default=True)
start_date = fields.Date(string="生效日期", copy=False, default=fields.Date.today())
end_date = fields.Date(string="失效日期", copy=False)
- is_enable = fields.Boolean(string="是否启用", compute="compute_is_enable", store=True)
+ is_enable = fields.Boolean(string="是否启用", compute="compute_is_enable")
entrust_notice = fields.Boolean(string="发送事务提醒消息", default=True)
workflow_data = fields.Char(string="委托流程记录方便到期删除")
diff --git a/soong_workflow/models/soong_workflow_record.py b/soong_workflow/models/soong_workflow_record.py
index 2bdcc717c..ca74ab65a 100644
--- a/soong_workflow/models/soong_workflow_record.py
+++ b/soong_workflow/models/soong_workflow_record.py
@@ -91,6 +91,11 @@ class SoongWorkflowRecord(models.Model):
compute='_compute_is_to_do',
search='_search_is_to_do',
)
+ is_circulation = fields.Boolean(
+ string="是否是传阅流程",
+ compute='_compute_is_circulation',
+ search='_search_is_circulation',
+ )
priority = fields.Selection([('0', 'Normal'), ('1', 'Urgent')], 'Priority', default='0', index=True)
@@ -273,14 +278,53 @@ class SoongWorkflowRecord(models.Model):
('approval_state', 'in', ['0', '1'])
]
valid_pairs = set()
+ # 仅审批待办(soong.workflow.log);传阅(log2)已拆到 is_circulation
for log in self.env['soong.workflow.log'].search(log_domain):
valid_pairs.add((log.model, log.res_id))
- for log in self.env['soong.workflow.log2'].search(log_domain):
- valid_pairs.add((log.model, log.res_id))
for rec in recs:
if (rec.res_model, rec.res_id) in valid_pairs:
rec.is_to_do = True
+ def _compute_is_circulation(self):
+ """传阅/抄送待阅:仅按 soong.workflow.log2 判定当前用户是否有【待阅】的传阅记录。"""
+ current_uid = self.env.user.id
+ self.is_circulation = False
+ valid_records = self.filtered(
+ lambda r: (current_uid in r.users_ids.ids)
+ and not r.reclaim_state
+ )
+ if not valid_records:
+ return
+ # 传阅只看运行中/结束的单据(草稿无传阅记录)
+ target_records = valid_records.filtered(
+ lambda r: r.res_model and r.res_id and r.approve_state not in ['draft', 'start']
+ )
+ if not target_records:
+ return
+
+ # 按模型分组:委托场景下,把"我委托给他人"的传阅 log 也算作我的传阅
+ by_model = {}
+ for rec in target_records:
+ by_model.setdefault(rec.res_model, []).append(rec)
+ for model_name, recs in by_model.items():
+ delegate_uid = self._entrust_delegate_uid(model_name, current_uid)
+ effective_uids = [current_uid]
+ if delegate_uid:
+ effective_uids.append(delegate_uid)
+ res_ids = [r.res_id for r in recs]
+ log2_domain = [
+ ('model', '=', model_name),
+ ('res_id', 'in', res_ids),
+ ('done_by', 'in', effective_uids),
+ ('approval_state', 'in', ['0', '1'])
+ ]
+ valid_pairs = set()
+ for log2 in self.env['soong.workflow.log2'].search(log2_domain):
+ valid_pairs.add((log2.model, log2.res_id))
+ for rec in recs:
+ if (rec.res_model, rec.res_id) in valid_pairs:
+ rec.is_circulation = True
+
def _search_is_to_do(self, operator, value):
current_uid = self.env.user.id
base_domain = [
@@ -311,10 +355,9 @@ class SoongWorkflowRecord(models.Model):
('approval_state', 'in', ['0', '1'])
]
valid_pairs = set()
+ # 仅审批待办(soong.workflow.log);传阅(log2)已拆到 is_circulation
for log in self.env['soong.workflow.log'].search(log_domain):
valid_pairs.add((log.model, log.res_id))
- for log in self.env['soong.workflow.log2'].search(log_domain):
- valid_pairs.add((log.model, log.res_id))
for rec in recs:
if (rec.res_model, rec.res_id) in valid_pairs:
pair_ids.append(rec.id)
@@ -348,6 +391,63 @@ class SoongWorkflowRecord(models.Model):
return domain
+ def _search_is_circulation(self, operator, value):
+ """传阅菜单搜索:仅按 soong.workflow.log2 判定。"""
+ current_uid = self.env.user.id
+ base_domain = [
+ ('users_ids', 'in', current_uid),
+ ('reclaim_state', '=', False),
+ ('active', 'in', [True, False])
+ ]
+ candidate_records = self.search(base_domain)
+ if not candidate_records:
+ return [('id', '=', False)]
+
+ def _circulation_pair_ids(records):
+ pair_ids = []
+ by_model = {}
+ for rec in records:
+ by_model.setdefault(rec.res_model, []).append(rec)
+ for model_name, recs in by_model.items():
+ delegate_uid = self._entrust_delegate_uid(model_name, current_uid)
+ effective_uids = [current_uid]
+ if delegate_uid:
+ effective_uids.append(delegate_uid)
+ res_ids = [r.res_id for r in recs]
+ log2_domain = [
+ ('model', '=', model_name),
+ ('res_id', 'in', res_ids),
+ ('done_by', 'in', effective_uids),
+ ('approval_state', 'in', ['0', '1'])
+ ]
+ valid_pairs = set()
+ for log2 in self.env['soong.workflow.log2'].search(log2_domain):
+ valid_pairs.add((log2.model, log2.res_id))
+ for rec in recs:
+ if (rec.res_model, rec.res_id) in valid_pairs:
+ pair_ids.append(rec.id)
+ return pair_ids
+
+ if (operator == '=' and value) or (operator == '!=' and not value):
+ target_records = candidate_records.filtered(
+ lambda r: r.res_model and r.res_id and r.approve_state not in ['draft', 'start']
+ )
+ circulation_ids = _circulation_pair_ids(target_records) if target_records else []
+ domain = [('id', 'in', circulation_ids)] if circulation_ids else [('id', '=', False)]
+
+ elif (operator == '=' and not value) or (operator == '!=' and value):
+ target_records = candidate_records.filtered(
+ lambda r: r.res_model and r.res_id and r.approve_state not in ['draft', 'start']
+ )
+ circulation_ids = _circulation_pair_ids(target_records) if target_records else []
+ all_ids = candidate_records.ids
+ non_circulation_ids = [rid for rid in all_ids if rid not in circulation_ids]
+ domain = [('id', 'in', non_circulation_ids)] if non_circulation_ids else [('id', '=', False)]
+ else:
+ domain = [('id', '=', False)]
+
+ return domain
+
@api.depends('employee_ids', 'res_model', 'res_id', 'reclaim_state', 'approve_state', 'employee2_ids', 'users_ids')
def _compute_is_done(self):
current_uid = self.env.user.id
@@ -952,6 +1052,7 @@ class SoongWorkflowRecord(models.Model):
if all_records:
all_records._compute_is_done()
all_records._compute_is_to_do()
+ all_records._compute_is_circulation()
return super(SoongWorkflowRecord, self).get_view(view_id, view_type, **options)
diff --git a/soong_workflow/views/soong_workflow_record.xml b/soong_workflow/views/soong_workflow_record.xml
index 63a885a48..cde10a2d9 100644
--- a/soong_workflow/views/soong_workflow_record.xml
+++ b/soong_workflow/views/soong_workflow_record.xml
@@ -442,6 +442,17 @@
+
+ 传阅
+ ir.actions.act_window
+ soong.workflow.record
+ tree,kanban,search
+ {'header_search_default_approve_state': 1, 'check_employee': 1, 'default_order': 'display_end_time desc'}
+
+ [('is_circulation', '=', True)]
+
+
+
已办
ir.actions.act_window
diff --git a/yuthon_work_brand/views/hr_menus.xml b/yuthon_work_brand/views/hr_menus.xml
index cf1e00962..157dd4e11 100644
--- a/yuthon_work_brand/views/hr_menus.xml
+++ b/yuthon_work_brand/views/hr_menus.xml
@@ -799,7 +799,8 @@