From 1e100e4db71e21d68d780290179ab4e1f86ba80e Mon Sep 17 00:00:00 2001 From: Stephen Adamson Date: Fri, 19 Jun 2026 11:34:26 +0100 Subject: [PATCH] feat(backend): remove auto loyalty redemption from booking progress Remove auto-apply of pending loyalty redemption during ProgressBookingHandler. Now only checks if loyalty was applied on this booking (via booking_discounts) to skip stamp award. Redemption is purely manual via ApplyLoyaltyRedemption. Use LoyaltyStampCost constant instead of hardcoded 10. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- backend/handlers/bookings/bookings.go | 56 +++++---------------------- 1 file changed, 9 insertions(+), 47 deletions(-) diff --git a/backend/handlers/bookings/bookings.go b/backend/handlers/bookings/bookings.go index 245f44d..94afab3 100644 --- a/backend/handlers/bookings/bookings.go +++ b/backend/handlers/bookings/bookings.go @@ -2553,51 +2553,13 @@ func ProgressBookingHandler(w http.ResponseWriter, r *http.Request) { log.Printf("Failed to calculate booking total for %s: %v", bookingID, err) } - // Apply existing pending loyalty redemption (earned from previous 10 bookings) - // Skip if already applied at payment time (or by admin) - var loyaltyAlreadyApplied bool - tx.QueryRow(r.Context(), `SELECT EXISTS(SELECT 1 FROM booking_discounts WHERE booking_id = $1 AND discount_source = 'loyalty')`, bookingID).Scan(&loyaltyAlreadyApplied) - if bookingTotal > 0 && !loyaltyAlreadyApplied { - var redemptionID string - if err := tx.QueryRow(r.Context(), ` - SELECT id FROM loyalty_redemptions - WHERE user_id = $1 AND status = 'pending' AND expires_at > NOW() - ORDER BY redeemed_at ASC LIMIT 1 - `, booking.User.ID).Scan(&redemptionID); err == nil && redemptionID != "" { - discountAmount := roundTo2(bookingTotal * 0.10) + // Don't award a stamp if this booking already used a loyalty redemption + // (take or receive, never both). + var loyaltyAppliedOnThisBooking bool + tx.QueryRow(r.Context(), `SELECT EXISTS(SELECT 1 FROM booking_discounts WHERE booking_id = $1 AND discount_source = 'loyalty')`, bookingID).Scan(&loyaltyAppliedOnThisBooking) - 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, 'loyalty', $3, NULL, NULL, 10.00, $4, $5) - `, bookingID, booking.User.ID, redemptionID, 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 { - log.Printf("ALERT: failed to insert payment record: %v", err) - } - - if _, err := tx.Exec(r.Context(), ` - UPDATE loyalty_redemptions SET status = 'applied', applied_to_booking_id = $1, applied_at = NOW() - WHERE id = $2 - `, bookingID, redemptionID); err != nil { - log.Printf("ALERT: failed to update loyalty redemption: %v", err) - } - - if _, err := tx.Exec(r.Context(), ` - UPDATE users SET loyalty_stamps = GREATEST(0, loyalty_stamps - 10) WHERE id = $1 - `, booking.User.ID); err != nil { - log.Printf("ALERT: failed to update loyalty stamps: %v", err) - } - } - } - - // Increment stamps (max 1 per day, only for paid bookings) var newStampCount int - if bookingTotal > 0 { + if bookingTotal > 0 && !loyaltyAppliedOnThisBooking { if err := tx.QueryRow(r.Context(), ` UPDATE users SET loyalty_stamps = loyalty_stamps + 1 @@ -2617,12 +2579,12 @@ func ProgressBookingHandler(w http.ResponseWriter, r *http.Request) { } } - // Create pending redemption when stamps reach 10 - if newStampCount == 10 { + // Create pending redemption when stamps reach LoyaltyStampCost + if newStampCount == payments.LoyaltyStampCost { _, err = tx.Exec(r.Context(), ` INSERT INTO loyalty_redemptions (user_id, stamps_redeemed, status, redeemed_at) - VALUES ($1, 10, 'pending', NOW()) - `, booking.User.ID) + VALUES ($1, $2, 'pending', NOW()) + `, booking.User.ID, payments.LoyaltyStampCost) if err != nil { log.Printf("Failed to create loyalty redemption for user %s: %v", booking.User.ID, err) }