fix: ruff lint + format fixes in tests, ESLint fixes in frontend
This commit is contained in:
@@ -25,8 +25,12 @@ router = APIRouter(prefix="/contacts", tags=["contacts"])
|
||||
async def list_contacts(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
pagination: dict = Depends(get_pagination),
|
||||
search: str | None = Query(None, description="Search in company_name, city, email, vat_id"),
|
||||
role: str | None = Query(None, description="Filter by role (kaeufer, verkaeufer, beide)"),
|
||||
search: str | None = Query(
|
||||
None, description="Search in company_name, city, email, vat_id"
|
||||
),
|
||||
role: str | None = Query(
|
||||
None, description="Filter by role (kaeufer, verkaeufer, beide)"
|
||||
),
|
||||
is_eu: bool | None = Query(None, description="Filter EU (true) or Inland (false)"),
|
||||
is_private: bool | None = Query(None, description="Filter private contacts"),
|
||||
sort: str | None = Query(None, description="Sort field (prefix - for descending)"),
|
||||
@@ -66,7 +70,9 @@ async def create_contact(
|
||||
return ContactResponse.model_validate(contact)
|
||||
|
||||
|
||||
@router.get("/{contact_id}", response_model=ContactResponse, status_code=status.HTTP_200_OK)
|
||||
@router.get(
|
||||
"/{contact_id}", response_model=ContactResponse, status_code=status.HTTP_200_OK
|
||||
)
|
||||
async def get_contact(
|
||||
contact_id: uuid.UUID,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
@@ -77,12 +83,16 @@ async def get_contact(
|
||||
if contact is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail={"error": {"code": "CONTACT_NOT_FOUND", "message": "Contact not found"}},
|
||||
detail={
|
||||
"error": {"code": "CONTACT_NOT_FOUND", "message": "Contact not found"}
|
||||
},
|
||||
)
|
||||
return ContactResponse.model_validate(contact)
|
||||
|
||||
|
||||
@router.put("/{contact_id}", response_model=ContactResponse, status_code=status.HTTP_200_OK)
|
||||
@router.put(
|
||||
"/{contact_id}", response_model=ContactResponse, status_code=status.HTTP_200_OK
|
||||
)
|
||||
async def update_contact(
|
||||
contact_id: uuid.UUID,
|
||||
body: ContactUpdate,
|
||||
@@ -100,12 +110,16 @@ async def update_contact(
|
||||
if contact is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail={"error": {"code": "CONTACT_NOT_FOUND", "message": "Contact not found"}},
|
||||
detail={
|
||||
"error": {"code": "CONTACT_NOT_FOUND", "message": "Contact not found"}
|
||||
},
|
||||
)
|
||||
return ContactResponse.model_validate(contact)
|
||||
|
||||
|
||||
@router.delete("/{contact_id}", response_model=ContactResponse, status_code=status.HTTP_200_OK)
|
||||
@router.delete(
|
||||
"/{contact_id}", response_model=ContactResponse, status_code=status.HTTP_200_OK
|
||||
)
|
||||
async def delete_contact(
|
||||
contact_id: uuid.UUID,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
@@ -116,7 +130,9 @@ async def delete_contact(
|
||||
if contact is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail={"error": {"code": "CONTACT_NOT_FOUND", "message": "Contact not found"}},
|
||||
detail={
|
||||
"error": {"code": "CONTACT_NOT_FOUND", "message": "Contact not found"}
|
||||
},
|
||||
)
|
||||
return ContactResponse.model_validate(contact)
|
||||
|
||||
@@ -139,7 +155,9 @@ async def add_contact_person(
|
||||
if person is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail={"error": {"code": "CONTACT_NOT_FOUND", "message": "Contact not found"}},
|
||||
detail={
|
||||
"error": {"code": "CONTACT_NOT_FOUND", "message": "Contact not found"}
|
||||
},
|
||||
)
|
||||
return ContactPersonResponse.model_validate(person)
|
||||
|
||||
@@ -159,6 +177,11 @@ async def remove_contact_person(
|
||||
if not deleted:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail={"error": {"code": "PERSON_NOT_FOUND", "message": "Contact person not found"}},
|
||||
detail={
|
||||
"error": {
|
||||
"code": "PERSON_NOT_FOUND",
|
||||
"message": "Contact person not found",
|
||||
}
|
||||
},
|
||||
)
|
||||
return None
|
||||
|
||||
@@ -68,7 +68,9 @@ async def copilot_action(
|
||||
return ActionResponse(**result)
|
||||
|
||||
|
||||
@router.get("/history", response_model=ChatHistoryResponse, status_code=status.HTTP_200_OK)
|
||||
@router.get(
|
||||
"/history", response_model=ChatHistoryResponse, status_code=status.HTTP_200_OK
|
||||
)
|
||||
async def copilot_history(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
pagination: dict = Depends(get_pagination),
|
||||
|
||||
@@ -19,7 +19,9 @@ from app.services import datev_service
|
||||
router = APIRouter(prefix="/datev", tags=["datev"])
|
||||
|
||||
|
||||
@router.post("/export", response_model=DATEVExportResponse, status_code=status.HTTP_201_CREATED)
|
||||
@router.post(
|
||||
"/export", response_model=DATEVExportResponse, status_code=status.HTTP_201_CREATED
|
||||
)
|
||||
async def create_export(
|
||||
body: DATEVExportCreate,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
@@ -37,7 +39,9 @@ async def create_export(
|
||||
return DATEVExportResponse.model_validate(export)
|
||||
|
||||
|
||||
@router.get("/exports", response_model=DATEVExportListResponse, status_code=status.HTTP_200_OK)
|
||||
@router.get(
|
||||
"/exports", response_model=DATEVExportListResponse, status_code=status.HTTP_200_OK
|
||||
)
|
||||
async def list_exports(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
pagination: dict = Depends(get_pagination),
|
||||
@@ -68,7 +72,12 @@ async def download_export(
|
||||
if result is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail={"error": {"code": "EXPORT_NOT_FOUND", "message": "DATEV export not found"}},
|
||||
detail={
|
||||
"error": {
|
||||
"code": "EXPORT_NOT_FOUND",
|
||||
"message": "DATEV export not found",
|
||||
}
|
||||
},
|
||||
)
|
||||
filename, csv_bytes = result
|
||||
return Response(
|
||||
|
||||
@@ -3,7 +3,14 @@
|
||||
import os
|
||||
import uuid
|
||||
|
||||
from fastapi import APIRouter, Depends, File as FastAPIFile, HTTPException, UploadFile, status
|
||||
from fastapi import (
|
||||
APIRouter,
|
||||
Depends,
|
||||
File as FastAPIFile,
|
||||
HTTPException,
|
||||
UploadFile,
|
||||
status,
|
||||
)
|
||||
from fastapi.responses import FileResponse as FastAPIFileResponse
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
@@ -22,9 +29,7 @@ from app.services import file_service, vehicle_service
|
||||
router = APIRouter(prefix="/vehicles", tags=["files"])
|
||||
|
||||
|
||||
async def _verify_vehicle_exists(
|
||||
db: AsyncSession, vehicle_id: uuid.UUID
|
||||
) -> Vehicle:
|
||||
async def _verify_vehicle_exists(db: AsyncSession, vehicle_id: uuid.UUID) -> Vehicle:
|
||||
"""Verify that a vehicle exists, raising 404 if not."""
|
||||
vehicle = await vehicle_service.get_vehicle_by_id(db, vehicle_id)
|
||||
if vehicle is None:
|
||||
|
||||
@@ -2,7 +2,16 @@
|
||||
|
||||
import uuid
|
||||
|
||||
from fastapi import APIRouter, BackgroundTasks, Depends, File, Form, HTTPException, UploadFile, status
|
||||
from fastapi import (
|
||||
APIRouter,
|
||||
BackgroundTasks,
|
||||
Depends,
|
||||
File,
|
||||
Form,
|
||||
HTTPException,
|
||||
UploadFile,
|
||||
status,
|
||||
)
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.config import settings
|
||||
@@ -79,7 +88,12 @@ async def process_image(
|
||||
except (ValueError, TypeError):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail={"error": {"code": "INVALID_VEHICLE_ID", "message": "Invalid vehicle UUID"}},
|
||||
detail={
|
||||
"error": {
|
||||
"code": "INVALID_VEHICLE_ID",
|
||||
"message": "Invalid vehicle UUID",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
# Fetch vehicle info for better retouch prompt
|
||||
@@ -112,7 +126,9 @@ async def process_image(
|
||||
return RetouchProcessResponse(
|
||||
message="Retouch processing queued",
|
||||
retouch_id=result.id,
|
||||
status=result.status.value if isinstance(result.status, RetouchStatus) else str(result.status),
|
||||
status=result.status.value
|
||||
if isinstance(result.status, RetouchStatus)
|
||||
else str(result.status),
|
||||
)
|
||||
|
||||
|
||||
@@ -136,7 +152,12 @@ async def get_retouch_result(
|
||||
if result is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail={"error": {"code": "RETOUCH_NOT_FOUND", "message": "Retouch result not found"}},
|
||||
detail={
|
||||
"error": {
|
||||
"code": "RETOUCH_NOT_FOUND",
|
||||
"message": "Retouch result not found",
|
||||
}
|
||||
},
|
||||
)
|
||||
return RetouchResultResponse.model_validate(result)
|
||||
|
||||
|
||||
@@ -2,7 +2,17 @@
|
||||
|
||||
import uuid
|
||||
|
||||
from fastapi import APIRouter, BackgroundTasks, Depends, File, Form, HTTPException, Query, UploadFile, status
|
||||
from fastapi import (
|
||||
APIRouter,
|
||||
BackgroundTasks,
|
||||
Depends,
|
||||
File,
|
||||
Form,
|
||||
HTTPException,
|
||||
Query,
|
||||
UploadFile,
|
||||
status,
|
||||
)
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.config import settings
|
||||
@@ -78,7 +88,12 @@ async def upload_scan(
|
||||
except (ValueError, TypeError):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail={"error": {"code": "INVALID_VEHICLE_ID", "message": "Invalid vehicle UUID"}},
|
||||
detail={
|
||||
"error": {
|
||||
"code": "INVALID_VEHICLE_ID",
|
||||
"message": "Invalid vehicle UUID",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
try:
|
||||
@@ -101,7 +116,9 @@ async def upload_scan(
|
||||
return OCRUploadResponse(
|
||||
message="OCR processing queued",
|
||||
ocr_result_id=ocr_result.id,
|
||||
status=ocr_result.status.value if isinstance(ocr_result.status, OCRStatus) else str(ocr_result.status),
|
||||
status=ocr_result.status.value
|
||||
if isinstance(ocr_result.status, OCRStatus)
|
||||
else str(ocr_result.status),
|
||||
)
|
||||
|
||||
|
||||
@@ -120,7 +137,9 @@ async def get_ocr_result(
|
||||
if ocr_result is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail={"error": {"code": "OCR_NOT_FOUND", "message": "OCR result not found"}},
|
||||
detail={
|
||||
"error": {"code": "OCR_NOT_FOUND", "message": "OCR result not found"}
|
||||
},
|
||||
)
|
||||
return OCRResultResponse.model_validate(ocr_result)
|
||||
|
||||
@@ -164,7 +183,9 @@ async def apply_ocr_to_vehicle(
|
||||
):
|
||||
"""Apply OCR structured data to the linked vehicle."""
|
||||
try:
|
||||
ocr_result, vehicle, updated_fields = await ocr_service.apply_to_vehicle(db, result_id)
|
||||
ocr_result, vehicle, updated_fields = await ocr_service.apply_to_vehicle(
|
||||
db, result_id
|
||||
)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
|
||||
@@ -27,9 +27,15 @@ router = APIRouter(prefix="/sales", tags=["sales"])
|
||||
async def list_sales(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
pagination: dict = Depends(get_pagination),
|
||||
status_filter: str | None = Query(None, alias="status", description="Filter by sale status"),
|
||||
date_from: str | None = Query(None, description="Filter sales from this date (YYYY-MM-DD)"),
|
||||
date_to: str | None = Query(None, description="Filter sales up to this date (YYYY-MM-DD)"),
|
||||
status_filter: str | None = Query(
|
||||
None, alias="status", description="Filter by sale status"
|
||||
),
|
||||
date_from: str | None = Query(
|
||||
None, description="Filter sales from this date (YYYY-MM-DD)"
|
||||
),
|
||||
date_to: str | None = Query(
|
||||
None, description="Filter sales up to this date (YYYY-MM-DD)"
|
||||
),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
"""List sales with pagination, filtering by status and date range."""
|
||||
@@ -43,7 +49,12 @@ async def list_sales(
|
||||
except ValueError:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail={"error": {"code": "INVALID_DATE", "message": f"Invalid date_from format: {date_from}"}},
|
||||
detail={
|
||||
"error": {
|
||||
"code": "INVALID_DATE",
|
||||
"message": f"Invalid date_from format: {date_from}",
|
||||
}
|
||||
},
|
||||
)
|
||||
if date_to:
|
||||
try:
|
||||
@@ -51,7 +62,12 @@ async def list_sales(
|
||||
except ValueError:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail={"error": {"code": "INVALID_DATE", "message": f"Invalid date_to format: {date_to}"}},
|
||||
detail={
|
||||
"error": {
|
||||
"code": "INVALID_DATE",
|
||||
"message": f"Invalid date_to format: {date_to}",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
sales, total = await sale_service.list_sales(
|
||||
@@ -127,7 +143,9 @@ async def update_sale(
|
||||
return SaleResponse.model_validate(sale)
|
||||
|
||||
|
||||
@router.delete("/{sale_id}", response_model=SaleResponse, status_code=status.HTTP_200_OK)
|
||||
@router.delete(
|
||||
"/{sale_id}", response_model=SaleResponse, status_code=status.HTTP_200_OK
|
||||
)
|
||||
async def delete_sale(
|
||||
sale_id: uuid.UUID,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
@@ -143,7 +161,11 @@ async def delete_sale(
|
||||
return SaleResponse.model_validate(sale)
|
||||
|
||||
|
||||
@router.post("/{sale_id}/contract", response_model=ContractResponse, status_code=status.HTTP_200_OK)
|
||||
@router.post(
|
||||
"/{sale_id}/contract",
|
||||
response_model=ContractResponse,
|
||||
status_code=status.HTTP_200_OK,
|
||||
)
|
||||
async def regenerate_contract(
|
||||
sale_id: uuid.UUID,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
@@ -179,7 +201,12 @@ async def download_contract(
|
||||
if not sale.contract_pdf_path or not os.path.exists(sale.contract_pdf_path):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail={"error": {"code": "CONTRACT_NOT_FOUND", "message": "Contract PDF not generated yet"}},
|
||||
detail={
|
||||
"error": {
|
||||
"code": "CONTRACT_NOT_FOUND",
|
||||
"message": "Contract PDF not generated yet",
|
||||
}
|
||||
},
|
||||
)
|
||||
return FileResponse(
|
||||
path=sale.contract_pdf_path,
|
||||
@@ -188,7 +215,11 @@ async def download_contract(
|
||||
)
|
||||
|
||||
|
||||
@router.post("/{sale_id}/verify-ust-id", response_model=UstIdVerifyResponse, status_code=status.HTTP_200_OK)
|
||||
@router.post(
|
||||
"/{sale_id}/verify-ust-id",
|
||||
response_model=UstIdVerifyResponse,
|
||||
status_code=status.HTTP_200_OK,
|
||||
)
|
||||
async def verify_ust_id(
|
||||
sale_id: uuid.UUID,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
|
||||
@@ -89,7 +89,9 @@ async def update_user(
|
||||
return UserResponse.model_validate(user)
|
||||
|
||||
|
||||
@router.delete("/{user_id}", response_model=UserResponse, status_code=status.HTTP_200_OK)
|
||||
@router.delete(
|
||||
"/{user_id}", response_model=UserResponse, status_code=status.HTTP_200_OK
|
||||
)
|
||||
async def delete_user(
|
||||
user_id: uuid.UUID,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
|
||||
@@ -30,7 +30,9 @@ async def list_vehicles(
|
||||
availability: str | None = Query(None, description="Filter by availability"),
|
||||
min_price: float | None = Query(None, ge=0, description="Minimum price"),
|
||||
max_price: float | None = Query(None, ge=0, description="Maximum price"),
|
||||
search: str | None = Query(None, description="Search in make, model, fin, location"),
|
||||
search: str | None = Query(
|
||||
None, description="Search in make, model, fin, location"
|
||||
),
|
||||
sort: str | None = Query(None, description="Sort field (prefix - for descending)"),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
@@ -72,7 +74,9 @@ async def create_vehicle(
|
||||
return VehicleResponse.model_validate(vehicle)
|
||||
|
||||
|
||||
@router.get("/{vehicle_id}", response_model=VehicleResponse, status_code=status.HTTP_200_OK)
|
||||
@router.get(
|
||||
"/{vehicle_id}", response_model=VehicleResponse, status_code=status.HTTP_200_OK
|
||||
)
|
||||
async def get_vehicle(
|
||||
vehicle_id: uuid.UUID,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
@@ -83,12 +87,16 @@ async def get_vehicle(
|
||||
if vehicle is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail={"error": {"code": "VEHICLE_NOT_FOUND", "message": "Vehicle not found"}},
|
||||
detail={
|
||||
"error": {"code": "VEHICLE_NOT_FOUND", "message": "Vehicle not found"}
|
||||
},
|
||||
)
|
||||
return VehicleResponse.model_validate(vehicle)
|
||||
|
||||
|
||||
@router.put("/{vehicle_id}", response_model=VehicleResponse, status_code=status.HTTP_200_OK)
|
||||
@router.put(
|
||||
"/{vehicle_id}", response_model=VehicleResponse, status_code=status.HTTP_200_OK
|
||||
)
|
||||
async def update_vehicle(
|
||||
vehicle_id: uuid.UUID,
|
||||
body: VehicleUpdate,
|
||||
@@ -112,12 +120,16 @@ async def update_vehicle(
|
||||
if vehicle is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail={"error": {"code": "VEHICLE_NOT_FOUND", "message": "Vehicle not found"}},
|
||||
detail={
|
||||
"error": {"code": "VEHICLE_NOT_FOUND", "message": "Vehicle not found"}
|
||||
},
|
||||
)
|
||||
return VehicleResponse.model_validate(vehicle)
|
||||
|
||||
|
||||
@router.delete("/{vehicle_id}", response_model=VehicleResponse, status_code=status.HTTP_200_OK)
|
||||
@router.delete(
|
||||
"/{vehicle_id}", response_model=VehicleResponse, status_code=status.HTTP_200_OK
|
||||
)
|
||||
async def delete_vehicle(
|
||||
vehicle_id: uuid.UUID,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
@@ -128,7 +140,9 @@ async def delete_vehicle(
|
||||
if vehicle is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail={"error": {"code": "VEHICLE_NOT_FOUND", "message": "Vehicle not found"}},
|
||||
detail={
|
||||
"error": {"code": "VEHICLE_NOT_FOUND", "message": "Vehicle not found"}
|
||||
},
|
||||
)
|
||||
return VehicleResponse.model_validate(vehicle)
|
||||
|
||||
@@ -148,7 +162,9 @@ async def push_to_mobile_de(
|
||||
if vehicle is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail={"error": {"code": "VEHICLE_NOT_FOUND", "message": "Vehicle not found"}},
|
||||
detail={
|
||||
"error": {"code": "VEHICLE_NOT_FOUND", "message": "Vehicle not found"}
|
||||
},
|
||||
)
|
||||
|
||||
listing = await mobilede_service.push_listing(db, vehicle)
|
||||
@@ -176,7 +192,9 @@ async def get_mobile_de_status(
|
||||
if vehicle is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail={"error": {"code": "VEHICLE_NOT_FOUND", "message": "Vehicle not found"}},
|
||||
detail={
|
||||
"error": {"code": "VEHICLE_NOT_FOUND", "message": "Vehicle not found"}
|
||||
},
|
||||
)
|
||||
|
||||
listing = await mobilede_service.get_listing_status(db, vehicle_id)
|
||||
|
||||
Reference in New Issue
Block a user