mirror of
https://github.com/Dvorinka/Bookra.git
synced 2026-10-29 07:54:44 +00:00
feat: series-aware schedule edits + waitlist ledger removal (M32)
PATCH /v1/catalog/class-schedules/:id patches a recurring rule and, with applyToFuture, retimes materialized future sessions to the new local start time on their existing dates — moving confirmed and waitlisted bookings with them and re-arming reminders. Zones-page schedule rows gain an inline editor (CS/EN). Also drops the vestigial waitlist_entries table (migration 00020): positions derive from bookings.created_at, so the ledger was written but never read. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
55fc0d06e3
commit
65a693cf38
17 files changed
+840
-230
No files matched your search
@@ -18,23 +18,23 @@ type DashboardKPI struct {
|
||||
}
|
||||
|
||||
type UpcomingBooking struct {
|
||||
ID string `json:"id"`
|
||||
Reference string `json:"reference"`
|
||||
CustomerName string `json:"customerName"`
|
||||
CustomerEmail string `json:"customerEmail"`
|
||||
Service string `json:"service,omitempty"`
|
||||
Location string `json:"location,omitempty"`
|
||||
StaffName string `json:"staffName,omitempty"`
|
||||
Notes string `json:"notes,omitempty"`
|
||||
Intake map[string]string `json:"intake,omitempty"`
|
||||
ID string `json:"id"`
|
||||
Reference string `json:"reference"`
|
||||
CustomerName string `json:"customerName"`
|
||||
CustomerEmail string `json:"customerEmail"`
|
||||
Service string `json:"service,omitempty"`
|
||||
Location string `json:"location,omitempty"`
|
||||
StaffName string `json:"staffName,omitempty"`
|
||||
Notes string `json:"notes,omitempty"`
|
||||
Intake map[string]string `json:"intake,omitempty"`
|
||||
// IntakeLabels maps Intake keys to the service's declared field labels.
|
||||
IntakeLabels map[string]string `json:"intakeLabels,omitempty"`
|
||||
StartsAt time.Time `json:"startsAt"`
|
||||
EndsAt time.Time `json:"endsAt"`
|
||||
Status string `json:"status"`
|
||||
Label string `json:"label,omitempty"`
|
||||
ClassSessionID *string `json:"classSessionId,omitempty"`
|
||||
WaitlistPosition int `json:"waitlistPosition,omitempty"`
|
||||
StartsAt time.Time `json:"startsAt"`
|
||||
EndsAt time.Time `json:"endsAt"`
|
||||
Status string `json:"status"`
|
||||
Label string `json:"label,omitempty"`
|
||||
ClassSessionID *string `json:"classSessionId,omitempty"`
|
||||
WaitlistPosition int `json:"waitlistPosition,omitempty"`
|
||||
}
|
||||
|
||||
type WidgetSnippet struct {
|
||||
@@ -169,9 +169,9 @@ type CreateBookingRequest struct {
|
||||
Notes string `json:"notes"`
|
||||
// Intake carries structured intake answers keyed by the service's
|
||||
// declared IntakeField keys; only declared keys are stored.
|
||||
Intake map[string]string `json:"intake,omitempty"`
|
||||
StartsAt string `json:"startsAt"`
|
||||
EndsAt string `json:"endsAt"`
|
||||
Intake map[string]string `json:"intake,omitempty"`
|
||||
StartsAt string `json:"startsAt"`
|
||||
EndsAt string `json:"endsAt"`
|
||||
}
|
||||
|
||||
type CreateBookingResponse struct {
|
||||
@@ -334,11 +334,11 @@ type CreateServiceRequest struct {
|
||||
}
|
||||
|
||||
type UpdateServiceRequest struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
DurationMinutes *int `json:"durationMinutes,omitempty"`
|
||||
BufferBeforeMinutes *int `json:"bufferBeforeMinutes,omitempty"`
|
||||
BufferAfterMinutes *int `json:"bufferAfterMinutes,omitempty"`
|
||||
PriceCents *int `json:"priceCents,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
DurationMinutes *int `json:"durationMinutes,omitempty"`
|
||||
BufferBeforeMinutes *int `json:"bufferBeforeMinutes,omitempty"`
|
||||
BufferAfterMinutes *int `json:"bufferAfterMinutes,omitempty"`
|
||||
PriceCents *int `json:"priceCents,omitempty"`
|
||||
IntakeFields *[]IntakeField `json:"intakeFields,omitempty"`
|
||||
}
|
||||
|
||||
@@ -413,16 +413,16 @@ type UpsertClassTemplateRequest struct {
|
||||
}
|
||||
|
||||
type ClassSession struct {
|
||||
ID string `json:"id"`
|
||||
TenantID string `json:"tenantId"`
|
||||
TemplateID string `json:"templateId"`
|
||||
TemplateTitle string `json:"templateTitle"`
|
||||
LocationID *string `json:"locationId,omitempty"`
|
||||
LocationName string `json:"locationName,omitempty"`
|
||||
StartsAt time.Time `json:"startsAt"`
|
||||
EndsAt time.Time `json:"endsAt"`
|
||||
Capacity int `json:"capacity"`
|
||||
BookedCount int `json:"bookedCount"`
|
||||
ID string `json:"id"`
|
||||
TenantID string `json:"tenantId"`
|
||||
TemplateID string `json:"templateId"`
|
||||
TemplateTitle string `json:"templateTitle"`
|
||||
LocationID *string `json:"locationId,omitempty"`
|
||||
LocationName string `json:"locationName,omitempty"`
|
||||
StartsAt time.Time `json:"startsAt"`
|
||||
EndsAt time.Time `json:"endsAt"`
|
||||
Capacity int `json:"capacity"`
|
||||
BookedCount int `json:"bookedCount"`
|
||||
// WaitlistCount is the number of customers queued for a free seat.
|
||||
WaitlistCount int `json:"waitlistCount"`
|
||||
// ScheduleID links the session back to the recurring rule that generated
|
||||
@@ -492,6 +492,19 @@ type CreateClassScheduleRequest struct {
|
||||
StartsLocal string `json:"startsLocal" binding:"required"` // "HH:MM"
|
||||
}
|
||||
|
||||
// UpdateClassScheduleRequest patches a recurring rule; nil fields keep their
|
||||
// current values. A LocationID of "" clears the location. ApplyToFuture
|
||||
// additionally retimes already-materialized future sessions (and their live
|
||||
// bookings) to the new start time and location; a day-of-week change only
|
||||
// affects sessions materialized afterwards.
|
||||
type UpdateClassScheduleRequest struct {
|
||||
DayOfWeek *int `json:"dayOfWeek"`
|
||||
StartsLocal *string `json:"startsLocal"` // "HH:MM"
|
||||
LocationID *string `json:"locationId"`
|
||||
Active *bool `json:"active"`
|
||||
ApplyToFuture bool `json:"applyToFuture"`
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// CUSTOMER MODELS
|
||||
// ============================================
|
||||
@@ -530,25 +543,25 @@ type UpdateCustomerRequest struct {
|
||||
// ============================================
|
||||
|
||||
type CustomerBookingView struct {
|
||||
Reference string `json:"reference"`
|
||||
CustomerName string `json:"customerName"`
|
||||
CustomerEmail string `json:"customerEmail"`
|
||||
Service string `json:"service"`
|
||||
BusinessName string `json:"businessName"`
|
||||
TenantSlug string `json:"tenantSlug,omitempty"`
|
||||
ServiceID *string `json:"serviceId,omitempty"`
|
||||
StaffID *string `json:"staffId,omitempty"`
|
||||
Reference string `json:"reference"`
|
||||
CustomerName string `json:"customerName"`
|
||||
CustomerEmail string `json:"customerEmail"`
|
||||
Service string `json:"service"`
|
||||
BusinessName string `json:"businessName"`
|
||||
TenantSlug string `json:"tenantSlug,omitempty"`
|
||||
ServiceID *string `json:"serviceId,omitempty"`
|
||||
StaffID *string `json:"staffId,omitempty"`
|
||||
// ClassSessionID identifies session-bound bookings; they cannot be
|
||||
// rescheduled to arbitrary times (see RescheduleBooking).
|
||||
ClassSessionID *string `json:"classSessionId,omitempty"`
|
||||
StartsAt time.Time `json:"startsAt"`
|
||||
EndsAt time.Time `json:"endsAt"`
|
||||
Location string `json:"location"`
|
||||
Status string `json:"status"`
|
||||
Notes string `json:"notes,omitempty"`
|
||||
Intake map[string]string `json:"intake,omitempty"`
|
||||
ClassSessionID *string `json:"classSessionId,omitempty"`
|
||||
StartsAt time.Time `json:"startsAt"`
|
||||
EndsAt time.Time `json:"endsAt"`
|
||||
Location string `json:"location"`
|
||||
Status string `json:"status"`
|
||||
Notes string `json:"notes,omitempty"`
|
||||
Intake map[string]string `json:"intake,omitempty"`
|
||||
// IntakeLabels maps Intake keys to the service's declared field labels.
|
||||
IntakeLabels map[string]string `json:"intakeLabels,omitempty"`
|
||||
IntakeLabels map[string]string `json:"intakeLabels,omitempty"`
|
||||
// WaitlistPosition is the 1-based queue spot for waitlisted class
|
||||
// bookings; zero for any other status.
|
||||
WaitlistPosition int `json:"waitlistPosition,omitempty"`
|
||||
|
||||
Reference in new issue
Block a user