Files
eventspace/backend/app/models/guest.py
Felipe Cardoso 79f08a1208 Add quantity column to GuestGifts table and update references
Introduced a `quantity` field to track the number of reserved gifts in the many-to-many GuestGifts table. Updated all related CRUD operations, models, and imports to reflect the added column. Replaced `guest_gifts` with `GuestGifts` for consistency in naming conventions.
2025-03-19 09:56:30 +01:00

94 lines
3.5 KiB
Python

from datetime import datetime, timezone
from enum import Enum
from sqlalchemy import Column, String, Boolean, ForeignKey, UniqueConstraint, Integer, Enum as SQLEnum, DateTime, Table
from sqlalchemy.dialects.postgresql import UUID, JSONB
from sqlalchemy.orm import relationship
from .base import Base, TimestampMixin, UUIDMixin
class GuestStatus(str, Enum):
INVITED = "invited" # Initial state when guest is added
PENDING = "pending" # Invitation sent, waiting for response
CONFIRMED = "confirmed" # RSVP confirmed attendance
DECLINED = "declined" # RSVP declined attendance
WAITLISTED = "waitlisted" # On waitlist if event is at capacity
CANCELLED = "cancelled" # Guest cancelled after initial confirmation
class Guest(Base, UUIDMixin, TimestampMixin):
__tablename__ = 'guests'
# Foreign Keys
event_id = Column(UUID(as_uuid=True), ForeignKey('events.id'), nullable=False)
invited_by = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=False)
user_id = Column(UUID(as_uuid=True), ForeignKey('users.id')) # Optional, if guest is a registered user
# Guest Information
full_name = Column(String, nullable=False)
email = Column(String)
phone = Column(String)
invitation_code = Column(String, unique=True, nullable=False)
# Guest Status
status = Column(SQLEnum(GuestStatus), nullable=False, default=GuestStatus.INVITED)
max_additional_guests = Column(Integer, default=10)
actual_additional_guests = Column(Integer, default=0)
# Tracking
invitation_sent_at = Column(DateTime(timezone=True))
last_reminded_at = Column(DateTime(timezone=True))
response_date = Column(DateTime(timezone=True))
# Additional Information
dietary_restrictions = Column(String)
notes = Column(String)
custom_fields = Column(JSONB)
# Access Management
is_blocked = Column(Boolean, default=False)
can_bring_guests = Column(Boolean, default=True)
# Relationships
event = relationship("Event", back_populates="guests")
inviter = relationship("User", foreign_keys=[invited_by])
user = relationship("User", foreign_keys=[user_id])
rsvp = relationship("RSVP", back_populates="guest", uselist=False)
gifts = relationship("GiftItem", secondary="guest_gifts", back_populates="reserved_by")
__table_args__ = (
UniqueConstraint('event_id', 'email', name='uq_event_guest_email'),
)
def __repr__(self):
return f"<Guest {self.full_name} ({self.status.value})>"
@property
def total_guests(self):
"""Total number of guests including additional guests"""
return 1 + (self.actual_additional_guests or 0)
@property
def has_responded(self):
"""Check if guest has responded to invitation"""
return self.status in (GuestStatus.CONFIRMED, GuestStatus.DECLINED)
def update_status(self, new_status: GuestStatus):
"""Update guest status and record response date"""
self.status = new_status
if new_status in (GuestStatus.CONFIRMED, GuestStatus.DECLINED):
self.response_date = datetime.now(timezone.utc)
# Association table for guest gifts (many-to-many relationship)
GuestGifts = Table(
'guest_gifts',
Base.metadata,
Column('guest_id', UUID(as_uuid=True), ForeignKey('guests.id'), primary_key=True),
Column('gift_id', UUID(as_uuid=True), ForeignKey('gift_items.id'), primary_key=True),
Column('reserved_at', DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)),
Column('notes', String),
Column('quantity', Integer, default=1),
)