diff --git a/backend/handlers/payments/loyalty.go b/backend/handlers/payments/loyalty.go index 97a6083..0cf6677 100644 --- a/backend/handlers/payments/loyalty.go +++ b/backend/handlers/payments/loyalty.go @@ -60,6 +60,15 @@ func ApplyLoyaltyRedemption(w http.ResponseWriter, r *http.Request) { return } + // Loyalty redemption must be on the first payment — reject if a real payment + // (non-discount) already exists on this booking. + var realPaymentExists bool + db.DB.QueryRow(r.Context(), `SELECT EXISTS(SELECT 1 FROM payments WHERE booking_id = $1 AND payment_method != 'discount')`, bookingID).Scan(&realPaymentExists) + if realPaymentExists { + http.Error(w, "Loyalty must be redeemed on the first payment for this booking", http.StatusBadRequest) + return + } + var loyaltyStamps int if err := db.DB.QueryRow(r.Context(), `SELECT loyalty_stamps FROM users WHERE id = $1`, userID).Scan(&loyaltyStamps); err != nil { if errors.Is(err, pgx.ErrNoRows) { @@ -70,7 +79,7 @@ func ApplyLoyaltyRedemption(w http.ResponseWriter, r *http.Request) { http.Error(w, "internal server error", http.StatusInternalServerError) return } - if loyaltyStamps < 10 { + if loyaltyStamps < LoyaltyStampCost { http.Error(w, "Insufficient loyalty stamps", http.StatusBadRequest) return } @@ -125,17 +134,12 @@ func ApplyLoyaltyRedemption(w http.ResponseWriter, r *http.Request) { return } - discountAmount := roundTo2(bookingTotal * 0.10) - - if discountAmount <= 0 { - http.Error(w, "Booking total is zero, no discount applicable", http.StatusBadRequest) - return - } + discountAmount := roundTo2(bookingTotal * LoyaltyDiscountPercent / 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, 'loyalty', $3, NULL, NULL, 10.00, $4, $5) - `, bookingID, userID, redemptionID, bookingTotal, discountAmount); err != nil { + VALUES ($1, $2, 'loyalty', $3, NULL, NULL, $6, $4, $5) + `, bookingID, userID, redemptionID, bookingTotal, discountAmount, LoyaltyDiscountPercent); err != nil { log.Printf("Failed to insert booking discount: %v", err) http.Error(w, "internal server error", http.StatusInternalServerError) return diff --git a/backend/handlers/payments/refund_policy.go b/backend/handlers/payments/refund_policy.go index 0736247..62dc686 100644 --- a/backend/handlers/payments/refund_policy.go +++ b/backend/handlers/payments/refund_policy.go @@ -16,5 +16,6 @@ const ( ProtectedDepositMaxPct = 0.50 RequiredDepositPct = 0.20 - LoyaltyStampCost = 10 + LoyaltyStampCost = 10 + LoyaltyDiscountPercent = 10.0 ) diff --git a/backend/handlers/payments/refunds.go b/backend/handlers/payments/refunds.go index 12eee00..6116107 100644 --- a/backend/handlers/payments/refunds.go +++ b/backend/handlers/payments/refunds.go @@ -255,7 +255,7 @@ func ProcessCancellationRefund( if err != nil { log.Printf("Failed to refund loyalty stamps for booking %s: %v", bookingID, err) } else { - log.Printf("Refunded 10 loyalty stamps to user %s after cancellation of booking %s", bookingUserID, bookingID) + log.Printf("Refunded %d loyalty stamps to user %s after cancellation of booking %s", LoyaltyStampCost, bookingUserID, bookingID) } } }