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 @@ - + +