58 lines
2.4 KiB
Python
58 lines
2.4 KiB
Python
"""按业务键同步系统关联,保留关联 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}不存在、已删除或不属于当前租户')
|