Files
erp-nutzfahrzeuge/backend/app/services/price_compare_service.py
T

96 lines
3.1 KiB
Python
Raw Normal View History

"""Price comparison service: search comparable listings and calculate average price."""
from __future__ import annotations
import logging
import random
import uuid
from typing import Any
from sqlalchemy.ext.asyncio import AsyncSession
from app.models.vehicle import Vehicle
from app.schemas.retouch import ComparableListing, PriceCompareResponse
from app.services.vehicle_service import get_vehicle_by_id
logger = logging.getLogger(__name__)
def _generate_mock_listings(vehicle: Vehicle) -> list[ComparableListing]:
"""Generate mock mobile.de comparable listings based on vehicle data.
In production, this would call the mobile.de Search API.
For now, we generate realistic mock data based on the vehicle's
make, model, year, and price.
"""
listings: list[ComparableListing] = []
base_price = float(vehicle.price) if vehicle.price else 25000.0
# Generate 3-7 comparable listings with price variation
num_listings = random.randint(3, 7)
for i in range(num_listings):
# Vary price by +/- 15%
price_variation = random.uniform(-0.15, 0.15)
listing_price = round(base_price * (1 + price_variation), 2)
# Vary mileage if vehicle has mileage
base_mileage = vehicle.mileage_km or 100000
mileage_variation = random.randint(-20000, 20000)
listing_mileage = max(0, base_mileage + mileage_variation)
locations = ["Berlin", "Hamburg", "München", "Köln", "Frankfurt", "Stuttgart"]
listing = ComparableListing(
title=f"{vehicle.make} {vehicle.model} {vehicle.year or ''}".strip(),
make=vehicle.make,
model=vehicle.model,
year=vehicle.year,
price=listing_price,
mileage_km=listing_mileage,
location=random.choice(locations),
url=f"https://suchen.mobile.de/fahrzeuge/details.html?id={random.randint(1000000, 9999999)}",
source="mobile.de",
)
listings.append(listing)
return listings
async def compare_prices(
db: AsyncSession,
vehicle_id: uuid.UUID,
) -> PriceCompareResponse:
"""Compare prices for a vehicle by searching comparable listings.
Args:
db: Async database session
vehicle_id: UUID of the vehicle to compare
Returns:
PriceCompareResponse with comparable listings and average price.
If vehicle not found, raises ValueError.
If no comparable listings found, returns empty list with null average.
"""
vehicle = await get_vehicle_by_id(db, vehicle_id)
if vehicle is None:
raise ValueError(f"Vehicle {vehicle_id} not found")
# Search for comparable listings
# In production: call mobile.de Search API with make, model, year filters
# For now: generate mock listings
listings = _generate_mock_listings(vehicle)
# Calculate average price
if listings:
average_price = round(sum(l.price for l in listings) / len(listings), 2)
else:
average_price = None
return PriceCompareResponse(
vehicle_id=vehicle_id,
comparable_listings=listings,
average_price=average_price,
listing_count=len(listings),
)