diff --git a/backend/app/__pycache__/utils.cpython-314.pyc b/backend/app/__pycache__/utils.cpython-314.pyc index 1f90343..0a8720d 100644 Binary files a/backend/app/__pycache__/utils.cpython-314.pyc and b/backend/app/__pycache__/utils.cpython-314.pyc differ diff --git a/backend/app/models/__pycache__/product.cpython-314.pyc b/backend/app/models/__pycache__/product.cpython-314.pyc index 151e4dd..028e468 100644 Binary files a/backend/app/models/__pycache__/product.cpython-314.pyc and b/backend/app/models/__pycache__/product.cpython-314.pyc differ diff --git a/backend/app/models/product.py b/backend/app/models/product.py index bc97490..c36f30a 100644 --- a/backend/app/models/product.py +++ b/backend/app/models/product.py @@ -11,7 +11,7 @@ class Product(Base): name = Column(String, index=True) slug = Column(String, unique=True, index=True, nullable=True) description = Column(Text) - price = Column(Float) + price = Column(Float, nullable=True) # Nullable - can inherit from model discount_price = Column(Float, nullable=True) category_id = Column(Integer, ForeignKey("category.id")) model_id = Column(Integer, ForeignKey("model.id", ondelete="SET NULL"), nullable=True) @@ -31,3 +31,12 @@ class Product(Base): model = relationship("Model", back_populates="products") cart_items = relationship("CartItem", back_populates="product") order_items = relationship("OrderItem", back_populates="product") + + def get_effective_price(self) -> float: + """Get the effective price - either product's own price or model's base_price""" + if self.price is not None: + return float(self.price) + elif self.model and self.model.base_price is not None: + return float(self.model.base_price) + else: + return 0.0 # Default fallback diff --git a/backend/app/routers/__pycache__/products.cpython-314.pyc b/backend/app/routers/__pycache__/products.cpython-314.pyc index a852b37..b2fa4c3 100644 Binary files a/backend/app/routers/__pycache__/products.cpython-314.pyc and b/backend/app/routers/__pycache__/products.cpython-314.pyc differ diff --git a/backend/app/routers/products.py b/backend/app/routers/products.py index f314829..97c7006 100644 --- a/backend/app/routers/products.py +++ b/backend/app/routers/products.py @@ -60,10 +60,13 @@ def list_products( products = query.offset(skip).limit(limit).all() - # Inherit sizes from model if product doesn't have sizes + # Inherit sizes and price from model if product doesn't have them for product in products: if (not product.sizes or len(product.sizes) == 0) and product.model_id and product.model: product.sizes = product.model.sizes or [] + # Inherit price from model if not set + if product.price is None and product.model_id and product.model and product.model.base_price: + product.price = float(product.model.base_price) return products @@ -72,10 +75,13 @@ def list_products( def search(q: str, skip: int = 0, limit: int = 20, db: Session = Depends(get_db)): products = search_products(db, q, skip=skip, limit=limit) - # Inherit sizes from model if product doesn't have sizes + # Inherit sizes and price from model if product doesn't have them for product in products: if (not product.sizes or len(product.sizes) == 0) and product.model_id and product.model: product.sizes = product.model.sizes or [] + # Inherit price from model if not set + if product.price is None and product.model_id and product.model and product.model.base_price: + product.price = float(product.model.base_price) return products @@ -89,6 +95,9 @@ def get_product(product_id: int, db: Session = Depends(get_db)): # If product doesn't have sizes but has a model, inherit sizes from model if (not product.sizes or len(product.sizes) == 0) and product.model_id and product.model: product.sizes = product.model.sizes or [] + # Inherit price from model if not set + if product.price is None and product.model_id and product.model and product.model.base_price: + product.price = float(product.model.base_price) return product @@ -99,6 +108,24 @@ def create_new_product( db: Session = Depends(get_db), admin: User = Depends(get_current_admin_user), ): + # Validate price: either product has price OR model has base_price + if product.price is None: + if not product.model_id: + raise HTTPException( + status_code=400, + detail="Price is required when no model is assigned" + ) + # Check if model exists and has base_price + from app.models import Model + model = db.query(Model).filter(Model.id == product.model_id).first() + if not model: + raise HTTPException(status_code=404, detail="Model not found") + if model.base_price is None: + raise HTTPException( + status_code=400, + detail="Model must have a base_price set if product price is not provided" + ) + # Auto-generate slug if not provided if not product.slug: base_slug = generate_slug(f"{product.brand} {product.name}") @@ -110,7 +137,18 @@ def create_new_product( counter += 1 product.slug = slug - return create_product(db, product) + created_product = create_product(db, product) + + # Refresh to get the model relationship + db.refresh(created_product) + + # Inherit price and sizes from model if needed + if created_product.price is None and created_product.model_id and created_product.model: + created_product.price = float(created_product.model.base_price) + if (not created_product.sizes or len(created_product.sizes) == 0) and created_product.model_id and created_product.model: + created_product.sizes = created_product.model.sizes or [] + + return created_product @router.put("/{product_id}", response_model=ProductResponse) @@ -123,6 +161,16 @@ def update_existing_product( product = update_product(db, product_id, product_update) if not product: raise HTTPException(status_code=404, detail="Product not found") + + # Refresh to ensure model relationship is loaded + db.refresh(product) + + # Inherit price and sizes from model if needed + if product.price is None and product.model_id and product.model and product.model.base_price: + product.price = float(product.model.base_price) + if (not product.sizes or len(product.sizes) == 0) and product.model_id and product.model: + product.sizes = product.model.sizes or [] + return product diff --git a/backend/app/schemas/__pycache__/product.cpython-314.pyc b/backend/app/schemas/__pycache__/product.cpython-314.pyc index d857622..3b37ae2 100644 Binary files a/backend/app/schemas/__pycache__/product.cpython-314.pyc and b/backend/app/schemas/__pycache__/product.cpython-314.pyc differ diff --git a/backend/app/schemas/product.py b/backend/app/schemas/product.py index 7e2029a..98d9ea4 100644 --- a/backend/app/schemas/product.py +++ b/backend/app/schemas/product.py @@ -8,7 +8,7 @@ class ProductCreate(BaseModel): name: str slug: Optional[str] = None description: str - price: float + price: Optional[float] = None # Optional - inherits from model if not set discount_price: Optional[float] = None category_id: int model_id: Optional[int] = None @@ -49,7 +49,7 @@ class ProductResponse(BaseModel): name: str slug: Optional[str] description: str - price: float + price: Optional[float] # May be None if inherited from model discount_price: Optional[float] category_id: int model_id: Optional[int] diff --git a/frontend/src/pages/Admin.jsx b/frontend/src/pages/Admin.jsx index cc844ef..4b342ec 100644 --- a/frontend/src/pages/Admin.jsx +++ b/frontend/src/pages/Admin.jsx @@ -209,7 +209,7 @@ export default function Admin() { const productData = { ...formData, - price: parseFloat(formData.price), + price: formData.price ? parseFloat(formData.price) : null, // Allow null - inherits from model discount_price: formData.discount_price ? parseFloat(formData.discount_price) : null, category_id: parseInt(formData.category_id), model_id: formData.model_id ? parseInt(formData.model_id) : null, @@ -821,8 +821,27 @@ export default function Admin() {
- - + + m.id === parseInt(formData.model_id))?.base_price} + placeholder={ + formData.model_id && models.find(m => m.id === parseInt(formData.model_id))?.base_price + ? `Model price: ₪${parseFloat(models.find(m => m.id === parseInt(formData.model_id)).base_price).toFixed(2)}` + : 'Enter price' + } + /> + {formData.model_id && models.find(m => m.id === parseInt(formData.model_id))?.base_price && ( + + Leave empty to use model's base price of ₪{parseFloat(models.find(m => m.id === parseInt(formData.model_id)).base_price).toFixed(2)} + + )}