Files
drivers_bot/tests/test_product_readiness.py
2026-05-15 04:45:54 +09:00

339 lines
11 KiB
Python

import pytest
@pytest.mark.asyncio
async def test_license_plate_can_be_saved_and_edited(client, auth_headers) -> None:
car = (
await client.post(
"/api/cars",
headers=auth_headers,
json={"name": "Plate car", "plate_number": "12 가 3456"},
)
).json()
updated = await client.patch(
f"/api/cars/{car['id']}",
headers=auth_headers,
json={"plate_number": "34 나 7890", "body_type": "SUV"},
)
assert updated.status_code == 200
assert updated.json()["plate_number"] == "34 나 7890"
assert updated.json()["body_type"] == "SUV"
@pytest.mark.asyncio
async def test_insurance_six_months_allocates_proportionally(client, auth_headers) -> None:
car = (await client.post("/api/cars", headers=auth_headers, json={"name": "Insurance 6"})).json()
await client.post(
"/api/expenses",
headers=auth_headers,
json={
"car_id": car["id"],
"entry_date": "2026-01-01",
"category": "insurance",
"title": "Insurance",
"total_cost": 600,
"period_start": "2026-01-01",
"period_months": 6,
"payment_period_months": 6,
"is_recurring": True,
},
)
stats = await client.get(
f"/api/cars/{car['id']}/stats?date_from=2026-02-01&date_to=2026-02-28",
headers=auth_headers,
)
assert stats.status_code == 200
assert stats.json()["cost_by_category"]["insurance"] == "100.00"
@pytest.mark.asyncio
async def test_custom_insurance_period_allocates_by_overlap(client, auth_headers) -> None:
car = (await client.post("/api/cars", headers=auth_headers, json={"name": "Insurance custom"})).json()
await client.post(
"/api/expenses",
headers=auth_headers,
json={
"car_id": car["id"],
"entry_date": "2026-01-15",
"category": "insurance",
"title": "Short insurance",
"total_cost": 310,
"period_start": "2026-01-15",
"period_end": "2026-02-14",
"is_recurring": True,
},
)
stats = await client.get(
f"/api/cars/{car['id']}/stats?date_from=2026-02-01&date_to=2026-02-28",
headers=auth_headers,
)
assert stats.status_code == 200
assert stats.json()["cost_by_category"]["insurance"] == "140.00"
@pytest.mark.asyncio
async def test_loan_calculator_regular_and_zero_rate(client, auth_headers) -> None:
regular = await client.post(
"/api/loans/calculate",
headers=auth_headers,
json={"principal": 6000000, "term_months": 36, "annual_interest_rate": 5.5},
)
zero = await client.post(
"/api/loans/calculate",
headers=auth_headers,
json={"principal": 1200, "term_months": 12, "annual_interest_rate": 0},
)
assert regular.status_code == 200
assert float(regular.json()["monthly_payment"]) > 0
assert zero.json()["monthly_payment"] == "100.00"
assert zero.json()["total_interest"] == "0.00"
@pytest.mark.asyncio
async def test_ownership_cost_includes_credit_and_fixed_variable_split(client, auth_headers) -> None:
car = (
await client.post(
"/api/cars",
headers=auth_headers,
json={
"name": "Credit car",
"purchase_type": "credit",
"loan_principal": 1200,
"loan_term_months": 12,
"loan_annual_interest_rate": 0,
"loan_first_payment_date": "2026-01-01",
},
)
).json()
await client.post(
"/api/fuel",
headers=auth_headers,
json={
"car_id": car["id"],
"entry_date": "2026-01-10",
"odometer": 1000,
"liters": 20,
"price_per_liter": 2,
},
)
await client.post(
"/api/expenses",
headers=auth_headers,
json={
"car_id": car["id"],
"entry_date": "2026-01-12",
"category": "fine",
"title": "Fine",
"total_cost": 30,
},
)
stats = await client.get(
f"/api/cars/{car['id']}/stats?date_from=2026-01-01&date_to=2026-01-31",
headers=auth_headers,
)
payload = stats.json()
assert payload["loan_principal_cost"] == "100.00"
assert payload["loan_interest_cost"] == "0.00"
assert payload["fixed_costs"] == "100.00"
assert payload["variable_costs"] == "70.00"
assert payload["total_cost_with_credit"] == "170.00"
assert payload["total_cost_without_credit"] == "70.00"
@pytest.mark.asyncio
async def test_odometer_lower_fuel_requires_confirmation_and_delete_recalculates(client, auth_headers) -> None:
car = (await client.post("/api/cars", headers=auth_headers, json={"name": "Odo car"})).json()
first = (
await client.post(
"/api/fuel",
headers=auth_headers,
json={
"car_id": car["id"],
"entry_date": "2026-01-01",
"odometer": 1000,
"liters": 20,
"price_per_liter": 2,
},
)
).json()
second = (
await client.post(
"/api/fuel",
headers=auth_headers,
json={
"car_id": car["id"],
"entry_date": "2026-01-02",
"odometer": 2000,
"liters": 20,
"price_per_liter": 2,
},
)
).json()
blocked = await client.post(
"/api/fuel",
headers=auth_headers,
json={
"car_id": car["id"],
"entry_date": "2026-01-03",
"odometer": 900,
"liters": 20,
"price_per_liter": 2,
},
)
await client.delete(f"/api/fuel/{second['id']}", headers=auth_headers)
refreshed = await client.get(f"/api/cars/{car['id']}", headers=auth_headers)
history = await client.get(f"/api/cars/{car['id']}/odometer-history", headers=auth_headers)
assert first["odometer"] == 1000
assert blocked.status_code == 409
assert refreshed.json()["current_odometer"] == 1000
assert len(history.json()) >= 2
@pytest.mark.asyncio
async def test_service_lower_odometer_can_be_confirmed(client, auth_headers) -> None:
car = (
await client.post(
"/api/cars",
headers=auth_headers,
json={"name": "Service odo", "current_odometer": 1000},
)
).json()
blocked = await client.post(
"/api/service",
headers=auth_headers,
json={
"car_id": car["id"],
"entry_date": "2026-01-02",
"odometer": 900,
"service_type": "maintenance",
"title": "Correction",
"total_cost": 0,
},
)
confirmed = await client.post(
"/api/service",
headers=auth_headers,
json={
"car_id": car["id"],
"entry_date": "2026-01-02",
"odometer": 900,
"service_type": "maintenance",
"title": "Correction",
"total_cost": 0,
"confirm_lower_odometer": True,
},
)
assert blocked.status_code == 409
assert confirmed.status_code == 201
@pytest.mark.asyncio
async def test_full_tank_analysis_uses_full_tank_intervals_and_warns(client, auth_headers) -> None:
car = (await client.post("/api/cars", headers=auth_headers, json={"name": "Tank car"})).json()
for odometer, liters, full in [
(1000, 40, True),
(1200, 10, False),
(1500, 35, True),
(1600, 40, True),
]:
await client.post(
"/api/fuel",
headers=auth_headers,
json={
"car_id": car["id"],
"entry_date": "2026-01-01",
"odometer": odometer,
"liters": liters,
"price_per_liter": 2,
"is_full_tank": full,
},
)
analytics = await client.get(f"/api/cars/{car['id']}/analytics", headers=auth_headers)
payload = analytics.json()
assert payload["average_full_tank_distance"] == 300.0
assert payload["last_full_tank_distance"] == 100
assert payload["full_tank_warning"] is not None
@pytest.mark.asyncio
async def test_parser_recognizes_full_tank_and_credit_purchase(client, auth_headers) -> None:
fuel = await client.post(
"/api/parse/record",
headers=auth_headers,
json={"text": "заправил полный бак 43 литра на 72000, пробег 184230"},
)
purchase = await client.post(
"/api/parse/record",
headers=auth_headers,
json={"text": "купил машину за 8500000 вон, кредит 6000000 на 36 месяцев под 5.5%"},
)
assert fuel.json()["event_type"] == "fuel"
assert fuel.json()["data"]["is_full_tank"] is True
assert purchase.json()["event_type"] == "vehicle_purchase"
assert purchase.json()["data"]["purchase_type"] == "credit"
assert purchase.json()["data"]["loan_term_months"] == 36
@pytest.mark.asyncio
async def test_admin_request_changes_keeps_application_visible_to_moderation(
client, auth_headers, admin_auth_headers, internal_headers
) -> None:
center = (
await client.post(
"/api/service-centers",
headers=auth_headers,
json={"display_name": "Needs Work Service", "country": "KR"},
)
).json()
await client.post(
"/api/users",
headers=internal_headers,
json={"telegram_id": 9001, "platform_role": "admin"},
)
response = await client.post(
f"/api/admin/service-centers/{center['id']}/request-changes",
headers=admin_auth_headers,
json={"reason": "Добавьте документы", "comment": "Нужны фото регистрации"},
)
assert response.status_code == 200
assert response.json()["verification_status"] == "needs_changes"
@pytest.mark.asyncio
async def test_service_center_application_is_visible_to_moderators(
client, auth_headers, admin_auth_headers, internal_headers
) -> None:
center = (
await client.post(
"/api/service-centers",
headers=auth_headers,
json={"display_name": "Pending Review Service", "country": "KR"},
)
).json()
await client.post(
"/api/users",
headers=internal_headers,
json={"telegram_id": 9001, "platform_role": "moderator"},
)
pending = await client.get("/api/admin/service-centers/pending", headers=admin_auth_headers)
assert pending.status_code == 200
assert center["id"] in [item["id"] for item in pending.json()]