feat: Square payment integration, booking flow redesign, and timezone/weekday fixes
- Add Square payment integration (mock + handlers + UI): terminal/online payments, refunds, tips, saved cards, webhooks. Build-tagged dev/prod clients. - Redesign booking flow: Step 4 conditional (deposit only), Step 5 confirmation screen with booking ID, auto-submit on transition. - Redesign schedule modal: 2x3 button grid with Pay Deposit/Pay Early logic. - Add deposit warning banner at Step 1 for users with outstanding deposits. - Fix weekday conversion bug: Go 0=Sunday vs DB 0=Monday mismatch in 6 locations. - Fix timezone bug: UTC vs London time in closing hours validation. - Fix frontend error parsing: plain text backend errors now displayed correctly. - Fix crypto.randomUUID fallback for environments without Web Crypto. - Add 7 new regression tests: closing hours, advance check, active booking limit, weekday conversion, UTC/London, deposit snapshot, exceptional hours. - Fix 3 flaky tests: dynamic dates instead of fixed, no-show timing.
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"crussell/auth"
|
||||
"crussell/internal/dav"
|
||||
"crussell/internal/s3"
|
||||
"crussell/internal/square"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
@@ -24,11 +25,13 @@ import (
|
||||
"crussell/handlers/admin"
|
||||
"crussell/handlers/bookings"
|
||||
"crussell/handlers/notifications"
|
||||
"crussell/handlers/payments"
|
||||
"crussell/handlers/portfolio"
|
||||
"crussell/handlers/scheduling"
|
||||
"crussell/handlers/services"
|
||||
"crussell/handlers/today"
|
||||
"crussell/handlers/user"
|
||||
"crussell/handlers/webhooks"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -61,6 +64,11 @@ func initS3() {
|
||||
}
|
||||
}
|
||||
|
||||
func initSquare() {
|
||||
payments.SquareClient = square.NewClient()
|
||||
fmt.Println("Square client initialized (dev mock)")
|
||||
}
|
||||
|
||||
func healthCheckHandler(w http.ResponseWriter, r *http.Request) {
|
||||
status := "ok"
|
||||
services := map[string]string{
|
||||
@@ -101,6 +109,7 @@ func main() {
|
||||
initDB()
|
||||
initDav()
|
||||
initS3()
|
||||
initSquare()
|
||||
|
||||
r := chi.NewRouter()
|
||||
|
||||
@@ -218,6 +227,13 @@ func main() {
|
||||
r.Delete("/bookings/{id}", bookings.DeleteBookingHandler)
|
||||
r.Post("/bookings/{id}/edit-request", bookings.RequestEditHandler)
|
||||
r.Delete("/bookings/{id}/edit-request", bookings.DeleteEditRequestHandler)
|
||||
|
||||
// User payment routes
|
||||
r.Post("/bookings/{id}/payment", payments.CreateBookingPayment)
|
||||
r.Get("/user/payment-methods", payments.GetUserPaymentMethods)
|
||||
r.Delete("/user/payment-methods/{id}", payments.DeletePaymentMethod)
|
||||
r.Post("/bookings/{id}/tip", payments.CreateTipPayment)
|
||||
r.Get("/bookings/{id}/payment-summary", payments.GetBookingPaymentSummary)
|
||||
})
|
||||
|
||||
// Admin-only (no rate limit - trusted users with authenticated sessions)
|
||||
@@ -283,9 +299,17 @@ r.Route("/admin/users", func(r chi.Router) {
|
||||
r.Delete("/{id}", admin.DeleteDiscountCampaign)
|
||||
r.Get("/{id}/stats", admin.GetCampaignStats)
|
||||
})
|
||||
|
||||
// Admin payment routes
|
||||
r.Post("/admin/bookings/{id}/payment", payments.CreateTerminalPayment)
|
||||
r.Get("/admin/payments/{checkout_id}/status", payments.GetCheckoutStatus)
|
||||
r.Post("/admin/payments/{payment_id}/refund", payments.RefundPayment)
|
||||
})
|
||||
})
|
||||
|
||||
// Webhooks (no auth - Square sends to base path)
|
||||
r.Post("/webhooks/square", webhooks.HandleSquareWebhook)
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: ":8080",
|
||||
Handler: r,
|
||||
|
||||
Reference in New Issue
Block a user