Files
AutonetSellCar/backend/app/api/dealer.py
AutonetSellCar Deploy 1f0dcb1ddb Initial commit: AutonetSellCar platform with deployment system
- Frontend: Next.js 14 with TypeScript
- Backend: FastAPI with SQLAlchemy
- Agent: Carmodoo sync agent
- Deployment: Docker Compose based staging/production setup
- Scripts: Automated deployment with rollback support

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 13:24:39 +09:00

255 lines
8.3 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from datetime import datetime
from typing import List
from ..database import get_db
from ..models import User, DealerApplication, DealerInfo
from ..models.dealer import generate_dealer_code
from ..schemas import (
DealerApplicationCreate, DealerApplicationResponse,
DealerApplicationReject, DealerInfoResponse, DealerPublicInfo,
)
from .auth import get_current_user
from .notification import notify_dealer_approved, notify_dealer_rejected
router = APIRouter(prefix="/dealer", tags=["dealer"])
@router.post("/apply", response_model=DealerApplicationResponse)
def apply_dealer(
application: DealerApplicationCreate,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Submit a dealer application"""
# Check if user already has a pending or approved application
existing = db.query(DealerApplication).filter(
DealerApplication.user_id == current_user.id,
DealerApplication.status.in_(["pending", "approved"])
).first()
if existing:
if existing.status == "approved":
raise HTTPException(status_code=400, detail="You are already a dealer")
raise HTTPException(status_code=400, detail="You already have a pending application")
# Check if user is already a dealer
if current_user.is_dealer:
raise HTTPException(status_code=400, detail="You are already a dealer")
# Create new application
new_application = DealerApplication(
user_id=current_user.id,
business_name=application.business_name,
business_number=application.business_number,
real_name=application.real_name,
id_number_encrypted=application.id_number, # TODO: Encrypt this properly
phone=application.phone,
bank_name=application.bank_name,
bank_account=application.bank_account,
account_holder=application.account_holder,
photo_url=application.photo_url,
status="pending"
)
db.add(new_application)
db.commit()
db.refresh(new_application)
return new_application
@router.get("/my-application", response_model=DealerApplicationResponse)
def get_my_application(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Get current user's dealer application"""
application = db.query(DealerApplication).filter(
DealerApplication.user_id == current_user.id
).order_by(DealerApplication.applied_at.desc()).first()
if not application:
raise HTTPException(status_code=404, detail="No application found")
return application
@router.get("/my-info", response_model=DealerInfoResponse)
def get_my_dealer_info(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Get current user's dealer info (if approved)"""
if not current_user.is_dealer:
raise HTTPException(status_code=403, detail="You are not a dealer")
dealer_info = db.query(DealerInfo).filter(
DealerInfo.user_id == current_user.id
).first()
if not dealer_info:
raise HTTPException(status_code=404, detail="Dealer info not found")
return dealer_info
@router.get("/list", response_model=List[DealerPublicInfo])
def list_dealers(
db: Session = Depends(get_db)
):
"""Get list of active dealers (public info only)"""
dealers = db.query(DealerInfo).filter(
DealerInfo.is_active == True
).all()
return dealers
# Admin endpoints
@router.get("/admin/applications", response_model=List[DealerApplicationResponse])
def get_applications(
status_filter: str = None,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""[Admin] Get all dealer applications"""
if not current_user.is_admin:
raise HTTPException(status_code=403, detail="Admin access required")
query = db.query(DealerApplication)
if status_filter:
query = query.filter(DealerApplication.status == status_filter)
applications = query.order_by(DealerApplication.applied_at.desc()).all()
return applications
@router.put("/admin/applications/{application_id}/approve", response_model=DealerInfoResponse)
def approve_application(
application_id: int,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""[Admin] Approve a dealer application"""
if not current_user.is_admin:
raise HTTPException(status_code=403, detail="Admin access required")
application = db.query(DealerApplication).filter(
DealerApplication.id == application_id
).first()
if not application:
raise HTTPException(status_code=404, detail="Application not found")
if application.status != "pending":
raise HTTPException(status_code=400, detail="Application is not pending")
# Generate unique dealer code
dealer_code = generate_dealer_code()
while db.query(DealerInfo).filter(DealerInfo.dealer_code == dealer_code).first():
dealer_code = generate_dealer_code()
# Create dealer info
dealer_info = DealerInfo(
user_id=application.user_id,
dealer_code=dealer_code,
business_name=application.business_name,
real_name=application.real_name,
phone=application.phone,
photo_url=application.photo_url,
bank_name=application.bank_name,
bank_account=application.bank_account,
account_holder=application.account_holder,
)
# Update application status
application.status = "approved"
application.approved_at = datetime.utcnow()
# Update user is_dealer flag
user = db.query(User).filter(User.id == application.user_id).first()
user.is_dealer = True
db.add(dealer_info)
db.commit()
db.refresh(dealer_info)
# TODO: Generate dealer card image here
# dealer_info.dealer_card_url = generate_dealer_card(dealer_info)
# db.commit()
# Send notification to user about dealer approval
notify_dealer_approved(db, application.user_id, dealer_code)
return dealer_info
@router.put("/admin/applications/{application_id}/reject")
def reject_application(
application_id: int,
reject_data: DealerApplicationReject,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""[Admin] Reject a dealer application"""
if not current_user.is_admin:
raise HTTPException(status_code=403, detail="Admin access required")
application = db.query(DealerApplication).filter(
DealerApplication.id == application_id
).first()
if not application:
raise HTTPException(status_code=404, detail="Application not found")
if application.status != "pending":
raise HTTPException(status_code=400, detail="Application is not pending")
application.status = "rejected"
application.rejected_reason = reject_data.reason
db.commit()
# Send notification to user about dealer rejection
notify_dealer_rejected(db, application.user_id, reject_data.reason)
return {"message": "Application rejected", "reason": reject_data.reason}
@router.get("/admin/dealers", response_model=List[DealerInfoResponse])
def get_all_dealers(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""[Admin] Get all dealers with full info"""
if not current_user.is_admin:
raise HTTPException(status_code=403, detail="Admin access required")
dealers = db.query(DealerInfo).all()
return dealers
@router.put("/admin/dealers/{dealer_id}/toggle-active")
def toggle_dealer_active(
dealer_id: int,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""[Admin] Toggle dealer active status"""
if not current_user.is_admin:
raise HTTPException(status_code=403, detail="Admin access required")
dealer = db.query(DealerInfo).filter(DealerInfo.id == dealer_id).first()
if not dealer:
raise HTTPException(status_code=404, detail="Dealer not found")
dealer.is_active = not dealer.is_active
# Also update user's is_dealer status
user = db.query(User).filter(User.id == dealer.user_id).first()
if user:
user.is_dealer = dealer.is_active
db.commit()
return {"message": f"Dealer {'activated' if dealer.is_active else 'deactivated'}", "is_active": dealer.is_active}