shop product refactoring

This commit is contained in:
2025-10-04 23:38:53 +02:00
parent 4d2866af5e
commit 0114b6c46e
68 changed files with 2234 additions and 2236 deletions

View File

@@ -5,7 +5,7 @@ from .base import Base
from .user import User
from .marketplace_product import MarketplaceProduct
from .stock import Stock
from .shop import Shop
from .vendor import Vendor
from .product import Product
from .marketplace_import_job import MarketplaceImportJob
@@ -14,7 +14,7 @@ __all__ = [
"User",
"MarketplaceProduct",
"Stock",
"Shop",
"Vendor",
"Product",
"MarketplaceImportJob",
]

View File

@@ -20,9 +20,9 @@ class MarketplaceImportJob(Base, TimestampMixin):
marketplace = Column(
String, nullable=False, index=True, default="Letzshop"
) # Index for marketplace filtering
shop_name = Column(String, nullable=False, index=True) # Index for shop filtering
shop_id = Column(
Integer, ForeignKey("shops.id"), nullable=False
vendor_name = Column(String, nullable=False, index=True) # Index for vendor filtering
vendor_id = Column(
Integer, ForeignKey("vendors.id"), nullable=False
) # Add proper foreign key
user_id = Column(
Integer, ForeignKey("users.id"), nullable=False
@@ -44,19 +44,19 @@ class MarketplaceImportJob(Base, TimestampMixin):
# Relationship to user
user = relationship("User", foreign_keys=[user_id])
shop = relationship("Shop", back_populates="marketplace_import_jobs")
vendor = relationship("Vendor", back_populates="marketplace_import_jobs")
# Additional indexes for marketplace import job queries
__table_args__ = (
Index(
"idx_marketplace_import_user_marketplace", "user_id", "marketplace"
), # User's marketplace imports
Index("idx_marketplace_import_shop_status", "status"), # Shop import status
Index("idx_marketplace_import_shop_id", "shop_id"),
Index("idx_marketplace_import_vendor_status", "status"), # Vendor import status
Index("idx_marketplace_import_vendor_id", "vendor_id"),
)
def __repr__(self):
return (
f"<MarketplaceImportJob(id={self.id}, marketplace='{self.marketplace}', shop='{self.shop_name}', "
f"<MarketplaceImportJob(id={self.id}, marketplace='{self.marketplace}', vendor='{self.vendor_name}', "
f"status='{self.status}', imported={self.imported_count})>"
)

View File

@@ -55,7 +55,7 @@ class MarketplaceProduct(Base, TimestampMixin):
marketplace = Column(
String, index=True, nullable=True, default="Letzshop"
) # Index for marketplace filtering
shop_name = Column(String, index=True, nullable=True) # Index for shop filtering
vendor_name = Column(String, index=True, nullable=True) # Index for vendor filtering
# Relationship to stock (one-to-many via GTIN)
stock_entries = relationship(
@@ -69,8 +69,8 @@ class MarketplaceProduct(Base, TimestampMixin):
# Additional indexes for marketplace queries
__table_args__ = (
Index(
"idx_marketplace_shop", "marketplace", "shop_name"
), # Composite index for marketplace+shop queries
"idx_marketplace_vendor", "marketplace", "vendor_name"
), # Composite index for marketplace+vendor queries
Index(
"idx_marketplace_brand", "marketplace", "brand"
), # Composite index for marketplace+brand queries
@@ -79,5 +79,5 @@ class MarketplaceProduct(Base, TimestampMixin):
def __repr__(self):
return (
f"<MarketplaceProduct(marketplace_product_id='{self.marketplace_product_id}', title='{self.title}', marketplace='{self.marketplace}', "
f"shop='{self.shop_name}')>"
f"vendor='{self.vendor_name}')>"
)

View File

@@ -8,11 +8,11 @@ from sqlalchemy.orm import relationship
from app.core.database import Base
from models.database.base import TimestampMixin
class Product(Base):
class Product(Base, TimestampMixin):
__tablename__ = "products"
id = Column(Integer, primary_key=True, index=True)
shop_id = Column(Integer, ForeignKey("shops.id"), nullable=False)
vendor_id = Column(Integer, ForeignKey("vendors.id"), nullable=False)
marketplace_product_id = Column(Integer, ForeignKey("marketplace_products.id"), nullable=False)
# Shop-specific overrides (can override the main product data)
@@ -32,17 +32,13 @@ class Product(Base):
min_quantity = Column(Integer, default=1)
max_quantity = Column(Integer)
# Timestamps
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# Relationships
shop = relationship("Shop", back_populates="product")
vendor = relationship("Vendor", back_populates="product")
marketplace_product = relationship("MarketplaceProduct", back_populates="product")
# Constraints
__table_args__ = (
UniqueConstraint("shop_id", "marketplace_product_id", name="uq_product"),
Index("idx_product_active", "shop_id", "is_active"),
Index("idx_product_featured", "shop_id", "is_featured"),
UniqueConstraint("vendor_id", "marketplace_product_id", name="uq_product"),
Index("idx_product_active", "vendor_id", "is_active"),
Index("idx_product_featured", "vendor_id", "is_featured"),
)

View File

@@ -18,10 +18,10 @@ class Stock(Base, TimestampMixin):
location = Column(String, nullable=False, index=True)
quantity = Column(Integer, nullable=False, default=0)
reserved_quantity = Column(Integer, default=0) # For orders being processed
shop_id = Column(Integer, ForeignKey("shops.id")) # Optional: shop-specific stock
vendor_id = Column(Integer, ForeignKey("vendors.id")) # Optional: vendor -specific stock
# Relationships
shop = relationship("Shop")
vendor = relationship("Shop")
# Composite unique constraint to prevent duplicate GTIN-location combinations
__table_args__ = (

View File

@@ -15,7 +15,7 @@ class User(Base, TimestampMixin):
email = Column(String, unique=True, index=True, nullable=False)
username = Column(String, unique=True, index=True, nullable=False)
hashed_password = Column(String, nullable=False)
role = Column(String, nullable=False, default="user") # user, admin, shop_owner
role = Column(String, nullable=False, default="user") # user, admin, vendor_owner
is_active = Column(Boolean, default=True, nullable=False)
last_login = Column(DateTime, nullable=True)
@@ -23,7 +23,7 @@ class User(Base, TimestampMixin):
marketplace_import_jobs = relationship(
"MarketplaceImportJob", back_populates="user"
)
owned_shops = relationship("Shop", back_populates="owner")
owned_vendors = relationship("Vendor", back_populates="owner")
def __repr__(self):
return f"<User(username='{self.username}', email='{self.email}', role='{self.role}')>"

View File

@@ -1,7 +1,4 @@
from datetime import datetime
from sqlalchemy import (Boolean, Column, DateTime, Float, ForeignKey, Index,
Integer, String, Text, UniqueConstraint)
from sqlalchemy import (Boolean, Column, ForeignKey, Integer, String, Text)
from sqlalchemy.orm import relationship
# Import Base from the central database module instead of creating a new one
@@ -9,14 +6,14 @@ from app.core.database import Base
from models.database.base import TimestampMixin
class Shop(Base, TimestampMixin):
__tablename__ = "shops"
class Vendor(Base, TimestampMixin):
__tablename__ = "vendors"
id = Column(Integer, primary_key=True, index=True)
shop_code = Column(
vendor_code = Column(
String, unique=True, index=True, nullable=False
) # e.g., "TECHSTORE", "FASHIONHUB"
shop_name = Column(String, nullable=False) # Display name
vendor_name = Column(String, nullable=False) # Display name
description = Column(Text)
owner_id = Column(Integer, ForeignKey("users.id"), nullable=False)
@@ -34,8 +31,8 @@ class Shop(Base, TimestampMixin):
is_verified = Column(Boolean, default=False)
# Relationships
owner = relationship("User", back_populates="owned_shops")
product = relationship("Product", back_populates="shop")
owner = relationship("User", back_populates="owned_vendors")
product = relationship("Product", back_populates="vendor")
marketplace_import_jobs = relationship(
"MarketplaceImportJob", back_populates="shop"
"MarketplaceImportJob", back_populates="vendor"
)