Files
AutonetSellCar/backend/app/api/vehicle_requests.py
AutonetSellCar Deploy 1d8e4435b3 Feature: Russian language support & Vehicle Requests improvements
- Add Russian language support (title_ru, subtitle_ru) for hero banners
- Add fuel/transmission translations for Mongolian (경유→Дизель, 오토→Автомат)
- Improve Vehicle Requests admin page:
  - Display real request ID and user email
  - Show detailed request info (maker, grade, year, fuel, mileage)
  - Replace modal search with Cars page integration
- Add "Add to Request" flow in Cars page for vehicle recommendations
- Fix image URL handling in FilmStripSlider and car detail page

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 18:56:28 +09:00

415 lines
14 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from typing import List
from datetime import datetime, timedelta
from ..database import get_db
from ..models import VehicleRequest, RequestVehicle, PurchasedVehicle, User, DealerInfo, SystemSettings
from ..schemas import (
VehicleRequestCreate, VehicleRequestResponse,
RequestVehicleCreate, RequestVehicleResponse, RequestVehicleApprove,
PurchasedVehicleCreate, PurchasedVehicleResponse, PurchasedVehicleUpdateStatus,
VehicleRequestWithVehicles,
)
from .auth import get_current_user
from .notification import notify_vehicle_recommended, notify_shipping_update
def get_system_settings(db: Session) -> SystemSettings:
"""Get or create system settings"""
settings = db.query(SystemSettings).first()
if not settings:
settings = SystemSettings()
db.add(settings)
db.commit()
db.refresh(settings)
return settings
def calculate_dealer_commission(vehicle_price_krw: int, db: Session) -> tuple:
"""Calculate dealer and platform commission based on Mongolia margin"""
settings = get_system_settings(db)
# Calculate Mongolia margin (vehicle price * margin percent)
mongolia_margin = vehicle_price_krw * (settings.mongolia_margin_percent / 100)
# 50/50 split between dealer and platform
dealer_commission = int(mongolia_margin * 0.5)
platform_commission = int(mongolia_margin * 0.5)
return dealer_commission, platform_commission
router = APIRouter(prefix="/vehicle-requests", tags=["vehicle-requests"])
# Development mode - skip 24 hour wait
DEV_MODE = True
# =====================
# User Endpoints
# =====================
QUOTE_REQUEST_COST = 1.0 # 1 CC for quote request submission
@router.post("/", response_model=VehicleRequestResponse)
def create_request(
request_data: VehicleRequestCreate,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Create a new vehicle search request (costs 1 CC)"""
# Check if user has enough CC
if (current_user.cc_balance or 0) < QUOTE_REQUEST_COST:
raise HTTPException(
status_code=400,
detail=f"Insufficient CC balance. You need {QUOTE_REQUEST_COST} CC to submit a vehicle request. Current balance: {current_user.cc_balance or 0}"
)
# Deduct CC from user's balance
current_user.cc_balance = (current_user.cc_balance or 0) - QUOTE_REQUEST_COST
# Create the request
request = VehicleRequest(
user_id=current_user.id,
cc_paid=QUOTE_REQUEST_COST,
**request_data.model_dump()
)
db.add(request)
db.commit()
db.refresh(request)
return request
@router.get("/my-requests", response_model=List[VehicleRequestWithVehicles])
def get_my_requests(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Get current user's vehicle requests with approved vehicles"""
requests = db.query(VehicleRequest).filter(
VehicleRequest.user_id == current_user.id
).order_by(VehicleRequest.created_at.desc()).all()
result = []
for req in requests:
# In dev mode, show all approved vehicles immediately
# In production, only show after 24 hours
if DEV_MODE or (req.created_at and datetime.utcnow() - req.created_at > timedelta(hours=24)):
approved_vehicles = [v for v in req.recommended_vehicles if v.is_approved]
else:
approved_vehicles = []
result.append(VehicleRequestWithVehicles(
request=VehicleRequestResponse.model_validate(req),
approved_vehicles=[RequestVehicleResponse.model_validate(v) for v in approved_vehicles]
))
return result
# =====================
# Purchased Vehicles (Find My Car)
# =====================
@router.get("/purchased", response_model=List[PurchasedVehicleResponse])
def get_purchased_vehicles(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Get user's purchased vehicles with shipping status"""
vehicles = db.query(PurchasedVehicle).filter(
PurchasedVehicle.user_id == current_user.id
).order_by(PurchasedVehicle.purchased_at.desc()).all()
return vehicles
# =====================
# Admin Endpoints
# =====================
@router.get("/admin/list", response_model=List[VehicleRequestResponse])
def admin_get_all_requests(
status: str = None,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Admin: Get all vehicle requests"""
if not current_user.is_admin:
raise HTTPException(status_code=403, detail="Admin access required")
query = db.query(VehicleRequest)
if status:
query = query.filter(VehicleRequest.status == status)
requests = query.order_by(VehicleRequest.created_at.desc()).all()
# User 정보 추가
result = []
for req in requests:
user = db.query(User).filter(User.id == req.user_id).first()
req_dict = {
"id": req.id,
"user_id": req.user_id,
"user_email": user.email if user else None,
"user_name": user.name if user else None,
"maker_code": req.maker_code,
"maker_name": req.maker_name,
"model_code": req.model_code,
"model_name": req.model_name,
"grade_code": req.grade_code,
"grade_name": req.grade_name,
"year_from": req.year_from,
"year_to": req.year_to,
"mileage_min": req.mileage_min,
"mileage_max": req.mileage_max,
"fuel": req.fuel,
"displacement_min": req.displacement_min,
"displacement_max": req.displacement_max,
"status": req.status,
"admin_reviewed_at": req.admin_reviewed_at,
"created_at": req.created_at,
}
result.append(req_dict)
return result
@router.get("/admin/{request_id}", response_model=VehicleRequestWithVehicles)
def admin_get_request_detail(
request_id: int,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Admin: Get request detail with all recommended vehicles"""
if not current_user.is_admin:
raise HTTPException(status_code=403, detail="Admin access required")
request = db.query(VehicleRequest).filter(VehicleRequest.id == request_id).first()
if not request:
raise HTTPException(status_code=404, detail="Request not found")
return VehicleRequestWithVehicles(
request=VehicleRequestResponse.model_validate(request),
approved_vehicles=[RequestVehicleResponse.model_validate(v) for v in request.recommended_vehicles]
)
@router.post("/admin/{request_id}/vehicles", response_model=RequestVehicleResponse)
def admin_add_vehicle(
request_id: int,
vehicle_data: RequestVehicleCreate,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Admin: Add a vehicle to a request"""
if not current_user.is_admin:
raise HTTPException(status_code=403, detail="Admin access required")
request = db.query(VehicleRequest).filter(VehicleRequest.id == request_id).first()
if not request:
raise HTTPException(status_code=404, detail="Request not found")
vehicle = RequestVehicle(
request_id=request_id,
car_data=vehicle_data.car_data,
is_approved=vehicle_data.is_approved,
approved_at=datetime.utcnow() if vehicle_data.is_approved else None
)
db.add(vehicle)
# Update request status
request.status = "reviewed"
request.admin_reviewed_at = datetime.utcnow()
db.commit()
db.refresh(vehicle)
return vehicle
@router.post("/admin/{request_id}/approve-vehicles")
def admin_approve_vehicles(
request_id: int,
approval: RequestVehicleApprove,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Admin: Approve multiple vehicles for a request"""
if not current_user.is_admin:
raise HTTPException(status_code=403, detail="Admin access required")
vehicles = db.query(RequestVehicle).filter(
RequestVehicle.request_id == request_id,
RequestVehicle.id.in_(approval.vehicle_ids)
).all()
for vehicle in vehicles:
vehicle.is_approved = True
vehicle.approved_at = datetime.utcnow()
# Update request status
request = db.query(VehicleRequest).filter(VehicleRequest.id == request_id).first()
if request:
request.status = "completed"
request.admin_reviewed_at = datetime.utcnow()
db.commit()
# Send notification to user
if request and len(vehicles) > 0:
notify_vehicle_recommended(db, request.user_id, request_id, len(vehicles))
return {"message": f"Approved {len(vehicles)} vehicles"}
@router.put("/admin/{request_id}/status")
def admin_update_request_status(
request_id: int,
new_status: str,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Admin: Update request status"""
if not current_user.is_admin:
raise HTTPException(status_code=403, detail="Admin access required")
request = db.query(VehicleRequest).filter(VehicleRequest.id == request_id).first()
if not request:
raise HTTPException(status_code=404, detail="Request not found")
request.status = new_status
request.admin_reviewed_at = datetime.utcnow()
db.commit()
return {"message": "Status updated"}
@router.delete("/admin/{request_id}/vehicles/{vehicle_id}")
def admin_delete_vehicle(
request_id: int,
vehicle_id: int,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Admin: Delete a recommended vehicle from a request"""
if not current_user.is_admin:
raise HTTPException(status_code=403, detail="Admin access required")
vehicle = db.query(RequestVehicle).filter(
RequestVehicle.id == vehicle_id,
RequestVehicle.request_id == request_id
).first()
if not vehicle:
raise HTTPException(status_code=404, detail="Vehicle not found")
db.delete(vehicle)
db.commit()
return {"message": "Vehicle deleted successfully"}
# =====================
# Admin: Purchased Vehicles Management
# =====================
@router.post("/admin/purchased", response_model=PurchasedVehicleResponse)
def admin_create_purchased(
vehicle_data: PurchasedVehicleCreate,
user_id: int,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Admin: Create a purchased vehicle record"""
if not current_user.is_admin:
raise HTTPException(status_code=403, detail="Admin access required")
# Calculate dealer commission if dealer is selected
dealer_commission_krw = 0
platform_commission_krw = 0
if vehicle_data.selected_dealer_id:
# Verify dealer exists and is active
dealer_info = db.query(DealerInfo).filter(
DealerInfo.id == vehicle_data.selected_dealer_id,
DealerInfo.is_active == True
).first()
if not dealer_info:
raise HTTPException(status_code=400, detail="Selected dealer not found or inactive")
# Calculate commissions
dealer_commission_krw, platform_commission_krw = calculate_dealer_commission(
vehicle_data.vehicle_price_krw, db
)
# Credit commission to dealer's account
dealer_info.total_commission_earned += dealer_commission_krw
vehicle = PurchasedVehicle(
user_id=user_id,
car_name=vehicle_data.car_name,
car_data=vehicle_data.car_data,
car_image=vehicle_data.car_image,
vehicle_price_krw=vehicle_data.vehicle_price_krw,
domestic_cost_krw=vehicle_data.domestic_cost_krw,
shipping_cost_usd=vehicle_data.shipping_cost_usd,
total_cost_krw=vehicle_data.total_cost_krw,
car_type=vehicle_data.car_type,
selected_dealer_id=vehicle_data.selected_dealer_id,
dealer_commission_krw=dealer_commission_krw,
platform_commission_krw=platform_commission_krw,
)
db.add(vehicle)
db.commit()
db.refresh(vehicle)
return vehicle
@router.get("/admin/purchased/all", response_model=List[PurchasedVehicleResponse])
def admin_get_all_purchased(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Admin: Get all purchased vehicles"""
if not current_user.is_admin:
raise HTTPException(status_code=403, detail="Admin access required")
vehicles = db.query(PurchasedVehicle).order_by(PurchasedVehicle.purchased_at.desc()).all()
return vehicles
@router.put("/admin/purchased/{vehicle_id}/status", response_model=PurchasedVehicleResponse)
def admin_update_shipping_status(
vehicle_id: int,
status_update: PurchasedVehicleUpdateStatus,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Admin: Update shipping status of a purchased vehicle"""
if not current_user.is_admin:
raise HTTPException(status_code=403, detail="Admin access required")
vehicle = db.query(PurchasedVehicle).filter(PurchasedVehicle.id == vehicle_id).first()
if not vehicle:
raise HTTPException(status_code=404, detail="Vehicle not found")
vehicle.shipping_status = status_update.shipping_status
vehicle.status_updated_at = datetime.utcnow()
if status_update.current_location:
vehicle.current_location = status_update.current_location
if status_update.estimated_arrival:
vehicle.estimated_arrival = status_update.estimated_arrival
if status_update.shipping_status == 7: # Delivered (배송완료)
vehicle.delivered_at = datetime.utcnow()
db.commit()
db.refresh(vehicle)
# Send notification to user about shipping update
notify_shipping_update(db, vehicle.user_id, vehicle.id, status_update.shipping_status, vehicle.car_name)
return vehicle