"""按业务键同步系统关联,保留关联 ID,并复用已停用关联。""" from datetime import datetime from app.core.utils import generate_uuid def sync_relations(db, model, tenant_no, owner, key_fields, desired_keys, actor, unique_history=False): desired = list(dict.fromkeys(desired_keys)) rows = db.query(model).filter( model.tenant_no == tenant_no, *(getattr(model, field) == value for field, value in owner.items()), ).with_for_update().all() grouped = {} for row in rows: grouped.setdefault(tuple(getattr(row, f) for f in key_fields), []).append(row) desired_set = set(desired) # 历史重复关系需专项修复;不能为规避唯一键而物理删除或静默替换原记录。 for key, matches in grouped.items(): active = [r for r in matches if r.del_flag == 0] if len(active) > 1 or (unique_history and active and key not in desired_set and len(matches) > 1): raise ValueError("存在重复的历史关联,请先核查后再调整该关联") now = datetime.now() for key, matches in grouped.items(): if key not in desired_set: for row in matches: if row.del_flag == 0: row.del_flag = 1 row.update_by = actor row.update_time = now for key in desired: matches = grouped.get(key, []) active = next((r for r in matches if r.del_flag == 0), None) if active is not None: continue if matches: row = sorted(matches, key=lambda r: r.id)[0] row.del_flag = 0 row.update_by = actor row.update_time = now else: db.add(model( id=generate_uuid(), tenant_no=tenant_no, **owner, **dict(zip(key_fields, key)), order_num=0, create_by=actor, create_dept_id='', create_time=now, update_by=actor, update_time=now, del_flag=0, )) def assert_relation_targets(db, model, tenant_no, ids, label): targets = {value for value in ids or [] if value} if not targets: return found = {row.id for row in db.query(model).filter( model.id.in_(targets), model.tenant_no == tenant_no, model.del_flag == 0, ).all()} if targets != found: raise ValueError(f'{label}不存在、已删除或不属于当前租户')