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