mirror of
https://github.com/myronblair/tomtomgames-app
synced 2026-06-30 17:49:57 -05:00
164 lines
7.7 KiB
PHP
164 lines
7.7 KiB
PHP
<?php
|
|
require_once __DIR__ . '/../../includes/auth.php';
|
|
require_once __DIR__ . '/../../includes/square.php';
|
|
|
|
header('Content-Type: application/json');
|
|
|
|
if (!isLoggedIn()) { echo json_encode(['success'=>false,'error'=>'Not authenticated']); exit; }
|
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false,'error'=>'Method not allowed']); exit; }
|
|
|
|
$data = json_decode(file_get_contents('php://input'), true);
|
|
$sourceId = trim($data['source_id'] ?? '');
|
|
$tokens = (int)($data['tokens'] ?? 0);
|
|
$priceCents = (int)($data['price_cents'] ?? 0);
|
|
$method = trim($data['method'] ?? 'card');
|
|
$platformId = trim($data['platform_id'] ?? '');
|
|
$gameAlias = trim($data['game_alias'] ?? '');
|
|
$playerName = trim($data['player_name'] ?? '');
|
|
$isCustom = (bool)($data['is_custom'] ?? false);
|
|
$billing = $data['billing'] ?? [];
|
|
$userId = $_SESSION['user_id'];
|
|
|
|
// ─── Validate ─────────────────────────────────────────────
|
|
if ($tokens < 1 || $priceCents < 100) {
|
|
echo json_encode(['success'=>false,'error'=>'Minimum purchase is $1 (1 token).']); exit;
|
|
}
|
|
|
|
// Validate preset packages (custom bypasses preset check)
|
|
if (!$isCustom) {
|
|
$packages = json_decode(TOKEN_PACKAGES, true);
|
|
$validPkg = false;
|
|
foreach ($packages as $pkg) {
|
|
if ($pkg['tokens'] === $tokens && ($pkg['price'] * 100) === $priceCents) { $validPkg = true; break; }
|
|
}
|
|
if (!$validPkg) {
|
|
echo json_encode(['success'=>false,'error'=>'Invalid token package.']); exit;
|
|
}
|
|
} else {
|
|
// Custom: tokens must equal dollars (1:1 ratio), cap at $500
|
|
if ($tokens !== ($priceCents / 100) || $tokens > 500) {
|
|
echo json_encode(['success'=>false,'error'=>'Invalid custom amount.']); exit;
|
|
}
|
|
}
|
|
|
|
// Sanitize billing fields
|
|
$billingFirst = substr(trim($billing['first_name'] ?? ''), 0, 80);
|
|
$billingLast = substr(trim($billing['last_name'] ?? ''), 0, 80);
|
|
$billingAddress = substr(trim($billing['address'] ?? ''), 0, 200);
|
|
$billingCity = substr(trim($billing['city'] ?? ''), 0, 80);
|
|
$billingState = strtoupper(substr(trim($billing['state'] ?? ''), 0, 2));
|
|
$billingZip = substr(trim($billing['zip'] ?? ''), 0, 10);
|
|
$billingEmail = substr(strtolower(trim($billing['email'] ?? '')), 0, 150);
|
|
$cardholderName = trim("$billingFirst $billingLast");
|
|
|
|
$isManual = in_array($method, ['venmo','chime','cashapp','zelle']);
|
|
|
|
// ─── Manual payment ────────────────────────────────────────
|
|
if ($isManual) {
|
|
$stmt = db()->prepare("
|
|
INSERT INTO token_purchases
|
|
(user_id, tokens, amount_cents, payment_method, platform_id, game_alias,
|
|
player_name, billing_name, billing_email, is_custom, status)
|
|
VALUES (?,?,?,?,?,?,?,?,?,?,'pending')
|
|
");
|
|
$stmt->execute([
|
|
$userId, $tokens, $priceCents, $method, $platformId, $gameAlias,
|
|
$playerName, $cardholderName, $billingEmail, $isCustom ? 1 : 0
|
|
]);
|
|
$pid = db()->lastInsertId();
|
|
logActivity('manual_payment_pending', $userId, null, 'purchase', 0, "Manual payment pending: {$paymentMethod} \${$amountDollars}");
|
|
echo json_encode(['success'=>true,'manual'=>true,'purchase_id'=>$pid,
|
|
'message'=>"Request #{$pid} submitted! Tokens credited after payment verification."]);
|
|
exit;
|
|
}
|
|
|
|
// ─── Card payment via Square ───────────────────────────────
|
|
if (empty($sourceId)) { echo json_encode(['success'=>false,'error'=>'Card payment token required.']); exit; }
|
|
|
|
$square = new SquarePayment();
|
|
$note = "TomGames {$tokens}tok | {$platformId} | {$gameAlias} | user#{$userId}" . ($isCustom ? ' [CUSTOM]' : '');
|
|
|
|
// Build buyer info for Square
|
|
$buyerInfo = [];
|
|
if ($cardholderName) $buyerInfo['buyer_email_address'] = $billingEmail ?: null;
|
|
$billingAddr = [];
|
|
if ($billingAddress) $billingAddr['address_line_1'] = $billingAddress;
|
|
if ($billingCity) $billingAddr['locality'] = $billingCity;
|
|
if ($billingState) $billingAddr['administrative_district_level_1'] = $billingState;
|
|
if ($billingZip) $billingAddr['postal_code'] = $billingZip;
|
|
$billingAddr['country'] = 'US';
|
|
|
|
$result = $square->charge($sourceId, $priceCents, $note, $cardholderName, $billingAddr, $billingEmail);
|
|
|
|
if (!$result['success']) {
|
|
// Log failed attempt
|
|
db()->prepare("INSERT INTO token_purchases (user_id,tokens,amount_cents,payment_method,platform_id,game_alias,player_name,billing_name,billing_email,is_custom,status,failure_reason) VALUES (?,?,?,'card',?,?,?,?,?,?,'failed',?)")
|
|
->execute([$userId,$tokens,$priceCents,$platformId,$gameAlias,$playerName,$cardholderName,$billingEmail,$isCustom?1:0,$result['error']]);
|
|
echo json_encode(['success'=>false,'error'=>$result['error']]); exit;
|
|
}
|
|
|
|
// ─── Credit tokens ─────────────────────────────────────────
|
|
db()->beginTransaction();
|
|
try {
|
|
db()->prepare("UPDATE users SET tokens=tokens+? WHERE id=?")->execute([$tokens,$userId]);
|
|
$cardBrand = $result['card_brand'] ?? null;
|
|
$cardLast4 = $result['last_4'] ?? null;
|
|
$receiptUrl= $result['receipt_url'] ?? null;
|
|
|
|
db()->prepare("
|
|
INSERT INTO token_purchases
|
|
(user_id, tokens, amount_cents, payment_method, square_payment_id,
|
|
platform_id, game_alias, player_name, billing_name, billing_address,
|
|
billing_city, billing_state, billing_zip, billing_email,
|
|
is_custom, card_brand, card_last4, receipt_url, status)
|
|
VALUES (?,?,?,'card',?,?,?,?,?,?,?,?,?,?,?,?,?,?,'completed')
|
|
")->execute([
|
|
$userId, $tokens, $priceCents, $result['payment_id'],
|
|
$platformId, $gameAlias, $playerName,
|
|
$cardholderName, $billingAddress, $billingCity, $billingState, $billingZip, $billingEmail,
|
|
$isCustom ? 1 : 0, $cardBrand, $cardLast4, $receiptUrl
|
|
]);
|
|
|
|
db()->commit();
|
|
} catch (Exception $e) {
|
|
db()->rollBack();
|
|
echo json_encode(['success'=>false,'error'=>'Token credit failed. Payment ID: '.$result['payment_id']]); exit;
|
|
}
|
|
|
|
// ─── Update saved billing (separate try — must NOT roll back token credit) ──
|
|
try {
|
|
db()->prepare("
|
|
INSERT INTO saved_billing (user_id,first_name,last_name,email,address,city,state,zip,card_brand,card_last4)
|
|
VALUES (?,?,?,?,?,?,?,?,?,?)
|
|
ON DUPLICATE KEY UPDATE
|
|
card_brand=VALUES(card_brand), card_last4=VALUES(card_last4),
|
|
first_name=COALESCE(NULLIF(VALUES(first_name),''),first_name),
|
|
last_name=COALESCE(NULLIF(VALUES(last_name),''),last_name),
|
|
email=COALESCE(NULLIF(VALUES(email),''),email),
|
|
address=COALESCE(NULLIF(VALUES(address),''),address),
|
|
city=COALESCE(NULLIF(VALUES(city),''),city),
|
|
state=COALESCE(NULLIF(VALUES(state),''),state),
|
|
zip=COALESCE(NULLIF(VALUES(zip),''),zip)
|
|
")->execute([
|
|
$userId, $billingFirst, $billingLast, $billingEmail,
|
|
$billingAddress, $billingCity, $billingState, $billingZip,
|
|
$cardBrand, $cardLast4
|
|
]);
|
|
} catch (Exception $e) { /* non-critical — tokens already credited */ }
|
|
|
|
$bal = db()->prepare("SELECT tokens FROM users WHERE id=?");
|
|
$bal->execute([$userId]);
|
|
$newBal = (float)$bal->fetchColumn();
|
|
logActivity('token_purchase', $userId, null, 'purchase', (int)db()->lastInsertId(),
|
|
"Bought {$tokens} tokens via {$paymentMethod} for \${$amountDollars}");
|
|
echo json_encode([
|
|
'success' => true,
|
|
'manual' => false,
|
|
'tokens_added' => (int)$tokens,
|
|
'new_balance' => $newBal,
|
|
'payment_id' => $result['payment_id'],
|
|
'card_brand' => $cardBrand,
|
|
'card_last4' => $cardLast4,
|
|
'receipt_url' => $receiptUrl,
|
|
]);
|