fix(payments): compare global coupon redemptions against max_redemptions not max_redemptions_per_user
All checks were successful
build-and-release / build (employees) (push) Successful in 11s
build-and-release / build (cron) (push) Successful in 14s
build-and-release / build (customers) (push) Successful in 16s
build-and-release / build (catering-services) (push) Successful in 19s
build-and-release / build (companies) (push) Successful in 21s
build-and-release / build (developers) (push) Successful in 20s
build-and-release / build (fitness-trainers) (push) Successful in 7s
build-and-release / build (gateway) (push) Successful in 9s
build-and-release / build (graphic-designers) (push) Successful in 8s
build-and-release / build (job-seekers) (push) Successful in 8s
build-and-release / build (jobs) (push) Successful in 10s
build-and-release / build (social-media-managers) (push) Successful in 8s
build-and-release / build (makeup-artists) (push) Successful in 12s
build-and-release / build (photographers) (push) Successful in 8s
build-and-release / build (tutors) (push) Successful in 7s
build-and-release / build (users) (push) Successful in 6s
backend-integration-tests / ai-credits (push) Successful in 9s
build-and-release / build (ugc-content-creators) (push) Successful in 11s
build-and-release / build (video-editors) (push) Successful in 11s
build-and-release / build (payments) (push) Successful in 1m0s
All checks were successful
build-and-release / build (employees) (push) Successful in 11s
build-and-release / build (cron) (push) Successful in 14s
build-and-release / build (customers) (push) Successful in 16s
build-and-release / build (catering-services) (push) Successful in 19s
build-and-release / build (companies) (push) Successful in 21s
build-and-release / build (developers) (push) Successful in 20s
build-and-release / build (fitness-trainers) (push) Successful in 7s
build-and-release / build (gateway) (push) Successful in 9s
build-and-release / build (graphic-designers) (push) Successful in 8s
build-and-release / build (job-seekers) (push) Successful in 8s
build-and-release / build (jobs) (push) Successful in 10s
build-and-release / build (social-media-managers) (push) Successful in 8s
build-and-release / build (makeup-artists) (push) Successful in 12s
build-and-release / build (photographers) (push) Successful in 8s
build-and-release / build (tutors) (push) Successful in 7s
build-and-release / build (users) (push) Successful in 6s
backend-integration-tests / ai-credits (push) Successful in 9s
build-and-release / build (ugc-content-creators) (push) Successful in 11s
build-and-release / build (video-editors) (push) Successful in 11s
build-and-release / build (payments) (push) Successful in 1m0s
validate_coupon was checking: total_redemptions (= redemptions_used, global count) >= max_per_user (per-user limit) which means a coupon with max_redemptions=1000 and max_redemptions_per_user=1 would be marked exhausted after the first person ever used it. Fix: also SELECT max_redemptions and compare global count against it. The per-user check on line 192 (user_redemptions >= max_per_user) was already correct and is unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
86e1fd47d2
commit
4e0e6af3e1
1 changed files with 11 additions and 10 deletions
|
|
@ -151,17 +151,18 @@ async fn validate_coupon(
|
|||
original_price: i32,
|
||||
) -> Result<Option<(i32, String, i32)>, String> {
|
||||
// Get coupon details
|
||||
let coupon: Option<(Uuid, String, i32, Option<i32>, i32, i32, Vec<Uuid>)> = sqlx::query_as(
|
||||
let coupon: Option<(Uuid, String, i32, Option<i32>, i32, i32, Vec<Uuid>, i32)> = sqlx::query_as(
|
||||
r#"
|
||||
SELECT
|
||||
id, discount_type,
|
||||
SELECT
|
||||
id, discount_type,
|
||||
CAST(discount_value * 100 AS INTEGER) as discount_value,
|
||||
CAST(max_discount_amount * 100 AS INTEGER) as max_discount_amount,
|
||||
max_redemptions_per_user, redemptions_used, applicable_package_ids
|
||||
max_redemptions_per_user, redemptions_used, applicable_package_ids,
|
||||
max_redemptions
|
||||
FROM ai_coupons
|
||||
WHERE code = $1
|
||||
AND is_active = TRUE
|
||||
AND valid_from <= NOW()
|
||||
WHERE code = $1
|
||||
AND is_active = TRUE
|
||||
AND valid_from <= NOW()
|
||||
AND (valid_until IS NULL OR valid_until > NOW())
|
||||
"#
|
||||
)
|
||||
|
|
@ -170,12 +171,12 @@ async fn validate_coupon(
|
|||
.await
|
||||
.map_err(|e| format!("DB error: {e}"))?;
|
||||
|
||||
let Some((coupon_id, discount_type, discount_value, max_discount_amount, max_per_user, total_redemptions, applicable_packages)) = coupon else {
|
||||
let Some((coupon_id, discount_type, discount_value, max_discount_amount, max_per_user, total_redemptions, applicable_packages, global_limit)) = coupon else {
|
||||
return Ok(None); // Coupon not found or invalid
|
||||
};
|
||||
|
||||
// Check if coupon has remaining redemptions
|
||||
if total_redemptions >= max_per_user {
|
||||
// Check if coupon has remaining global redemptions
|
||||
if total_redemptions >= global_limit {
|
||||
return Err("Coupon redemption limit reached".to_string());
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue