diff --git a/backend/handlers/bookings/admin_reserve.go b/backend/handlers/bookings/admin_reserve.go index 8028954..ff2c82c 100644 --- a/backend/handlers/bookings/admin_reserve.go +++ b/backend/handlers/bookings/admin_reserve.go @@ -130,7 +130,7 @@ func AdminReserveSlotHandler(w http.ResponseWriter, r *http.Request) { var cnt int db.DB.QueryRow(r.Context(), ` - SELECT COUNT(*) FROM bookings WHERE status IN ('confirmed','in_progress','completed') + SELECT COUNT(*) FROM bookings WHERE status IN ('pending','confirmed','in_progress','completed') AND start_time < $2 AND start_time + (INTERVAL '1 minute' * ( SELECT COALESCE(SUM(dur),60) FROM ( @@ -147,15 +147,23 @@ func AdminReserveSlotHandler(w http.ResponseWriter, r *http.Request) { return } - blockerOverlap, blockerDesc, err := scheduling.CheckTimeBlockerOverlap(r.Context(), req.StartTime, endTime) + blockerOverlap, _, err := scheduling.CheckTimeBlockerOverlap(r.Context(), req.StartTime, endTime) if err != nil { log.Printf("Failed to check time blocker overlap: %v", err) } else if blockerOverlap { - http.Error(w, fmt.Sprintf("Cannot book this time - slot is blocked: %s", blockerDesc), http.StatusConflict) + http.Error(w, "Cannot book this time - slot is blocked", http.StatusConflict) return } - _, err = db.DB.Exec(r.Context(), ` + tx, err := db.DB.Begin(r.Context()) + if err != nil { + log.Printf("Failed to start transaction: %v", err) + http.Error(w, "Internal server error", http.StatusInternalServerError) + return + } + defer tx.Rollback(r.Context()) + + _, err = tx.Exec(r.Context(), ` DELETE FROM time_blockers WHERE description LIKE 'RESERVATION:admin:%' AND created_by = $1 @@ -174,7 +182,7 @@ func AdminReserveSlotHandler(w http.ResponseWriter, r *http.Request) { description := fmt.Sprintf("RESERVATION:admin:%s:%s:%d", req.ReservationType, customerID, time.Now().UnixNano()) var reservationID string var createdAt time.Time - err = db.DB.QueryRow(r.Context(), ` + err = tx.QueryRow(r.Context(), ` INSERT INTO time_blockers (start_time, duration_minutes, description, created_by) VALUES ($1, $2, $3, $4) RETURNING id, created_at @@ -185,6 +193,12 @@ func AdminReserveSlotHandler(w http.ResponseWriter, r *http.Request) { return } + if err := tx.Commit(r.Context()); err != nil { + log.Printf("Failed to commit transaction: %v", err) + http.Error(w, "Internal server error", http.StatusInternalServerError) + return + } + expiresAt := createdAt.Add(time.Duration(req.TTLMinutes) * time.Minute) response := AdminReserveSlotResponse{ diff --git a/backend/handlers/bookings/admin_reserve_test.go b/backend/handlers/bookings/admin_reserve_test.go index 8d83b83..878b4cb 100644 --- a/backend/handlers/bookings/admin_reserve_test.go +++ b/backend/handlers/bookings/admin_reserve_test.go @@ -1,5 +1,5 @@ -//go:build test -// +build test +//go:build test && dev +// +build test,dev package bookings