refactor: remove all backward compatibility code across 70 files
Some checks failed
Some checks failed
Clean up 28 backward compatibility instances identified in the codebase. The app is not live, so all shims are replaced with the target architecture: - Remove legacy Inventory.location column (use bin_location exclusively) - Remove dashboard _extract_metric_value helper (use flat metrics dict) - Remove legacy stat field duplicates (total_stores, total_imports, etc.) - Remove 13 re-export shims and class aliases across modules - Remove module-enabling JSON fallback (use PlatformModule junction table) - Remove menu_to_legacy_format() conversion (return dataclasses directly) - Remove title/description from MarketplaceProductBase schema - Clean billing convenience method docstrings - Clean test fixtures and backward-compat comments - Add PlatformModule seeding to init_production.py Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -12,8 +12,8 @@ from sqlalchemy.orm import Session
|
||||
|
||||
from app.api.deps import get_current_admin_api, require_module_access
|
||||
from app.core.database import get_db
|
||||
from app.modules.analytics.schemas import ImportStatsResponse # IMPORT-002
|
||||
from app.modules.analytics.services.stats_service import stats_service # IMPORT-002
|
||||
from app.modules.core.schemas.dashboard import ImportStatsResponse
|
||||
from app.modules.enums import FrontendType
|
||||
from app.modules.marketplace.schemas import (
|
||||
AdminMarketplaceImportJobListResponse,
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
# app/modules/marketplace/schemas/marketplace_product.py
|
||||
"""Pydantic schemas for MarketplaceProduct API validation.
|
||||
|
||||
Note: title and description are stored in MarketplaceProductTranslation table,
|
||||
but we keep them in the API schemas for convenience. The service layer
|
||||
handles creating/updating translations separately.
|
||||
Note: title and description are stored in MarketplaceProductTranslation table.
|
||||
The service layer handles creating/updating translations separately via
|
||||
dedicated title/description parameters. MarketplaceProductCreate includes
|
||||
a required title field for API convenience.
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
@@ -32,10 +33,6 @@ class MarketplaceProductBase(BaseModel):
|
||||
|
||||
marketplace_product_id: str | None = None
|
||||
|
||||
# Localized fields (passed to translations)
|
||||
title: str | None = None
|
||||
description: str | None = None
|
||||
|
||||
# Links and media
|
||||
link: str | None = None
|
||||
image_link: str | None = None
|
||||
|
||||
@@ -112,10 +112,7 @@ class MarketplaceProductService:
|
||||
)
|
||||
|
||||
# Create the product (without title/description - those go in translations)
|
||||
product_dict = product_data.model_dump()
|
||||
# Remove any title/description if present in schema (for backwards compatibility)
|
||||
product_dict.pop("title", None)
|
||||
product_dict.pop("description", None)
|
||||
product_dict = product_data.model_dump(exclude={"title", "description"})
|
||||
|
||||
db_product = MarketplaceProduct(**product_dict)
|
||||
db.add(db_product)
|
||||
@@ -259,17 +256,21 @@ class MarketplaceProductService:
|
||||
MarketplaceProduct.store_name.ilike(search_term),
|
||||
MarketplaceProduct.brand.ilike(search_term),
|
||||
MarketplaceProduct.gtin.ilike(search_term),
|
||||
MarketplaceProduct.marketplace_product_id.ilike(search_term),
|
||||
MarketplaceProduct.marketplace_product_id.ilike(
|
||||
search_term
|
||||
),
|
||||
MarketplaceProductTranslation.title.ilike(search_term),
|
||||
MarketplaceProductTranslation.description.ilike(search_term),
|
||||
MarketplaceProductTranslation.description.ilike(
|
||||
search_term
|
||||
),
|
||||
)
|
||||
)
|
||||
.distinct()
|
||||
.subquery()
|
||||
)
|
||||
query = query.filter(MarketplaceProduct.id.in_(
|
||||
db.query(id_subquery.c.id)
|
||||
))
|
||||
query = query.filter(
|
||||
MarketplaceProduct.id.in_(db.query(id_subquery.c.id))
|
||||
)
|
||||
|
||||
total = query.count()
|
||||
products = query.offset(skip).limit(limit).all()
|
||||
@@ -305,12 +306,10 @@ class MarketplaceProductService:
|
||||
try:
|
||||
product = self.get_product_by_id_or_raise(db, marketplace_product_id)
|
||||
|
||||
# Update fields
|
||||
update_data = product_update.model_dump(exclude_unset=True)
|
||||
|
||||
# Remove title/description from update data (handled separately)
|
||||
update_data.pop("title", None)
|
||||
update_data.pop("description", None)
|
||||
# Update fields (exclude title/description - handled separately via translations)
|
||||
update_data = product_update.model_dump(
|
||||
exclude_unset=True, exclude={"title", "description"}
|
||||
)
|
||||
|
||||
# Validate GTIN if being updated
|
||||
if "gtin" in update_data and update_data["gtin"]:
|
||||
@@ -447,14 +446,16 @@ class MarketplaceProductService:
|
||||
"""
|
||||
try:
|
||||
# SVC-005 - Admin/internal function for inventory lookup by GTIN
|
||||
inventory_entries = db.query(Inventory).filter(Inventory.gtin == gtin).all() # SVC-005
|
||||
inventory_entries = (
|
||||
db.query(Inventory).filter(Inventory.gtin == gtin).all()
|
||||
) # SVC-005
|
||||
if not inventory_entries:
|
||||
return None
|
||||
|
||||
total_quantity = sum(entry.quantity for entry in inventory_entries)
|
||||
locations = [
|
||||
InventoryLocationResponse(
|
||||
location=entry.location,
|
||||
location=entry.bin_location,
|
||||
quantity=entry.quantity,
|
||||
reserved_quantity=entry.reserved_quantity or 0,
|
||||
available_quantity=entry.quantity - (entry.reserved_quantity or 0),
|
||||
@@ -661,17 +662,13 @@ class MarketplaceProductService:
|
||||
.distinct()
|
||||
.subquery()
|
||||
)
|
||||
query = query.filter(MarketplaceProduct.id.in_(
|
||||
db.query(id_subquery.c.id)
|
||||
))
|
||||
query = query.filter(MarketplaceProduct.id.in_(db.query(id_subquery.c.id)))
|
||||
|
||||
if marketplace:
|
||||
query = query.filter(MarketplaceProduct.marketplace == marketplace)
|
||||
|
||||
if store_name:
|
||||
query = query.filter(
|
||||
MarketplaceProduct.store_name.ilike(f"%{store_name}%")
|
||||
)
|
||||
query = query.filter(MarketplaceProduct.store_name.ilike(f"%{store_name}%"))
|
||||
|
||||
if availability:
|
||||
query = query.filter(MarketplaceProduct.availability == availability)
|
||||
@@ -966,8 +963,12 @@ class MarketplaceProductService:
|
||||
primary_image_url=mp.image_link,
|
||||
additional_images=mp.additional_images,
|
||||
# === Digital product fields ===
|
||||
download_url=mp.download_url if hasattr(mp, "download_url") else None,
|
||||
license_type=mp.license_type if hasattr(mp, "license_type") else None,
|
||||
download_url=mp.download_url
|
||||
if hasattr(mp, "download_url")
|
||||
else None,
|
||||
license_type=mp.license_type
|
||||
if hasattr(mp, "license_type")
|
||||
else None,
|
||||
)
|
||||
|
||||
db.add(product)
|
||||
@@ -990,12 +991,14 @@ class MarketplaceProductService:
|
||||
translations_copied += 1
|
||||
|
||||
copied += 1
|
||||
details.append({
|
||||
"id": mp.id,
|
||||
"status": "copied",
|
||||
"gtin": mp.gtin,
|
||||
"translations_copied": translations_copied,
|
||||
})
|
||||
details.append(
|
||||
{
|
||||
"id": mp.id,
|
||||
"status": "copied",
|
||||
"gtin": mp.gtin,
|
||||
"translations_copied": translations_copied,
|
||||
}
|
||||
)
|
||||
|
||||
except SQLAlchemyError as e:
|
||||
logger.error(f"Failed to copy product {mp.id}: {str(e)}")
|
||||
|
||||
@@ -204,7 +204,7 @@ class TestProductService:
|
||||
|
||||
def test_update_product_not_found(self, db):
|
||||
"""Test updating non-existent product raises MarketplaceProductNotFoundException"""
|
||||
update_data = MarketplaceProductUpdate(title="Updated Title")
|
||||
update_data = MarketplaceProductUpdate(brand="Updated Brand")
|
||||
|
||||
with pytest.raises(MarketplaceProductNotFoundException) as exc_info:
|
||||
self.service.update_product(db, "NONEXISTENT", update_data)
|
||||
@@ -230,10 +230,13 @@ class TestProductService:
|
||||
):
|
||||
"""Test updating product with empty title preserves existing title in translation"""
|
||||
original_title = test_marketplace_product.get_title()
|
||||
update_data = MarketplaceProductUpdate(title="")
|
||||
update_data = MarketplaceProductUpdate()
|
||||
|
||||
updated_product = self.service.update_product(
|
||||
db, test_marketplace_product.marketplace_product_id, update_data
|
||||
db,
|
||||
test_marketplace_product.marketplace_product_id,
|
||||
update_data,
|
||||
title="",
|
||||
)
|
||||
|
||||
# Empty title update preserves existing translation title
|
||||
|
||||
Reference in New Issue
Block a user