updates
This commit is contained in:
@@ -21,22 +21,18 @@ from ..config.settings import settings
|
||||
|
||||
router = APIRouter(prefix="/service-bookings", tags=["service-bookings"])
|
||||
|
||||
|
||||
def generate_service_booking_number() -> str:
|
||||
"""Generate unique service booking number"""
|
||||
prefix = "SB"
|
||||
timestamp = datetime.utcnow().strftime("%Y%m%d")
|
||||
random_suffix = random.randint(1000, 9999)
|
||||
return f"{prefix}{timestamp}{random_suffix}"
|
||||
|
||||
|
||||
@router.post("/")
|
||||
async def create_service_booking(
|
||||
booking_data: dict,
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Create a new service booking"""
|
||||
try:
|
||||
services = booking_data.get("services", [])
|
||||
total_amount = float(booking_data.get("total_amount", 0))
|
||||
@@ -48,7 +44,7 @@ async def create_service_booking(
|
||||
if total_amount <= 0:
|
||||
raise HTTPException(status_code=400, detail="Total amount must be greater than 0")
|
||||
|
||||
# Validate services and calculate total
|
||||
|
||||
calculated_total = 0
|
||||
service_items_data = []
|
||||
|
||||
@@ -59,7 +55,7 @@ async def create_service_booking(
|
||||
if not service_id:
|
||||
raise HTTPException(status_code=400, detail="Service ID is required for each item")
|
||||
|
||||
# Check if service exists and is active
|
||||
|
||||
service = db.query(Service).filter(Service.id == service_id).first()
|
||||
if not service:
|
||||
raise HTTPException(status_code=404, detail=f"Service with ID {service_id} not found")
|
||||
@@ -78,17 +74,17 @@ async def create_service_booking(
|
||||
"total_price": item_total
|
||||
})
|
||||
|
||||
# Verify calculated total matches provided total (with small tolerance for floating point)
|
||||
|
||||
if abs(calculated_total - total_amount) > 0.01:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Total amount mismatch. Calculated: {calculated_total}, Provided: {total_amount}"
|
||||
)
|
||||
|
||||
# Generate booking number
|
||||
|
||||
booking_number = generate_service_booking_number()
|
||||
|
||||
# Create service booking
|
||||
|
||||
service_booking = ServiceBooking(
|
||||
booking_number=booking_number,
|
||||
user_id=current_user.id,
|
||||
@@ -98,9 +94,9 @@ async def create_service_booking(
|
||||
)
|
||||
|
||||
db.add(service_booking)
|
||||
db.flush() # Flush to get the ID
|
||||
db.flush()
|
||||
|
||||
# Create service booking items
|
||||
|
||||
for item_data in service_items_data:
|
||||
booking_item = ServiceBookingItem(
|
||||
service_booking_id=service_booking.id,
|
||||
@@ -114,12 +110,12 @@ async def create_service_booking(
|
||||
db.commit()
|
||||
db.refresh(service_booking)
|
||||
|
||||
# Load relationships
|
||||
|
||||
service_booking = db.query(ServiceBooking).options(
|
||||
joinedload(ServiceBooking.service_items).joinedload(ServiceBookingItem.service)
|
||||
).filter(ServiceBooking.id == service_booking.id).first()
|
||||
|
||||
# Format response
|
||||
|
||||
booking_dict = {
|
||||
"id": service_booking.id,
|
||||
"booking_number": service_booking.booking_number,
|
||||
@@ -157,13 +153,11 @@ async def create_service_booking(
|
||||
db.rollback()
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.get("/me")
|
||||
async def get_my_service_bookings(
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get all service bookings for current user"""
|
||||
try:
|
||||
bookings = db.query(ServiceBooking).options(
|
||||
joinedload(ServiceBooking.service_items).joinedload(ServiceBookingItem.service)
|
||||
@@ -204,14 +198,12 @@ async def get_my_service_bookings(
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.get("/{id}")
|
||||
async def get_service_booking_by_id(
|
||||
id: int,
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get service booking by ID"""
|
||||
try:
|
||||
booking = db.query(ServiceBooking).options(
|
||||
joinedload(ServiceBooking.service_items).joinedload(ServiceBookingItem.service)
|
||||
@@ -220,7 +212,7 @@ async def get_service_booking_by_id(
|
||||
if not booking:
|
||||
raise HTTPException(status_code=404, detail="Service booking not found")
|
||||
|
||||
# Check access
|
||||
|
||||
if booking.user_id != current_user.id and current_user.role_id != 1:
|
||||
raise HTTPException(status_code=403, detail="Forbidden")
|
||||
|
||||
@@ -259,7 +251,6 @@ async def get_service_booking_by_id(
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/{id}/payment/stripe/create-intent")
|
||||
async def create_service_stripe_payment_intent(
|
||||
id: int,
|
||||
@@ -267,9 +258,8 @@ async def create_service_stripe_payment_intent(
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Create Stripe payment intent for service booking"""
|
||||
try:
|
||||
# Check if Stripe is configured
|
||||
|
||||
secret_key = get_stripe_secret_key(db)
|
||||
if not secret_key:
|
||||
secret_key = settings.STRIPE_SECRET_KEY
|
||||
@@ -286,7 +276,7 @@ async def create_service_stripe_payment_intent(
|
||||
if amount <= 0:
|
||||
raise HTTPException(status_code=400, detail="Amount must be greater than 0")
|
||||
|
||||
# Verify service booking exists and user has access
|
||||
|
||||
booking = db.query(ServiceBooking).filter(ServiceBooking.id == id).first()
|
||||
if not booking:
|
||||
raise HTTPException(status_code=404, detail="Service booking not found")
|
||||
@@ -294,22 +284,22 @@ async def create_service_stripe_payment_intent(
|
||||
if booking.user_id != current_user.id and current_user.role_id != 1:
|
||||
raise HTTPException(status_code=403, detail="Forbidden")
|
||||
|
||||
# Verify amount matches booking total
|
||||
|
||||
if abs(float(booking.total_amount) - amount) > 0.01:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Amount mismatch. Booking total: {booking.total_amount}, Provided: {amount}"
|
||||
)
|
||||
|
||||
# Create payment intent
|
||||
|
||||
intent = StripeService.create_payment_intent(
|
||||
amount=amount,
|
||||
currency=currency,
|
||||
description=f"Service Booking #{booking.booking_number}",
|
||||
description=f"Service Booking
|
||||
db=db
|
||||
)
|
||||
|
||||
# Get publishable key
|
||||
|
||||
publishable_key = get_stripe_publishable_key(db)
|
||||
if not publishable_key:
|
||||
publishable_key = settings.STRIPE_PUBLISHABLE_KEY
|
||||
@@ -333,7 +323,6 @@ async def create_service_stripe_payment_intent(
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/{id}/payment/stripe/confirm")
|
||||
async def confirm_service_stripe_payment(
|
||||
id: int,
|
||||
@@ -341,14 +330,13 @@ async def confirm_service_stripe_payment(
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Confirm Stripe payment for service booking"""
|
||||
try:
|
||||
payment_intent_id = payment_data.get("payment_intent_id")
|
||||
|
||||
if not payment_intent_id:
|
||||
raise HTTPException(status_code=400, detail="payment_intent_id is required")
|
||||
|
||||
# Verify service booking exists and user has access
|
||||
|
||||
booking = db.query(ServiceBooking).filter(ServiceBooking.id == id).first()
|
||||
if not booking:
|
||||
raise HTTPException(status_code=404, detail="Service booking not found")
|
||||
@@ -356,7 +344,7 @@ async def confirm_service_stripe_payment(
|
||||
if booking.user_id != current_user.id and current_user.role_id != 1:
|
||||
raise HTTPException(status_code=403, detail="Forbidden")
|
||||
|
||||
# Retrieve and verify payment intent
|
||||
|
||||
intent_data = StripeService.retrieve_payment_intent(payment_intent_id, db)
|
||||
|
||||
if intent_data["status"] != "succeeded":
|
||||
@@ -365,15 +353,15 @@ async def confirm_service_stripe_payment(
|
||||
detail=f"Payment intent status is {intent_data['status']}, expected 'succeeded'"
|
||||
)
|
||||
|
||||
# Verify amount matches
|
||||
amount_paid = intent_data["amount"] / 100 # Convert from cents
|
||||
|
||||
amount_paid = intent_data["amount"] / 100
|
||||
if abs(float(booking.total_amount) - amount_paid) > 0.01:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Payment amount does not match booking total"
|
||||
)
|
||||
|
||||
# Create payment record
|
||||
|
||||
payment = ServicePayment(
|
||||
service_booking_id=booking.id,
|
||||
amount=booking.total_amount,
|
||||
@@ -386,7 +374,7 @@ async def confirm_service_stripe_payment(
|
||||
|
||||
db.add(payment)
|
||||
|
||||
# Update booking status
|
||||
|
||||
booking.status = ServiceBookingStatus.confirmed
|
||||
|
||||
db.commit()
|
||||
|
||||
Reference in New Issue
Block a user