'ReverePayments', 'version' => '1.0.0', 'author' => 'Paymenter', 'website' => 'https://paymenter.org', ]; } public function getUrl($total, $products, $orderId, $client = null) { $apiKey = ExtensionHelper::getConfig('ReverePayments', 'revere_api_key'); $publicCheckoutKey = ExtensionHelper::getConfig('ReverePayments', 'revere_public_checkout_key'); $publicCheckoutKey = 'checkout_public_R7Kgf3GyG9Bru9W5vhR293qd22U8rn8H'; $isTestMode = ExtensionHelper::getConfig('ReverePayments', 'revere_test_mode'); // TODO: find out what the sandbox url is $baseRevereApiUrl = $isTestMode ? 'https://api.sandbox.reverepayments.dev' : 'https://api.reverepayments.dev'; $baseCartUrl = $isTestMode ? 'https://secure.reverepayments.com' : 'https://secure.reverepayments.com'; $lineItems = []; foreach ($products as $product) { // Ensure the product exists in Revere Payments // This will create or update the product if needed $this->createOrUpdateProduct($product); // Use the generateProductSku method for consistency $sku = $this->generateProductSku($product); $lineItems[] = [ 'sku' => $sku, 'quantity' => $product->quantity, ]; } $curl = curl_init(); $data = [ 'lineItems' => $lineItems, 'receipt' => [ 'showReceipt' => true ], 'key' => $publicCheckoutKey, ]; curl_setopt_array($curl, array( CURLOPT_URL => 'https://secure.reverepayments.com/api/v4/cart', CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 0, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS => json_encode($data), CURLOPT_HTTPHEADER => array( 'Accept: application/json, text/plain, */*', 'Accept-Encoding: gzip, deflate, br, zstd', 'Accept-Language: en-US,en;q=0.9', 'Cache-Control: no-cache', 'Connection: keep-alive', 'Content-Type: application/json', 'Origin: null', 'Pragma: no-cache', 'Sec-Fetch-Dest: empty', 'Sec-Fetch-Mode: cors', 'Sec-Fetch-Site: cross-site', 'Sec-GPC: 1', 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36', 'sec-ch-ua: "Chromium";v="134", "Not:A-Brand";v="24", "Brave";v="134"', 'sec-ch-ua-mobile: ?0', 'sec-ch-ua-platform: "macOS"' ), )); $response = curl_exec($curl); $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); curl_close($curl); if ($httpCode < 200 || $httpCode >= 300) { throw new Exception('Failed to create Revere payment session: ' . $response); } $responseData = json_decode($response, true); if (!isset($responseData['id'])) { throw new Exception('Invalid response from Revere Payments API'); } $redirectUrl = "https://collectcheckout.com/collect-checkout/?cartId=" . $responseData['id']; return $redirectUrl; } public function webhook(Request $request) { $payload = $request->getContent(); $signature = $request->header('revere-signature'); $webhookSecret = ExtensionHelper::getConfig('ReverePayments', 'revere_webhook_secret'); // Verify webhook signature $computedSignature = hash_hmac('sha256', $payload, $webhookSecret); if (!hash_equals($computedSignature, $signature)) { http_response_code(400); exit('Invalid signature'); } $event = json_decode($payload); if ($event->type === 'payment.succeeded') { $orderId = $event->data->metadata->order_id; ExtensionHelper::paymentDone($orderId); } return response()->json(['success' => true]); } public function pay($total, $products, $orderId) { return $this->getUrl($total, $products, $orderId); } public function getConfig() { return [ [ 'name' => 'revere_api_key', 'friendlyName' => 'Revere API Key', 'type' => 'text', 'description' => 'Your Revere Payments Checkout Public Key (starts with checkout_public_)', 'required' => true, ], [ 'name' => 'revere_webhook_secret', 'friendlyName' => 'Revere Webhook Secret', 'type' => 'text', 'description' => 'Your Revere Payments webhook secret for verifying webhook signatures', 'required' => true, ], [ 'name' => 'revere_public_checkout_key', 'friendlyName' => 'Revere Public Checkout Key', 'type' => 'text', 'description' => 'Your Revere Payments Checkout Public Key (starts with checkout_public_)', 'required' => true, ], [ 'name' => 'revere_test_mode', 'friendlyName' => 'Test Mode', 'type' => 'boolean', 'description' => 'Enable test mode to use sandbox environment', 'required' => false, 'default' => false, ] ]; } /** * Generate a unique SKU for a product that can be reused * * @param object $product The product object * @return string The generated SKU */ private function generateProductSku($product) { // Create a unique but consistent SKU based on product attributes // Format: PM-{product_id}-{hash of product name} return $product->name; } /** * Create a product in Revere Payments system * * @param object $product The product to create * @return array The created product data */ public function createOrUpdateProduct($product) { $apiKey = ExtensionHelper::getConfig('ReverePayments', 'revere_api_key'); $isTestMode = ExtensionHelper::getConfig('ReverePayments', 'revere_test_mode'); $baseRevereApiUrl = $isTestMode ? 'https://api.sandbox.reverepayments.dev' : 'https://api.reverepayments.dev'; $sku = $this->generateProductSku($product); // Try to ADD the product and if it fails, update the product $productData = [ 'security_key' => $apiKey, 'products' => 'add_product', 'product_sku' => $sku, 'product_description' => $product->name ?? $product->description, 'product_cost' => $product->price, 'product_currency' => 'USD', ]; // Initialize cURL session $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'https://secure.reverepayments.com/api/transact.php'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/x-www-form-urlencoded', 'Accept: application/json', ]); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($productData)); // Execute cURL request $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($httpCode < 200 || $httpCode >= 300) { throw new Exception('Failed to create or update product in Revere Payments: ' . $response); } $responseData = []; parse_str($response, $responseData); $isSkuInUse = isset($responseData['responsetext']) && str_contains($responseData['responsetext'], "SKU already in use"); if ($isSkuInUse) { return $responseData; // Try to update the product if it already exists // If the response text contains "SKU already in use", we need to update the sku // $productData = [ // 'security_key' => $apiKey, // 'products' => 'update_product', // // 'product_id' => $responseData['product_id'], // 'product_sku' => $sku, // 'product_description' => $product->name ?? $product->description, // 'product_cost' => $product->price, // 'product_currency' => 'USD', // ]; // // Initialize cURL session // $ch = curl_init(); // curl_setopt($ch, CURLOPT_URL, 'https://secure.reverepayments.com/api/transact.php'); // curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // curl_setopt($ch, CURLOPT_POST, true); // curl_setopt($ch, CURLOPT_HTTPHEADER, [ // 'Content-Type: application/x-www-form-urlencoded', // 'Accept: application/json', // ]); // curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($productData)); // // Execute cURL request // $response = curl_exec($ch); // $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); // curl_close($ch); // if ($httpCode < 200 || $httpCode >= 300) { // throw new Exception('Failed to create or update product in Revere Payments: ' . $response); // } // $responseData = json_decode($response, true); } if (!isset($responseData['response']) || $responseData['response'] != "1") { throw new Exception('Invalid response from Revere Payments API: ' . $responseData . '\n\n'. $response); } return $responseData; } }