fix: correct global milestone discount indentation (C1)
CI / Env docs check (push) Successful in 20s
CI / Docker compose check (push) Successful in 23s
CI / Nginx config check (push) Successful in 24s
CI / Frontend major deps (push) Successful in 35s
CI / Frontend deps check (push) Successful in 36s
CI / Secrets scan (push) Successful in 48s
CI / Go build (push) Successful in 45s
CI / Frontend build (push) Successful in 47s
CI / Knip (push) Successful in 55s
CI / Go vet (prod) (push) Successful in 1m39s
CI / Frontend a11y check (push) Successful in 2m7s
CI / Go vet (dev) (push) Successful in 2m6s
CI / go mod tidy (push) Successful in 32s
CI / golangci-lint (push) Has been cancelled
CI / Staticcheck (dev) (push) Has been cancelled
CI / Staticcheck (prod) (push) Has been cancelled
CI / Security scan (dev) (push) Has been cancelled
CI / Security scan (prod) (push) Has been cancelled
CI / Tests (prod) (push) Has been cancelled
CI / Tests (dev) (push) Has been cancelled
CI / Race (prod) (push) Has been cancelled
CI / Race (dev) (push) Has been cancelled
CI / Go vulnerabilities (push) Has been cancelled
CI / Svelte strict check (push) Has been cancelled
CI / Frontend QC (audit) (push) Has been cancelled
CI / Frontend QC (typecheck) (push) Has been cancelled
CI / Frontend QC (lint) (push) Has been cancelled

