fix: ruff lint + format fixes in tests, ESLint fixes in frontend

This commit is contained in:
2026-07-17 21:28:58 +02:00
parent 341d0c6f38
commit fbb1b39b57
56 changed files with 1399 additions and 721 deletions
+89 -45
View File
@@ -3,9 +3,8 @@
import uuid
from datetime import date
from decimal import Decimal
from unittest.mock import patch, MagicMock
from unittest.mock import patch
import pytest
import pytest_asyncio
from httpx import AsyncClient
from sqlalchemy.ext.asyncio import AsyncSession
@@ -14,7 +13,6 @@ from app.models.sale import Sale
from app.models.vehicle import Vehicle
from app.models.contact import Contact
from app.utils.contract_pdf import build_contract_html
from app.utils.datev import generate_datev_csv, validate_datev_csv, DATEV_HEADERS
@pytest_asyncio.fixture
@@ -75,7 +73,9 @@ async def test_seller(db_session: AsyncSession) -> Contact:
@pytest_asyncio.fixture
async def test_sale(db_session: AsyncSession, test_vehicle: Vehicle, test_buyer: Contact) -> Sale:
async def test_sale(
db_session: AsyncSession, test_vehicle: Vehicle, test_buyer: Contact
) -> Sale:
"""Create a test sale."""
sale = Sale(
vehicle_id=test_vehicle.id,
@@ -109,16 +109,21 @@ class TestSaleCRUD:
assert data["page"] == 1
assert data["page_size"] == 20
async def test_create_sale(self, admin_client: AsyncClient, test_vehicle, test_buyer):
async def test_create_sale(
self, admin_client: AsyncClient, test_vehicle, test_buyer
):
"""POST /sales with valid data returns 201."""
response = await admin_client.post("/api/v1/sales/", json={
"vehicle_id": str(test_vehicle.id),
"buyer_contact_id": str(test_buyer.id),
"sale_price": "45000.00",
"sale_date": "2025-01-15",
"status": "draft",
"is_gwg": False,
})
response = await admin_client.post(
"/api/v1/sales/",
json={
"vehicle_id": str(test_vehicle.id),
"buyer_contact_id": str(test_buyer.id),
"sale_price": "45000.00",
"sale_date": "2025-01-15",
"status": "draft",
"is_gwg": False,
},
)
assert response.status_code == 201
data = response.json()
assert data["vehicle_id"] == str(test_vehicle.id)
@@ -127,20 +132,30 @@ class TestSaleCRUD:
assert data["status"] == "draft"
assert data["is_gwg"] is False
async def test_create_sale_without_vehicle_id(self, admin_client: AsyncClient, test_buyer):
async def test_create_sale_without_vehicle_id(
self, admin_client: AsyncClient, test_buyer
):
"""POST /sales without vehicle_id returns 422."""
response = await admin_client.post("/api/v1/sales/", json={
"buyer_contact_id": str(test_buyer.id),
"sale_price": "45000.00",
})
response = await admin_client.post(
"/api/v1/sales/",
json={
"buyer_contact_id": str(test_buyer.id),
"sale_price": "45000.00",
},
)
assert response.status_code == 422
async def test_create_sale_without_buyer_contact_id(self, admin_client: AsyncClient, test_vehicle):
async def test_create_sale_without_buyer_contact_id(
self, admin_client: AsyncClient, test_vehicle
):
"""POST /sales without buyer_contact_id returns 422."""
response = await admin_client.post("/api/v1/sales/", json={
"vehicle_id": str(test_vehicle.id),
"sale_price": "45000.00",
})
response = await admin_client.post(
"/api/v1/sales/",
json={
"vehicle_id": str(test_vehicle.id),
"sale_price": "45000.00",
},
)
assert response.status_code == 422
async def test_get_sale_by_id(self, admin_client: AsyncClient, test_sale):
@@ -159,16 +174,21 @@ class TestSaleCRUD:
async def test_update_sale(self, admin_client: AsyncClient, test_sale):
"""PUT /sales/:id updates sale fields."""
response = await admin_client.put(f"/api/v1/sales/{test_sale.id}", json={
"sale_price": "42000.00",
"status": "completed",
})
response = await admin_client.put(
f"/api/v1/sales/{test_sale.id}",
json={
"sale_price": "42000.00",
"status": "completed",
},
)
assert response.status_code == 200
data = response.json()
assert data["sale_price"] == "42000.00"
assert data["status"] == "completed"
async def test_delete_sale_cancels_and_restores_vehicle(self, admin_client: AsyncClient, test_sale, db_session):
async def test_delete_sale_cancels_and_restores_vehicle(
self, admin_client: AsyncClient, test_sale, db_session
):
"""DELETE /sales/:id cancels sale and restores vehicle status to 'available'."""
# First set vehicle to sold (as create_sale would)
vehicle = await db_session.get(Vehicle, test_sale.vehicle_id)
@@ -193,9 +213,13 @@ class TestSaleCRUD:
for item in data["items"]:
assert item["status"] == "completed"
async def test_list_sales_with_date_filter(self, admin_client: AsyncClient, test_sale):
async def test_list_sales_with_date_filter(
self, admin_client: AsyncClient, test_sale
):
"""GET /sales?date_from=2025-01-01&date_to=2025-12-31 filters by date range."""
response = await admin_client.get("/api/v1/sales/?date_from=2025-01-01&date_to=2025-12-31")
response = await admin_client.get(
"/api/v1/sales/?date_from=2025-01-01&date_to=2025-12-31"
)
assert response.status_code == 200
data = response.json()
assert data["total"] >= 1
@@ -204,22 +228,29 @@ class TestSaleCRUD:
class TestSaleVehicleStatus:
"""Test vehicle status changes on sale create/delete."""
async def test_create_sale_sets_vehicle_sold(self, admin_client: AsyncClient, test_vehicle, test_buyer, db_session):
async def test_create_sale_sets_vehicle_sold(
self, admin_client: AsyncClient, test_vehicle, test_buyer, db_session
):
"""Creating a sale sets vehicle availability to 'sold'."""
response = await admin_client.post("/api/v1/sales/", json={
"vehicle_id": str(test_vehicle.id),
"buyer_contact_id": str(test_buyer.id),
"sale_price": "45000.00",
"sale_date": "2025-01-15",
"status": "draft",
})
response = await admin_client.post(
"/api/v1/sales/",
json={
"vehicle_id": str(test_vehicle.id),
"buyer_contact_id": str(test_buyer.id),
"sale_price": "45000.00",
"sale_date": "2025-01-15",
"status": "draft",
},
)
assert response.status_code == 201
# Verify vehicle status
await db_session.refresh(test_vehicle)
assert test_vehicle.availability == "sold"
async def test_cancel_sale_restores_vehicle_available(self, admin_client: AsyncClient, test_sale, db_session):
async def test_cancel_sale_restores_vehicle_available(
self, admin_client: AsyncClient, test_sale, db_session
):
"""Cancelling a sale restores vehicle availability to 'available'."""
# Set vehicle to sold first
vehicle = await db_session.get(Vehicle, test_sale.vehicle_id)
@@ -246,15 +277,20 @@ class TestContractPDF:
assert data["sale_id"] == str(test_sale.id)
assert "contract_pdf_path" in data
async def test_download_contract_not_found(self, admin_client: AsyncClient, test_sale):
async def test_download_contract_not_found(
self, admin_client: AsyncClient, test_sale
):
"""GET /sales/:id/contract returns 404 if no PDF generated."""
response = await admin_client.get(f"/api/v1/sales/{test_sale.id}/contract")
assert response.status_code == 404
async def test_download_contract_pdf(self, admin_client: AsyncClient, test_sale, db_session):
async def test_download_contract_pdf(
self, admin_client: AsyncClient, test_sale, db_session
):
"""GET /sales/:id/contract returns PDF content."""
# Create a fake PDF file
import os
os.makedirs("/tmp/contracts", exist_ok=True)
pdf_path = f"/tmp/contracts/contract_{test_sale.id}.pdf"
with open(pdf_path, "wb") as f:
@@ -283,7 +319,9 @@ class TestContractPDF:
assert "Geringwertige Wirtschaftsgüter" in html
assert "§ 6 Abs. 2 EStG" in html
def test_gwg_clause_not_in_contract_when_price_too_high(self, test_sale, test_vehicle, test_buyer):
def test_gwg_clause_not_in_contract_when_price_too_high(
self, test_sale, test_vehicle, test_buyer
):
"""GwG clause does NOT appear when price > 800 even if is_gwg=true."""
test_sale.is_gwg = True
test_sale.sale_price = Decimal("5000.00")
@@ -293,7 +331,9 @@ class TestContractPDF:
html = build_contract_html(test_sale)
assert "Geringwertige Wirtschaftsgüter" not in html
def test_gwg_clause_not_in_contract_when_not_gwg(self, test_sale, test_vehicle, test_buyer):
def test_gwg_clause_not_in_contract_when_not_gwg(
self, test_sale, test_vehicle, test_buyer
):
"""GwG clause does NOT appear when is_gwg=false."""
test_sale.is_gwg = False
test_sale.sale_price = Decimal("500.00")
@@ -303,7 +343,9 @@ class TestContractPDF:
html = build_contract_html(test_sale)
assert "Geringwertige Wirtschaftsgüter" not in html
def test_contract_html_contains_ust_id_field(self, test_sale, test_vehicle, test_buyer):
def test_contract_html_contains_ust_id_field(
self, test_sale, test_vehicle, test_buyer
):
"""Contract HTML contains USt-IdNr. field."""
test_sale.vehicle = test_vehicle
test_sale.buyer = test_buyer
@@ -318,7 +360,9 @@ class TestUstIdVerification:
async def test_verify_ust_id_disabled(self, admin_client: AsyncClient, test_sale):
"""POST /sales/:id/verify-ust-id returns not verified when BZSt API disabled."""
response = await admin_client.post(f"/api/v1/sales/{test_sale.id}/verify-ust-id")
response = await admin_client.post(
f"/api/v1/sales/{test_sale.id}/verify-ust-id"
)
assert response.status_code == 200
data = response.json()
assert data["verified"] is False