refactor: enforce strict architecture rules and add Pydantic response models

- Update architecture rules to be stricter (API-003 now blocks ALL exception
  raising in endpoints, not just HTTPException)
- Update get_current_vendor_api dependency to guarantee token_vendor_id presence
- Remove redundant _get_vendor_from_token helpers from all vendor API files
- Move vendor access validation to service layer methods
- Add Pydantic response models for media, notification, and payment endpoints
- Add get_active_vendor_by_code service method for public vendor lookup
- Add get_import_job_for_vendor service method with vendor validation
- Update validation script to detect exception raising patterns in endpoints

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-12-04 23:26:03 +01:00
parent cbfbbb4654
commit 81bfc49f77
25 changed files with 1225 additions and 530 deletions

View File

@@ -10,48 +10,16 @@ This module provides:
import logging
from fastapi import APIRouter, Depends, Path
from sqlalchemy import func
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.exceptions import VendorNotFoundException
from models.database.vendor import Vendor
from app.services.vendor_service import vendor_service
from models.schema.vendor import VendorDetailResponse
router = APIRouter()
logger = logging.getLogger(__name__)
def _get_vendor_by_code(db: Session, vendor_code: str) -> Vendor:
"""
Helper to get active vendor by vendor_code.
Args:
db: Database session
vendor_code: Vendor code (case-insensitive)
Returns:
Vendor object
Raises:
VendorNotFoundException: If vendor not found or inactive
"""
vendor = (
db.query(Vendor)
.filter(
func.upper(Vendor.vendor_code) == vendor_code.upper(),
Vendor.is_active == True,
)
.first()
)
if not vendor:
logger.warning(f"Vendor not found or inactive: {vendor_code}")
raise VendorNotFoundException(vendor_code, identifier_type="code")
return vendor
@router.get("/{vendor_code}", response_model=VendorDetailResponse)
def get_vendor_info(
vendor_code: str = Path(..., description="Vendor code"),
@@ -81,7 +49,7 @@ def get_vendor_info(
"""
logger.info(f"Public vendor info request: {vendor_code}")
vendor = _get_vendor_by_code(db, vendor_code)
vendor = vendor_service.get_active_vendor_by_code(db, vendor_code)
logger.info(f"Vendor info retrieved: {vendor.name} ({vendor.vendor_code})")