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:
2026-01-30 21:26:13 +01:00
parent cad862f469
commit 434db1560a
28 changed files with 1032 additions and 7 deletions

View File

@@ -0,0 +1,125 @@
# app/modules/cart/exceptions.py
"""
Cart module exceptions.
Module-specific exceptions for shopping cart operations.
"""
from app.exceptions.base import (
BusinessLogicException,
ResourceNotFoundException,
ValidationException,
)
class CartItemNotFoundException(ResourceNotFoundException):
"""Raised when a cart item is not found."""
def __init__(self, product_id: int, session_id: str):
super().__init__(
resource_type="CartItem",
identifier=str(product_id),
message=f"Product {product_id} not found in cart",
error_code="CART_ITEM_NOT_FOUND",
)
self.details.update({"product_id": product_id, "session_id": session_id})
class EmptyCartException(ValidationException):
"""Raised when trying to perform operations on an empty cart."""
def __init__(self, session_id: str):
super().__init__(message="Cart is empty", details={"session_id": session_id})
self.error_code = "CART_EMPTY"
class CartValidationException(ValidationException):
"""Raised when cart data validation fails."""
def __init__(
self,
message: str = "Cart validation failed",
field: str | None = None,
details: dict | None = None,
):
super().__init__(
message=message,
field=field,
details=details,
)
self.error_code = "CART_VALIDATION_FAILED"
class InsufficientInventoryForCartException(BusinessLogicException):
"""Raised when product doesn't have enough inventory for cart operation."""
def __init__(
self,
product_id: int,
product_name: str,
requested: int,
available: int,
):
message = (
f"Insufficient inventory for product '{product_name}'. "
f"Requested: {requested}, Available: {available}"
)
super().__init__(
message=message,
error_code="INSUFFICIENT_INVENTORY_FOR_CART",
details={
"product_id": product_id,
"product_name": product_name,
"requested_quantity": requested,
"available_quantity": available,
},
)
class InvalidCartQuantityException(ValidationException):
"""Raised when cart quantity is invalid."""
def __init__(
self, quantity: int, min_quantity: int = 1, max_quantity: int | None = None
):
if quantity < min_quantity:
message = f"Quantity must be at least {min_quantity}"
elif max_quantity and quantity > max_quantity:
message = f"Quantity cannot exceed {max_quantity}"
else:
message = f"Invalid quantity: {quantity}"
super().__init__(
message=message,
field="quantity",
details={
"quantity": quantity,
"min_quantity": min_quantity,
"max_quantity": max_quantity,
},
)
self.error_code = "INVALID_CART_QUANTITY"
class ProductNotAvailableForCartException(BusinessLogicException):
"""Raised when product is not available for adding to cart."""
def __init__(self, product_id: int, reason: str):
super().__init__(
message=f"Product {product_id} cannot be added to cart: {reason}",
error_code="PRODUCT_NOT_AVAILABLE_FOR_CART",
details={
"product_id": product_id,
"reason": reason,
},
)
__all__ = [
"CartItemNotFoundException",
"CartValidationException",
"EmptyCartException",
"InsufficientInventoryForCartException",
"InvalidCartQuantityException",
"ProductNotAvailableForCartException",
]

View File

@@ -0,0 +1,42 @@
{
"title": "Warenkorb",
"description": "Warenkorbverwaltung für Kunden",
"cart": {
"title": "Ihr Warenkorb",
"empty": "Ihr Warenkorb ist leer",
"empty_subtitle": "Fügen Sie Artikel hinzu, um einzukaufen",
"continue_shopping": "Weiter einkaufen",
"proceed_to_checkout": "Zur Kasse"
},
"item": {
"product": "Produkt",
"quantity": "Menge",
"price": "Preis",
"total": "Gesamt",
"remove": "Entfernen",
"update": "Aktualisieren"
},
"summary": {
"title": "Bestellübersicht",
"subtotal": "Zwischensumme",
"shipping": "Versand",
"estimated_shipping": "Wird an der Kasse berechnet",
"tax": "MwSt.",
"total": "Gesamtsumme"
},
"validation": {
"invalid_quantity": "Ungültige Menge",
"min_quantity": "Mindestmenge ist {min}",
"max_quantity": "Höchstmenge ist {max}",
"insufficient_inventory": "Nur {available} verfügbar"
},
"messages": {
"item_added": "Artikel zum Warenkorb hinzugefügt",
"item_updated": "Warenkorb aktualisiert",
"item_removed": "Artikel aus dem Warenkorb entfernt",
"cart_cleared": "Warenkorb geleert",
"product_not_available": "Produkt nicht verfügbar",
"error_adding": "Fehler beim Hinzufügen zum Warenkorb",
"error_updating": "Fehler beim Aktualisieren des Warenkorbs"
}
}

