fix: standardize billing order status values and apply full-day expiry grace rule

- home_handling_functions.php: display expiration as Y-m-d only (not Y-m-d H:i);
  apply full-day grace by comparing date-only (midnight) in PHP so a server
  expiring on today's date remains Active the entire day
- cron-shop.php Step B & C: change server_expiration_date comparisons from
  < DATE_SUB(NOW(), ...) to DATE(server_expiration_date) < DATE_SUB(CURDATE(), ...)
  ensuring the full expiration day is honoured
- user_games/check_expire.php: change all three expiration queries from
  <= time() to < strtotime(date('Y-m-d')) (today-midnight) for full-day grace
- billing/test_integration.php: replace status='paid' (old order status) with
  status IN ('Active','paid') for backward compat during migration
- user_games/billing_integration.php: clarify comment that billing_invoices.status
  uses the payment lifecycle ('paid'/'unpaid'/'due'), separate from billing_orders.status
- Add modules/billing/sql/normalize_billing_order_status.sql migration script
  to convert installed->Active, paid->Active, suspended->Expired in existing rows
- Update CHANGELOG.md

Agent-Logs-Url: https://github.com/GameServerPanel/GSP/sessions/439845e0-926e-4b49-9cd0-810457b73c12

Co-authored-by: iaretechnician <2749183+iaretechnician@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-05-05 17:24:41 +00:00 committed by GitHub
parent 5f3013b4a4
commit 5b2162fb28
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 79 additions and 20 deletions

View file

@ -0,0 +1,37 @@
-- normalize_billing_order_status.sql
-- ============================================================
-- Migrate legacy billing_orders.status values to the canonical
-- three-value lifecycle used by GSP billing:
--
-- Active server is provisioned and current
-- Invoiced renewal invoice generated; payment due
-- Expired invoice unpaid past due date; server pending deletion
--
-- Old values and their mappings:
-- installed -> Active (was written by old provisioner)
-- paid -> Active (was written after PayPal capture, before provisioning)
-- suspended -> Expired (was written by old cron when overdue)
--
-- Run this ONCE against the panel database after deploying the updated
-- cron-shop.php and application code. It is safe to re-run (idempotent).
-- ============================================================
-- Map old 'installed' to 'Active'
UPDATE `gsp_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 home.php?m=billing&p=provision_servers after this migration.)
UPDATE `gsp_billing_orders`
SET `status` = 'Active'
WHERE `status` = 'paid';
-- Map old 'suspended' to 'Expired'
UPDATE `gsp_billing_orders`
SET `status` = 'Expired'
WHERE `status` = 'suspended';
-- Optional: verify counts after migration
-- SELECT status, COUNT(*) AS count FROM gsp_billing_orders GROUP BY status ORDER BY count DESC;