fix: audit nolint:errcheck — fix dangerous suppression patterns
CI / Nginx config check (push) Successful in 14s
CI / Docker compose check (push) Successful in 14s
CI / Env docs check (push) Successful in 15s
CI / Frontend major deps (push) Successful in 25s
CI / Frontend deps check (push) Successful in 26s
CI / Secrets scan (push) Successful in 36s
CI / Go build (push) Successful in 42s
CI / Frontend build (push) Successful in 48s
CI / Knip (push) Successful in 28s
CI / Frontend a11y check (push) Successful in 1m26s
CI / Go vet (prod) (push) Failing after 2m9s
CI / go mod tidy (push) Successful in 59s
CI / Go vet (dev) (push) Failing after 2m10s
CI / Staticcheck (prod) (push) Failing after 2m42s
CI / Staticcheck (dev) (push) Failing after 2m56s
CI / Frontend QC (audit) (push) Successful in 1m7s
CI / golangci-lint (push) Successful in 3m38s
CI / Go vulnerabilities (push) Successful in 1m40s
CI / Frontend QC (typecheck) (push) Successful in 1m45s
CI / Frontend QC (lint) (push) Failing after 1m21s
CI / Svelte strict check (push) Has been skipped
CI / Security scan (prod) (push) Successful in 4m18s
CI / Security scan (dev) (push) Successful in 4m28s
CI / Tests (prod) (push) Has been skipped
CI / Tests (dev) (push) Has been skipped
CI / Race (prod) (push) Has been skipped
CI / Race (dev) (push) Has been skipped
CI / Nginx config check (push) Successful in 14s
CI / Docker compose check (push) Successful in 14s
CI / Env docs check (push) Successful in 15s
CI / Frontend major deps (push) Successful in 25s
CI / Frontend deps check (push) Successful in 26s
CI / Secrets scan (push) Successful in 36s
CI / Go build (push) Successful in 42s
CI / Frontend build (push) Successful in 48s
CI / Knip (push) Successful in 28s
CI / Frontend a11y check (push) Successful in 1m26s
CI / Go vet (prod) (push) Failing after 2m9s
CI / go mod tidy (push) Successful in 59s
CI / Go vet (dev) (push) Failing after 2m10s
CI / Staticcheck (prod) (push) Failing after 2m42s
CI / Staticcheck (dev) (push) Failing after 2m56s
CI / Frontend QC (audit) (push) Successful in 1m7s
CI / golangci-lint (push) Successful in 3m38s
CI / Go vulnerabilities (push) Successful in 1m40s
CI / Frontend QC (typecheck) (push) Successful in 1m45s
CI / Frontend QC (lint) (push) Failing after 1m21s
CI / Svelte strict check (push) Has been skipped
CI / Security scan (prod) (push) Successful in 4m18s
CI / Security scan (dev) (push) Successful in 4m28s
CI / Tests (prod) (push) Has been skipped
CI / Tests (dev) (push) Has been skipped
CI / Race (prod) (push) Has been skipped
CI / Race (dev) (push) Has been skipped
This commit is contained in:
@@ -2698,8 +2698,9 @@ func ProgressBookingHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
// Don't award a stamp if this booking already used a loyalty redemption
|
// Don't award a stamp if this booking already used a loyalty redemption
|
||||||
// (take or receive, never both).
|
// (take or receive, never both).
|
||||||
var loyaltyAppliedOnThisBooking bool
|
var loyaltyAppliedOnThisBooking bool
|
||||||
//nolint:errcheck // zero value is acceptable fallback on scan failure
|
if err := tx.QueryRow(r.Context(), `SELECT EXISTS(SELECT 1 FROM booking_discounts WHERE booking_id = $1 AND discount_source = 'loyalty')`, bookingID).Scan(&loyaltyAppliedOnThisBooking); err != nil {
|
||||||
_ = tx.QueryRow(r.Context(), `SELECT EXISTS(SELECT 1 FROM booking_discounts WHERE booking_id = $1 AND discount_source = 'loyalty')`, bookingID).Scan(&loyaltyAppliedOnThisBooking)
|
log.Printf("Failed to check loyalty applied on booking %s: %v", bookingID, err)
|
||||||
|
}
|
||||||
|
|
||||||
var newStampCount int
|
var newStampCount int
|
||||||
if bookingTotal > 0 && !loyaltyAppliedOnThisBooking {
|
if bookingTotal > 0 && !loyaltyAppliedOnThisBooking {
|
||||||
@@ -2735,8 +2736,9 @@ func ProgressBookingHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// Skip time-based campaign if already applied at payment time
|
// Skip time-based campaign if already applied at payment time
|
||||||
var timeBasedApplied bool
|
var timeBasedApplied bool
|
||||||
//nolint:errcheck // zero value is acceptable fallback on scan failure
|
if err := tx.QueryRow(r.Context(), `SELECT EXISTS(SELECT 1 FROM booking_discounts WHERE booking_id = $1 AND discount_source = 'campaign' AND campaign_type = 'time_based')`, bookingID).Scan(&timeBasedApplied); err != nil {
|
||||||
_ = tx.QueryRow(r.Context(), `SELECT EXISTS(SELECT 1 FROM booking_discounts WHERE booking_id = $1 AND discount_source = 'campaign' AND campaign_type = 'time_based')`, bookingID).Scan(&timeBasedApplied)
|
log.Printf("Failed to check time-based campaign applied on booking %s: %v", bookingID, err)
|
||||||
|
}
|
||||||
if bookingTotal > 0 && !timeBasedApplied {
|
if bookingTotal > 0 && !timeBasedApplied {
|
||||||
var campaignID string
|
var campaignID string
|
||||||
var campaignPercent float64
|
var campaignPercent float64
|
||||||
@@ -2778,13 +2780,14 @@ func ProgressBookingHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
var milestoneCampaignID string
|
var milestoneCampaignID string
|
||||||
var milestonePercent float64
|
var milestonePercent float64
|
||||||
//nolint:errcheck // zero value is acceptable fallback on scan failure
|
if err := tx.QueryRow(r.Context(), `
|
||||||
_ = tx.QueryRow(r.Context(), `
|
|
||||||
SELECT id, discount_percent FROM discount_campaigns
|
SELECT id, discount_percent FROM discount_campaigns
|
||||||
WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'per_user_booking_count'
|
WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'per_user_booking_count'
|
||||||
AND milestone_value = $1
|
AND milestone_value = $1
|
||||||
AND NOT EXISTS (SELECT 1 FROM booking_discounts WHERE user_id = $2 AND source_id = discount_campaigns.id)
|
AND NOT EXISTS (SELECT 1 FROM booking_discounts WHERE user_id = $2 AND source_id = discount_campaigns.id)
|
||||||
`, userBookingCount, booking.User.ID).Scan(&milestoneCampaignID, &milestonePercent)
|
`, userBookingCount, booking.User.ID).Scan(&milestoneCampaignID, &milestonePercent); err != nil {
|
||||||
|
log.Printf("Failed to query per-user milestone campaign for booking %s: %v", bookingID, err)
|
||||||
|
}
|
||||||
|
|
||||||
if milestoneCampaignID != "" {
|
if milestoneCampaignID != "" {
|
||||||
discountAmount := roundTo2(bookingTotal * milestonePercent / 100)
|
discountAmount := roundTo2(bookingTotal * milestonePercent / 100)
|
||||||
@@ -2808,29 +2811,32 @@ func ProgressBookingHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var globalMilestoneApplied bool
|
var globalMilestoneApplied bool
|
||||||
//nolint:errcheck // zero value is acceptable fallback on scan failure
|
if err := tx.QueryRow(r.Context(), `SELECT EXISTS(SELECT 1 FROM booking_discounts WHERE booking_id = $1 AND discount_source = 'campaign' AND campaign_type = 'milestone' AND milestone_type = 'global_booking_count')`, bookingID).Scan(&globalMilestoneApplied); err != nil {
|
||||||
_ = tx.QueryRow(r.Context(), `SELECT EXISTS(SELECT 1 FROM booking_discounts WHERE booking_id = $1 AND discount_source = 'campaign' AND campaign_type = 'milestone' AND milestone_type = 'global_booking_count')`, bookingID).Scan(&globalMilestoneApplied)
|
log.Printf("Failed to check global milestone applied on booking %s: %v", bookingID, err)
|
||||||
|
}
|
||||||
if !globalMilestoneApplied {
|
if !globalMilestoneApplied {
|
||||||
var globalCount int
|
var globalCount int
|
||||||
//nolint:errcheck // zero value is acceptable fallback on scan failure
|
//nolint:errcheck // zero value is acceptable fallback on scan failure
|
||||||
_ = tx.QueryRow(r.Context(), `SELECT COUNT(*) FROM bookings WHERE status = 'completed'`).Scan(&globalCount)
|
_ = tx.QueryRow(r.Context(), `SELECT COUNT(*) FROM bookings WHERE status = 'completed'`).Scan(&globalCount)
|
||||||
|
|
||||||
var hasInPersonPayment bool
|
var hasInPersonPayment bool
|
||||||
//nolint:errcheck // zero value is acceptable fallback on scan failure
|
if err := tx.QueryRow(r.Context(), `
|
||||||
_ = 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 {
|
||||||
SELECT EXISTS(SELECT 1 FROM payments WHERE booking_id = $1 AND payment_method = 'in_person_card')`, bookingID).Scan(&hasInPersonPayment)
|
log.Printf("Failed to check in-person payment on booking %s: %v", bookingID, err)
|
||||||
|
}
|
||||||
|
|
||||||
if hasInPersonPayment {
|
if hasInPersonPayment {
|
||||||
var globalCampaignID string
|
var globalCampaignID string
|
||||||
var globalPercent float64
|
var globalPercent float64
|
||||||
//nolint:errcheck // zero value is acceptable fallback on scan failure
|
if err := tx.QueryRow(r.Context(), `
|
||||||
_ = tx.QueryRow(r.Context(), `
|
|
||||||
SELECT id, discount_percent FROM discount_campaigns
|
SELECT id, discount_percent FROM discount_campaigns
|
||||||
WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'global_booking_count'
|
WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'global_booking_count'
|
||||||
AND milestone_value <= $1
|
AND milestone_value <= $1
|
||||||
AND (max_redemptions IS NULL OR times_redeemed < max_redemptions)
|
AND (max_redemptions IS NULL OR times_redeemed < max_redemptions)
|
||||||
ORDER BY milestone_value DESC LIMIT 1
|
ORDER BY milestone_value DESC LIMIT 1
|
||||||
`, globalCount).Scan(&globalCampaignID, &globalPercent)
|
`, globalCount).Scan(&globalCampaignID, &globalPercent); err != nil {
|
||||||
|
log.Printf("Failed to query global milestone campaign for booking %s: %v", bookingID, err)
|
||||||
|
}
|
||||||
|
|
||||||
if globalCampaignID != "" {
|
if globalCampaignID != "" {
|
||||||
discountAmount := roundTo2(bookingTotal * globalPercent / 100)
|
discountAmount := roundTo2(bookingTotal * globalPercent / 100)
|
||||||
|
|||||||
@@ -283,14 +283,11 @@ func AdminCreateBookingForUserHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get deposit info
|
// Get deposit info — deposit_required already fetched above in the main booking query.
|
||||||
var depositRequired bool
|
|
||||||
var preStartPaid float64
|
var preStartPaid float64
|
||||||
//nolint:errcheck // zero value is acceptable fallback on scan failure
|
//nolint:errcheck // zero value is acceptable fallback on scan failure (aggregate with COALESCE)
|
||||||
_ = db.Conn.QueryRow(r.Context(), `SELECT deposit_required FROM bookings WHERE id = $1`, existingID).Scan(&depositRequired)
|
|
||||||
//nolint:errcheck // zero value is acceptable fallback on scan failure
|
|
||||||
_ = 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'`, existingID).Scan(&preStartPaid)
|
_ = 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'`, existingID).Scan(&preStartPaid)
|
||||||
populateDepositFields(&existingBooking, depositRequired, preStartPaid)
|
populateDepositFields(&existingBooking, existingBooking.DepositRequired, preStartPaid)
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
@@ -1211,13 +1208,19 @@ func RequestEditHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
// Query payment and timing info (used for validation AND auto-approval later)
|
// Query payment and timing info (used for validation AND auto-approval later)
|
||||||
var hasPayments bool
|
var hasPayments bool
|
||||||
hoursUntilCurrent := currentStartTime.Sub(clock.Now()).Hours()
|
hoursUntilCurrent := currentStartTime.Sub(clock.Now()).Hours()
|
||||||
//nolint:errcheck // zero value is acceptable fallback on scan failure
|
if err := db.Conn.QueryRow(r.Context(), "SELECT EXISTS(SELECT 1 FROM payments WHERE booking_id = $1 AND status = 'completed')", bookingID).Scan(&hasPayments); err != nil {
|
||||||
_ = db.Conn.QueryRow(r.Context(), "SELECT EXISTS(SELECT 1 FROM payments WHERE booking_id = $1 AND status = 'completed')", bookingID).Scan(&hasPayments)
|
log.Printf("Failed to check payments for booking %s: %v", bookingID, err)
|
||||||
|
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Check if booking has discounts (affects auto-approval decisions)
|
// Check if booking has discounts (affects auto-approval decisions)
|
||||||
var hasDiscounts bool
|
var hasDiscounts bool
|
||||||
//nolint:errcheck // zero value is acceptable fallback on scan failure
|
if err := db.Conn.QueryRow(r.Context(), "SELECT EXISTS(SELECT 1 FROM booking_discounts WHERE booking_id = $1)", bookingID).Scan(&hasDiscounts); err != nil {
|
||||||
_ = db.Conn.QueryRow(r.Context(), "SELECT EXISTS(SELECT 1 FROM booking_discounts WHERE booking_id = $1)", bookingID).Scan(&hasDiscounts)
|
log.Printf("Failed to check discounts for booking %s: %v", bookingID, err)
|
||||||
|
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if req.NewStartTime != nil && !req.NewStartTime.Equal(currentStartTime) {
|
if req.NewStartTime != nil && !req.NewStartTime.Equal(currentStartTime) {
|
||||||
if hasPayments && hoursUntilCurrent < 72 {
|
if hasPayments && hoursUntilCurrent < 72 {
|
||||||
@@ -1447,8 +1450,7 @@ func RequestEditHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
var durationMinutes int
|
var durationMinutes int
|
||||||
if len(req.NewServices) > 0 {
|
if len(req.NewServices) > 0 {
|
||||||
//nolint:errcheck // zero value is acceptable fallback on scan failure
|
if err := tx.QueryRow(r.Context(), `
|
||||||
_ = tx.QueryRow(r.Context(), `
|
|
||||||
SELECT COALESCE(SUM(dur), 60) FROM (
|
SELECT COALESCE(SUM(dur), 60) FROM (
|
||||||
SELECT s.duration_minutes AS dur
|
SELECT s.duration_minutes AS dur
|
||||||
FROM services s
|
FROM services s
|
||||||
@@ -1458,12 +1460,17 @@ func RequestEditHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
FROM custom_services cs
|
FROM custom_services cs
|
||||||
WHERE cs.id = ANY($1)
|
WHERE cs.id = ANY($1)
|
||||||
) sub
|
) sub
|
||||||
`, req.NewServices).Scan(&durationMinutes)
|
`, req.NewServices).Scan(&durationMinutes); err != nil {
|
||||||
|
log.Printf("Failed to calculate duration for edit request %s: %v, using default", bookingID, err)
|
||||||
|
durationMinutes = 60
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
//nolint:errcheck // zero value is acceptable fallback on scan failure
|
if err := tx.QueryRow(r.Context(), `
|
||||||
_ = tx.QueryRow(r.Context(), `
|
|
||||||
SELECT total_duration_minutes FROM bookings WHERE id = $1
|
SELECT total_duration_minutes FROM bookings WHERE id = $1
|
||||||
`, bookingID).Scan(&durationMinutes)
|
`, bookingID).Scan(&durationMinutes); err != nil {
|
||||||
|
log.Printf("Failed to get booking duration for edit request %s: %v, using default", bookingID, err)
|
||||||
|
durationMinutes = 60
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = tx.Exec(r.Context(), `
|
_, err = tx.Exec(r.Context(), `
|
||||||
|
|||||||
@@ -141,10 +141,11 @@ func calculateDiscountPreview(ctx context.Context, bookingID string, userID stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
var bookingTotal float64
|
var bookingTotal float64
|
||||||
//nolint:errcheck // zero value is acceptable fallback on scan failure
|
if err := db.Conn.QueryRow(ctx, `
|
||||||
_ = db.Conn.QueryRow(ctx, `
|
|
||||||
SELECT total_amount FROM bookings WHERE id = $1
|
SELECT total_amount FROM bookings WHERE id = $1
|
||||||
`, bookingID).Scan(&bookingTotal)
|
`, bookingID).Scan(&bookingTotal); err != nil {
|
||||||
|
log.Printf("Failed to query booking total for discount preview %s: %v", bookingID, err)
|
||||||
|
}
|
||||||
|
|
||||||
if bookingTotal <= 0 {
|
if bookingTotal <= 0 {
|
||||||
return resp
|
return resp
|
||||||
@@ -185,13 +186,14 @@ func calculateDiscountPreview(ctx context.Context, bookingID string, userID stri
|
|||||||
var milestoneCampaignID string
|
var milestoneCampaignID string
|
||||||
var milestonePercent float64
|
var milestonePercent float64
|
||||||
var milestoneName string
|
var milestoneName string
|
||||||
//nolint:errcheck // zero value is acceptable fallback on scan failure
|
if err := db.Conn.QueryRow(ctx, `
|
||||||
_ = db.Conn.QueryRow(ctx, `
|
|
||||||
SELECT id, discount_percent, name FROM discount_campaigns
|
SELECT id, discount_percent, name FROM discount_campaigns
|
||||||
WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'per_user_booking_count'
|
WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'per_user_booking_count'
|
||||||
AND milestone_value = $1
|
AND milestone_value = $1
|
||||||
AND NOT EXISTS (SELECT 1 FROM booking_discounts WHERE user_id = $2 AND source_id = discount_campaigns.id)
|
AND NOT EXISTS (SELECT 1 FROM booking_discounts WHERE user_id = $2 AND source_id = discount_campaigns.id)
|
||||||
`, userBookingCount, userID).Scan(&milestoneCampaignID, &milestonePercent, &milestoneName)
|
`, userBookingCount, userID).Scan(&milestoneCampaignID, &milestonePercent, &milestoneName); err != nil {
|
||||||
|
log.Printf("Failed to query milestone campaign for discount preview (user %s, count %d): %v", userID, userBookingCount, err)
|
||||||
|
}
|
||||||
|
|
||||||
if milestoneCampaignID != "" {
|
if milestoneCampaignID != "" {
|
||||||
var exists int
|
var exists int
|
||||||
@@ -1021,8 +1023,7 @@ func CreateBookingPayment(w http.ResponseWriter, r *http.Request) {
|
|||||||
// Promote deposit to confirmed if total paid meets the 20% threshold.
|
// Promote deposit to confirmed if total paid meets the 20% threshold.
|
||||||
// Check is inside the transaction so it sees the just-inserted payments.
|
// Check is inside the transaction so it sees the just-inserted payments.
|
||||||
var depositMet bool
|
var depositMet bool
|
||||||
//nolint:errcheck // zero value is acceptable fallback on scan failure
|
if err := tx.QueryRow(r.Context(), `
|
||||||
_ = tx.QueryRow(r.Context(), `
|
|
||||||
WITH booking_total AS (
|
WITH booking_total AS (
|
||||||
SELECT total_amount * 100 AS total_cents FROM bookings WHERE id = $1
|
SELECT total_amount * 100 AS total_cents FROM bookings WHERE id = $1
|
||||||
),
|
),
|
||||||
@@ -1033,7 +1034,9 @@ func CreateBookingPayment(w http.ResponseWriter, r *http.Request) {
|
|||||||
)
|
)
|
||||||
SELECT pt.paid_cents >= ROUND(bt.total_cents * 0.2)
|
SELECT pt.paid_cents >= ROUND(bt.total_cents * 0.2)
|
||||||
FROM booking_total bt, paid_total pt
|
FROM booking_total bt, paid_total pt
|
||||||
`, bookingID).Scan(&depositMet)
|
`, bookingID).Scan(&depositMet); err != nil {
|
||||||
|
log.Printf("Failed to check deposit threshold for booking %s: %v", bookingID, err)
|
||||||
|
}
|
||||||
|
|
||||||
if depositMet {
|
if depositMet {
|
||||||
if _, err := tx.Exec(r.Context(), `
|
if _, err := tx.Exec(r.Context(), `
|
||||||
@@ -1139,13 +1142,14 @@ func applyEligibleCampaignsAtPayment(ctx context.Context, q db.Querier, bookingI
|
|||||||
|
|
||||||
var milestoneCampaignID string
|
var milestoneCampaignID string
|
||||||
var milestonePercent float64
|
var milestonePercent float64
|
||||||
//nolint:errcheck // zero value is acceptable fallback on scan failure
|
if err := q.QueryRow(ctx, `
|
||||||
_ = q.QueryRow(ctx, `
|
|
||||||
SELECT id, discount_percent FROM discount_campaigns
|
SELECT id, discount_percent FROM discount_campaigns
|
||||||
WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'per_user_booking_count'
|
WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'per_user_booking_count'
|
||||||
AND milestone_value = $1
|
AND milestone_value = $1
|
||||||
AND NOT EXISTS (SELECT 1 FROM booking_discounts WHERE user_id = $2 AND source_id = discount_campaigns.id)
|
AND NOT EXISTS (SELECT 1 FROM booking_discounts WHERE user_id = $2 AND source_id = discount_campaigns.id)
|
||||||
`, userBookingCount, userID).Scan(&milestoneCampaignID, &milestonePercent)
|
`, userBookingCount, userID).Scan(&milestoneCampaignID, &milestonePercent); err != nil {
|
||||||
|
log.Printf("Failed to query per-user milestone campaign: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
if milestoneCampaignID != "" {
|
if milestoneCampaignID != "" {
|
||||||
var exists int
|
var exists int
|
||||||
@@ -1251,15 +1255,16 @@ func applyEligibleCampaignsAtPayment(ctx context.Context, q db.Querier, bookingI
|
|||||||
|
|
||||||
var globalCampaignID string
|
var globalCampaignID string
|
||||||
var globalPercent float64
|
var globalPercent float64
|
||||||
//nolint:errcheck // zero value is acceptable fallback on scan failure
|
if err := q.QueryRow(ctx, `
|
||||||
_ = q.QueryRow(ctx, `
|
|
||||||
SELECT id, discount_percent FROM discount_campaigns
|
SELECT id, discount_percent FROM discount_campaigns
|
||||||
WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'global_booking_count'
|
WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'global_booking_count'
|
||||||
AND milestone_value <= $1
|
AND milestone_value <= $1
|
||||||
AND (max_redemptions IS NULL OR times_redeemed < max_redemptions)
|
AND (max_redemptions IS NULL OR times_redeemed < max_redemptions)
|
||||||
AND NOT EXISTS (SELECT 1 FROM booking_discounts WHERE source_id = discount_campaigns.id AND booking_id = $2)
|
AND NOT EXISTS (SELECT 1 FROM booking_discounts WHERE source_id = discount_campaigns.id AND booking_id = $2)
|
||||||
ORDER BY milestone_value DESC LIMIT 1
|
ORDER BY milestone_value DESC LIMIT 1
|
||||||
`, globalCount, bookingID).Scan(&globalCampaignID, &globalPercent)
|
`, globalCount, bookingID).Scan(&globalCampaignID, &globalPercent); err != nil {
|
||||||
|
log.Printf("Failed to query global milestone campaign: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
if globalCampaignID != "" {
|
if globalCampaignID != "" {
|
||||||
var exists int
|
var exists int
|
||||||
|
|||||||
Reference in New Issue
Block a user