From fe3f2b0894c74d55c5e0ba106014f1867d3e892f Mon Sep 17 00:00:00 2001 From: Felipe Cardoso Date: Wed, 19 Mar 2025 10:16:55 +0100 Subject: [PATCH] Add API endpoint to retrieve all guest gift reservations Introduced a new route to fetch all guest gift reservations, ensuring API compatibility with GiftPurchase objects. Refactored CRUD functions to optimize data fetching and avoid N+1 queries. Added validation to restrict access to non-public event-related reservations. --- backend/app/api/routes/events/gifts.py | 18 +++++++++++ backend/app/crud/gift.py | 45 ++++++++++++++++++++------ 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/backend/app/api/routes/events/gifts.py b/backend/app/api/routes/events/gifts.py index 586dc08..fea612a 100644 --- a/backend/app/api/routes/events/gifts.py +++ b/backend/app/api/routes/events/gifts.py @@ -1048,3 +1048,21 @@ def read_gift_purchases_by_guest( raise HTTPException(status_code=403, detail="Not enough permissions") return gift_purchase_crud.get_gift_reservations_by_guest(db, guest_id=guest_id) + +@router.get( + "/purchases/guest/all", + response_model=List[GiftPurchase], + operation_id="read_guests_gift_purchases" +) +def read_all_guest_gift_reservations( + *, + db: Session = Depends(get_db), +) -> Any: + """ + Retrieve all guest gift reservations. + """ + reservations = gift_purchase_crud.get_all_guest_gift_reservations(db=db) + + if not reservations: + reservations = [] + return reservations diff --git a/backend/app/crud/gift.py b/backend/app/crud/gift.py index d4035b7..6fe1427 100644 --- a/backend/app/crud/gift.py +++ b/backend/app/crud/gift.py @@ -2,15 +2,13 @@ from datetime import datetime, timezone from typing import List, Optional, Dict, Any, Union from uuid import UUID -from sqlalchemy import asc, desc -from sqlalchemy.orm import Session +from sqlalchemy import asc, desc, select +from sqlalchemy.orm import Session, joinedload from app.crud.base import CRUDBase -from app.models import gift as gift_models -from app.models.gift import GiftItem, GiftCategory, GiftPurchase, GiftStatus, EventGiftCategory -from app.models.guest import Guest from app.models.event import Event -from app.schemas import gifts as gift_schemas +from app.models.gift import GiftItem, GiftCategory, GiftPurchase, GiftStatus, EventGiftCategory +from app.models.guest import Guest, GuestGifts from app.schemas.gifts import ( GiftItemCreate, GiftItemUpdate, GiftCategoryCreate, GiftCategoryUpdate, @@ -152,6 +150,7 @@ class CRUDGiftItem(CRUDBase[GiftItem, GiftItemCreate, GiftItemUpdate]): return gift # Always return the gift object, even if no changes were made + class CRUDEventGiftCategory: def create(self, db: Session, *, obj_in: EventGiftCategoryCreate) -> EventGiftCategory: """Create a new event-category association""" @@ -336,9 +335,6 @@ class CRUDGiftPurchase(CRUDBase[GiftPurchase, GiftPurchaseCreate, GiftPurchaseUp result = [] for gift in guest.gifts: # Access the association data through the relationship metadata - from sqlalchemy import select - from app.models.guest import GuestGifts - # Get the reservation data stmt = select(GuestGifts).where( (GuestGifts.c.guest_id == guest_id) & @@ -360,6 +356,37 @@ class CRUDGiftPurchase(CRUDBase[GiftPurchase, GiftPurchaseCreate, GiftPurchaseUp return result + def get_all_guest_gift_reservations(self, db: Session) -> List[GiftPurchase]: + """Retrieve all guest gift reservations and convert them into GiftPurchase-like objects for API compatibility.""" + + stmt = select(Guest).options(joinedload(Guest.gifts)) + guests = db.scalars(stmt).all() + + result = [] + + for guest in guests: + # Fetch all gifts and their reservation details per guest at once to avoid N+1 issues + for gift in guest.gifts: + reservation_stmt = select(GuestGifts).where( + (GuestGifts.c.guest_id == guest.id) & + (GuestGifts.c.gift_id == gift.id) + ) + + reservation = db.execute(reservation_stmt).first() + + if reservation: + purchase = GiftPurchase( + id=UUID('00000000-0000-0000-0000-000000000000'), # Placeholder UUID + gift_id=gift.id, + guest_id=guest.id, + quantity=1, # Default + purchased_at=reservation.reserved_at, + notes=reservation.notes + ) + result.append(purchase) + + return result + # Create CRUD instances gift_item_crud = CRUDGiftItem(GiftItem)