From 9d541d55a2298a3d425657ec9f0e2d11cd692493 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 10:54:52 +0000 Subject: [PATCH] Add enhanced coupon system with game filters and admin management page Co-authored-by: iaretechnician <2749183+iaretechnician@users.noreply.github.com> --- modules/billing/admin.php | 1 + modules/billing/admin_coupons.php | 414 +++++++++++++++++++++++ modules/billing/create_coupons_table.sql | 106 ++++++ 3 files changed, 521 insertions(+) create mode 100644 modules/billing/admin_coupons.php create mode 100644 modules/billing/create_coupons_table.sql diff --git a/modules/billing/admin.php b/modules/billing/admin.php index b08e4690..61f9444a 100644 --- a/modules/billing/admin.php +++ b/modules/billing/admin.php @@ -24,6 +24,7 @@ function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
Manage Servers & Services Invoice History + Manage Coupons Edit Site Config
diff --git a/modules/billing/admin_coupons.php b/modules/billing/admin_coupons.php new file mode 100644 index 00000000..80bcd63c --- /dev/null +++ b/modules/billing/admin_coupons.php @@ -0,0 +1,414 @@ + 0) { + $error = "Coupon code '$code' already exists."; + } else { + $sql = "INSERT INTO {$table_prefix}billing_coupons + (code, name, description, discount_percent, usage_type, game_filter_type, game_filter_list, max_uses, expires, is_active) + VALUES ('$code', '$name', '$description', $discount_percent, '$usage_type', '$game_filter_type', " . + ($game_filter_list === 'NULL' ? 'NULL' : "'$game_filter_list'") . ", $max_uses, $expires, 1)"; + + if (mysqli_query($db, $sql)) { + $status = "Coupon '$code' added successfully."; + } else { + $error = "Error adding coupon: " . mysqli_error($db); + } + } + } + + // Update existing coupon + elseif (isset($_POST['update_coupon'])) { + $coupon_id = intval($_POST['coupon_id']); + $code = mysqli_real_escape_string($db, trim($_POST['code'])); + $name = mysqli_real_escape_string($db, trim($_POST['name'])); + $description = mysqli_real_escape_string($db, trim($_POST['description'])); + $discount_percent = floatval($_POST['discount_percent']); + $usage_type = mysqli_real_escape_string($db, $_POST['usage_type']); + $game_filter_type = mysqli_real_escape_string($db, $_POST['game_filter_type']); + $game_filter_list = isset($_POST['game_filter_list']) && $_POST['game_filter_type'] === 'specific_games' + ? mysqli_real_escape_string($db, json_encode($_POST['game_filter_list'])) + : 'NULL'; + $max_uses = !empty($_POST['max_uses']) ? intval($_POST['max_uses']) : 'NULL'; + $expires = !empty($_POST['expires']) ? "'" . mysqli_real_escape_string($db, $_POST['expires']) . "'" : 'NULL'; + $is_active = isset($_POST['is_active']) ? 1 : 0; + + $sql = "UPDATE {$table_prefix}billing_coupons SET + code = '$code', + name = '$name', + description = '$description', + discount_percent = $discount_percent, + usage_type = '$usage_type', + game_filter_type = '$game_filter_type', + game_filter_list = " . ($game_filter_list === 'NULL' ? 'NULL' : "'$game_filter_list'") . ", + max_uses = $max_uses, + expires = $expires, + is_active = $is_active + WHERE coupon_id = $coupon_id"; + + if (mysqli_query($db, $sql)) { + $status = "Coupon updated successfully."; + } else { + $error = "Error updating coupon: " . mysqli_error($db); + } + } + + // Delete coupon + elseif (isset($_POST['delete_coupon'])) { + $coupon_id = intval($_POST['coupon_id']); + if (mysqli_query($db, "DELETE FROM {$table_prefix}billing_coupons WHERE coupon_id = $coupon_id")) { + $status = "Coupon deleted successfully."; + } else { + $error = "Error deleting coupon: " . mysqli_error($db); + } + } + } +} + +// Get all available games from server configs +$game_options = []; +$games_dir = __DIR__ . '/../../config_games/server_configs/'; +if (is_dir($games_dir)) { + $files = scandir($games_dir); + foreach ($files as $file) { + if (pathinfo($file, PATHINFO_EXTENSION) === 'xml' && strpos($file, '.bak') === false) { + $game_key = str_replace('.xml', '', $file); + $game_options[] = $game_key; + } + } + sort($game_options); +} + +// Get all coupons +$coupons_result = mysqli_query($db, "SELECT * FROM {$table_prefix}billing_coupons ORDER BY created_date DESC"); +?> + + + + + + Admin — Coupon Management + + + + + + +
+

