Files
hms-licht-ton/backend/app/routers/rental_requests.py
T

143 lines
5.1 KiB
Python
Raw Normal View History

"""Rental request router: accept Mietanfrage, save, forward to Rentman."""
import random
from datetime import datetime
from fastapi import APIRouter, Depends, HTTPException, status, Request
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from typing import Any
from app.database import get_db
from app.models.equipment import EquipmentCache
from app.models.rental_request import RentalRequest, RentalRequestItem
from app.schemas.rental_request import RentalRequestCreate, RentalRequestResponse
from app.services.rentman_service import RentmanService
from app.services.email_service import EmailService
from app.cache import cache
router = APIRouter(prefix="/api/rental-requests", tags=["rental-requests"])
def generate_reference_number() -> str:
"""Generate a unique reference number: HMS-YYYY-NNNNN."""
year = datetime.now().year
num = random.randint(1, 99999)
return f"HMS-{year}-{num:05d}"
@router.post("", response_model=RentalRequestResponse, status_code=status.HTTP_201_CREATED)
async def create_rental_request(
payload: RentalRequestCreate,
request: Request,
db: AsyncSession = Depends(get_db),
) -> Any:
"""Create a rental request, save to DB, forward to Rentman, send email."""
# Rate limiting
client_ip = request.client.host if request.client else "unknown"
rate_key = f"rate:rental:{client_ip}"
count = await cache.incr_rate(rate_key, window=60)
if count > 5:
raise HTTPException(status_code=status.HTTP_429_TOO_MANY_REQUESTS, detail="Too many requests")
ref_number = generate_reference_number()
# Save to database
rental = RentalRequest(
reference_number=ref_number,
event_name=payload.event_name,
date_start=payload.date_start,
date_end=payload.date_end,
location=payload.location,
person_count=payload.person_count,
contact_name=payload.contact_name,
contact_company=payload.contact_company,
contact_email=str(payload.contact_email),
contact_phone=payload.contact_phone,
contact_street=payload.contact_street,
contact_postalcode=payload.contact_postalcode,
contact_city=payload.contact_city,
message=payload.message,
status="pending",
rentman_sync_status="pending",
)
db.add(rental)
await db.flush()
# Fetch equipment info for items
items_data = []
for item in payload.items:
result = await db.execute(select(EquipmentCache).where(EquipmentCache.id == item.equipment_id))
eq = result.scalar_one_or_none()
eq_name = eq.name if eq else "Unknown"
eq_rentman_id = eq.rentman_id if eq else ""
req_item = RentalRequestItem(
rental_request_id=rental.id,
equipment_id=item.equipment_id,
equipment_name=eq_name,
rentman_equipment_id=eq_rentman_id,
quantity=item.quantity,
rentman_sync_status="pending",
)
db.add(req_item)
items_data.append({
"equipment_name": eq_name,
"rentman_equipment_id": eq_rentman_id,
"quantity": item.quantity,
})
await db.commit()
# Forward to Rentman
rentman = RentmanService()
rentman_payload = RentmanService.build_project_request_payload({
"event_name": payload.event_name,
"date_start": str(payload.date_start),
"date_end": str(payload.date_end),
"contact_name": payload.contact_name,
"contact_company": payload.contact_company,
"contact_email": str(payload.contact_email),
"contact_phone": payload.contact_phone,
"contact_street": payload.contact_street,
"contact_postalcode": payload.contact_postalcode,
"contact_city": payload.contact_city,
"location": payload.location,
"message": payload.message,
})
try:
rentman_response = await rentman.create_project_request(rentman_payload)
rentman_request_id = str(rentman_response.get("id", ""))
rental.rentman_request_id = rentman_request_id
rental.rentman_sync_status = "project_created"
# Add equipment items to Rentman
for item_data in items_data:
eq_payload = RentmanService.build_equipment_payload(item_data)
try:
await rentman.add_equipment_to_request(rentman_request_id, eq_payload)
except Exception:
# Item-level failure: mark as failed but continue
pass
rental.rentman_sync_status = "success"
except Exception:
rental.rentman_sync_status = "failed"
rental.rentman_sync_error = "Rentman API request failed"
await db.commit()
# Send confirmation email
email_service = EmailService()
try:
await email_service.send_rental_confirmation(
to_addr=str(payload.contact_email),
reference_number=ref_number,
event_name=payload.event_name,
items=items_data,
db=db,
)
except Exception:
# Email failure should not affect response
pass
return RentalRequestResponse(reference_number=ref_number, status="pending")