diff --git a/backend/handlers/bookings/bookings.go b/backend/handlers/bookings/bookings.go index 5a1a73b..f6751e7 100644 --- a/backend/handlers/bookings/bookings.go +++ b/backend/handlers/bookings/bookings.go @@ -80,9 +80,15 @@ type ProgressBookingRequest struct { // ConfirmBookingRequest represents the request payload for confirming a booking type ConfirmBookingRequest struct { + ServiceOverrides []ServiceOverride `json:"service_overrides,omitempty"` + Notes *string `json:"notes,omitempty"` +} + +// ServiceOverride represents override values for a specific service in a booking +type ServiceOverride struct { + ServiceID string `json:"service_id" validate:"required"` OverridePrice *float64 `json:"override_price,omitempty"` OverrideDurationMinutes *int `json:"override_duration_minutes,omitempty"` - Notes *string `json:"notes,omitempty"` } // DeleteBookingRequest represents the request payload for deleting a booking with payment @@ -594,13 +600,16 @@ func ConfirmBookingHandler(w http.ResponseWriter, r *http.Request) { return } - if req.OverridePrice != nil && *req.OverridePrice < 0 { - http.Error(w, "Override price cannot be negative", http.StatusBadRequest) - return - } - if req.OverrideDurationMinutes != nil && *req.OverrideDurationMinutes <= 0 { - http.Error(w, "Override duration must be positive", http.StatusBadRequest) - return + // Validate override values + for _, override := range req.ServiceOverrides { + if override.OverridePrice != nil && *override.OverridePrice < 0 { + http.Error(w, "Override price cannot be negative", http.StatusBadRequest) + return + } + if override.OverrideDurationMinutes != nil && *override.OverrideDurationMinutes <= 0 { + http.Error(w, "Override duration must be positive", http.StatusBadRequest) + return + } } tx, err := db.DB.Begin(r.Context()) @@ -640,29 +649,58 @@ func ConfirmBookingHandler(w http.ResponseWriter, r *http.Request) { http.Error(w, "Booking not found or already confirmed", http.StatusNotFound) return } + log.Printf("Failed to confirm booking %s: %v", bookingID, err) http.Error(w, "Internal server error", http.StatusInternalServerError) return } - // Update booking services with overrides if provided - if req.OverridePrice != nil || req.OverrideDurationMinutes != nil { - serviceQuery := ` - UPDATE booking_services - SET override_price = COALESCE($1, override_price), - override_duration_minutes = COALESCE($2, override_duration_minutes) - WHERE booking_id = $3 + // Update service overrides individually + if len(req.ServiceOverrides) > 0 { + // First, verify all service IDs belong to this booking + serviceCheckQuery := ` + SELECT COUNT(*) FROM booking_services + WHERE booking_id = $1 AND service_id = ANY($2) ` - _, err := tx.Exec(r.Context(), - serviceQuery, - req.OverridePrice, - req.OverrideDurationMinutes, - bookingID, - ) + serviceIDs := make([]string, len(req.ServiceOverrides)) + for i, override := range req.ServiceOverrides { + serviceIDs[i] = override.ServiceID + } + + var count int + err = tx.QueryRow(r.Context(), serviceCheckQuery, bookingID, serviceIDs).Scan(&count) if err != nil { - log.Printf("Failed to update service overrides for booking %s: %v", bookingID, err) + log.Printf("Failed to verify services for booking %s: %v", bookingID, err) http.Error(w, "Internal server error", http.StatusInternalServerError) return } + if count != len(req.ServiceOverrides) { + http.Error(w, "One or more service IDs do not belong to this booking", http.StatusBadRequest) + return + } + + // Update each service override + serviceUpdateQuery := ` + UPDATE booking_services + SET override_price = $1, + override_duration_minutes = $2 + WHERE booking_id = $3 AND service_id = $4 + ` + + for _, override := range req.ServiceOverrides { + _, err := tx.Exec(r.Context(), + serviceUpdateQuery, + override.OverridePrice, + override.OverrideDurationMinutes, + bookingID, + override.ServiceID, + ) + if err != nil { + log.Printf("Failed to update service override for booking %s, service %s: %v", + bookingID, override.ServiceID, err) + http.Error(w, "Internal server error", http.StatusInternalServerError) + return + } + } } if err := tx.Commit(r.Context()); err != nil {