shop management features

This commit is contained in:
2025-09-07 22:33:30 +02:00
parent 3342f1ab45
commit 9a5d70e825
3 changed files with 482 additions and 26 deletions

View File

@@ -1,5 +1,5 @@
# models/database_models.py - Updated with Marketplace Support
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Index, UniqueConstraint, Boolean
from sqlalchemy import Column, Integer, String, Float, DateTime, Boolean, Text, ForeignKey, UniqueConstraint, Index
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from datetime import datetime
@@ -14,16 +14,52 @@ class User(Base):
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") # 'admin' or 'user'
role = Column(String, nullable=False, default="user") # user, admin, shop_owner
is_active = Column(Boolean, default=True, nullable=False)
last_login = Column(DateTime, nullable=True)
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
# Relationships
marketplace_import_jobs = relationship("MarketplaceImportJob", back_populates="user")
owned_shops = relationship("Shop", back_populates="owner")
def __repr__(self):
return f"<User(username='{self.username}', email='{self.email}', role='{self.role}')>"
class Shop(Base):
__tablename__ = "shops"
id = Column(Integer, primary_key=True, index=True)
shop_code = Column(String, unique=True, index=True, nullable=False) # e.g., "TECHSTORE", "FASHIONHUB"
shop_name = Column(String, nullable=False) # Display name
description = Column(Text)
owner_id = Column(Integer, ForeignKey("users.id"), nullable=False)
# Contact information
contact_email = Column(String)
contact_phone = Column(String)
website = Column(String)
# Business information
business_address = Column(Text)
tax_number = Column(String)
# Status
is_active = Column(Boolean, default=True)
is_verified = Column(Boolean, default=False)
# Timestamps
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# Relationships
owner = relationship("User", back_populates="owned_shops")
shop_products = relationship("ShopProduct", back_populates="shop")
marketplace_import_jobs = relationship("MarketplaceImportJob", back_populates="shop")
class Product(Base):
__tablename__ = "products"
@@ -76,6 +112,7 @@ class Product(Base):
# Relationship to stock (one-to-many via GTIN)
stock_entries = relationship("Stock", foreign_keys="Stock.gtin", primaryjoin="Product.gtin == Stock.gtin",
viewonly=True)
shop_products = relationship("ShopProduct", back_populates="product")
# Additional indexes for marketplace queries
__table_args__ = (
@@ -84,7 +121,48 @@ class Product(Base):
)
def __repr__(self):
return f"<Product(product_id='{self.product_id}', title='{self.title}', marketplace='{self.marketplace}', shop='{self.shop_name}')>"
return (f"<Product(product_id='{self.product_id}', title='{self.title}', marketplace='{self.marketplace}', "
f"shop='{self.shop_name}')>")
class ShopProduct(Base):
__tablename__ = "shop_products"
id = Column(Integer, primary_key=True, index=True)
shop_id = Column(Integer, ForeignKey("shops.id"), nullable=False)
product_id = Column(Integer, ForeignKey("products.id"), nullable=False)
# Shop-specific overrides (can override the main product data)
shop_product_id = Column(String) # Shop's internal product ID
shop_price = Column(Float) # Override main product price
shop_sale_price = Column(Float)
shop_currency = Column(String)
shop_availability = Column(String) # Override availability
shop_condition = Column(String)
# Shop-specific metadata
is_featured = Column(Boolean, default=False)
is_active = Column(Boolean, default=True)
display_order = Column(Integer, default=0)
# Inventory management
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="shop_products")
product = relationship("Product", back_populates="shop_products")
# Constraints
__table_args__ = (
UniqueConstraint('shop_id', 'product_id', name='uq_shop_product'),
Index('idx_shop_product_active', 'shop_id', 'is_active'),
Index('idx_shop_product_featured', 'shop_id', 'is_featured'),
)
class Stock(Base):
@@ -94,9 +172,15 @@ class Stock(Base):
gtin = Column(String, index=True, nullable=False) # Foreign key relationship would be ideal
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
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
# Relationships
shop = relationship("Shop")
# Composite unique constraint to prevent duplicate GTIN-location combinations
__table_args__ = (
UniqueConstraint('gtin', 'location', name='uq_stock_gtin_location'),
@@ -116,24 +200,34 @@ class MarketplaceImportJob(Base):
source_url = Column(String, nullable=False)
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
user_id = Column(Integer, ForeignKey('users.id')) # Foreign key to users table
shop_id = Column(Integer, ForeignKey("shops.id"), nullable=False) # Add proper foreign key
user_id = Column(Integer, ForeignKey('users.id'), nullable=False) # Foreign key to users table
# Results
imported_count = Column(Integer, default=0)
updated_count = Column(Integer, default=0)
error_count = Column(Integer, default=0)
total_processed = Column(Integer, default=0)
# Error handling
error_message = Column(String)
# Timestamps
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
started_at = Column(DateTime)
completed_at = Column(DateTime)
# Relationship to user
user = relationship("User", foreign_keys=[user_id])
shop = relationship("Shop", 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', 'shop_name', 'status'), # Shop import status
Index('idx_marketplace_import_shop_status', 'status'), # Shop import status
Index('idx_marketplace_import_shop_id', 'shop_id'),
)
def __repr__(self):
return f"<MarketplaceImportJob(id={self.id}, marketplace='{self.marketplace}', shop='{self.shop_name}', status='{self.status}', imported={self.imported_count})>"
return (f"<MarketplaceImportJob(id={self.id}, marketplace='{self.marketplace}', shop='{self.shop_name}', "
f"status='{self.status}', imported={self.imported_count})>")