bmc_hub/app/vendors/backend/router.py

175 lines
6.1 KiB
Python
Raw Normal View History

"""
Vendors API Router
Endpoints for managing suppliers and vendors
"""
from fastapi import APIRouter, HTTPException, Query
from typing import List, Optional
from app.models.schemas import Vendor, VendorCreate, VendorUpdate
from app.core.database import execute_query
import logging
logger = logging.getLogger(__name__)
router = APIRouter()
@router.get("/vendors", response_model=List[Vendor], tags=["Vendors"])
async def list_vendors(
search: Optional[str] = Query(None, description="Search by name, CVR, or domain"),
category: Optional[str] = Query(None, description="Filter by category"),
is_active: Optional[bool] = Query(None, description="Filter by active status"),
skip: int = Query(0, ge=0),
limit: int = Query(50, ge=1, le=100)
):
"""Get list of vendors with optional filtering"""
query = "SELECT * FROM vendors WHERE 1=1"
params = []
if search:
query += " AND (name ILIKE %s OR cvr_number ILIKE %s OR domain ILIKE %s)"
search_param = f"%{search}%"
params.extend([search_param, search_param, search_param])
if category:
query += " AND category = %s"
params.append(category)
if is_active is not None:
query += " AND is_active = %s"
params.append(is_active)
query += " ORDER BY name LIMIT %s OFFSET %s"
params.extend([limit, skip])
result = execute_query(query, tuple(params))
return result or []
@router.get("/vendors/{vendor_id}", response_model=Vendor, tags=["Vendors"])
async def get_vendor(vendor_id: int):
"""Get vendor by ID"""
query = "SELECT * FROM vendors WHERE id = %s"
result = execute_query(query, (vendor_id,))
if not result or len(result) == 0:
raise HTTPException(status_code=404, detail="Vendor not found")
return result[0]
@router.post("/vendors", response_model=Vendor, tags=["Vendors"])
async def create_vendor(vendor: VendorCreate):
"""Create a new vendor"""
try:
query = """
INSERT INTO vendors (
name, cvr_number, email, phone, address, postal_code, city,
website, domain, email_pattern, category, priority, notes, is_active
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
RETURNING *
"""
params = (
vendor.name, vendor.cvr_number, vendor.email, vendor.phone,
vendor.address, vendor.postal_code, vendor.city, vendor.website,
vendor.domain, vendor.email_pattern, vendor.category, vendor.priority,
vendor.notes, vendor.is_active
)
result = execute_query(query, params)
if not result or len(result) == 0:
raise HTTPException(status_code=500, detail="Failed to create vendor")
logger.info(f"✅ Created vendor: {vendor.name}")
return result[0]
except Exception as e:
logger.error(f"❌ Error creating vendor: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.put("/vendors/{vendor_id}", response_model=Vendor, tags=["Vendors"])
async def update_vendor(vendor_id: int, vendor: VendorUpdate):
"""Update an existing vendor"""
# Check if vendor exists
existing = execute_query("SELECT id FROM vendors WHERE id = %s", (vendor_id,))
if not existing:
raise HTTPException(status_code=404, detail="Vendor not found")
# Build update query
update_fields = []
params = []
if vendor.name is not None:
update_fields.append("name = %s")
params.append(vendor.name)
if vendor.cvr_number is not None:
update_fields.append("cvr_number = %s")
params.append(vendor.cvr_number)
if vendor.email is not None:
update_fields.append("email = %s")
params.append(vendor.email)
if vendor.phone is not None:
update_fields.append("phone = %s")
params.append(vendor.phone)
if vendor.address is not None:
update_fields.append("address = %s")
params.append(vendor.address)
if vendor.postal_code is not None:
update_fields.append("postal_code = %s")
params.append(vendor.postal_code)
if vendor.city is not None:
update_fields.append("city = %s")
params.append(vendor.city)
if vendor.website is not None:
update_fields.append("website = %s")
params.append(vendor.website)
if vendor.domain is not None:
update_fields.append("domain = %s")
params.append(vendor.domain)
if vendor.email_pattern is not None:
update_fields.append("email_pattern = %s")
params.append(vendor.email_pattern)
if vendor.category is not None:
update_fields.append("category = %s")
params.append(vendor.category)
if vendor.priority is not None:
update_fields.append("priority = %s")
params.append(vendor.priority)
if vendor.notes is not None:
update_fields.append("notes = %s")
params.append(vendor.notes)
if vendor.is_active is not None:
update_fields.append("is_active = %s")
params.append(vendor.is_active)
if not update_fields:
raise HTTPException(status_code=400, detail="No fields to update")
params.append(vendor_id)
query = f"UPDATE vendors SET {', '.join(update_fields)} WHERE id = %s RETURNING *"
try:
result = execute_query(query, tuple(params))
if not result:
raise HTTPException(status_code=500, detail="Failed to update vendor")
logger.info(f"✅ Updated vendor: {vendor_id}")
return result[0]
except Exception as e:
logger.error(f"❌ Error updating vendor: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.delete("/vendors/{vendor_id}", tags=["Vendors"])
async def delete_vendor(vendor_id: int):
"""Soft delete a vendor (set is_active = false)"""
query = "UPDATE vendors SET is_active = false WHERE id = %s RETURNING id"
result = execute_query(query, (vendor_id,))
if not result:
raise HTTPException(status_code=404, detail="Vendor not found")
logger.info(f"✅ Deleted vendor: {vendor_id}")
return {"message": "Vendor deleted successfully"}