from sqlalchemy import Column, Integer, String, Float, DateTime, ForeignKey from sqlalchemy.orm import relationship from app.db.database import Base from sqlalchemy import event from sqlalchemy.orm import Session class PhysicalItem(Base): __tablename__ = "physical_items" id = Column(Integer, primary_key=True) item_type = Column(String) product_id = Column(Integer, ForeignKey("tcgplayer_products.id"), nullable=False) created_at = Column(DateTime(timezone=True)) updated_at = Column(DateTime(timezone=True)) deleted_at = Column(DateTime(timezone=True), nullable=True) __mapper_args__ = { 'polymorphic_on': item_type, 'polymorphic_identity': 'physical_item' } # Relationships product = relationship("TCGPlayerProduct") inventory_item = relationship("InventoryItem", uselist=False, back_populates="physical_item") transaction_item = relationship("TransactionItem", back_populates="physical_item") class SealedCase(PhysicalItem): __tablename__ = "sealed_cases" id = Column(Integer, ForeignKey('physical_items.id'), primary_key=True) expected_value = Column(Float) num_boxes = Column(Integer) __mapper_args__ = { 'polymorphic_identity': 'sealed_case' } # Relationships boxes = relationship("SealedBox", back_populates="case", foreign_keys="[SealedBox.case_id]") open_event = relationship("OpenEvent", uselist=False, back_populates="sealed_case") class SealedBox(PhysicalItem): __tablename__ = "sealed_boxes" id = Column(Integer, ForeignKey('physical_items.id'), primary_key=True) case_id = Column(Integer, ForeignKey("sealed_cases.id"), nullable=True) expected_value = Column(Float) __mapper_args__ = { 'polymorphic_identity': 'sealed_box' } # Relationships case = relationship("SealedCase", back_populates="boxes", foreign_keys=[case_id]) open_event = relationship("OpenEvent", uselist=False, back_populates="sealed_box") # event listeners @event.listens_for(SealedCase, 'before_insert') def set_expected_value(mapper, connection, target): session = Session.object_session(target) if session: expected_value = session.query(SealedExpectedValue).filter(SealedExpectedValue.product_id == target.product_id).filter(SealedExpectedValue.deleted_at == None).order_by(SealedExpectedValue.created_at.desc()).first() if expected_value: target.expected_value = expected_value.expected_value else: raise ValueError("No expected value found for this product") @event.listens_for(SealedBox, 'before_insert') def set_expected_value(mapper, connection, target): session = Session.object_session(target) if session: expected_value = session.query(SealedExpectedValue).filter(SealedExpectedValue.product_id == target.product_id).filter(SealedExpectedValue.deleted_at == None).order_by(SealedExpectedValue.created_at.desc()).first() if expected_value: target.expected_value = expected_value.expected_value else: raise ValueError("No expected value found for this product") class OpenBox(PhysicalItem): __tablename__ = "open_boxes" id = Column(Integer, ForeignKey('physical_items.id'), primary_key=True) open_event_id = Column(Integer, ForeignKey("open_events.id")) sealed_box_id = Column(Integer, ForeignKey("sealed_boxes.id")) __mapper_args__ = { 'polymorphic_identity': 'open_box' } # Relationships open_event = relationship("OpenEvent", back_populates="resulting_boxes") sealed_box = relationship("SealedBox", foreign_keys=[sealed_box_id]) cards = relationship("OpenCard", back_populates="box", foreign_keys="[OpenCard.box_id]") class OpenCard(PhysicalItem): __tablename__ = "open_cards" id = Column(Integer, ForeignKey('physical_items.id'), primary_key=True) open_event_id = Column(Integer, ForeignKey("open_events.id")) box_id = Column(Integer, ForeignKey("open_boxes.id"), nullable=True) __mapper_args__ = { 'polymorphic_identity': 'open_card' } # Relationships open_event = relationship("OpenEvent", back_populates="resulting_cards") box = relationship("OpenBox", back_populates="cards", foreign_keys=[box_id]) class InventoryItem(Base): __tablename__ = "inventory_items" id = Column(Integer, primary_key=True, index=True) physical_item_id = Column(Integer, ForeignKey("physical_items.id"), unique=True) cost_basis = Column(Float) # Current cost basis for this item parent_id = Column(Integer, ForeignKey("inventory_items.id"), nullable=True) # For tracking hierarchy created_at = Column(DateTime(timezone=True)) updated_at = Column(DateTime(timezone=True)) deleted_at = Column(DateTime(timezone=True), nullable=True) # Relationships physical_item = relationship("PhysicalItem", back_populates="inventory_item") parent = relationship("InventoryItem", remote_side=[id], back_populates="children") children = relationship("InventoryItem", back_populates="parent", overlaps="parent") marketplace_listing = relationship("MarketplaceListing", back_populates="inventory_item") class TransactionItem(Base): __tablename__ = "transaction_items" id = Column(Integer, primary_key=True, index=True) transaction_id = Column(Integer, ForeignKey("transactions.id")) physical_item_id = Column(Integer, ForeignKey("physical_items.id")) unit_price = Column(Float, nullable=False) created_at = Column(DateTime(timezone=True)) updated_at = Column(DateTime(timezone=True)) deleted_at = Column(DateTime(timezone=True), nullable=True) # Relationships transaction = relationship("Transaction", back_populates="transaction_items") physical_item = relationship("PhysicalItem", back_populates="transaction_items") class OpenEvent(Base): __tablename__ = "open_events" id = Column(Integer, primary_key=True, index=True) sealed_case_id = Column(Integer, ForeignKey("sealed_cases.id"), nullable=True) sealed_box_id = Column(Integer, ForeignKey("sealed_boxes.id"), nullable=True) open_date = Column(DateTime(timezone=True)) created_at = Column(DateTime(timezone=True)) updated_at = Column(DateTime(timezone=True)) deleted_at = Column(DateTime(timezone=True), nullable=True) # Relationships sealed_case = relationship("SealedCase", back_populates="open_event") sealed_box = relationship("SealedBox", back_populates="open_event") resulting_boxes = relationship("OpenBox", back_populates="open_event") resulting_cards = relationship("OpenCard", back_populates="open_event") class Vendor(Base): __tablename__ = "vendors" id = Column(Integer, primary_key=True, index=True) name = Column(String, unique=True, index=True) created_at = Column(DateTime(timezone=True)) updated_at = Column(DateTime(timezone=True)) deleted_at = Column(DateTime(timezone=True), nullable=True) class Customer(Base): __tablename__ = "customers" id = Column(Integer, primary_key=True, index=True) name = Column(String, unique=True, index=True) created_at = Column(DateTime(timezone=True)) updated_at = Column(DateTime(timezone=True)) class Transaction(Base): __tablename__ = "transactions" id = Column(Integer, primary_key=True, index=True) vendor_id = Column(Integer, ForeignKey("vendors.id"), nullable=True) customer_id = Column(Integer, ForeignKey("customers.id"), nullable=True) marketplace_id = Column(Integer, ForeignKey("marketplaces.id"), nullable=True) transaction_type = Column(String) # 'purchase' or 'sale' transaction_date = Column(DateTime(timezone=True)) transaction_total_amount = Column(Float) transaction_notes = Column(String) created_at = Column(DateTime(timezone=True)) updated_at = Column(DateTime(timezone=True)) deleted_at = Column(DateTime(timezone=True), nullable=True) # Relationships transaction_items = relationship("TransactionItem", back_populates="transaction") class SealedExpectedValue(Base): __tablename__ = "sealed_expected_values" id = Column(Integer, primary_key=True, index=True) product_id = Column(Integer, ForeignKey("tcgplayer_products.id"), nullable=True) expected_value = Column(Float) created_at = Column(DateTime(timezone=True)) updated_at = Column(DateTime(timezone=True)) deleted_at = Column(DateTime(timezone=True), nullable=True) class MostRecentTCGPlayerPrice(Base): __tablename__ = "most_recent_tcgplayer_price" __table_args__ = {'extend_existing': True, 'autoload_with': None, 'info': {'is_view': True}} id = Column(Integer, primary_key=True, index=True) product_id = Column(Integer, ForeignKey("tcgplayer_products.id")) date = Column(DateTime) low_price = Column(Float) mid_price = Column(Float) high_price = Column(Float) market_price = Column(Float) direct_low_price = Column(Float) sub_type_name = Column(String) created_at = Column(DateTime(timezone=True)) updated_at = Column(DateTime(timezone=True)) # Relationships product = relationship("TCGPlayerProduct", back_populates="most_recent_tcgplayer_price") class Marketplace(Base): __tablename__ = "marketplaces" id = Column(Integer, primary_key=True, index=True) name = Column(String, unique=True, index=True) created_at = Column(DateTime(timezone=True)) updated_at = Column(DateTime(timezone=True)) listings = relationship("MarketplaceListing", back_populates="marketplace") class MarketplaceListing(Base): __tablename__ = "marketplace_listings" id = Column(Integer, primary_key=True, index=True) inventory_item_id = Column(Integer, ForeignKey("inventory_items.id"), nullable=False) marketplace_id = Column(Integer, ForeignKey("marketplaces.id"), nullable=False) product_id = Column(Integer, ForeignKey("tcgplayer_products.id"), nullable=False) listing_date = Column(DateTime(timezone=True)) delisting_date = Column(DateTime(timezone=True), nullable=True) listed_price = Column(Float) created_at = Column(DateTime(timezone=True)) updated_at = Column(DateTime(timezone=True)) deleted_at = Column(DateTime(timezone=True), nullable=True) # Relationships inventory_item = relationship("InventoryItem", back_populates="marketplace_listings") marketplace = relationship("Marketplace", back_populates="listings") product = relationship("TCGPlayerProduct", back_populates="marketplace_listings")