Skip to content

Commit 8cd5ffe

Browse files
feat: added unique confirm booking migration
1 parent b22c5a6 commit 8cd5ffe

File tree

5 files changed

+34
-16
lines changed

5 files changed

+34
-16
lines changed

cmd/api/booking.go

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"time"
1414

1515
"github.com/go-chi/chi/v5"
16+
"github.com/jackc/pgx/v5/pgconn"
1617
)
1718

1819
// AvailableTimeSlot represents a free time interval for booking.
@@ -58,7 +59,6 @@ func (app *application) availableTimesHandler(w http.ResponseWriter, r *http.Req
5859
app.badRequestResponse(w, r, fmt.Errorf("missing date"))
5960
return
6061
}
61-
fmt.Printf("⏰ dateStr: %s\n", dateStr)
6262

6363
// Set the target timezone to Asia/Kathmandu
6464
loc, err := time.LoadLocation("Asia/Kathmandu")
@@ -75,12 +75,9 @@ func (app *application) availableTimesHandler(w http.ResponseWriter, r *http.Req
7575
return
7676
}
7777

78-
fmt.Printf("⏰ date after Parse: %s\n", date)
79-
8078
dateInKtm := date.In(loc)
81-
fmt.Printf("⏰ date in Ktm: %s\n", dateInKtm)
79+
8280
dayOfWeek := strings.ToLower(dateInKtm.Weekday().String())
83-
fmt.Printf("⏰day of week in ktm: %s\n", dayOfWeek)
8481

8582
// Step 3: Load pricing slots and bookings for the venue and the selected date
8683
pricingSlots, err := app.store.Bookings.GetPricingSlots(r.Context(), venueID, dayOfWeek)
@@ -113,11 +110,6 @@ func (app *application) availableTimesHandler(w http.ResponseWriter, r *http.Req
113110

114111
pricingSlots = filtered
115112

116-
fmt.Println("📊 Pricing slots:")
117-
for _, ps := range pricingSlots {
118-
fmt.Printf("- %s to %s at %d\n", ps.StartTime.Format("15:04"), ps.EndTime.Format("15:04"), ps.Price)
119-
}
120-
121113
bookings, err := app.store.Bookings.GetBookingsForDate(r.Context(), venueID, date)
122114
if err != nil {
123115
app.internalServerError(w, r, err)
@@ -232,7 +224,14 @@ func (app *application) bookVenueHandler(w http.ResponseWriter, r *http.Request)
232224

233225
// Determine the day and fetch pricing slots for that day.
234226
localStart := payload.StartTime.In(loc)
227+
235228
dayOfWeek := strings.ToLower(localStart.Weekday().String())
229+
230+
//sample data
231+
//start_time 🎯: 2025-07-02 08:00:00 +0545 +0545
232+
//end_time 🎯: 2025-07-02 09:00:00 +0545 +0545
233+
//localStart 🎯: 2025-07-02 08:00:00 +0545 +0545
234+
//dayOfWeek 🎯: wednesday
236235
pricingSlots, err := app.store.Bookings.GetPricingSlots(r.Context(), venueID, dayOfWeek)
237236
if err != nil || len(pricingSlots) == 0 {
238237
http.Error(w, "No pricing available for this day", http.StatusBadRequest)
@@ -576,12 +575,17 @@ func (app *application) getScheduledBookingsHandler(w http.ResponseWriter, r *ht
576575
return
577576
}
578577

579-
date, err := time.Parse("2006-01-02", dateStr)
578+
loc, _ := time.LoadLocation("Asia/Kathmandu")
579+
580+
// Parse date string in Kathmandu local time
581+
date, err := time.ParseInLocation("2006-01-02", dateStr, loc)
580582
if err != nil {
581583
app.badRequestResponse(w, r, fmt.Errorf("invalid date format: %w", err))
582584
return
583585
}
584586

587+
//date will be Parsed time is: 2025-06-29 00:00:00 +0545 +0545
588+
585589
// 3) fetch from store
586590
bookings, err := app.store.Bookings.GetScheduledBookingsForVenueDate(r.Context(), vid, date)
587591
if err != nil {
@@ -623,10 +627,17 @@ func (app *application) acceptBookingHandler(w http.ResponseWriter, r *http.Requ
623627
if err := app.store.Bookings.AcceptBooking(r.Context(), vid, bid); err != nil {
624628
if err == sql.ErrNoRows {
625629
app.notFoundResponse(w, r, errors.New("not found"))
630+
return
631+
}
632+
633+
var pgErr *pgconn.PgError
634+
if errors.As(err, &pgErr) && pgErr.Code == "23505" && pgErr.ConstraintName == "unique_confirmed_bookings_per_venue_time" {
635+
app.conflictResponse(w, r, errors.New("booking with this time already exists"))
636+
return
626637
} else {
627638
app.internalServerError(w, r, err)
639+
return
628640
}
629-
return
630641
}
631642

632643
w.WriteHeader(http.StatusNoContent)

cmd/api/middleware.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,6 @@ func (app *application) AuthTokenMiddleware(next http.Handler) http.Handler {
9292
return
9393
}
9494

95-
fmt.Println("AuthTokenMiddleware running .....🔐🔐")
96-
9795
ctx = context.WithValue(ctx, userCtx, user)
9896
next.ServeHTTP(w, r.WithContext(ctx))
9997
})
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- Remove the unique index for confirmed bookings
2+
DROP INDEX IF EXISTS unique_confirmed_bookings_per_venue_time;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-- Add unique index to prevent duplicate confirmed bookings for the same venue and time
2+
CREATE UNIQUE INDEX IF NOT EXISTS unique_confirmed_bookings_per_venue_time
3+
ON bookings (venue_id, start_time, end_time)
4+
WHERE status = 'confirmed';
5+
6+
7+
-- 👉 No two bookings can have the same venue_id, start_time, and end_time if they are both 'confirmed'.

internal/store/bookings.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,8 @@ func (s *BookingStore) GetPendingBookingsForVenueDate(ctx context.Context, venue
298298

299299
func (s *BookingStore) GetScheduledBookingsForVenueDate(ctx context.Context, venueID int64, date time.Time) ([]ScheduledBooking, error) {
300300
// normalize to date only
301-
startOfDay := time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, date.Location())
302-
endOfDay := startOfDay.Add(24 * time.Hour)
301+
startOfDay := date.In(time.UTC)
302+
endOfDay := date.Add(24 * time.Hour).In(time.UTC)
303303

304304
const q = `
305305
SELECT

0 commit comments

Comments
 (0)