| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768 |
- """Scoped child reconciliation. Callers supply the complete writable scope, never global IDs."""
- from datetime import datetime
- from fastapi import HTTPException
- from app.core.utils import generate_uuid
- def validate_child_ids(items, existing, label):
- """Validate the whole collection before a caller mutates any ORM instance."""
- by_id = {row.id: row for row in existing}
- seen = set()
- for item in items or []:
- row_id = (getattr(item, 'id', None) or '').strip()
- if not row_id:
- continue
- if row_id in seen:
- raise HTTPException(422, f'{label} id 重复:{row_id}')
- if row_id not in by_id:
- raise HTTPException(422, f'{label} id 无效、已删除或不属于当前主单:{row_id}')
- seen.add(row_id)
- return by_id, seen
- def prepare_keyed_rows(existing, values, key_fields, label):
- """Natural-key relations keep their identities; ambiguous keys must be corrected explicitly."""
- old = {}
- for row in existing:
- key = tuple(getattr(row, field, None) or '' for field in key_fields)
- if key in old:
- raise HTTPException(409, f'{label}存在重复历史记录,请先核对')
- old[key] = row
- seen = set()
- pairs = []
- for value in values:
- key = tuple(value.get(field) or '' for field in key_fields)
- if key in seen:
- raise HTTPException(422, f'{label}不能重复提交')
- seen.add(key)
- row = old.get(key)
- if value.get('id') and (row is None or value['id'] != row.id):
- raise HTTPException(422, f'{label} id 无效或不属于当前主单')
- pairs.append((row, value))
- return pairs, [row for key, row in old.items() if key not in seen]
- def apply_keyed_rows(db, model, prepared, *, user_id, dept_id='', order_start=0):
- pairs, removed = prepared
- now = datetime.now()
- result = []
- for idx, (row, value) in enumerate(pairs, start=order_start):
- fields = {key: val for key, val in value.items() if key != 'id'}
- if row is None:
- row = model(id=generate_uuid(), create_by=user_id, create_dept_id=dept_id or '',
- create_time=now, del_flag=0, **fields)
- db.add(row)
- else:
- for key, val in fields.items():
- setattr(row, key, val)
- row.order_num = idx
- row.update_by = user_id
- row.update_time = now
- result.append(row)
- for row in removed:
- row.del_flag = 1
- row.update_by = user_id
- row.update_time = now
- return result
|