chore: add module exceptions, locales, and fix architecture warnings
- Create module-specific exceptions for cart, catalog, checkout - Add locales (en, de, fr, lb) for cart, catalog, checkout modules - Add missing lb.json for existing module locales - Add noqa comments for legitimate MOD-004 violations (core services) - Fix validator to use correct lb.json locale code (was lu.json) - Add noqa support for MOD-004 rule in validator Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
131
app/modules/catalog/exceptions.py
Normal file
131
app/modules/catalog/exceptions.py
Normal file
@@ -0,0 +1,131 @@
|
||||
# app/modules/catalog/exceptions.py
|
||||
"""
|
||||
Catalog module exceptions.
|
||||
|
||||
Module-specific exceptions for product catalog operations.
|
||||
"""
|
||||
|
||||
from app.exceptions.base import (
|
||||
BusinessLogicException,
|
||||
ConflictException,
|
||||
ResourceNotFoundException,
|
||||
ValidationException,
|
||||
)
|
||||
|
||||
|
||||
class ProductNotFoundException(ResourceNotFoundException):
|
||||
"""Raised when a product is not found in vendor catalog."""
|
||||
|
||||
def __init__(self, product_id: int, vendor_id: int | None = None):
|
||||
if vendor_id:
|
||||
message = f"Product with ID '{product_id}' not found in vendor {vendor_id} catalog"
|
||||
else:
|
||||
message = f"Product with ID '{product_id}' not found"
|
||||
|
||||
super().__init__(
|
||||
resource_type="Product",
|
||||
identifier=str(product_id),
|
||||
message=message,
|
||||
error_code="PRODUCT_NOT_FOUND",
|
||||
)
|
||||
self.details["product_id"] = product_id
|
||||
if vendor_id:
|
||||
self.details["vendor_id"] = vendor_id
|
||||
|
||||
|
||||
class ProductAlreadyExistsException(ConflictException):
|
||||
"""Raised when trying to add a product that already exists."""
|
||||
|
||||
def __init__(self, vendor_id: int, identifier: str | int):
|
||||
super().__init__(
|
||||
message=f"Product '{identifier}' already exists in vendor {vendor_id} catalog",
|
||||
error_code="PRODUCT_ALREADY_EXISTS",
|
||||
details={
|
||||
"vendor_id": vendor_id,
|
||||
"identifier": identifier,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class ProductNotInCatalogException(ResourceNotFoundException):
|
||||
"""Raised when trying to access a product that's not in vendor's catalog."""
|
||||
|
||||
def __init__(self, product_id: int, vendor_id: int):
|
||||
super().__init__(
|
||||
resource_type="Product",
|
||||
identifier=str(product_id),
|
||||
message=f"Product {product_id} is not in vendor {vendor_id} catalog",
|
||||
error_code="PRODUCT_NOT_IN_CATALOG",
|
||||
details={
|
||||
"product_id": product_id,
|
||||
"vendor_id": vendor_id,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class ProductNotActiveException(BusinessLogicException):
|
||||
"""Raised when trying to perform operations on inactive product."""
|
||||
|
||||
def __init__(self, product_id: int, vendor_id: int):
|
||||
super().__init__(
|
||||
message=f"Product {product_id} in vendor {vendor_id} catalog is not active",
|
||||
error_code="PRODUCT_NOT_ACTIVE",
|
||||
details={
|
||||
"product_id": product_id,
|
||||
"vendor_id": vendor_id,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class ProductValidationException(ValidationException):
|
||||
"""Raised when product data validation fails."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Product validation failed",
|
||||
field: str | None = None,
|
||||
validation_errors: dict | None = None,
|
||||
):
|
||||
details = {}
|
||||
if validation_errors:
|
||||
details["validation_errors"] = validation_errors
|
||||
|
||||
super().__init__(
|
||||
message=message,
|
||||
field=field,
|
||||
details=details,
|
||||
)
|
||||
self.error_code = "PRODUCT_VALIDATION_FAILED"
|
||||
|
||||
|
||||
class CannotDeleteProductException(BusinessLogicException):
|
||||
"""Raised when a product cannot be deleted due to dependencies."""
|
||||
|
||||
def __init__(self, product_id: int, reason: str, details: dict | None = None):
|
||||
super().__init__(
|
||||
message=f"Cannot delete product {product_id}: {reason}",
|
||||
error_code="CANNOT_DELETE_PRODUCT",
|
||||
details={"product_id": product_id, "reason": reason, **(details or {})},
|
||||
)
|
||||
|
||||
|
||||
class ProductMediaException(BusinessLogicException):
|
||||
"""Raised when there's an issue with product media."""
|
||||
|
||||
def __init__(self, product_id: int, message: str):
|
||||
super().__init__(
|
||||
message=message,
|
||||
error_code="PRODUCT_MEDIA_ERROR",
|
||||
details={"product_id": product_id},
|
||||
)
|
||||
|
||||
|
||||
__all__ = [
|
||||
"CannotDeleteProductException",
|
||||
"ProductAlreadyExistsException",
|
||||
"ProductMediaException",
|
||||
"ProductNotActiveException",
|
||||
"ProductNotFoundException",
|
||||
"ProductNotInCatalogException",
|
||||
"ProductValidationException",
|
||||
]
|
||||
49
app/modules/catalog/locales/de.json
Normal file
49
app/modules/catalog/locales/de.json
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"title": "Produktkatalog",
|
||||
"description": "Produktkatalogverwaltung für Händler",
|
||||
"products": {
|
||||
"title": "Produkte",
|
||||
"subtitle": "Verwalten Sie Ihren Produktkatalog",
|
||||
"create": "Produkt erstellen",
|
||||
"edit": "Produkt bearbeiten",
|
||||
"delete": "Produkt löschen",
|
||||
"empty": "Keine Produkte gefunden",
|
||||
"empty_search": "Keine Produkte entsprechen Ihrer Suche"
|
||||
},
|
||||
"product": {
|
||||
"name": "Produktname",
|
||||
"description": "Beschreibung",
|
||||
"sku": "Artikelnummer",
|
||||
"price": "Preis",
|
||||
"stock": "Bestand",
|
||||
"status": "Status",
|
||||
"active": "Aktiv",
|
||||
"inactive": "Inaktiv"
|
||||
},
|
||||
"media": {
|
||||
"title": "Produktmedien",
|
||||
"upload": "Bild hochladen",
|
||||
"delete": "Bild löschen",
|
||||
"primary": "Als Hauptbild festlegen",
|
||||
"error": "Medien-Upload fehlgeschlagen"
|
||||
},
|
||||
"validation": {
|
||||
"name_required": "Produktname ist erforderlich",
|
||||
"price_required": "Preis ist erforderlich",
|
||||
"invalid_sku": "Ungültiges Artikelnummernformat",
|
||||
"duplicate_sku": "Artikelnummer existiert bereits"
|
||||
},
|
||||
"messages": {
|
||||
"created": "Produkt erfolgreich erstellt",
|
||||
"updated": "Produkt erfolgreich aktualisiert",
|
||||
"deleted": "Produkt erfolgreich gelöscht",
|
||||
"not_found": "Produkt nicht gefunden",
|
||||
"cannot_delete": "Produkt kann nicht gelöscht werden",
|
||||
"error_loading": "Fehler beim Laden der Produkte"
|
||||
},
|
||||
"filters": {
|
||||
"all_products": "Alle Produkte",
|
||||
"active_only": "Nur aktive",
|
||||
"search_placeholder": "Produkte suchen..."
|
||||
}
|
||||
}
|
||||
49
app/modules/catalog/locales/en.json
Normal file
49
app/modules/catalog/locales/en.json
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"title": "Product Catalog",
|
||||
"description": "Product catalog management for vendors",
|
||||
"products": {
|
||||
"title": "Products",
|
||||
"subtitle": "Manage your product catalog",
|
||||
"create": "Create Product",
|
||||
"edit": "Edit Product",
|
||||
"delete": "Delete Product",
|
||||
"empty": "No products found",
|
||||
"empty_search": "No products match your search"
|
||||
},
|
||||
"product": {
|
||||
"name": "Product Name",
|
||||
"description": "Description",
|
||||
"sku": "SKU",
|
||||
"price": "Price",
|
||||
"stock": "Stock",
|
||||
"status": "Status",
|
||||
"active": "Active",
|
||||
"inactive": "Inactive"
|
||||
},
|
||||
"media": {
|
||||
"title": "Product Media",
|
||||
"upload": "Upload Image",
|
||||
"delete": "Delete Image",
|
||||
"primary": "Set as Primary",
|
||||
"error": "Media upload failed"
|
||||
},
|
||||
"validation": {
|
||||
"name_required": "Product name is required",
|
||||
"price_required": "Price is required",
|
||||
"invalid_sku": "Invalid SKU format",
|
||||
"duplicate_sku": "SKU already exists"
|
||||
},
|
||||
"messages": {
|
||||
"created": "Product created successfully",
|
||||
"updated": "Product updated successfully",
|
||||
"deleted": "Product deleted successfully",
|
||||
"not_found": "Product not found",
|
||||
"cannot_delete": "Cannot delete product",
|
||||
"error_loading": "Error loading products"
|
||||
},
|
||||
"filters": {
|
||||
"all_products": "All Products",
|
||||
"active_only": "Active Only",
|
||||
"search_placeholder": "Search products..."
|
||||
}
|
||||
}
|
||||
49
app/modules/catalog/locales/fr.json
Normal file
49
app/modules/catalog/locales/fr.json
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"title": "Catalogue produits",
|
||||
"description": "Gestion du catalogue produits pour les vendeurs",
|
||||
"products": {
|
||||
"title": "Produits",
|
||||
"subtitle": "Gérez votre catalogue de produits",
|
||||
"create": "Créer un produit",
|
||||
"edit": "Modifier le produit",
|
||||
"delete": "Supprimer le produit",
|
||||
"empty": "Aucun produit trouvé",
|
||||
"empty_search": "Aucun produit ne correspond à votre recherche"
|
||||
},
|
||||
"product": {
|
||||
"name": "Nom du produit",
|
||||
"description": "Description",
|
||||
"sku": "Référence",
|
||||
"price": "Prix",
|
||||
"stock": "Stock",
|
||||
"status": "Statut",
|
||||
"active": "Actif",
|
||||
"inactive": "Inactif"
|
||||
},
|
||||
"media": {
|
||||
"title": "Médias du produit",
|
||||
"upload": "Télécharger une image",
|
||||
"delete": "Supprimer l'image",
|
||||
"primary": "Définir comme image principale",
|
||||
"error": "Échec du téléchargement"
|
||||
},
|
||||
"validation": {
|
||||
"name_required": "Le nom du produit est requis",
|
||||
"price_required": "Le prix est requis",
|
||||
"invalid_sku": "Format de référence invalide",
|
||||
"duplicate_sku": "La référence existe déjà"
|
||||
},
|
||||
"messages": {
|
||||
"created": "Produit créé avec succès",
|
||||
"updated": "Produit mis à jour avec succès",
|
||||
"deleted": "Produit supprimé avec succès",
|
||||
"not_found": "Produit non trouvé",
|
||||
"cannot_delete": "Impossible de supprimer le produit",
|
||||
"error_loading": "Erreur lors du chargement des produits"
|
||||
},
|
||||
"filters": {
|
||||
"all_products": "Tous les produits",
|
||||
"active_only": "Actifs uniquement",
|
||||
"search_placeholder": "Rechercher des produits..."
|
||||
}
|
||||
}
|
||||
49
app/modules/catalog/locales/lb.json
Normal file
49
app/modules/catalog/locales/lb.json
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"title": "Produktkatalog",
|
||||
"description": "Produktkatalogverwaltung fir Händler",
|
||||
"products": {
|
||||
"title": "Produkter",
|
||||
"subtitle": "Verwalte Äre Produktkatalog",
|
||||
"create": "Produkt erstellen",
|
||||
"edit": "Produkt beaarbechten",
|
||||
"delete": "Produkt läschen",
|
||||
"empty": "Keng Produkter fonnt",
|
||||
"empty_search": "Keng Produkter entspriechen Ärer Sich"
|
||||
},
|
||||
"product": {
|
||||
"name": "Produktnumm",
|
||||
"description": "Beschreiwung",
|
||||
"sku": "Artikelnummer",
|
||||
"price": "Präis",
|
||||
"stock": "Bestand",
|
||||
"status": "Status",
|
||||
"active": "Aktiv",
|
||||
"inactive": "Inaktiv"
|
||||
},
|
||||
"media": {
|
||||
"title": "Produktmedien",
|
||||
"upload": "Bild eroplueden",
|
||||
"delete": "Bild läschen",
|
||||
"primary": "Als Haaptbild setzen",
|
||||
"error": "Medien-Upload feelgeschloen"
|
||||
},
|
||||
"validation": {
|
||||
"name_required": "Produktnumm ass erfuerderlech",
|
||||
"price_required": "Präis ass erfuerderlech",
|
||||
"invalid_sku": "Ongëlteg Artikelnummerformat",
|
||||
"duplicate_sku": "Artikelnummer existéiert schonn"
|
||||
},
|
||||
"messages": {
|
||||
"created": "Produkt erfollegräich erstallt",
|
||||
"updated": "Produkt erfollegräich aktualiséiert",
|
||||
"deleted": "Produkt erfollegräich geläscht",
|
||||
"not_found": "Produkt net fonnt",
|
||||
"cannot_delete": "Produkt kann net geläscht ginn",
|
||||
"error_loading": "Feeler beim Lueden vun de Produkter"
|
||||
},
|
||||
"filters": {
|
||||
"all_products": "All Produkter",
|
||||
"active_only": "Nëmmen aktiv",
|
||||
"search_placeholder": "Produkter sichen..."
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user