from sqlalchemy import Column, String, Boolean, DateTime, Enum as SQLEnum, Text, Integer, ForeignKey, JSON from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import relationship from datetime import datetime, timezone import uuid import enum from database import Base class UserStatus(enum.Enum): pending_email = "pending_email" pending_approval = "pending_approval" pre_approved = "pre_approved" payment_pending = "payment_pending" active = "active" inactive = "inactive" class UserRole(enum.Enum): guest = "guest" member = "member" admin = "admin" class RSVPStatus(enum.Enum): yes = "yes" no = "no" maybe = "maybe" class SubscriptionStatus(enum.Enum): active = "active" expired = "expired" cancelled = "cancelled" class User(Base): __tablename__ = "users" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) email = Column(String, unique=True, nullable=False, index=True) password_hash = Column(String, nullable=False) first_name = Column(String, nullable=False) last_name = Column(String, nullable=False) phone = Column(String, nullable=False) address = Column(String, nullable=False) city = Column(String, nullable=False) state = Column(String, nullable=False) zipcode = Column(String, nullable=False) date_of_birth = Column(DateTime, nullable=False) lead_sources = Column(JSON, default=list) partner_first_name = Column(String, nullable=True) partner_last_name = Column(String, nullable=True) partner_is_member = Column(Boolean, default=False) partner_plan_to_become_member = Column(Boolean, default=False) referred_by_member_name = Column(String, nullable=True) status = Column(SQLEnum(UserStatus), default=UserStatus.pending_email, nullable=False) role = Column(SQLEnum(UserRole), default=UserRole.guest, nullable=False) email_verified = Column(Boolean, default=False) email_verification_token = Column(String, nullable=True) newsletter_subscribed = Column(Boolean, default=False) created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc)) updated_at = Column(DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc)) # Relationships events_created = relationship("Event", back_populates="creator") rsvps = relationship("EventRSVP", back_populates="user") subscriptions = relationship("Subscription", back_populates="user", foreign_keys="Subscription.user_id") class Event(Base): __tablename__ = "events" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) title = Column(String, nullable=False) description = Column(Text, nullable=True) start_at = Column(DateTime, nullable=False) end_at = Column(DateTime, nullable=False) location = Column(String, nullable=False) capacity = Column(Integer, nullable=True) created_by = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False) published = Column(Boolean, default=False) created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc)) updated_at = Column(DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc)) # Relationships creator = relationship("User", back_populates="events_created") rsvps = relationship("EventRSVP", back_populates="event", cascade="all, delete-orphan") class EventRSVP(Base): __tablename__ = "event_rsvps" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) event_id = Column(UUID(as_uuid=True), ForeignKey("events.id"), nullable=False) user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False) rsvp_status = Column(SQLEnum(RSVPStatus), default=RSVPStatus.maybe, nullable=False) attended = Column(Boolean, default=False) attended_at = Column(DateTime, nullable=True) created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc)) updated_at = Column(DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc)) # Relationships event = relationship("Event", back_populates="rsvps") user = relationship("User", back_populates="rsvps") class SubscriptionPlan(Base): __tablename__ = "subscription_plans" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name = Column(String, nullable=False) description = Column(Text, nullable=True) price_cents = Column(Integer, nullable=False) # Price in cents billing_cycle = Column(String, default="yearly", nullable=False) # yearly, monthly, etc. stripe_price_id = Column(String, nullable=True) # Stripe Price ID active = Column(Boolean, default=True) created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc)) updated_at = Column(DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc)) # Relationships subscriptions = relationship("Subscription", back_populates="plan") class Subscription(Base): __tablename__ = "subscriptions" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False) plan_id = Column(UUID(as_uuid=True), ForeignKey("subscription_plans.id"), nullable=False) stripe_subscription_id = Column(String, nullable=True) # Stripe Subscription ID stripe_customer_id = Column(String, nullable=True) # Stripe Customer ID status = Column(SQLEnum(SubscriptionStatus), default=SubscriptionStatus.active, nullable=False) start_date = Column(DateTime, nullable=False) end_date = Column(DateTime, nullable=True) amount_paid_cents = Column(Integer, nullable=True) # Amount paid in cents # Manual payment fields manual_payment = Column(Boolean, default=False, nullable=False) # Whether this was a manual offline payment manual_payment_notes = Column(Text, nullable=True) # Admin notes about the payment manual_payment_admin_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=True) # Admin who processed the payment manual_payment_date = Column(DateTime, nullable=True) # Date payment was received payment_method = Column(String, nullable=True) # Payment method: stripe, cash, bank_transfer, check, other created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc)) updated_at = Column(DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc)) # Relationships user = relationship("User", back_populates="subscriptions", foreign_keys=[user_id]) plan = relationship("SubscriptionPlan", back_populates="subscriptions")