feat(bookings): support out_of_hours flag in admin create booking
Add OutOfHours field to AdminCreateBookingForUserRequest. When true, skip exceptional hours closed check and include out_of_hours in INSERT. Add tests verifying: bypass of exceptional closure, rejection without flag, overlap detection still works, and time blocker warning. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -353,6 +353,7 @@ type AdminCreateBookingForUserRequest struct {
|
||||
CustomOverrides []ServiceOverride `json:"custom_service_overrides,omitempty"`
|
||||
Notes *string `json:"notes,omitempty" validate:"omitempty,max=1000000"`
|
||||
EnforceDeposits *bool `json:"enforce_deposits,omitempty"`
|
||||
OutOfHours bool `json:"out_of_hours"`
|
||||
}
|
||||
|
||||
func AdminCreateBookingForUserHandler(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -613,29 +614,31 @@ func AdminCreateBookingForUserHandler(w http.ResponseWriter, r *http.Request) {
|
||||
weekStart := req.StartTime.AddDate(0, 0, -daysToMonday+1).Truncate(24 * time.Hour)
|
||||
bookingTime := req.StartTime.Format("15:04:05")
|
||||
|
||||
// Check if there's an exceptional hours entry that makes this time unavailable
|
||||
var isClosed bool
|
||||
var checkErr error
|
||||
checkErr = db.Conn.QueryRow(r.Context(), `
|
||||
SELECT EXISTS (
|
||||
SELECT 1 FROM exceptional_working_hours ewh
|
||||
JOIN exceptional_group_applications ega ON ewh.group_id = ega.group_id
|
||||
WHERE ega.week_start = $1
|
||||
AND ewh.weekday = $2
|
||||
AND ewh.is_open = false
|
||||
AND ewh.start_time <= $3
|
||||
AND ewh.end_time >= $3
|
||||
)
|
||||
`, weekStart, weekday, bookingTime).Scan(&isClosed)
|
||||
if checkErr != nil {
|
||||
log.Printf("Failed to check exceptional hours: %v", checkErr)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if !req.OutOfHours {
|
||||
// Check if there's an exceptional hours entry that makes this time unavailable
|
||||
var isClosed bool
|
||||
var checkErr error
|
||||
checkErr = db.Conn.QueryRow(r.Context(), `
|
||||
SELECT EXISTS (
|
||||
SELECT 1 FROM exceptional_working_hours ewh
|
||||
JOIN exceptional_group_applications ega ON ewh.group_id = ega.group_id
|
||||
WHERE ega.week_start = $1
|
||||
AND ewh.weekday = $2
|
||||
AND ewh.is_open = false
|
||||
AND ewh.start_time <= $3
|
||||
AND ewh.end_time >= $3
|
||||
)
|
||||
`, weekStart, weekday, bookingTime).Scan(&isClosed)
|
||||
if checkErr != nil {
|
||||
log.Printf("Failed to check exceptional hours: %v", checkErr)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if isClosed {
|
||||
http.Error(w, "Cannot book during holiday hours when the salon is closed", http.StatusConflict)
|
||||
return
|
||||
if isClosed {
|
||||
http.Error(w, "Cannot book during holiday hours when the salon is closed", http.StatusConflict)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Check for overlapping confirmed/in_progress/completed bookings
|
||||
@@ -698,10 +701,11 @@ func AdminCreateBookingForUserHandler(w http.ResponseWriter, r *http.Request) {
|
||||
status,
|
||||
notes,
|
||||
created_by,
|
||||
idempotency_key
|
||||
idempotency_key,
|
||||
out_of_hours
|
||||
)
|
||||
VALUES ($1, $2, 'confirmed', $3, $4, $5)
|
||||
RETURNING id, user_id, start_time, status, notes, created_at, updated_at, created_by
|
||||
VALUES ($1, $2, 'confirmed', $3, $4, $5, $6)
|
||||
RETURNING id, user_id, start_time, status, notes, created_at, updated_at, created_by, out_of_hours
|
||||
`
|
||||
|
||||
var booking Booking
|
||||
@@ -715,6 +719,7 @@ func AdminCreateBookingForUserHandler(w http.ResponseWriter, r *http.Request) {
|
||||
req.Notes,
|
||||
adminID,
|
||||
sql.NullString{String: idempotencyKey, Valid: idempotencyKey != ""},
|
||||
req.OutOfHours,
|
||||
).Scan(
|
||||
&booking.ID,
|
||||
&booking.User.ID,
|
||||
@@ -724,6 +729,7 @@ func AdminCreateBookingForUserHandler(w http.ResponseWriter, r *http.Request) {
|
||||
&booking.CreatedAt,
|
||||
&booking.UpdatedAt,
|
||||
&booking.CreatedBy,
|
||||
&booking.OutOfHours,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user