diff --git a/assets/products/PROVA.png b/assets/products/PROVA.png new file mode 100644 index 0000000..8a267f8 Binary files /dev/null and b/assets/products/PROVA.png differ diff --git a/checkout/common.php b/checkout/common.php index 8a64281..1009df0 100644 --- a/checkout/common.php +++ b/checkout/common.php @@ -295,6 +295,78 @@ function kapvoe_create_checkout_session(array $config, array $payload): array { return $decoded; } +function kapvoe_decrement_sheet_stock(array $config, array $order, string $sessionId): array +{ + $url = (string)($config['stock_sync_url'] ?? ''); + $token = (string)($config['stock_sync_token'] ?? ''); + + if ($url === '' || $token === '') { + throw new RuntimeException('Falta configurar stock_sync_url o stock_sync_token'); + } + + $payload = [ + 'action' => 'decrement_stock', + 'token' => $token, + 'product_code' => (string)($order['product_code'] ?? ''), + 'quantity' => max(1, (int)($order['quantity'] ?? 1)), + 'order_id' => (string)($order['order_id'] ?? ''), + 'session_id' => $sessionId, + ]; + + if ($payload['product_code'] === '') { + throw new RuntimeException('La comanda no té product_code'); + } + + if ($payload['order_id'] === '') { + throw new RuntimeException('La comanda no té order_id'); + } + + if (!function_exists('curl_init')) { + throw new RuntimeException('cURL no està disponible al PHP'); + } + + $ch = curl_init($url); + + curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), + CURLOPT_HTTPHEADER => [ + 'Content-Type: application/json', + 'Accept: application/json', + ], + CURLOPT_TIMEOUT => 20, + CURLOPT_CONNECTTIMEOUT => 10, + ]); + + $response = curl_exec($ch); + + if ($response === false) { + $error = curl_error($ch); + curl_close($ch); + throw new RuntimeException("Error cURL stock sync: {$error}"); + } + + $statusCode = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + if ($statusCode < 200 || $statusCode >= 300) { + throw new RuntimeException("Stock sync HTTP {$statusCode}: {$response}"); + } + + $json = json_decode($response, true); + + if (!is_array($json)) { + throw new RuntimeException('Resposta no JSON del stock sync: ' . $response); + } + + if (!($json['ok'] ?? false)) { + throw new RuntimeException('Stock sync error: ' . ($json['error'] ?? 'error desconegut')); + } + + return $json; +} + function kapvoe_verify_stripe_signature(string $payload, string $header, string $secret, int $tolerance = 300): bool { if (!$header || !$secret) { return false; diff --git a/checkout/config.php b/checkout/config.php index 42a1567..18345b0 100644 --- a/checkout/config.php +++ b/checkout/config.php @@ -3,10 +3,10 @@ declare(strict_types=1); return [ // Clau secreta real de Stripe. NO la posis mai al HTML. - 'stripe_secret_key' => 'sk_test_51IvGaFHRV8rA2XwsDiGII0rVfot2HabnvF862L8G6rYIzUscZDMkM4WlVAV6GbYSMZsFEDF44PEppdJaLdGo0idB00UyabGh0u', + 'stripe_secret_key' => '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', // Secret del webhook de Stripe (Signing secret) - 'stripe_webhook_secret' => 'whsec_wBJZjwPIhPclM1i4bKUtnQqol26caq5L', + 'stripe_webhook_secret' => 'whsec_8FTXIXPWBSzFjJNQWuzetQF6LoNKv9sg', // Moneda 'currency' => 'eur', @@ -17,4 +17,7 @@ return [ // URLs públiques 'success_url' => 'https://kapvoe-portfoli.treblarella.org/checkout/payment-success.php', 'cancel_url' => 'https://kapvoe-portfoli.treblarella.org/checkout/payment-cancel.php', + + 'stock_sync_url' => 'https://script.google.com/macros/s/AKfycbyH6PuQPR342mwSiKCkYZ1lOnn1VccqzFO-ScbhwjvJoABU3LqVNJcS3gtPE5ZuT0JyvQ/exec', + 'stock_sync_token' => 'kapvoe_stock_2026_x7F9mQpL2vN8rT4sZ1kW', ]; diff --git a/checkout/stripe-webhook.php b/checkout/stripe-webhook.php index 79254e9..b4791fd 100644 --- a/checkout/stripe-webhook.php +++ b/checkout/stripe-webhook.php @@ -69,8 +69,15 @@ try { } $alreadyUpdated = (string)($order['stock_updated'] ?? '') === '1'; + $stockResult = null; if ($paymentStatus === 'paid' && !$alreadyUpdated) { + $stockResult = kapvoe_decrement_sheet_stock($config, $order, $sessionId); + + if (!($stockResult['ok'] ?? false)) { + throw new RuntimeException('No s\'ha pogut actualitzar l\'stock al Google Sheet'); + } + kapvoe_mark_order_stock_updated($config, $sessionId); $alreadyUpdated = true; } @@ -82,7 +89,8 @@ try { 'handled' => $type, 'session_id' => $sessionId, 'payment_intent_id' => $paymentIntentId, - 'already_updated' => $alreadyUpdated + 'already_updated' => $alreadyUpdated, + 'stock_result' => $stockResult ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); exit; @@ -103,4 +111,4 @@ try { 'error' => $e->getMessage() ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); exit; -} +} \ No newline at end of file