Files
inventory/backend/app/routers/objects.py
jze9 f99949559c Add inventory audit mode with camera QR scanning
Lets an employee walk the premises, scan each object's QR to confirm
it's present and record where it was found (defaulting to the last
picked location), and track found/not-found progress for the walk.
Scanning a box's QR shows its contents read-only without affecting
the found/not-found counts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-22 14:04:00 +05:00

72 lines
3.0 KiB
Python

import uuid
from fastapi import APIRouter, HTTPException, status
from sqlalchemy.exc import IntegrityError
from app.core.dependencies import CurrentUser, DbSession, get_minio_client
from app.schemas.object import ObjectCreate, ObjectRead, ObjectScan, ObjectUpdate
from app.services import objects as objects_service
router = APIRouter(prefix="/api/v1/objects", tags=["objects"])
@router.get("", response_model=list[ObjectRead])
async def list_objects(db: DbSession, search: str | None = None) -> list[ObjectRead]:
items = await objects_service.list_objects(db, search=search)
return [objects_service.build_object_read(o) for o in items]
@router.post("", response_model=ObjectRead, status_code=status.HTTP_201_CREATED)
async def create_object(db: DbSession, _: CurrentUser, data: ObjectCreate) -> ObjectRead:
try:
obj = await objects_service.create_object(db, data)
except IntegrityError:
await db.rollback()
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Inventory number already in use"
)
return objects_service.build_object_read(obj)
@router.get("/{object_id}", response_model=ObjectRead)
async def get_object(db: DbSession, object_id: uuid.UUID) -> ObjectRead:
obj = await objects_service.get_object(db, object_id)
if obj is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Object not found")
return objects_service.build_object_read(obj)
@router.put("/{object_id}", response_model=ObjectRead)
async def update_object(
db: DbSession, _: CurrentUser, object_id: uuid.UUID, data: ObjectUpdate
) -> ObjectRead:
obj = await objects_service.get_object(db, object_id)
if obj is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Object not found")
try:
obj = await objects_service.update_object(db, obj, data)
except IntegrityError:
await db.rollback()
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Inventory number already in use"
)
return objects_service.build_object_read(obj)
@router.post("/{object_id}/scan", response_model=ObjectRead)
async def scan_object(db: DbSession, _: CurrentUser, object_id: uuid.UUID, data: ObjectScan) -> ObjectRead:
"""Mark an object as found during an inventory audit walk, recording where it was seen."""
obj = await objects_service.get_object(db, object_id)
if obj is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Object not found")
obj = await objects_service.mark_object_found(db, obj, data.box_id)
return objects_service.build_object_read(obj)
@router.delete("/{object_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_object(db: DbSession, _: CurrentUser, object_id: uuid.UUID) -> None:
obj = await objects_service.get_object(db, object_id)
if obj is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Object not found")
await objects_service.delete_object(db, get_minio_client(), obj)