Laravel优惠券限制:单用户每张券仅用一次且一次仅用一张
Sounds like you're just missing a couple of key checks and a usage tracking table to enforce those two rules: one coupon per cart, and one use per user per coupon. Let's walk through how to implement this step by step.
1. Add a Coupon Usage Tracking Table
First, you need a way to track which users have used which coupons. Create a database table to log coupon usages—this will prevent repeat uses at both the application and database level.
CREATE TABLE IF NOT EXISTS coupon_usages ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, coupon_code VARCHAR(50) NOT NULL, used_at DATETIME DEFAULT CURRENT_TIMESTAMP, order_id INT NULL, -- Optional: Link to the completed order FOREIGN KEY (user_id) REFERENCES users(id), -- Replace with your actual users table name FOREIGN KEY (order_id) REFERENCES orders(id), -- Replace with your actual orders table name UNIQUE KEY user_coupon_unique (user_id, coupon_code) -- Critical: Enforces one use per user/coupon pair );
That UNIQUE KEY is a safety net—even if your application logic glitches, the database will reject duplicate entries for the same user and coupon.
2. Modify Your Cart Update Function
Now, update your cart logic to add the two required checks when a user tries to apply a coupon. Assuming your function is in PHP (given the $copname variable), here's how to integrate the checks:
Step 2.1: Block Multiple Active Coupons
First, check if the user already has a coupon applied to their cart. If yes, prevent adding another:
// Check if there's already an active coupon in the cart if (!empty($_SESSION['cart']['applied_coupon'])) { $_SESSION['cart_error'] = "You can only use one coupon at a time. Remove your current coupon first."; // Redirect back to cart or display error message header("Location: your-cart-page.php"); exit; }
Step 2.2: Check for Past Coupon Usage
Next, verify if the user has already used this coupon before by querying the coupon_usages table:
$current_user_id = $_SESSION['user_id']; // Get logged-in user's ID $target_coupon_code = $copname; // Your existing coupon code variable // Prepare query to check for existing usage $stmt = $pdo->prepare("SELECT id FROM coupon_usages WHERE user_id = ? AND coupon_code = ?"); $stmt->execute([$current_user_id, $target_coupon_code]); $has_used_coupon = $stmt->fetch(); if ($has_used_coupon) { $_SESSION['cart_error'] = "You've already used this coupon code. It can only be used once per user."; header("Location: your-cart-page.php"); exit; }
Step 2.3: Apply the Coupon (If Checks Pass)
If both checks are successful, proceed to apply the coupon to the cart as you already do—calculate discounts, update cart totals, etc.
3. Log Coupon Usage on Order Completion
Don't forget to log the coupon usage when the user successfully completes their order. This ensures the coupon is marked as used and can't be reused later:
// After creating the order successfully $new_order_id = $your_order_id_variable; // ID of the completed order // Insert into coupon_usages try { $stmt = $pdo->prepare("INSERT INTO coupon_usages (user_id, coupon_code, order_id) VALUES (?, ?, ?)"); $stmt->execute([$current_user_id, $target_coupon_code, $new_order_id]); } catch (PDOException $e) { // Handle duplicate entry error (in case of race conditions) $_SESSION['order_error'] = "There was an issue applying your coupon. Please try again."; header("Location: checkout-failure.php"); exit; }
Edge Cases to Consider
- Guest Users: If your system allows guest checkout, track coupon usage by email instead of user ID (since guests don't have an account). Adjust the
coupon_usagestable to include anemailcolumn and modify the checks accordingly. - Coupon Removal: If a user removes a coupon from their cart before placing the order, you don't need to log it—only log when the order is successfully completed.
- Race Conditions: The
UNIQUE KEYin the database will catch any duplicate usage attempts that slip through the application checks (e.g., two simultaneous requests from the same user). Make sure to handle that exception gracefully.
That should cover both of your requirements: one coupon per cart, and one use per user per coupon.
内容的提问来源于stack exchange,提问作者mafortis

