Panel/modules/billing/api/create_order.php
copilot-swe-agent[bot] 986a4e53b4
refactor(billing): clean architecture with payment gateway abstraction
- Add PaymentGatewayInterface contract for all payment providers
- Add PayPalGateway (reads credentials from config, not hardcoded)
- Add ManualGateway for admin-triggered payments
- Add StripeGateway stub for future implementation
- Add GatewayFactory for gateway instantiation by name
- Add BillingRepository: parameterized-SQL data layer
- Add BillingService: pricing, invoice creation, payment processing
- Add gsp_billing_transactions table (DB version 2) for audit trail
- Add new columns to gsp_billing_invoices (home_id, rate_type, players, period_start/end, subtotal, total_due, payment_status)
- Add gsp_billing_service_remote_servers mapping table
- Move PayPal credentials from api files into config.inc.php
- Fix double session_start() bug in capture_order.php
- Replace raw SQL with prepared statements throughout
- Refactor admin_invoices.php to use billing_invoices + BillingRepository
- Refactor admin_payments.php to read from gsp_billing_transactions
- Update admin.php with links to Transaction Log and Manage Invoices

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Co-authored-by: iaretechnician <2749183+iaretechnician@users.noreply.github.com>
2026-05-02 12:17:36 +00:00

84 lines
2.8 KiB
PHP

<?php
/**
* PayPal Create Order API Endpoint
* Uses PayPalGateway class. Credentials come from config — NOT hardcoded here.
*/
ini_set('display_errors', '0');
error_reporting(E_ALL);
require_once __DIR__ . '/../includes/config_loader.php';
require_once __DIR__ . '/../classes/PaymentGatewayInterface.php';
require_once __DIR__ . '/../classes/PayPalGateway.php';
require_once __DIR__ . '/../classes/GatewayFactory.php';
// Logging
$logDir = __DIR__ . '/../logs';
@mkdir($logDir, 0755, true);
$logFile = $logDir . '/paypal_create_order.log';
$requestId = uniqid('req_', true);
function co_log(string $label, $data): void {
global $logFile, $requestId;
$entry = '[' . date('Y-m-d H:i:s') . "] [$requestId] $label\n";
$entry .= is_array($data) || is_object($data) ? print_r($data, true) : (string)$data;
$entry .= "\n" . str_repeat('-', 80) . "\n";
@file_put_contents($logFile, $entry, FILE_APPEND | LOCK_EX);
}
header('Content-Type: application/json');
$rawInput = file_get_contents('php://input');
$in = json_decode($rawInput, true);
if (json_last_error() !== JSON_ERROR_NONE || !$in) {
http_response_code(400);
echo json_encode(['error' => 'invalid_json', 'request_id' => $requestId]);
exit;
}
co_log('REQUEST', ['amount' => $in['amount'] ?? null, 'invoice_id' => $in['invoice_id'] ?? null]);
// Resolve site base for return/cancel URLs
$siteBase = rtrim($GLOBALS['SITE_BASE_URL'] ?? '', '/');
$returnUrl = $in['return_url'] ?? '/payment_success.php';
$cancelUrl = $in['cancel_url'] ?? '/payment_cancel.php';
// Ensure absolute URLs
if (strpos($returnUrl, 'http') !== 0) {
$returnUrl = $siteBase . '/' . ltrim($returnUrl, '/');
}
if (strpos($cancelUrl, 'http') !== 0) {
$cancelUrl = $siteBase . '/' . ltrim($cancelUrl, '/');
}
// Build gateway params
$params = [
'amount' => $in['amount'] ?? '0.00',
'currency' => $in['currency'] ?? 'USD',
'invoice_id' => $in['invoice_id'] ?? null,
'custom_id' => $in['custom_id'] ?? $in['invoice_id'] ?? null,
'description' => $in['description'] ?? 'Game Server Order',
'return_url' => $returnUrl,
'cancel_url' => $cancelUrl,
'items' => $in['items'] ?? null,
];
try {
$gateway = GatewayFactory::make('paypal');
$result = $gateway->createPayment($params);
} catch (Exception $e) {
co_log('EXCEPTION', $e->getMessage());
http_response_code(500);
echo json_encode(['error' => 'gateway_error', 'message' => $e->getMessage(), 'request_id' => $requestId]);
exit;
}
if (!$result['success']) {
co_log('CREATE_FAILED', $result);
http_response_code(500);
echo json_encode(['error' => $result['error'] ?? 'create_failed', 'request_id' => $requestId]);
exit;
}
co_log('CREATE_SUCCESS', ['provider_order_id' => $result['provider_order_id']]);
echo json_encode($result['raw_response']);