← All changes
|
app/Modules/PaymentMethods/StripeGateway/API/API.php
+37
-12
1.5.5
→
1.6.5
View file →
| @@ -26,12 +26,12 @@ | ||
| 26 | 26 | |
| 27 | 27 | return $this->remoteRequest($path, $data, $apiKey, 'GET'); |
| 28 | 28 | } |
| 29 | 29 | |
| 30 | - public function createStripeObject($path, $data = [], $mode = 'current', $idempotencyKey = null) | |
| 30 | + public function createStripeObject($path, $data = [], $mode = 'current', $headers = []) | |
| 31 | 31 | { |
| 32 | 32 | $apiKey = (new StripeSettingsBase())->getApiKey($mode); |
| 33 | - return $this->remoteRequest($path, $data, $apiKey, 'POST', $idempotencyKey); | |
| 33 | + return $this->remoteRequest($path, $data, $apiKey, 'POST', $headers); | |
| 34 | 34 | } |
| 35 | 35 | |
| 36 | 36 | public function deleteStripeObject($path, $data = [], $mode = 'current') |
| 37 | 37 | { |
| @@ -38,11 +38,24 @@ | ||
| 38 | 38 | $apiKey = (new StripeSettingsBase())->getApiKey($mode); |
| 39 | 39 | return $this->remoteRequest($path, $data, $apiKey, 'DELETE'); |
| 40 | 40 | } |
| 41 | 41 | |
| 42 | - public function remoteRequest($path, $data, $apiKey, $method, $idempotencyKey = null) | |
| 42 | + public function remoteRequest($path, $data, $apiKey, $method, $extraHeaders = []) | |
| 43 | 43 | { |
| 44 | 44 | $stripeApiKey = $apiKey; |
| 45 | + | |
| 46 | + // Never fire a request with an empty Authorization header — Stripe replies | |
| 47 | + // with the cryptic "You did not provide an API key" error. This happens when | |
| 48 | + // the secret key for the requested mode is not configured (e.g. a store in | |
| 49 | + // test mode charging a live-mode order, or unconfigured keys). Fail early | |
| 50 | + // with an actionable message instead. | |
| 51 | + if (empty($stripeApiKey)) { | |
| 52 | + return new \WP_Error( | |
| 53 | + 'stripe_missing_api_key', | |
| 54 | + __('Stripe API key is not configured for this payment mode. Please add your Stripe keys in Payment Settings.', 'fluent-cart') | |
| 55 | + ); | |
| 56 | + } | |
| 57 | + | |
| 45 | 58 | $apiVersion = '2025-02-24.acacia'; |
| 46 | 59 | $sessionHeaders = array( |
| 47 | 60 | 'Authorization' => 'Bearer ' . $stripeApiKey, |
| 48 | 61 | 'Content-Type' => 'application/x-www-form-urlencoded', |
| @@ -48,13 +61,11 @@ | ||
| 48 | 61 | 'Content-Type' => 'application/x-www-form-urlencoded', |
| 49 | 62 | 'Stripe-Version' => $apiVersion |
| 50 | 63 | ); |
| 51 | 64 | |
| 52 | - // Stripe dedupes any POST carrying the same Idempotency-Key (valid 24h), | |
| 53 | - // so a duplicate/retried create request returns the original object instead | |
| 54 | - // of charging the customer or creating a second subscription again. | |
| 55 | - if ($idempotencyKey && $method === 'POST') { | |
| 56 | - $sessionHeaders['Idempotency-Key'] = $idempotencyKey; | |
| 65 | + // Per-request headers (e.g. Idempotency-Key for off-session renewal charges) | |
| 66 | + if ($extraHeaders && is_array($extraHeaders)) { | |
| 67 | + $sessionHeaders = array_merge($sessionHeaders, $extraHeaders); | |
| 57 | 68 | } |
| 58 | 69 | |
| 59 | 70 | $url = $this->apiUrl . $path; |
| 60 | 71 | |
| @@ -116,18 +127,32 @@ | ||
| 116 | 127 | |
| 117 | 128 | return $data; |
| 118 | 129 | } |
| 119 | 130 | |
| 120 | - public function getEvent($eventId) | |
| 131 | + /** | |
| 132 | + * Event ids are namespaced per mode, so a live id is unfetchable with a test key | |
| 133 | + * and vice versa. The store's global mode toggle is not a reliable proxy — a | |
| 134 | + * renewal is billed by Stripe on its own schedule, whatever the store is set to. | |
| 135 | + * | |
| 136 | + * @param string $eventId | |
| 137 | + * @param bool|null $livemode Mode the event belongs to; null falls back to the store setting. | |
| 138 | + * @return object|null|\WP_Error Null when the response body is not decodable JSON. | |
| 139 | + */ | |
| 140 | + public function getEvent($eventId, $livemode = null) | |
| 121 | 141 | { |
| 122 | - $api = $this->getApi(); | |
| 142 | + $mode = 'current'; | |
| 143 | + if (!is_null($livemode)) { | |
| 144 | + $mode = $livemode ? 'live' : 'test'; | |
| 145 | + } | |
| 146 | + | |
| 147 | + $api = $this->getApi($mode); | |
| 123 | 148 | return $api::request([], 'events/' . $eventId, 'GET'); |
| 124 | 149 | } |
| 125 | 150 | |
| 126 | - public function getApi() | |
| 151 | + public function getApi($mode = 'current') | |
| 127 | 152 | { |
| 128 | 153 | $api = new ApiRequest(); |
| 129 | - $api::set_secret_key((new StripeSettingsBase())->getApiKey()); | |
| 154 | + $api::set_secret_key((new StripeSettingsBase())->getApiKey($mode)); | |
| 130 | 155 | return $api; |
| 131 | 156 | } |
| 132 | 157 | |
| 133 | 158 | public function getApiKey($mode = 'current') |