View File

@@ -0,0 +1,42 @@
{
"title": "Shopping Cart",
"description": "Shopping cart management for customers",
"cart": {
"title": "Your Cart",
"empty": "Your cart is empty",
"empty_subtitle": "Add items to start shopping",
"continue_shopping": "Continue Shopping",
"proceed_to_checkout": "Proceed to Checkout"
},
"item": {
"product": "Product",
"quantity": "Quantity",
"price": "Price",
"total": "Total",
"remove": "Remove",
"update": "Update"
},
"summary": {
"title": "Order Summary",
"subtotal": "Subtotal",
"shipping": "Shipping",
"estimated_shipping": "Calculated at checkout",
"tax": "Tax",
"total": "Total"
},
"validation": {
"invalid_quantity": "Invalid quantity",
"min_quantity": "Minimum quantity is {min}",
"max_quantity": "Maximum quantity is {max}",
"insufficient_inventory": "Only {available} available"
},
"messages": {
"item_added": "Item added to cart",
"item_updated": "Cart updated",
"item_removed": "Item removed from cart",
"cart_cleared": "Cart cleared",
"product_not_available": "Product not available",
"error_adding": "Error adding item to cart",
"error_updating": "Error updating cart"
}
}

View File

@@ -0,0 +1,42 @@
{
"title": "Panier",
"description": "Gestion du panier pour les clients",
"cart": {
"title": "Votre panier",
"empty": "Votre panier est vide",
"empty_subtitle": "Ajoutez des articles pour commencer vos achats",
"continue_shopping": "Continuer mes achats",
"proceed_to_checkout": "Passer à la caisse"
},
"item": {
"product": "Produit",
"quantity": "Quantité",
"price": "Prix",
"total": "Total",
"remove": "Supprimer",
"update": "Mettre à jour"
},
"summary": {
"title": "Récapitulatif de commande",
"subtotal": "Sous-total",
"shipping": "Livraison",
"estimated_shipping": "Calculé à la caisse",
"tax": "TVA",
"total": "Total"
},
"validation": {
"invalid_quantity": "Quantité invalide",
"min_quantity": "Quantité minimum: {min}",
"max_quantity": "Quantité maximum: {max}",
"insufficient_inventory": "Seulement {available} disponible(s)"
},
"messages": {
"item_added": "Article ajouté au panier",
"item_updated": "Panier mis à jour",
"item_removed": "Article supprimé du panier",
"cart_cleared": "Panier vidé",
"product_not_available": "Produit non disponible",
"error_adding": "Erreur lors de l'ajout au panier",
"error_updating": "Erreur lors de la mise à jour du panier"
}
}

View File

@@ -0,0 +1,42 @@
{
"title": "Akafskuerf",
"description": "Kuerfverwaltung fir Clienten",
"cart": {
"title": "Äre Kuerf",
"empty": "Äre Kuerf ass eidel",
"empty_subtitle": "Setzt Artikelen derbäi fir anzekafen",
"continue_shopping": "Weider akafen",
"proceed_to_checkout": "Zur Keess"
},
"item": {
"product": "Produkt",
"quantity": "Unzuel",
"price": "Präis",
"total": "Gesamt",
"remove": "Ewechhuelen",
"update": "Aktualiséieren"
},
"summary": {
"title": "Bestelliwwersiicht",
"subtotal": "Zwëschesumm",
"shipping": "Liwwerung",
"estimated_shipping": "Gëtt bei der Keess berechent",
"tax": "MwSt.",
"total": "Gesamtsumm"
},
"validation": {
"invalid_quantity": "Ongëlteg Unzuel",
"min_quantity": "Mindestunzuel ass {min}",
"max_quantity": "Héichstunzuel ass {max}",
"insufficient_inventory": "Nëmmen {available} verfügbar"
},
"messages": {
"item_added": "Artikel an de Kuerf gesat",
"item_updated": "Kuerf aktualiséiert",
"item_removed": "Artikel aus dem Kuerf ewechgeholl",
"cart_cleared": "Kuerf eidel gemaach",
"product_not_available": "Produkt net verfügbar",
"error_adding": "Feeler beim Derbäisetzen an de Kuerf",
"error_updating": "Feeler beim Aktualiséiere vum Kuerf"
}
}