Coupon Management

+ + +
+ + + +
+ + + +

Add New Coupon

+
+ + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + + +
+ + +
+ +
+ + +
+ + +
+ + +

Existing Coupons

+ + 0): ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CodeNameDiscountTypeGame FilterUsesExpiresStatusActions
% + + + + + + All Games + + specific games + + + + / + + (unlimited) + + + + + + + +
+ + + +
+
+ +

No coupons found. Add your first coupon above.

+ + +
+ + + + + diff --git a/modules/billing/create_coupons_table.sql b/modules/billing/create_coupons_table.sql new file mode 100644 index 00000000..07c9093f --- /dev/null +++ b/modules/billing/create_coupons_table.sql @@ -0,0 +1,106 @@ +-- Enhanced coupon system for billing module +-- This creates a flexible coupon system with game filters and usage tracking + +-- Drop existing table if upgrading from old coupon module +DROP TABLE IF EXISTS `ogp_billing_coupons`; + +-- Create enhanced coupons table +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 when game_filter_type=specific_games', + `max_uses` INT(11) DEFAULT NULL COMMENT 'NULL for unlimited uses', + `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`), + KEY `idx_active_expires` (`is_active`, `expires`), + KEY `idx_created_by` (`created_by`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; + +-- Add coupon_id field to billing_orders if it doesn't exist +SET @tablename = 'ogp_billing_orders'; +SET @checkIfColumnExists = ( + SELECT COUNT(*) + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = @tablename + AND COLUMN_NAME = 'coupon_id' +); + +SET @addColumn = IF(@checkIfColumnExists = 0, + 'ALTER TABLE `ogp_billing_orders` ADD COLUMN `coupon_id` INT(11) DEFAULT NULL AFTER `user_id`, ADD KEY `idx_coupon` (`coupon_id`)', + 'SELECT "Column coupon_id already exists in ogp_billing_orders"' +); + +PREPARE stmt FROM @addColumn; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +-- Add coupon_id field to billing_invoices if it doesn't exist +SET @tablename = 'ogp_billing_invoices'; +SET @checkIfColumnExists = ( + SELECT COUNT(*) + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = @tablename + AND COLUMN_NAME = 'coupon_id' +); + +SET @addColumn = IF(@checkIfColumnExists = 0, + 'ALTER TABLE `ogp_billing_invoices` ADD COLUMN `coupon_id` INT(11) DEFAULT NULL AFTER `user_id`, ADD KEY `idx_coupon` (`coupon_id`)', + 'SELECT "Column coupon_id already exists in ogp_billing_invoices"' +); + +PREPARE stmt FROM @addColumn; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +-- Add discount_amount field to billing_invoices to track actual discount applied +SET @checkIfColumnExists = ( + SELECT COUNT(*) + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'ogp_billing_invoices' + AND COLUMN_NAME = 'discount_amount' +); + +SET @addColumn = IF(@checkIfColumnExists = 0, + 'ALTER TABLE `ogp_billing_invoices` ADD COLUMN `discount_amount` DECIMAL(10,2) NOT NULL DEFAULT 0.00 AFTER `amount`', + 'SELECT "Column discount_amount already exists in ogp_billing_invoices"' +); + +PREPARE stmt FROM @addColumn; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +-- Add discount_amount field to billing_orders to track permanent discounts +SET @checkIfColumnExists = ( + SELECT COUNT(*) + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'ogp_billing_orders' + AND COLUMN_NAME = 'discount_amount' +); + +SET @addColumn = IF(@checkIfColumnExists = 0, + 'ALTER TABLE `ogp_billing_orders` ADD COLUMN `discount_amount` DECIMAL(10,2) NOT NULL DEFAULT 0.00 AFTER `price`', + 'SELECT "Column discount_amount already exists in ogp_billing_orders"' +); + +PREPARE stmt FROM @addColumn; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +-- Sample coupons for testing +INSERT INTO `ogp_billing_coupons` (`code`, `name`, `description`, `discount_percent`, `usage_type`, `game_filter_type`, `game_filter_list`, `expires`) VALUES +('WELCOME10', 'Welcome 10% Off', 'New customer welcome discount - 10% off any game', 10.00, 'one_time', 'all_games', NULL, DATE_ADD(NOW(), INTERVAL 1 YEAR)), +('ARMA25', 'Arma Series 25% Off', 'Save 25% on any Arma game server', 25.00, 'permanent', 'specific_games', '["arma2_win32", "arma2oa_win32", "arma3_linux32", "arma3_linux64", "arma3_win64", "arma-reforger_linux64", "arma-reforger_win64"]', NULL);