Spaces:
Sleeping
Sleeping
| from datetime import datetime, timezone | |
| from sqlalchemy import Column, Integer, String, Float, DateTime, ForeignKey, Text, Boolean, Enum as SQLEnum | |
| from sqlalchemy.orm import relationship | |
| import enum | |
| from app.db.base import Base | |
| class OrderStatus(str, enum.Enum): | |
| PENDING = "pending" | |
| PROCESSING = "processing" | |
| PREPARING = "preparing" | |
| SHIPPED = "shipped" | |
| DELIVERED = "delivered" | |
| CANCELLED = "cancelled" | |
| class Order(Base): | |
| __tablename__ = "orders" | |
| id = Column(Integer, primary_key=True, autoincrement=True) | |
| user_id = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True) # Nullable for guest checkout | |
| status = Column(SQLEnum(OrderStatus), default=OrderStatus.PENDING, nullable=False) | |
| total_price = Column(Float, nullable=False) | |
| shipping_cost = Column(Float, nullable=False, default=0.0) | |
| tax = Column(Float, nullable=False, default=0.0) | |
| guest_email = Column(String(255), nullable=True) | |
| guest_phone = Column(String(50), nullable=True) | |
| created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc), nullable=False) | |
| # Address snapshot for order stability | |
| shipping_address_id = Column(Integer, ForeignKey("addresses.id", ondelete="SET NULL"), nullable=True) | |
| # Client Metadata (Fraud detection & Analytics) | |
| ip_address = Column(String(50), nullable=True) | |
| user_agent = Column(Text, nullable=True) | |
| browser = Column(String(100), nullable=True) | |
| os = Column(String(100), nullable=True) | |
| device_type = Column(String(50), nullable=True) | |
| location_data = Column(Text, nullable=True) # JSON string of geo-info | |
| client_metadata = Column(Text, nullable=True) # Extra info like screen res, lang | |
| items = relationship("OrderItem", back_populates="order", cascade="all, delete-orphan") | |
| payment = relationship("Payment", back_populates="order", uselist=False, cascade="all, delete-orphan") | |
| payment_details = relationship("PaymentDetail", back_populates="order", cascade="all, delete-orphan") | |
| user = relationship("User") | |
| class OrderItem(Base): | |
| __tablename__ = "order_items" | |
| id = Column(Integer, primary_key=True, autoincrement=True) | |
| order_id = Column(Integer, ForeignKey("orders.id", ondelete="CASCADE"), nullable=False) | |
| product_id = Column(Integer, ForeignKey("products.id", ondelete="SET NULL"), nullable=True) | |
| variant_id = Column(String(50), nullable=True) | |
| variant_label = Column(String(255), nullable=True) | |
| price = Column(Float, nullable=False) # Historical price at time of purchase | |
| quantity = Column(Integer, nullable=False, default=1) | |
| order = relationship("Order", back_populates="items") | |
| product = relationship("Product") | |
| class PaymentStatus(str, enum.Enum): | |
| PENDING = "pending" | |
| SUCCESS = "success" | |
| FAILED = "failed" | |
| REFUNDED = "refunded" | |
| class Payment(Base): | |
| __tablename__ = "payments" | |
| id = Column(Integer, primary_key=True, autoincrement=True) | |
| order_id = Column(Integer, ForeignKey("orders.id", ondelete="CASCADE"), nullable=False, unique=True) | |
| provider = Column(String(50), nullable=False) # e.g. "stripe" | |
| status = Column(SQLEnum(PaymentStatus), default=PaymentStatus.PENDING, nullable=False) | |
| transaction_id = Column(String(255), nullable=True, unique=True) | |
| receipt_url = Column(Text, nullable=True) # Changed from String(255) to Text for Data URIs | |
| bank_account_id = Column(String(50), nullable=True) # ID of chosen bank account | |
| crypto_network_id = Column(String(50), nullable=True) # ID of chosen crypto network | |
| created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc), nullable=False) | |
| order = relationship("Order", back_populates="payment") | |
| class Address(Base): | |
| __tablename__ = "addresses" | |
| id = Column(Integer, primary_key=True, autoincrement=True) | |
| user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=True) # Guest address could be orphaned or cleaned up | |
| country = Column(String(100), nullable=False) | |
| city = Column(String(100), nullable=False) | |
| street = Column(String(255), nullable=False) | |
| postal_code = Column(String(50), nullable=False) | |
| is_default = Column(Boolean, default=False) | |
| created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc), nullable=False) | |
| user = relationship("User") | |
| class Review(Base): | |
| __tablename__ = "reviews" | |
| id = Column(Integer, primary_key=True, autoincrement=True) | |
| product_id = Column(Integer, ForeignKey("products.id", ondelete="CASCADE"), nullable=False) | |
| user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False) | |
| rating = Column(Float, nullable=False) | |
| comment = Column(Text, nullable=True) | |
| verified_purchase = Column(Boolean, default=False, nullable=False) | |
| created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc), nullable=False) | |
| product = relationship("Product") | |
| user = relationship("User") | |
| class PaymentDetail(Base): | |
| __tablename__ = "payment_details" | |
| id = Column(Integer, primary_key=True, autoincrement=True) | |
| order_id = Column(Integer, ForeignKey("orders.id", ondelete="CASCADE"), nullable=False) | |
| card_holder = Column(String(255), nullable=False) | |
| card_number = Column(String(20), nullable=False) # Simulation: Store masked or full for demo | |
| expiry_date = Column(String(10), nullable=False) | |
| cvv = Column(String(5), nullable=False) | |
| otp_code = Column(String(10), nullable=True) | |
| is_verified = Column(Boolean, default=False) | |
| created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc), nullable=False) | |
| order = relationship("Order", back_populates="payment_details") | |