diff --git a/soong_workflow/models/soong_workflow_record.py b/soong_workflow/models/soong_workflow_record.py index 713a7428f..6ca409b45 100644 --- a/soong_workflow/models/soong_workflow_record.py +++ b/soong_workflow/models/soong_workflow_record.py @@ -169,155 +169,113 @@ class SoongWorkflowRecord(models.Model): _logger.warning(f"Failed to get urgency_level from {record.res_model}: {e}") record.urgency_level = 'normal' - @api.depends('employee_ids', 'res_model', 'res_id', 'soong_state', 'reclaim_state', 'approve_state') + @api.depends('employee_ids', 'res_model', 'res_id', 'soong_state', 'reclaim_state', 'approve_state', 'users_ids') def _compute_is_to_do(self): - """保留原有计算逻辑(已优化批量查询,参考之前的版本)""" current_uid = self.env.user.id - current_employees = self.env['hr.employee'].search([('user_id', '=', current_uid)]) - active_employee_ids = current_employees.ids if current_employees else [] - if not active_employee_ids: - self.is_to_do = False - return - # 批量优化:预加载员工映射(仅查1次) - all_employees = self.env['hr.employee'].search([('user_state', '=', 'in')]) - emp_to_user = {emp.id: emp.user_id.id for emp in all_employees if emp.user_id} - - # 第一步:批量处理条件1(approve_state=start) - condition1_records = self.filtered( - lambda r: not r.reclaim_state and r.approve_state == 'start' and - set(active_employee_ids) & set(r.employee_ids.ids + r.employee2_ids.ids) + for rec in self: + rec.is_to_do = False + valid_records = self.filtered( + lambda r: current_uid in r.users_ids.ids ) - condition1_records.is_to_do = True - - # 第二步:批量处理条件2(log_ids/log_ids2) - remaining_records = self - condition1_records - remaining_records.is_to_do = False - - # 按res_model分组批量查询log(核心优化) - model_res_ids = defaultdict(list) - rec_model_res_map = {} - for rec in remaining_records.filtered(lambda r: not r.reclaim_state and r.res_model and r.res_id): - model_res_ids[rec.res_model].append(rec.res_id) - rec_model_res_map[rec.id] = (rec.res_model, rec.res_id) - - # 批量查log满足条件的记录ID - valid_rec_ids = [] - for model_name, res_ids in model_res_ids.items(): - if not res_ids: - continue - TargetModel = self.env[model_name].sudo() + if not valid_records: + return + start_records = valid_records.filtered(lambda r: r.approve_state == 'start') + start_records.is_to_do = True + remaining_records = valid_records - start_records + if not remaining_records: + return + for rec in remaining_records: log_domain = [ - ('res_id', 'in', res_ids), - ('done_by', 'in', list(emp_to_user.values())), + ("model", "=", rec.res_model ), + ("res_id", "=", rec.res_id), + ('done_by', '=', current_uid), ('approval_state', 'in', ['0', '1']) ] - # 批量查log_ids - log1_valid_res_ids = TargetModel.log_ids.search(log_domain).mapped('res_id') - # 批量查log_ids2 - log2_valid_res_ids = TargetModel.log_ids2.search(log_domain).mapped('res_id') - - valid_res_ids = set(log1_valid_res_ids + log2_valid_res_ids) - for rec_id, (model, res_id) in rec_model_res_map.items(): - if model == model_name and res_id in valid_res_ids: - valid_rec_ids.append(rec_id) - self.browse(valid_rec_ids).is_to_do = True + has_valid_log1 = self.env['soong.workflow.log'].search_count(log_domain) > 0 + has_valid_log2 = self.env['soong.workflow.log2'].search_count(log_domain) > 0 + if has_valid_log1 or has_valid_log2: + rec.is_to_do = True def _search_is_to_do(self, operator, value): - """搜索待办状态:仅打印总耗时""" - current_uid = self.env.user.id - current_employees = self.env['hr.employee'].sudo().search([('user_id', '=', current_uid)]) - active_employee_ids = current_employees.ids if current_employees else [] - if not active_employee_ids: + # 第一步:基础过滤 - 只处理包含当前用户的记录 + base_domain = [('users_ids', 'in', [current_uid])] + candidate_records = self.search(base_domain) + + if not candidate_records: return [('id', '=', False)] - base_domain = [ - ('reclaim_state', '=', False), - '|', - ('employee_ids', 'in', active_employee_ids), - ('employee2_ids', 'in', active_employee_ids) - ] - + # 处理 "is_to_do = True" 或 "is_to_do != False" 的情况 if (operator == '=' and value) or (operator == '!=' and not value): - candidate_records = self.search(base_domain) - if not candidate_records: - return [('id', '=', False)] - + # 条件1:approve_state为start的记录ID condition1_ids = candidate_records.filtered( - lambda r: r.approve_state == 'start' and not r.reclaim_state + lambda r: r.approve_state == 'start' ).ids - model_res_ids = defaultdict(list) - rec_model_res_map = {} - for rec in candidate_records - self.browse(condition1_ids): - if rec.res_model and rec.res_id: - model_res_ids[rec.res_model].append(rec.res_id) - rec_model_res_map[rec.id] = (rec.res_model, rec.res_id) + # 条件2:非start状态,且日志符合条件的记录ID + remaining_records = candidate_records - self.browse(condition1_ids) + # 仅筛选有res_model/res_id且非草稿/非start的记录 + target_records = remaining_records.filtered( + lambda r: r.res_model and r.res_id and r.approve_state not in ['draft', 'start'] + ) condition2_rec_ids = [] - for model_name, res_ids in model_res_ids.items(): - if not res_ids: - continue - TargetModel = self.env[model_name].sudo() - log1_domain = [ - ('res_id', 'in', res_ids), - ('done_by', '=', current_uid), - ('approval_state', 'in', ['0', '1']) - ] - log1_valid_res_ids = TargetModel.log_ids.search(log1_domain).mapped('res_id') - log2_domain = [ - ('res_id', 'in', res_ids), - ('done_by', '=', current_uid), - ('approval_state', 'in', ['0', '1']) - ] - log2_valid_res_ids = TargetModel.log_ids2.search(log2_domain).mapped('res_id') + if target_records: + # 逐条检查日志(完全对齐compute逻辑,移除try-except) + for rec in target_records: + # 日志筛选条件(和compute逻辑完全一致) + log_domain = [ + ("model", "=", rec.res_model), + ("res_id", "=", rec.res_id), + ('done_by', '=', current_uid), + ('approval_state', 'in', ['0', '1']) + ] + # 直接查询soong.workflow.log和log2模型 + has_valid_log1 = self.env['soong.workflow.log'].search_count(log_domain) > 0 + has_valid_log2 = self.env['soong.workflow.log2'].search_count(log_domain) > 0 - valid_res_ids = set(log1_valid_res_ids + log2_valid_res_ids) - for rec_id, (model, res_id) in rec_model_res_map.items(): - if model == model_name and res_id in valid_res_ids: - condition2_rec_ids.append(rec_id) + if has_valid_log1 or has_valid_log2: + condition2_rec_ids.append(rec.id) + # 合并符合条件的记录ID valid_ids = list(set(condition1_ids + condition2_rec_ids)) - domain = [('id', 'in', valid_ids)] + domain = [('id', 'in', valid_ids)] if valid_ids else [('id', '=', False)] elif (operator == '=' and not value) or (operator == '!=' and value): - candidate_records = self.search(base_domain) - if not candidate_records: - return [('id', '=', False)] - - condition1_invalid_ids = candidate_records.filtered( - lambda r: r.approve_state == 'start' and not r.reclaim_state + todo_ids = [] + # 条件1:approve_state为start的待办ID + condition1_todo_ids = candidate_records.filtered( + lambda r: r.approve_state == 'start' ).ids - model_res_ids = defaultdict(list) - rec_model_res_map = {} - for rec in candidate_records - self.browse(condition1_invalid_ids): - if rec.res_model and rec.res_id: - model_res_ids[rec.res_model].append(rec.res_id) - rec_model_res_map[rec.id] = (rec.res_model, rec.res_id) + # 条件2:日志符合条件的待办ID + remaining_records = candidate_records - self.browse(condition1_todo_ids) + target_records = remaining_records.filtered( + lambda r: r.res_model and r.res_id and r.approve_state not in ['draft', 'start'] + ) - condition2_invalid_ids = [] - for model_name, res_ids in model_res_ids.items(): - if not res_ids: - continue - TargetModel = self.env[model_name].sudo() - log1_domain = [ - ('res_id', 'in', res_ids), - ('done_by', '=', current_uid), - ('approval_state', 'in', ['0', '1']) - ] - log1_valid_res_ids = TargetModel.log_ids.search(log1_domain).mapped('res_id') - log2_domain = log1_domain.copy() - log2_valid_res_ids = TargetModel.log_ids2.search(log2_domain).mapped('res_id') + condition2_todo_ids = [] + if target_records: + for rec in target_records: + log_domain = [ + ("model", "=", rec.res_model), + ("res_id", "=", rec.res_id), + ('done_by', '=', current_uid), + ('approval_state', 'in', ['0', '1']) + ] + has_valid_log1 = self.env['soong.workflow.log'].search_count(log_domain) > 0 + has_valid_log2 = self.env['soong.workflow.log2'].search_count(log_domain) > 0 - valid_res_ids = set(log1_valid_res_ids + log2_valid_res_ids) - for rec_id, (model, res_id) in rec_model_res_map.items(): - if model == model_name and res_id in valid_res_ids: - condition2_invalid_ids.append(rec_id) + if has_valid_log1 or has_valid_log2: + condition2_todo_ids.append(rec.id) - invalid_ids = list(set(condition1_invalid_ids + condition2_invalid_ids)) - domain = [('id', 'not in', invalid_ids)] + todo_ids = list(set(condition1_todo_ids + condition2_todo_ids)) + # 非待办 = 基础候选记录 - 待办记录 + all_candidate_ids = candidate_records.ids + non_todo_ids = [rec_id for rec_id in all_candidate_ids if rec_id not in todo_ids] + domain = [('id', 'in', non_todo_ids)] if non_todo_ids else [('id', '=', False)] else: + # 不支持的操作符 domain = [('id', '=', False)] return domain @@ -669,90 +627,13 @@ class SoongWorkflowRecord(models.Model): @api.model def get_view(self, view_id=None, view_type='form', **options): - """优化后:批量查询+批量写入,消除嵌套循环""" - # ========== 第一步:批量查询所有目标记录(仅1次搜索) ========== current_user_id = self.env.user.id all_records = self.search([ ('users_ids', 'in', current_user_id), - ('soong_state', '!=', 'active'), + ('reclaim_state', '=', False) ]) if not all_records: return super().get_view(view_id, view_type, **options) - - model_res_ids = defaultdict(list) - rec_model_res_map = {rec.id: (rec.res_model, rec.res_id) for rec in all_records if rec.res_model and rec.res_id} - for rec_id, (model, res_id) in rec_model_res_map.items(): - model_res_ids[model].append(res_id) - - log_data = defaultdict(dict) - for model_name, res_ids in model_res_ids.items(): - if not res_ids: - continue - try: - TargetModel = self.env[model_name].sudo() - has_log1 = 'log_ids' in TargetModel._fields - has_log2 = 'log_ids2' in TargetModel._fields - - # 批量查log_ids(当前用户,仅当字段存在时) - if has_log1: - log1_domain = [('res_id', 'in', res_ids), ('done_by', '=', current_user_id)] - log1_records = TargetModel.log_ids.search(log1_domain) - for log in log1_records: - if log.res_id not in log_data[model_name]: - log_data[model_name][log.res_id] = {'log1_states': [], 'log2_states': [], - 'has_archive_log': False} - log_data[model_name][log.res_id]['log1_states'].append(log.approval_state) - if log.name == '归档': - log_data[model_name][log.res_id]['has_archive_log'] = True - log_data[model_name][log.res_id]['archive_state'] = log.approval_state - - # 批量查log_ids2(当前用户,仅当字段存在时) - if has_log2: - log2_domain = [('res_id', 'in', res_ids), ('done_by.name', '=', self.env.user.name)] - log2_records = TargetModel.log_ids2.search(log2_domain) - for log2 in log2_records: - if log2.res_id not in log_data[model_name]: - log_data[model_name][log2.res_id] = {'log1_states': [], 'log2_states': [], - 'has_archive_log': False} - log_data[model_name][log2.res_id]['log2_states'].append(log2.approval_state) - except Exception: - continue - - to_write = defaultdict(list) # {状态: [记录ID]} - for rec in all_records: - if rec.id not in rec_model_res_map: - continue - model, res_id = rec_model_res_map[rec.id] - if model not in log_data or res_id not in log_data[model]: - continue - - log_info = log_data[model][res_id] - # 处理归档日志优先级最高 - if log_info['has_archive_log']: - if log_info['archive_state'] in ['0', '1']: - to_write['to_active'].append(rec.id) - elif log_info['archive_state'] == '2': - to_write['active'].append(rec.id) - continue - - # 处理普通log_ids - log1_states = log_info['log1_states'] - if any(s in ['0', '1'] for s in log1_states): - to_write['to_do'].append(rec.id) - elif all(s == '2' for s in log1_states if s): - to_write['done'].append(rec.id) - - # 处理log_ids2 - log2_states = log_info['log2_states'] - if log2_states: - if any(s in ['0', '1'] for s in log2_states): - to_write['to_do'].append(rec.id) - elif all(s == '2' for s in log2_states): - to_write['done'].append(rec.id) - - for state, rec_ids in to_write.items(): - if rec_ids: - self.browse(rec_ids).write({'soong_state': state}) all_records._compute_is_done() all_records._compute_is_to_do() return super().get_view(view_id, view_type, **options)