Files
tfm_ainventory/backend/routers/sync.py

78 lines
2.8 KiB
Python

from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from .. import models, schemas, auth
from ..database import get_db
import json
router = APIRouter(
prefix="/sync",
tags=["Sync"]
)
@router.post("/bulk-sync")
def bulk_sync(
payload: schemas.SyncPayload,
db: Session = Depends(get_db),
current_user: auth.TokenData = Depends(auth.get_current_user)
):
"""[C-01] Bulk sync offline operations — only for authenticated users."""
results = {"success": [], "errors": []}
for op in payload.operations:
try:
# DEDUPLICATION CHECK: If this UUID already exists, skip it
if op.uuid:
existing = db.query(models.AuditLog).filter(models.AuditLog.uuid == op.uuid).first()
if existing:
results["success"].append({"barcode": op.barcode, "type": op.type, "note": "Already synced"})
continue
item = db.query(models.Item).filter(models.Item.barcode == op.barcode).first()
if not item:
results["errors"].append({"barcode": op.barcode, "error": "Item not found"})
continue
if op.type == "CHECK_IN":
item.quantity += op.quantity
change = op.quantity
elif op.type == "CHECK_OUT" or op.type == "TRASH":
if item.quantity < op.quantity:
results["errors"].append({"barcode": op.barcode, "error": f"Insufficient stock (Available: {item.quantity})"})
continue
item.quantity -= op.quantity
change = -op.quantity
else:
results["errors"].append({"barcode": op.barcode, "error": f"Invalid operation type: {op.type}"})
continue
# Log audit with original offline timestamp and UUID
item_snapshot = {
"barcode": item.barcode,
"name": item.name,
"category": item.category,
"part_number": item.part_number
}
audit = models.AuditLog(
user_id=current_user.sub,
action=op.type,
target_item_id=item.id,
target_item_name=item.name,
target_item_pn=item.part_number,
target_item_barcode=item.barcode,
target_snapshot=json.dumps(item_snapshot),
quantity_change=change,
timestamp=op.timestamp,
uuid=op.uuid,
details="Offline Synchronization"
)
db.add(audit)
results["success"].append({"barcode": op.barcode, "type": op.type})
except Exception as e:
results["errors"].append({"barcode": op.barcode, "error": str(e)})
db.commit()
return results