""" 訂閱記錄 Model 管理租戶的訂閱狀態和歷史 """ from datetime import datetime, date from sqlalchemy import Column, Integer, String, Date, DateTime, Boolean, ForeignKey, Numeric from sqlalchemy.orm import relationship import enum from app.db.base import Base class SubscriptionStatus(str, enum.Enum): """訂閱狀態""" ACTIVE = "active" # 進行中 CANCELLED = "cancelled" # 已取消 EXPIRED = "expired" # 已過期 class Subscription(Base): """訂閱記錄表""" __tablename__ = "subscriptions" id = Column(Integer, primary_key=True, index=True) tenant_id = Column(Integer, ForeignKey("organizes.id", ondelete="CASCADE"), nullable=False, index=True) # 方案資訊 plan_id = Column(String(50), nullable=False, comment="方案 ID (starter/standard/enterprise)") start_date = Column(Date, nullable=False, comment="開始日期") end_date = Column(Date, nullable=False, comment="結束日期") status = Column(String(20), default=SubscriptionStatus.ACTIVE, nullable=False, comment="狀態") # 自動續約 auto_renew = Column(Boolean, default=True, nullable=False, comment="是否自動續約") # 時間記錄 created_at = Column(DateTime, default=datetime.utcnow, nullable=False) cancelled_at = Column(DateTime, nullable=True, comment="取消時間") # 關聯 tenant = relationship("Tenant", back_populates="subscriptions") def __repr__(self): return f"" @property def is_active(self) -> bool: """是否為活躍訂閱""" today = date.today() return ( self.status == SubscriptionStatus.ACTIVE and self.start_date <= today <= self.end_date ) @property def days_remaining(self) -> int: """剩餘天數""" if not self.is_active: return 0 return (self.end_date - date.today()).days def renew(self, months: int = 1) -> "Subscription": """續約 (創建新的訂閱記錄)""" from dateutil.relativedelta import relativedelta new_start = self.end_date + relativedelta(days=1) new_end = new_start + relativedelta(months=months) - relativedelta(days=1) return Subscription( tenant_id=self.tenant_id, plan_id=self.plan_id, start_date=new_start, end_date=new_end, status=SubscriptionStatus.ACTIVE, auto_renew=self.auto_renew )