11 KiB
Coupon System Documentation
Overview
The billing module now includes a comprehensive coupon system that allows administrators to create discount codes that customers can apply to their orders. The system supports:
- Percentage-based discounts (e.g., 10%, 25%, 50% off)
- One-time or permanent discounts (one-time applies to first invoice only, permanent applies to all renewals)
- Game-specific filtering (apply coupons to all games or specific games only)
- Usage limits (optional maximum number of uses per coupon)
- Expiration dates (optional expiry date for time-limited promotions)
- Automatic usage tracking (system tracks how many times each coupon has been used)
Database Schema
Table: ogp_billing_coupons
The main coupon table stores all coupon definitions:
CREATE TABLE `ogp_billing_coupons` (
`coupon_id` INT(11) NOT NULL AUTO_INCREMENT,
`code` VARCHAR(50) NOT NULL UNIQUE,
`name` VARCHAR(255) NOT NULL DEFAULT '',
`description` TEXT,
`discount_percent` DECIMAL(5,2) NOT NULL DEFAULT 0.00,
`usage_type` ENUM('one_time', 'permanent') NOT NULL DEFAULT 'one_time',
`game_filter_type` ENUM('all_games', 'specific_games') NOT NULL DEFAULT 'all_games',
`game_filter_list` TEXT COMMENT 'JSON array of game keys',
`max_uses` INT(11) DEFAULT NULL COMMENT 'NULL for unlimited',
`current_uses` INT(11) NOT NULL DEFAULT 0,
`expires` DATETIME DEFAULT NULL,
`created_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`created_by` INT(11) DEFAULT NULL,
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
PRIMARY KEY (`coupon_id`),
UNIQUE KEY `idx_code` (`code`)
);
Updated Tables
ogp_billing_invoices
Added columns:
coupon_idINT(11) - Links to the coupon useddiscount_amountDECIMAL(10,2) - Actual discount amount applied
ogp_billing_orders
Added columns:
coupon_idINT(11) - Links to the coupon used (for permanent discounts)discount_amountDECIMAL(10,2) - Discount amount for renewals
Installation
-
Run the SQL migration:
mysql -u [username] -p [database_name] < modules/billing/create_coupons_table.sql -
Verify installation:
- Check that the
ogp_billing_couponstable exists - Verify that
coupon_idanddiscount_amountcolumns were added to bothogp_billing_invoicesandogp_billing_orders
- Check that the
Admin Interface
Accessing Coupon Management
- Log in as an administrator
- Navigate to
/modules/billing/admin.php - Click on "Manage Coupons" button
- Or go directly to
/modules/billing/admin_coupons.php
Creating a New Coupon
-
On the Manage Coupons page, scroll to "Add New Coupon" section
-
Fill in the required fields:
- Coupon Code: Unique alphanumeric code (e.g., "SUMMER2025", "WELCOME10")
- Display Name: User-friendly name shown in admin interface
- Description: Internal notes about the coupon
- Discount Percentage: Number between 0-100 (e.g., 25 for 25% off)
- Usage Type:
- One Time: Discount applies only to the first invoice
- Permanent: Discount applies to initial order AND all future renewals
- Apply To:
- All Games: Works for any game server
- Specific Games: Works only for selected games
- Maximum Uses: Optional limit on total uses (blank = unlimited)
- Expiration Date: Optional expiry date (blank = never expires)
-
Click "Add Coupon" to save
Example Coupons
Welcome Discount (One-Time, All Games)
Code: WELCOME10
Name: Welcome 10% Off
Discount: 10%
Usage Type: One Time
Apply To: All Games
Max Uses: (unlimited)
Expires: (none)
Arma Series Promotion (Permanent, Specific Games)
Code: ARMA25
Name: Arma Series 25% Off
Discount: 25%
Usage Type: Permanent
Apply To: Specific Games
- arma2_win32
- arma2oa_win32
- arma3_linux32
- arma3_linux64
- arma3_win64
- arma-reforger_linux64
- arma-reforger_win64
Max Uses: 100
Expires: 2025-12-31
Editing Coupons
- On the Manage Coupons page, find the coupon in the list
- Click the "Edit" button
- Modify any fields (except code uniqueness is enforced)
- Click "Save Changes"
Deactivating Coupons
- Click "Edit" on the coupon
- Uncheck the "Active" checkbox
- Click "Save Changes"
Note: Deactivating prevents new uses but doesn't affect existing orders.
Deleting Coupons
- Find the coupon in the list
- Click "Delete" button
- Confirm the deletion
Warning: This permanently removes the coupon. Orders that used it will retain the discount but lose the coupon reference.
Customer Usage
Applying a Coupon
- Customer adds items to cart at
/modules/billing/cart.php - In the coupon section, enter coupon code in the input field
- Click "Apply Coupon"
- If valid, a success message appears showing:
- Coupon code
- Discount percentage
- Whether it's one-time or permanent
- Cart totals update automatically with discounted prices
- Proceed to checkout with PayPal as normal
Coupon Validation
The system validates:
- ✅ Code exists and is active
- ✅ Coupon hasn't expired
- ✅ Usage limit hasn't been reached
- ✅ Game matches filter (if game-specific)
Error messages shown if:
- ❌ Code is invalid or expired
- ❌ Usage limit reached
- ❌ Coupon doesn't apply to games in cart
Removing a Coupon
- On cart page, click "Remove" button next to active coupon
- Cart prices revert to original amounts
Coupon Behavior
One-Time Coupons
- Applied to the initial invoice only
- When order is renewed, renewal invoice uses original price
- Coupon is cleared from session after first payment
- Example: "WELCOME10" gives 10% off first month only
Permanent Coupons
- Applied to initial invoice AND stored in order record
- When order is renewed, the discount is automatically applied to renewal invoices
- Coupon stays associated with the order forever
- Example: "VIP50" gives 50% off forever for that specific server
Game Filtering
All Games
- Coupon applies to any game server in the cart
- All cart items receive the discount
Specific Games
- Coupon checks each cart item's
home_namefield - Only matching games receive the discount
- Uses partial string matching (e.g., "arma3" matches "arma3_linux64")
- Non-matching games show original price
Example:
Cart contains:
1. Arma 3 Server → ARMA25 coupon applies (25% off)
2. Minecraft Server → ARMA25 doesn't apply (full price)
3. Arma Reforger → ARMA25 applies (25% off)
Total discount = 25% off Arma servers only
Technical Implementation
Session Storage
Coupons are stored in $_SESSION['applied_coupon'] when applied:
$_SESSION['applied_coupon'] = [
'coupon_id' => 1,
'code' => 'ARMA25',
'discount_percent' => 25.00,
'usage_type' => 'permanent',
'game_filter_type' => 'specific_games',
'game_filter_list' => '["arma3_linux64","arma2_win32"]',
// ... other fields
];
Cart Calculation
In cart.php, the couponAppliesTo() function checks if a coupon applies to a specific game:
function couponAppliesTo($coupon, $game_name) {
if (!$coupon || $coupon['game_filter_type'] === 'all_games') {
return true;
}
if ($coupon['game_filter_type'] === 'specific_games') {
$allowed_games = json_decode($coupon['game_filter_list'], true);
foreach ($allowed_games as $allowed_game) {
if (stripos($game_name, $allowed_game) !== false) {
return true;
}
}
}
return false;
}
Discount calculation:
$rowtotal = $row['amount'] * $row['qty'] * $row['max_players'];
if ($applied_coupon && couponAppliesTo($applied_coupon, $row['home_name'])) {
$discountPercent = floatval($applied_coupon['discount_percent']);
$itemDiscount = ($rowtotal * $discountPercent) / 100;
$rowtotal = $rowtotal - $itemDiscount;
}
Payment Processing
In api/capture_order.php, when PayPal payment completes:
- Coupon info is retrieved from session
- Invoices are updated with
coupon_id - Coupon usage count is incremented
- For one-time coupons, cleared from session
- For permanent coupons, stored in order record
// Update invoice with coupon
UPDATE ogp_billing_invoices
SET status='paid', coupon_id=?, discount_amount=?
WHERE user_id=? AND status='due'
// Increment usage count
UPDATE ogp_billing_coupons
SET current_uses = current_uses + 1
WHERE coupon_id = ?
// For permanent coupons, store in order
INSERT INTO ogp_billing_orders (
..., coupon_id, discount_amount
) VALUES (
..., ?, ?
)
Display
Cart Page
- Shows applied coupon with code and percentage
- Displays success/error messages
- Updates prices in real-time
My Servers Page
- Shows original price (strikethrough)
- Shows discounted price (bold)
- Shows coupon code and percentage (green text)
Admin Invoices Page
- Same display as My Servers
- Visible to administrators for all orders
Troubleshooting
Coupon not applying
- Check if code is typed correctly (case-sensitive)
- Verify coupon is active in admin panel
- Check expiration date hasn't passed
- Verify usage limit hasn't been reached
- For game-specific coupons, ensure game matches filter
Discount not showing after payment
- Check
discount_amountcolumn exists in both tables - Verify coupon_id was saved to invoice/order
- Clear browser cache and refresh page
Permanent coupon not applying to renewals
- Verify
usage_typeis set to "permanent" - Check order record has
coupon_idpopulated - Ensure renewal invoice creation copies coupon from order
Security Considerations
- Code uniqueness: System enforces unique coupon codes
- Usage tracking: Prevents abuse by tracking total uses
- Expiration: Automatic validation prevents expired coupon use
- Admin-only creation: Only admins can create/edit coupons
- SQL injection protection: All inputs are sanitized with
mysqli_real_escape_string() - CSRF protection: Admin forms include CSRF tokens
Future Enhancements
Potential features for future development:
- Minimum purchase amount requirements
- First-time customer restrictions
- User-specific coupons (assign to individual users)
- Combination rules (allow/prevent stacking)
- Auto-generated unique codes for campaigns
- Email notification when coupon is used
- Analytics dashboard for coupon performance
- Referral system integration
Support
For issues or questions:
- Check the troubleshooting section above
- Review error logs in
/modules/billing/logs/ - Verify database schema matches documentation
- Contact system administrator
Last Updated: 2025-10-29 Version: 1.0 Module: Billing/Coupons