This commit is contained in:
2026-07-11 17:42:17 +01:00
parent 8ae592d0c5
commit 0edc111bfe
+60 -60
View File
@@ -1450,10 +1450,10 @@ func UpdateBookingServicesHandler(w http.ResponseWriter, r *http.Request) {
return
}
defer func() {
if err := tx.Rollback(r.Context()); err != nil && err.Error() != "tx is closed" {
slog.Error("failed to rollback transaction", "err", err)
}
}()
if err := tx.Rollback(r.Context()); err != nil && err.Error() != "tx is closed" {
slog.Error("failed to rollback transaction", "err", err)
}
}()
// Evict any pending_release bookings that overlap this slot.
if _, evictErr := EvictPendingReleaseOverlapping(r.Context(), tx, startTime, newEndTime); evictErr != nil {
@@ -1999,7 +1999,7 @@ func CreateBookingHandler(w http.ResponseWriter, r *http.Request) {
// Get payment info
var preStartPaid float64
if err := db.Conn.QueryRow(r.Context(), `SELECT COALESCE(SUM(amount), 0) FROM payments WHERE booking_id = $1 AND payment_type IN ('deposit', 'full') AND status = 'completed'`, existingBooking.ID).Scan(&preStartPaid); err != nil {
if err := db.Conn.QueryRow(r.Context(), `SELECT COALESCE(SUM(amount), 0) FROM payments WHERE booking_id = $1 AND payment_type IN ('deposit', 'full') AND status = 'completed'`, existingBooking.ID).Scan(&preStartPaid); err != nil {
log.Printf("Failed to scan preStartPaid for booking %s: %v", existingBooking.ID, err)
}
populateDepositFields(&existingBooking, existingBooking.DepositRequired, preStartPaid)
@@ -2233,10 +2233,10 @@ if err := db.Conn.QueryRow(r.Context(), `SELECT COALESCE(SUM(amount), 0) FROM pa
return
}
defer func() {
if err := tx.Rollback(r.Context()); err != nil && err.Error() != "tx is closed" {
slog.Error("failed to rollback transaction", "err", err)
}
}()
if err := tx.Rollback(r.Context()); err != nil && err.Error() != "tx is closed" {
slog.Error("failed to rollback transaction", "err", err)
}
}()
// Evict any pending_release bookings that overlap this slot.
if _, err := EvictPendingReleaseOverlapping(r.Context(), tx, req.StartTime, endTime); err != nil {
@@ -2444,10 +2444,10 @@ func EditBookingHandler(w http.ResponseWriter, r *http.Request) {
return
}
defer func() {
if err := tx.Rollback(r.Context()); err != nil && err.Error() != "tx is closed" {
slog.Error("failed to rollback transaction", "err", err)
}
}()
if err := tx.Rollback(r.Context()); err != nil && err.Error() != "tx is closed" {
slog.Error("failed to rollback transaction", "err", err)
}
}()
var durationMinutes int
if err := tx.QueryRow(r.Context(), `
@@ -2603,10 +2603,10 @@ func ProgressBookingHandler(w http.ResponseWriter, r *http.Request) {
return
}
defer func() {
if err := tx.Rollback(r.Context()); err != nil && err.Error() != "tx is closed" {
slog.Error("failed to rollback transaction", "err", err)
}
}()
if err := tx.Rollback(r.Context()); err != nil && err.Error() != "tx is closed" {
slog.Error("failed to rollback transaction", "err", err)
}
}()
// Read current status before updating to validate the transition
var currentStatus string
@@ -2826,42 +2826,42 @@ func ProgressBookingHandler(w http.ResponseWriter, r *http.Request) {
log.Printf("Failed to scan global completed booking count: %v", err)
}
var hasInPersonPayment bool
if err := tx.QueryRow(r.Context(), `
SELECT EXISTS(SELECT 1 FROM payments WHERE booking_id = $1 AND payment_method = 'in_person_card')`, bookingID).Scan(&hasInPersonPayment); err != nil {
log.Printf("Failed to check in-person payment on booking %s: %v", bookingID, err)
}
if hasInPersonPayment {
var globalCampaignID string
var globalPercent float64
var hasInPersonPayment bool
if err := tx.QueryRow(r.Context(), `
SELECT id, discount_percent FROM discount_campaigns
WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'global_booking_count'
AND milestone_value <= $1
AND (max_redemptions IS NULL OR times_redeemed < max_redemptions)
ORDER BY milestone_value DESC LIMIT 1
`, globalCount).Scan(&globalCampaignID, &globalPercent); err != nil {
log.Printf("Failed to query global milestone campaign for booking %s: %v", bookingID, err)
SELECT EXISTS(SELECT 1 FROM payments WHERE booking_id = $1 AND payment_method = 'in_person_card')`, bookingID).Scan(&hasInPersonPayment); err != nil {
log.Printf("Failed to check in-person payment on booking %s: %v", bookingID, err)
}
if globalCampaignID != "" {
if hasInPersonPayment {
var globalCampaignID string
var globalPercent float64
if err := tx.QueryRow(r.Context(), `
SELECT id, discount_percent FROM discount_campaigns
WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'global_booking_count'
AND milestone_value <= $1
AND (max_redemptions IS NULL OR times_redeemed < max_redemptions)
ORDER BY milestone_value DESC LIMIT 1
`, globalCount).Scan(&globalCampaignID, &globalPercent); err != nil {
log.Printf("Failed to query global milestone campaign for booking %s: %v", bookingID, err)
}
if globalCampaignID != "" {
discountAmount := roundTo2(bookingTotal * globalPercent / 100)
if _, err := tx.Exec(r.Context(), `
INSERT INTO booking_discounts (booking_id, user_id, discount_source, source_id, campaign_type, milestone_type, discount_percent, original_total, discount_amount)
VALUES ($1, $2, 'campaign', $3, 'milestone', 'global_booking_count', $4, $5, $6)
`, bookingID, booking.User.ID, globalCampaignID, globalPercent, bookingTotal, discountAmount); err != nil {
INSERT INTO booking_discounts (booking_id, user_id, discount_source, source_id, campaign_type, milestone_type, discount_percent, original_total, discount_amount)
VALUES ($1, $2, 'campaign', $3, 'milestone', 'global_booking_count', $4, $5, $6)
`, bookingID, booking.User.ID, globalCampaignID, globalPercent, bookingTotal, discountAmount); err != nil {
log.Printf("ALERT: failed to insert booking discount: %v", err)
}
if _, err := tx.Exec(r.Context(), `
INSERT INTO payments (booking_id, payment_type, payment_method, amount, status, created_by)
VALUES ($1, 'partial', 'discount', $2, 'completed', $3)
`, bookingID, discountAmount, booking.User.ID); err != nil {
INSERT INTO payments (booking_id, payment_type, payment_method, amount, status, created_by)
VALUES ($1, 'partial', 'discount', $2, 'completed', $3)
`, bookingID, discountAmount, booking.User.ID); err != nil {
log.Printf("ALERT: failed to insert payment record: %v", err)
}
if _, err := tx.Exec(r.Context(), `
UPDATE discount_campaigns SET times_redeemed = times_redeemed + 1 WHERE id = $1
`, globalCampaignID); err != nil {
UPDATE discount_campaigns SET times_redeemed = times_redeemed + 1 WHERE id = $1
`, globalCampaignID); err != nil {
log.Printf("ALERT: failed to insert payment record: %v", err)
}
}
@@ -3032,10 +3032,10 @@ func ConfirmBookingHandler(w http.ResponseWriter, r *http.Request) {
return
}
defer func() {
if err := tx.Rollback(r.Context()); err != nil && err.Error() != "tx is closed" {
slog.Error("failed to rollback transaction", "err", err)
}
}()
if err := tx.Rollback(r.Context()); err != nil && err.Error() != "tx is closed" {
slog.Error("failed to rollback transaction", "err", err)
}
}()
var bkStart time.Time
var dur int
@@ -3167,7 +3167,7 @@ func ConfirmBookingHandler(w http.ResponseWriter, r *http.Request) {
if dav.Service != nil {
var durationMinutes int
if err := db.Conn.QueryRow(r.Context(), `
if err := db.Conn.QueryRow(r.Context(), `
SELECT total_duration_minutes FROM bookings WHERE id = $1
`, bookingID).Scan(&durationMinutes); err != nil {
log.Printf("ALERT: failed to scan total_duration_minutes for booking %s: %v", bookingID, err)
@@ -3218,7 +3218,7 @@ func DeleteBookingHandler(w http.ResponseWriter, r *http.Request) {
}
if err := validators.Validate.Struct(&req); err != nil {
log.Printf("Failed to process request: %v", err)
http.Error(w, "Invalid request", http.StatusBadRequest)
http.Error(w, "Invalid request", http.StatusBadRequest)
return
}
allowed := map[string]bool{
@@ -3271,10 +3271,10 @@ func DeleteBookingHandler(w http.ResponseWriter, r *http.Request) {
return
}
defer func() {
if err := tx.Rollback(r.Context()); err != nil && err.Error() != "tx is closed" {
slog.Error("failed to rollback transaction", "err", err)
}
}()
if err := tx.Rollback(r.Context()); err != nil && err.Error() != "tx is closed" {
slog.Error("failed to rollback transaction", "err", err)
}
}()
result, err := tx.Exec(r.Context(), `
UPDATE bookings SET status = $1, updated_at = NOW() WHERE id = $2 AND user_id = $3
@@ -3362,10 +3362,10 @@ func DeleteBookingHandler(w http.ResponseWriter, r *http.Request) {
return
}
defer func() {
if err := tx.Rollback(r.Context()); err != nil && err.Error() != "tx is closed" {
slog.Error("failed to rollback transaction", "err", err)
}
}()
if err := tx.Rollback(r.Context()); err != nil && err.Error() != "tx is closed" {
slog.Error("failed to rollback transaction", "err", err)
}
}()
if _, err := tx.Exec(r.Context(), `DELETE FROM admin_notifications WHERE booking_id = $1`, bookingID); err != nil {
log.Printf("Failed to delete admin notifications for booking %s: %v", bookingID, err)
@@ -4201,10 +4201,10 @@ func AdminRescheduleBookingHandler(w http.ResponseWriter, r *http.Request) {
return
}
defer func() {
if err := tx.Rollback(r.Context()); err != nil && err.Error() != "tx is closed" {
slog.Error("failed to rollback transaction", "err", err)
}
}()
if err := tx.Rollback(r.Context()); err != nil && err.Error() != "tx is closed" {
slog.Error("failed to rollback transaction", "err", err)
}
}()
forgiveNoShow := req.ForgiveNoShow != nil && *req.ForgiveNoShow
if forgiveNoShow && bookingUserID != "" {