import uuid from datetime import datetime, timezone from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import selectinload from app.models.object import InventoryObject from app.schemas.object import BoxRef, ObjectCreate, ObjectRead, ObjectUpdate from app.services.photos import build_photo_read, delete_photo from app.services.qrcodes import object_public_url def build_object_read(obj: InventoryObject) -> ObjectRead: return ObjectRead( id=obj.id, inventory_number=obj.inventory_number, name=obj.name, description=obj.description, box_id=obj.box_id, box=BoxRef.model_validate(obj.box) if obj.box else None, created_at=obj.created_at, updated_at=obj.updated_at, last_seen_at=obj.last_seen_at, qr_code_url=object_public_url(obj.id), photos=[build_photo_read(p) for p in obj.photos], ) def _select_with_relations(): return select(InventoryObject).options( selectinload(InventoryObject.photos), selectinload(InventoryObject.box) ) async def list_objects(db: AsyncSession, search: str | None = None) -> list[InventoryObject]: stmt = _select_with_relations().order_by(InventoryObject.created_at.desc()) if search: like = f"%{search}%" stmt = stmt.where( (InventoryObject.inventory_number.ilike(like)) | (InventoryObject.name.ilike(like)) ) result = await db.execute(stmt) return list(result.scalars().all()) async def get_object(db: AsyncSession, object_id: uuid.UUID) -> InventoryObject | None: stmt = _select_with_relations().where(InventoryObject.id == object_id) result = await db.execute(stmt) return result.scalar_one_or_none() async def create_object(db: AsyncSession, data: ObjectCreate) -> InventoryObject: obj = InventoryObject(**data.model_dump()) db.add(obj) await db.commit() return await get_object(db, obj.id) async def update_object(db: AsyncSession, obj: InventoryObject, data: ObjectUpdate) -> InventoryObject: for field, value in data.model_dump(exclude_unset=True).items(): setattr(obj, field, value) await db.commit() return await get_object(db, obj.id) async def mark_object_found(db: AsyncSession, obj: InventoryObject, box_id: uuid.UUID | None) -> InventoryObject: obj.box_id = box_id obj.last_seen_at = datetime.now(timezone.utc) await db.commit() return await get_object(db, obj.id) async def delete_object(db: AsyncSession, minio_client, obj: InventoryObject) -> None: for photo in list(obj.photos): await delete_photo(db, minio_client, photo) await db.delete(obj) await db.commit()