fix billing+migration: correct migration indexes, table name, column names, webhook URL
Agent-Logs-Url: https://github.com/GameServerPanel/GSP/sessions/862c51a7-d835-4eb2-bd0e-2e2a5459036b Co-authored-by: iaretechnician <2749183+iaretechnician@users.noreply.github.com>
This commit is contained in:
parent
9dc051d090
commit
e010085347
7 changed files with 289 additions and 51 deletions
|
|
@ -296,8 +296,9 @@ function exec_ogp_module()
|
|||
|
||||
//WEBHOOK Discord=======================================================================================
|
||||
|
||||
$webhookurl = "https://discord.com/api/webhooks/710275918274363412/g5Tr-EUdEnLfFryOlscxJ6FuPiSJuE6EMKRYmh9UGMiqTUxU5-y9CQrBlDJW7znr0Tol";
|
||||
//$settings['webhookurl'];
|
||||
$webhookurl = !empty($settings['webhookurl']) ? $settings['webhookurl'] : '';
|
||||
|
||||
if (!empty($webhookurl)) {
|
||||
|
||||
|
||||
$msg = "A new server, ". $home_name ." ID #". $home_id . ", has just been created.";
|
||||
|
|
@ -314,6 +315,7 @@ function exec_ogp_module()
|
|||
//If you need to debug, or find out why you can't send message uncomment line below, and execute script.
|
||||
//echo $response;
|
||||
//end WEBHOOK Discord
|
||||
}
|
||||
}
|
||||
// END EMAIL
|
||||
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ $due_for_invoice = $db->resultQuery("
|
|||
AND sh.next_invoice_date IS NOT NULL
|
||||
AND sh.next_invoice_date <= NOW()
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM {$table_prefix}invoices inv
|
||||
SELECT 1 FROM {$table_prefix}billing_invoices inv
|
||||
WHERE inv.home_id = sh.home_id AND inv.billing_status = 'Invoiced'
|
||||
)
|
||||
ORDER BY sh.home_id ASC
|
||||
|
|
@ -142,7 +142,7 @@ if (is_array($due_for_invoice)) {
|
|||
|
||||
// Guard: skip if an invoice for this exact period already exists
|
||||
$exists = $db->resultQuery("
|
||||
SELECT invoice_id FROM {$table_prefix}invoices
|
||||
SELECT invoice_id FROM {$table_prefix}billing_invoices
|
||||
WHERE home_id = {$home_id}
|
||||
AND due_date = '" . $db->realEscapeSingle($due_date) . "'
|
||||
LIMIT 1
|
||||
|
|
@ -152,11 +152,11 @@ if (is_array($due_for_invoice)) {
|
|||
continue;
|
||||
}
|
||||
|
||||
// Create renewal invoice in {prefix}invoices
|
||||
// Create renewal invoice in {prefix}billing_invoices
|
||||
$db->query("
|
||||
INSERT INTO {$table_prefix}invoices
|
||||
INSERT INTO {$table_prefix}billing_invoices
|
||||
(home_id, user_id, due_date, billing_status, rate_type,
|
||||
price_per_player, player_slots, quantity, subtotal, total_due)
|
||||
rate_per_player, players, qty, subtotal, total_due)
|
||||
VALUES (
|
||||
{$home_id}, {$user_id},
|
||||
'" . $db->realEscapeSingle($due_date) . "',
|
||||
|
|
@ -219,10 +219,10 @@ $past_due = $db->resultQuery("
|
|||
AND (
|
||||
sh.last_invoice_id IS NULL
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM {$table_prefix}invoices inv
|
||||
SELECT 1 FROM {$table_prefix}billing_invoices inv
|
||||
WHERE inv.invoice_id = sh.last_invoice_id
|
||||
AND inv.billing_status = 'Invoiced'
|
||||
AND inv.paid_at IS NULL
|
||||
AND inv.paid_date IS NULL
|
||||
)
|
||||
)
|
||||
ORDER BY sh.home_id ASC
|
||||
|
|
@ -243,11 +243,11 @@ if (is_array($past_due)) {
|
|||
// Mark matching invoice Expired (if still unpaid)
|
||||
if ($last_invoice_id > 0) {
|
||||
$db->query("
|
||||
UPDATE {$table_prefix}invoices
|
||||
UPDATE {$table_prefix}billing_invoices
|
||||
SET billing_status = 'Expired'
|
||||
WHERE invoice_id = {$last_invoice_id}
|
||||
AND billing_status = 'Invoiced'
|
||||
AND paid_at IS NULL
|
||||
AND paid_date IS NULL
|
||||
");
|
||||
}
|
||||
|
||||
|
|
@ -358,9 +358,9 @@ if (is_array($to_delete)) {
|
|||
WHERE home_id = '{$home_id}'
|
||||
");
|
||||
|
||||
// Mark any open gsp_invoices for this home as Expired
|
||||
// Mark any open billing_invoices for this home as Expired
|
||||
$db->query("
|
||||
UPDATE {$table_prefix}invoices
|
||||
UPDATE {$table_prefix}billing_invoices
|
||||
SET billing_status = 'Expired'
|
||||
WHERE home_id = {$home_id}
|
||||
AND billing_status = 'Invoiced'
|
||||
|
|
@ -394,11 +394,11 @@ $db->logger("BILLING-CRON: --- Step D: Paid invoice safety-net ---");
|
|||
$paid_invoices = $db->resultQuery("
|
||||
SELECT inv.invoice_id, inv.home_id, inv.rate_type,
|
||||
sh.billing_status
|
||||
FROM {$table_prefix}invoices inv
|
||||
FROM {$table_prefix}billing_invoices inv
|
||||
INNER JOIN {$table_prefix}server_homes sh ON sh.home_id = inv.home_id
|
||||
WHERE inv.billing_status = 'Invoiced'
|
||||
AND sh.billing_status = 'Invoiced'
|
||||
AND (inv.paid_at IS NOT NULL OR inv.payment_id IS NOT NULL)
|
||||
AND (inv.paid_date IS NOT NULL OR inv.payment_txid IS NOT NULL)
|
||||
ORDER BY inv.invoice_id ASC
|
||||
");
|
||||
|
||||
|
|
@ -413,7 +413,7 @@ if (is_array($paid_invoices)) {
|
|||
$next_invoice_date = date('Y-m-d H:i:s', strtotime($period_map[$rate_type] ?? '+1 month'));
|
||||
|
||||
$db->query("
|
||||
UPDATE {$table_prefix}invoices
|
||||
UPDATE {$table_prefix}billing_invoices
|
||||
SET billing_status = 'Active'
|
||||
WHERE invoice_id = {$invoice_id}
|
||||
");
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
// Module general information
|
||||
$module_title = "billing";
|
||||
$module_version = "3.2";
|
||||
$db_version = 1;
|
||||
$db_version = 2;
|
||||
$module_required = FALSE;
|
||||
// Module description
|
||||
$module_description = "Billing storefront / provisioning integration. Public ordering runs as a standalone site; panel pages provide provisioning and admin order management.";
|
||||
|
|
@ -36,12 +36,14 @@ $module_menus = array();
|
|||
|
||||
$install_queries = array();
|
||||
|
||||
// Baseline schema — all billing tables with their final column set.
|
||||
// This is the single source of truth for fresh installs.
|
||||
// -----------------------------------------------------------------------
|
||||
// db_version 1 — Baseline schema for fresh installs.
|
||||
// All CREATE TABLE statements use IF NOT EXISTS so they are safe to re-run.
|
||||
// Existing installs at any previous db_version already have these tables and columns,
|
||||
// so no incremental ALTER chains are needed here.
|
||||
$install_queries[0] = array(
|
||||
// NOTE: The panel updater runs $install_queries[$i+1] when upgrading a
|
||||
// module from db_version $i. A module installed fresh at db_version 0
|
||||
// therefore runs $install_queries[1], not $install_queries[0].
|
||||
// -----------------------------------------------------------------------
|
||||
$install_queries[1] = array(
|
||||
// Billing Services — available game server packages
|
||||
"CREATE TABLE IF NOT EXISTS `".OGP_DB_PREFIX."billing_services` (
|
||||
`service_id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
|
|
@ -78,6 +80,7 @@ $install_queries[0] = array(
|
|||
`invoice_duration` VARCHAR(16) NOT NULL DEFAULT 'month',
|
||||
`max_players` INT(11) NOT NULL DEFAULT 0,
|
||||
`price` FLOAT(15,2) NOT NULL DEFAULT 0,
|
||||
`discount_amount` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
|
||||
`remote_control_password` VARCHAR(255) NULL,
|
||||
`ftp_password` VARCHAR(255) NULL,
|
||||
`home_id` VARCHAR(255) NOT NULL DEFAULT '0',
|
||||
|
|
@ -95,11 +98,13 @@ $install_queries[0] = array(
|
|||
|
||||
// Billing Invoices — created on cart add, paid after payment capture.
|
||||
// home_id is 0 until the service is provisioned after payment.
|
||||
// billing_status tracks the renewal lifecycle (Active / Invoiced / Expired)
|
||||
// independently of payment_status which tracks the payment state.
|
||||
"CREATE TABLE IF NOT EXISTS `".OGP_DB_PREFIX."billing_invoices` (
|
||||
`invoice_id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`order_id` INT(11) NOT NULL DEFAULT 0,
|
||||
`user_id` INT(11) NOT NULL,
|
||||
`service_id` INT(11) NOT NULL,
|
||||
`service_id` INT(11) NOT NULL DEFAULT 0,
|
||||
`home_id` INT(11) NOT NULL DEFAULT 0,
|
||||
`home_name` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`ip` INT(11) NOT NULL DEFAULT 0,
|
||||
|
|
@ -109,8 +114,10 @@ $install_queries[0] = array(
|
|||
`customer_name` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`customer_email` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`amount` FLOAT(15,2) NOT NULL DEFAULT 0,
|
||||
`discount_amount` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
|
||||
`currency` VARCHAR(3) NOT NULL DEFAULT 'USD',
|
||||
`status` VARCHAR(16) NOT NULL DEFAULT 'due',
|
||||
`billing_status` VARCHAR(16) NOT NULL DEFAULT 'due',
|
||||
`invoice_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`due_date` DATETIME NULL,
|
||||
`paid_date` DATETIME NULL,
|
||||
|
|
@ -127,12 +134,15 @@ $install_queries[0] = array(
|
|||
`total_due` DECIMAL(15,2) NOT NULL DEFAULT 0,
|
||||
`payment_status` ENUM('unpaid','paid','cancelled','refunded') NOT NULL DEFAULT 'unpaid',
|
||||
`qty` INT(11) NOT NULL DEFAULT 1,
|
||||
`coupon_id` INT(11) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`invoice_id`),
|
||||
KEY `order_id` (`order_id`),
|
||||
KEY `user_id` (`user_id`),
|
||||
KEY `status` (`status`),
|
||||
KEY `due_date` (`due_date`),
|
||||
KEY `service_id` (`service_id`)
|
||||
KEY `order_id` (`order_id`),
|
||||
KEY `user_id` (`user_id`),
|
||||
KEY `home_id` (`home_id`),
|
||||
KEY `status` (`status`),
|
||||
KEY `due_date` (`due_date`),
|
||||
KEY `service_id` (`service_id`),
|
||||
KEY `coupon_id` (`coupon_id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;",
|
||||
|
||||
// Billing Transactions — immutable payment audit trail
|
||||
|
|
@ -157,8 +167,163 @@ $install_queries[0] = array(
|
|||
KEY `payment_method` (`payment_method`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;",
|
||||
|
||||
// Billing Coupons — discount codes
|
||||
"CREATE TABLE IF NOT EXISTS `".OGP_DB_PREFIX."billing_coupons` (
|
||||
`coupon_id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`code` VARCHAR(50) NOT NULL,
|
||||
`name` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`description` TEXT NULL,
|
||||
`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 NULL,
|
||||
`max_uses` INT(11) NULL,
|
||||
`current_uses` INT(11) NOT NULL DEFAULT 0,
|
||||
`expires` DATETIME NULL,
|
||||
`created_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`created_by` INT(11) 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;",
|
||||
|
||||
// Billing Config — global and per-game-key billing settings used by cron
|
||||
"CREATE TABLE IF NOT EXISTS `".OGP_DB_PREFIX."billing_config` (
|
||||
`config_id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`game_key` VARCHAR(100) NULL DEFAULT NULL,
|
||||
`enabled` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`grace_days` INT(11) NOT NULL DEFAULT 0,
|
||||
`delete_after_expired_days` INT(11) NOT NULL DEFAULT 7,
|
||||
`rate_type` ENUM('daily','monthly','yearly') NOT NULL DEFAULT 'monthly',
|
||||
`price_per_player` DECIMAL(10,4) NOT NULL DEFAULT 0.0000,
|
||||
PRIMARY KEY (`config_id`),
|
||||
KEY `game_key` (`game_key`),
|
||||
KEY `enabled` (`enabled`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;",
|
||||
|
||||
// Drop legacy mapping table if it still exists from older installs
|
||||
"DROP TABLE IF EXISTS `".OGP_DB_PREFIX."billing_service_remote_servers`"
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// db_version 2 — Safe idempotent column migrations for existing installs.
|
||||
// Each callable checks whether the column already exists before running
|
||||
// ALTER TABLE, so this migration can be re-run without errors.
|
||||
// -----------------------------------------------------------------------
|
||||
$install_queries[2] = array(
|
||||
// billing_orders: add discount_amount if missing
|
||||
function($db) {
|
||||
if (!$db->query("ALTER TABLE `OGP_DB_PREFIXbilling_orders` ADD `discount_amount` DECIMAL(10,2) NOT NULL DEFAULT 0.00 AFTER `price`")) {
|
||||
return (stripos((string)$db->getError(), 'Duplicate column') !== false);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// billing_invoices: add home_id if missing (needed by cron-shop.php join)
|
||||
function($db) {
|
||||
if (!$db->query("ALTER TABLE `OGP_DB_PREFIXbilling_invoices` ADD `home_id` INT(11) NOT NULL DEFAULT 0 AFTER `service_id`")) {
|
||||
return (stripos((string)$db->getError(), 'Duplicate column') !== false);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// billing_invoices: add discount_amount if missing
|
||||
function($db) {
|
||||
if (!$db->query("ALTER TABLE `OGP_DB_PREFIXbilling_invoices` ADD `discount_amount` DECIMAL(10,2) NOT NULL DEFAULT 0.00 AFTER `amount`")) {
|
||||
return (stripos((string)$db->getError(), 'Duplicate column') !== false);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// billing_invoices: add billing_status (lifecycle: Active/Invoiced/Expired) if missing
|
||||
function($db) {
|
||||
if (!$db->query("ALTER TABLE `OGP_DB_PREFIXbilling_invoices` ADD `billing_status` VARCHAR(16) NOT NULL DEFAULT 'due' AFTER `status`")) {
|
||||
return (stripos((string)$db->getError(), 'Duplicate column') !== false);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// billing_invoices: add rate_type enum if missing
|
||||
function($db) {
|
||||
if (!$db->query("ALTER TABLE `OGP_DB_PREFIXbilling_invoices` ADD `rate_type` ENUM('daily','monthly','yearly') NOT NULL DEFAULT 'monthly' AFTER `invoice_duration`")) {
|
||||
return (stripos((string)$db->getError(), 'Duplicate column') !== false);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// billing_invoices: add rate_per_player if missing
|
||||
function($db) {
|
||||
if (!$db->query("ALTER TABLE `OGP_DB_PREFIXbilling_invoices` ADD `rate_per_player` DECIMAL(15,4) NOT NULL DEFAULT 0 AFTER `rate_type`")) {
|
||||
return (stripos((string)$db->getError(), 'Duplicate column') !== false);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// billing_invoices: add players if missing
|
||||
function($db) {
|
||||
if (!$db->query("ALTER TABLE `OGP_DB_PREFIXbilling_invoices` ADD `players` INT(11) NOT NULL DEFAULT 0 AFTER `rate_per_player`")) {
|
||||
return (stripos((string)$db->getError(), 'Duplicate column') !== false);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// billing_invoices: add subtotal if missing
|
||||
function($db) {
|
||||
if (!$db->query("ALTER TABLE `OGP_DB_PREFIXbilling_invoices` ADD `subtotal` DECIMAL(15,2) NOT NULL DEFAULT 0 AFTER `players`")) {
|
||||
return (stripos((string)$db->getError(), 'Duplicate column') !== false);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// billing_invoices: add total_due if missing
|
||||
function($db) {
|
||||
if (!$db->query("ALTER TABLE `OGP_DB_PREFIXbilling_invoices` ADD `total_due` DECIMAL(15,2) NOT NULL DEFAULT 0 AFTER `subtotal`")) {
|
||||
return (stripos((string)$db->getError(), 'Duplicate column') !== false);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// billing_invoices: add payment_status enum if missing
|
||||
function($db) {
|
||||
if (!$db->query("ALTER TABLE `OGP_DB_PREFIXbilling_invoices` ADD `payment_status` ENUM('unpaid','paid','cancelled','refunded') NOT NULL DEFAULT 'unpaid' AFTER `currency`")) {
|
||||
return (stripos((string)$db->getError(), 'Duplicate column') !== false);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// billing_invoices: add coupon_id if missing
|
||||
function($db) {
|
||||
if (!$db->query("ALTER TABLE `OGP_DB_PREFIXbilling_invoices` ADD `coupon_id` INT(11) NOT NULL DEFAULT 0 AFTER `qty`")) {
|
||||
return (stripos((string)$db->getError(), 'Duplicate column') !== false);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// Create billing_config table for cron-shop settings if missing
|
||||
"CREATE TABLE IF NOT EXISTS `OGP_DB_PREFIXbilling_config` (
|
||||
`config_id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`game_key` VARCHAR(100) NULL DEFAULT NULL,
|
||||
`enabled` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`grace_days` INT(11) NOT NULL DEFAULT 0,
|
||||
`delete_after_expired_days` INT(11) NOT NULL DEFAULT 7,
|
||||
`rate_type` ENUM('daily','monthly','yearly') NOT NULL DEFAULT 'monthly',
|
||||
`price_per_player` DECIMAL(10,4) NOT NULL DEFAULT 0.0000,
|
||||
PRIMARY KEY (`config_id`),
|
||||
KEY `game_key` (`game_key`),
|
||||
KEY `enabled` (`enabled`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;",
|
||||
// Create billing_coupons table if missing (older installs using panel.sql may not have it)
|
||||
"CREATE TABLE IF NOT EXISTS `OGP_DB_PREFIXbilling_coupons` (
|
||||
`coupon_id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`code` VARCHAR(50) NOT NULL,
|
||||
`name` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`description` TEXT NULL,
|
||||
`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 NULL,
|
||||
`max_uses` INT(11) NULL,
|
||||
`current_uses` INT(11) NOT NULL DEFAULT 0,
|
||||
`expires` DATETIME NULL,
|
||||
`created_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`created_by` INT(11) 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;"
|
||||
);
|
||||
|
||||
?>
|
||||
|
|
|
|||
|
|
@ -19,23 +19,23 @@
|
|||
-- 'Expired') are left unchanged.
|
||||
--
|
||||
-- Compatible with MySQL 5.7+ and MariaDB 10.2+.
|
||||
-- Table prefix is hardcoded to gsp_ (standalone billing module context).
|
||||
-- IMPORTANT: Replace <PREFIX> below with your table prefix (e.g. gsp_ or ogp_) (standalone billing module context).
|
||||
-- Run ONCE on an existing installation; safe to run again (no-op on clean data).
|
||||
|
||||
-- 'installed' → 'Active'
|
||||
UPDATE `gsp_billing_orders`
|
||||
UPDATE `<PREFIX>billing_orders`
|
||||
SET `status` = 'Active'
|
||||
WHERE `status` = 'installed';
|
||||
|
||||
-- 'paid' → 'Active'
|
||||
UPDATE `gsp_billing_orders`
|
||||
UPDATE `<PREFIX>billing_orders`
|
||||
SET `status` = 'Active'
|
||||
WHERE `status` = 'paid';
|
||||
|
||||
-- 'suspended' → 'Invoiced'
|
||||
-- These rows had an open renewal invoice; cron-shop Step B will move them to
|
||||
-- 'Expired' on the next run if the invoice remains unpaid.
|
||||
UPDATE `gsp_billing_orders`
|
||||
UPDATE `<PREFIX>billing_orders`
|
||||
SET `status` = 'Invoiced'
|
||||
WHERE `status` = 'suspended';
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ UPDATE `gsp_billing_orders`
|
|||
-- Expected result: only rows with status IN ('Active','Invoiced','Expired',
|
||||
-- 'in-cart','cancelled','refunded') should appear.
|
||||
SELECT `status`, COUNT(*) AS `count`
|
||||
FROM `gsp_billing_orders`
|
||||
FROM `<PREFIX>billing_orders`
|
||||
GROUP BY `status`
|
||||
ORDER BY `status`;
|
||||
|
||||
|
|
@ -56,8 +56,8 @@ SELECT o.`order_id`,
|
|||
o.`home_id` AS missing_home_id,
|
||||
o.`status`,
|
||||
o.`end_date`
|
||||
FROM `gsp_billing_orders` o
|
||||
LEFT JOIN `gsp_server_homes` sh ON sh.`home_id` = o.`home_id`
|
||||
FROM `<PREFIX>billing_orders` o
|
||||
LEFT JOIN `<PREFIX>server_homes` sh ON sh.`home_id` = o.`home_id`
|
||||
WHERE o.`home_id` != '0'
|
||||
AND o.`home_id` != ''
|
||||
AND sh.`home_id` IS NULL
|
||||
|
|
|
|||
|
|
@ -3,18 +3,18 @@
|
|||
-- Idempotent migration: adds columns required by the billing checkout fixes.
|
||||
-- Safe to run multiple times (uses IF-based prepared statements).
|
||||
-- Run against the panel database after deploying the updated PHP files.
|
||||
-- Table prefix is hardcoded to gsp_.
|
||||
-- IMPORTANT: Replace <PREFIX> with your actual table prefix (e.g. gsp_ or ogp_).
|
||||
-- =============================================================================
|
||||
|
||||
SET @db = DATABASE();
|
||||
SET @tbl = 'gsp_billing_invoices';
|
||||
SET @tbl = '<PREFIX>billing_invoices';
|
||||
|
||||
-- 1) coupon_id — tracks which coupon was applied to an invoice
|
||||
SET @cnt = 0;
|
||||
SELECT COUNT(*) INTO @cnt FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = @tbl AND COLUMN_NAME = 'coupon_id';
|
||||
SET @sql = IF(@cnt = 0,
|
||||
'ALTER TABLE `gsp_billing_invoices` ADD COLUMN `coupon_id` INT(11) NOT NULL DEFAULT 0 AFTER `qty`',
|
||||
'ALTER TABLE `<PREFIX>billing_invoices` ADD COLUMN `coupon_id` INT(11) NOT NULL DEFAULT 0 AFTER `qty`',
|
||||
'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ SET @cnt = 0;
|
|||
SELECT COUNT(*) INTO @cnt FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = @tbl AND COLUMN_NAME = 'discount_amount';
|
||||
SET @sql = IF(@cnt = 0,
|
||||
'ALTER TABLE `gsp_billing_invoices` ADD COLUMN `discount_amount` DECIMAL(10,2) NOT NULL DEFAULT 0.00 AFTER `amount`',
|
||||
'ALTER TABLE `<PREFIX>billing_invoices` ADD COLUMN `discount_amount` DECIMAL(10,2) NOT NULL DEFAULT 0.00 AFTER `amount`',
|
||||
'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
|
|
@ -33,14 +33,14 @@ SET @cnt = 0;
|
|||
SELECT COUNT(*) INTO @cnt FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = @tbl AND COLUMN_NAME = 'payment_status';
|
||||
SET @sql = IF(@cnt = 0,
|
||||
"ALTER TABLE `gsp_billing_invoices` ADD COLUMN `payment_status` ENUM('unpaid','paid','cancelled','refunded') NOT NULL DEFAULT 'unpaid' AFTER `currency`",
|
||||
"ALTER TABLE `<PREFIX>billing_invoices` ADD COLUMN `payment_status` ENUM('unpaid','paid','cancelled','refunded') NOT NULL DEFAULT 'unpaid' AFTER `currency`",
|
||||
'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- Backfill payment_status for existing rows:
|
||||
-- 'paid' → payment_status = 'paid'
|
||||
-- anything else → payment_status = 'unpaid'
|
||||
UPDATE `gsp_billing_invoices`
|
||||
UPDATE `<PREFIX>billing_invoices`
|
||||
SET `payment_status` = 'paid'
|
||||
WHERE `status` = 'paid' AND `payment_status` <> 'paid';
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ SET @cnt = 0;
|
|||
SELECT COUNT(*) INTO @cnt FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = @tbl AND COLUMN_NAME = 'subtotal';
|
||||
SET @sql = IF(@cnt = 0,
|
||||
'ALTER TABLE `gsp_billing_invoices` ADD COLUMN `subtotal` DECIMAL(15,2) NOT NULL DEFAULT 0 AFTER `discount_amount`',
|
||||
'ALTER TABLE `<PREFIX>billing_invoices` ADD COLUMN `subtotal` DECIMAL(15,2) NOT NULL DEFAULT 0 AFTER `discount_amount`',
|
||||
'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ SET @cnt = 0;
|
|||
SELECT COUNT(*) INTO @cnt FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = @tbl AND COLUMN_NAME = 'total_due';
|
||||
SET @sql = IF(@cnt = 0,
|
||||
'ALTER TABLE `gsp_billing_invoices` ADD COLUMN `total_due` DECIMAL(15,2) NOT NULL DEFAULT 0 AFTER `subtotal`',
|
||||
'ALTER TABLE `<PREFIX>billing_invoices` ADD COLUMN `total_due` DECIMAL(15,2) NOT NULL DEFAULT 0 AFTER `subtotal`',
|
||||
'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
|
|
@ -67,21 +67,21 @@ SET @cnt = 0;
|
|||
SELECT COUNT(*) INTO @cnt FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = @tbl AND INDEX_NAME = 'coupon_id';
|
||||
SET @sql = IF(@cnt = 0,
|
||||
'ALTER TABLE `gsp_billing_invoices` ADD KEY `coupon_id` (`coupon_id`)',
|
||||
'ALTER TABLE `<PREFIX>billing_invoices` ADD KEY `coupon_id` (`coupon_id`)',
|
||||
'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- -------------------------
|
||||
-- billing_orders additions
|
||||
-- -------------------------
|
||||
SET @tbl = 'gsp_billing_orders';
|
||||
SET @tbl = '<PREFIX>billing_orders';
|
||||
|
||||
-- 7) coupon_id on billing_orders (already in baseline schema but guard for older installs)
|
||||
SET @cnt = 0;
|
||||
SELECT COUNT(*) INTO @cnt FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = @tbl AND COLUMN_NAME = 'coupon_id';
|
||||
SET @sql = IF(@cnt = 0,
|
||||
'ALTER TABLE `gsp_billing_orders` ADD COLUMN `coupon_id` INT(11) NOT NULL DEFAULT 0 AFTER `paid_ts`',
|
||||
'ALTER TABLE `<PREFIX>billing_orders` ADD COLUMN `coupon_id` INT(11) NOT NULL DEFAULT 0 AFTER `paid_ts`',
|
||||
'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ SET @cnt = 0;
|
|||
SELECT COUNT(*) INTO @cnt FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = @tbl AND COLUMN_NAME = 'discount_amount';
|
||||
SET @sql = IF(@cnt = 0,
|
||||
'ALTER TABLE `gsp_billing_orders` ADD COLUMN `discount_amount` DECIMAL(10,2) NOT NULL DEFAULT 0.00 AFTER `price`',
|
||||
'ALTER TABLE `<PREFIX>billing_orders` ADD COLUMN `discount_amount` DECIMAL(10,2) NOT NULL DEFAULT 0.00 AFTER `price`',
|
||||
'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
|
|
|
|||
|
|
@ -17,19 +17,19 @@
|
|||
-- ============================================================
|
||||
|
||||
-- Map old 'installed' to 'Active'
|
||||
UPDATE `gsp_billing_orders`
|
||||
UPDATE `<PREFIX>billing_orders`
|
||||
SET `status` = 'Active'
|
||||
WHERE `status` = 'installed';
|
||||
|
||||
-- Map old 'paid' to 'Active'
|
||||
-- (Orders that were paid but not yet provisioned should be provisioned
|
||||
-- via the admin orders panel after this migration.)
|
||||
UPDATE `gsp_billing_orders`
|
||||
UPDATE `<PREFIX>billing_orders`
|
||||
SET `status` = 'Active'
|
||||
WHERE `status` = 'paid';
|
||||
|
||||
-- Map old 'suspended' to 'Expired'
|
||||
UPDATE `gsp_billing_orders`
|
||||
UPDATE `<PREFIX>billing_orders`
|
||||
SET `status` = 'Expired'
|
||||
WHERE `status` = 'suspended';
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
// Module general information
|
||||
$module_title = "Game manager";
|
||||
$module_version = "1.33";
|
||||
$db_version = 1;
|
||||
$db_version = 2;
|
||||
$module_required = TRUE;
|
||||
$module_menus = array( array( 'subpage' => 'game_monitor', 'name'=>'Game Monitor', 'group'=>'user' ) );
|
||||
$module_access_rights = array('u' => 'allow_updates', 'p' => 'allow_parameter_usage', 'e' => 'allow_extra_params', 'c' => 'allow_custom_fields');
|
||||
|
|
@ -87,4 +87,75 @@ $install_queries[0] = array(
|
|||
`server_status_cache` longtext NOT NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1;"
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// db_version 2 — Add billing lifecycle columns to server_homes.
|
||||
// Each callable is idempotent: it checks whether the column already exists
|
||||
// and treats a "Duplicate column name" error as success (not a real failure).
|
||||
// -----------------------------------------------------------------------
|
||||
$install_queries[2] = array(
|
||||
// billing_status: current lifecycle state (Active / Invoiced / Expired)
|
||||
function($db) {
|
||||
if (!$db->query("ALTER TABLE `OGP_DB_PREFIXserver_homes` ADD `billing_status` VARCHAR(16) NOT NULL DEFAULT 'Active'")) {
|
||||
return (stripos((string)$db->getError(), 'Duplicate column') !== false);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// billing_enabled: whether this server participates in billing automation
|
||||
function($db) {
|
||||
if (!$db->query("ALTER TABLE `OGP_DB_PREFIXserver_homes` ADD `billing_enabled` TINYINT(1) NOT NULL DEFAULT 0")) {
|
||||
return (stripos((string)$db->getError(), 'Duplicate column') !== false);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// next_invoice_date: when cron-shop should generate the next renewal invoice
|
||||
function($db) {
|
||||
if (!$db->query("ALTER TABLE `OGP_DB_PREFIXserver_homes` ADD `next_invoice_date` DATETIME NULL DEFAULT NULL")) {
|
||||
return (stripos((string)$db->getError(), 'Duplicate column') !== false);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// last_invoice_id: FK to billing_invoices.invoice_id (most recent renewal)
|
||||
function($db) {
|
||||
if (!$db->query("ALTER TABLE `OGP_DB_PREFIXserver_homes` ADD `last_invoice_id` INT(11) NOT NULL DEFAULT 0")) {
|
||||
return (stripos((string)$db->getError(), 'Duplicate column') !== false);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// billing_expires_at: canonical billing expiration date (DATETIME)
|
||||
function($db) {
|
||||
if (!$db->query("ALTER TABLE `OGP_DB_PREFIXserver_homes` ADD `billing_expires_at` DATETIME NULL DEFAULT NULL")) {
|
||||
return (stripos((string)$db->getError(), 'Duplicate column') !== false);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// billing_price: price stored at provisioning time for renewals
|
||||
function($db) {
|
||||
if (!$db->query("ALTER TABLE `OGP_DB_PREFIXserver_homes` ADD `billing_price` DECIMAL(15,4) NOT NULL DEFAULT 0.0000")) {
|
||||
return (stripos((string)$db->getError(), 'Duplicate column') !== false);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// billing_rate_type: 'daily' / 'monthly' / 'yearly'
|
||||
function($db) {
|
||||
if (!$db->query("ALTER TABLE `OGP_DB_PREFIXserver_homes` ADD `billing_rate_type` ENUM('daily','monthly','yearly') NOT NULL DEFAULT 'monthly'")) {
|
||||
return (stripos((string)$db->getError(), 'Duplicate column') !== false);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// billing_players: slot count used to calculate per-player pricing
|
||||
function($db) {
|
||||
if (!$db->query("ALTER TABLE `OGP_DB_PREFIXserver_homes` ADD `billing_players` INT(11) NOT NULL DEFAULT 0")) {
|
||||
return (stripos((string)$db->getError(), 'Duplicate column') !== false);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// billing_invoice_sent_at: timestamp of last renewal invoice email
|
||||
function($db) {
|
||||
if (!$db->query("ALTER TABLE `OGP_DB_PREFIXserver_homes` ADD `billing_invoice_sent_at` DATETIME NULL DEFAULT NULL")) {
|
||||
return (stripos((string)$db->getError(), 'Duplicate column') !== false);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
);
|
||||
?>
|
||||
Loading…
Add table
Add a link
Reference in a new issue