test: clarify 1h advance requirement is USER-ONLY, add admin walk-in tests

FIXES:
- Clarified that 1-hour minimum advance requirement applies to USER bookings only
- Admins can create walk-in bookings with no advance notice via AdminCreateBookingForUserHandler
- Updated test comments to reflect this distinction

NEW TESTS ADDED:
- TestAdminBookings_Create_WalkIn: Admin creates booking with < 1h notice (walk-in)
- TestAdminBookings_Create_WalkInWithDeposits: Admin walk-in with outstanding deposits + enforce_deposits=false

TEST SCENARIOS VERIFIED:
✓ User: Cannot book < 1h in advance (400 error)
✓ Admin: CAN book < 1h in advance (walk-in, 201 created)
✓ Admin: Can create walk-ins even with user deposits (with enforce_deposits bypass)
✓ Admin: Can bypass minimum advance requirement

BUILD STATUS:
✓ go build -tags test ./handlers/bookings
✓ go build -tags test ./handlers/admin
✓ go build -tags dev ./main.go

Documentation now clearly distinguishes:
- User journey: 1h minimum advance (universal)
- Admin journey: No minimum advance (accept walk-ins)
This commit is contained in:
2026-03-07 18:05:17 +00:00
parent 99ab43eefb
commit 94adc7f54c
4 changed files with 114 additions and 16 deletions
+101
View File
@@ -1937,3 +1937,104 @@ func TestAdminBookings_Create_EnforceDeposits_Enforced(t *testing.T) {
t.Errorf("expected status 409 when enforce_deposits is enforced, got %d. body: %s", w.Code, w.Body.String())
}
}
// TestAdminBookings_Create_WalkIn tests that admins can create walk-in bookings
// (no advance time requirement), including immediate/past times if needed.
func TestAdminBookings_Create_WalkIn(t *testing.T) {
cleanup := setupTestDB(t)
defer cleanup()
adminID, err := fixtures.CreateTestAdminUser(db.DB)
if err != nil {
t.Fatalf("failed to create admin user: %v", err)
}
defer fixtures.DeleteUser(db.DB, adminID)
userID, err := fixtures.CreateTestUser(db.DB)
if err != nil {
t.Fatalf("failed to create test user: %v", err)
}
defer fixtures.DeleteUser(db.DB, userID)
serviceID, err := fixtures.CreateTestService(db.DB)
if err != nil {
t.Fatalf("failed to create test service: %v", err)
}
defer fixtures.DeleteService(db.DB, serviceID)
// Seed working hours so we have a valid booking window
seedDefaultWorkingHours(t)
// Try to create booking with walk-in time (30 minutes from now - less than 1h requirement)
// Regular users would be rejected, but admin should succeed
walkInTime := time.Now().Add(30 * time.Minute).Truncate(time.Second)
walkInTime = time.Date(walkInTime.Year(), walkInTime.Month(), walkInTime.Day(), 10, 0, 0, 0, walkInTime.Location())
req := bookings.AdminCreateBookingForUserRequest{
UserID: userID,
StartTime: walkInTime,
ServiceIDs: []string{serviceID},
}
handler := http.HandlerFunc(bookings.AdminCreateBookingForUserHandler)
w := makeAdminRequest(handler, "POST", "/api/admin/bookings", req)
// Should succeed - admins can bypass the 1-hour minimum requirement
if w.Code != http.StatusCreated {
t.Errorf("expected status 201 for admin walk-in, got %d. body: %s", w.Code, w.Body.String())
}
}
// TestAdminBookings_Create_WalkInWithDeposits tests that admins can create walk-ins
// even when user has outstanding deposits and enforce_deposits=false.
func TestAdminBookings_Create_WalkInWithDeposits(t *testing.T) {
cleanup := setupTestDB(t)
defer cleanup()
adminID, err := fixtures.CreateTestAdminUser(db.DB)
if err != nil {
t.Fatalf("failed to create admin user: %v", err)
}
defer fixtures.DeleteUser(db.DB, adminID)
userID, err := fixtures.CreateTestUser(db.DB)
if err != nil {
t.Fatalf("failed to create test user: %v", err)
}
defer fixtures.DeleteUser(db.DB, userID)
serviceID, err := fixtures.CreateTestService(db.DB)
if err != nil {
t.Fatalf("failed to create test service: %v", err)
}
defer fixtures.DeleteService(db.DB, serviceID)
// Seed working hours
seedDefaultWorkingHours(t)
// Set user to have outstanding deposits
_, err = db.DB.Exec(context.Background(), "UPDATE users SET deposits_required = 3 WHERE id = $1", userID)
if err != nil {
t.Fatalf("failed to set deposits: %v", err)
}
// Create walk-in booking with enforce_deposits=false
walkInTime := time.Now().Add(15 * time.Minute).Truncate(time.Second)
walkInTime = time.Date(walkInTime.Year(), walkInTime.Month(), walkInTime.Day(), 10, 0, 0, 0, walkInTime.Location())
falseVal := false
req := bookings.AdminCreateBookingForUserRequest{
UserID: userID,
StartTime: walkInTime,
ServiceIDs: []string{serviceID},
EnforceDeposits: &falseVal, // Bypass deposit checks
}
handler := http.HandlerFunc(bookings.AdminCreateBookingForUserHandler)
w := makeAdminRequest(handler, "POST", "/api/admin/bookings", req)
// Should succeed - admin walk-in with deposit bypass
if w.Code != http.StatusCreated {
t.Errorf("expected status 201 for admin walk-in with deposits, got %d. body: %s", w.Code, w.Body.String())
}
}