PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.5
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.5
1.6.6 1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 All 49 releases
← All changes | app/Modules/PaymentMethods/StripeGateway/Webhook/Webhook.php +39 -3 1.6.3 → 1.6.5 View file →
@@ -104,8 +104,9 @@
104 104
105 105 public function processAndInsertOrderByEvent($event)
106 106 {
107 107 $eventType = $event->type;
108 + $eventLivemode = isset($event->livemode) ? (bool)$event->livemode : null;
108 109
109 110 $this->unresolvedReason = '';
110 111
111 112 $metaDataEvents = [
@@ -117,8 +118,9 @@
117 118 'checkout.session.completed',
118 119 'customer.subscription.deleted',
119 120 'customer.subscription.updated',
120 121 'setup_intent.succeeded', // recovers zero-payable system-subscription vaulting if the AJAX confirm is lost
122 + 'invoice.payment_failed',
121 123 ];
122 124
123 125 if (!in_array($eventType, $metaDataEvents)) {
124 126 $this->unresolvedReason = __('Event type has no order resolver.', 'fluent-cart');
@@ -129,9 +131,9 @@
129 131
130 132 if ($eventType === 'setup_intent.succeeded') {
131 133 $setupIntentId = Arr::get((array)$vendorDataObject, 'id');
132 134 if ($setupIntentId) {
133 - $result = (new Confirmations())->confirmSetupIntent($setupIntentId);
135 + $result = (new Confirmations())->confirmSetupIntent($setupIntentId, null, StripeHelper::modeFromLivemode($eventLivemode));
134 136 if (!is_wp_error($result)) {
135 137 wp_send_json([
136 138 'message' => 'Setup intent confirmed successfully.',
137 139 ], 200);
@@ -146,9 +148,9 @@
146 148 //check if subscription billing_cycle invoice paid or failed
147 149 $isSubscriptionCycle = $vendorDataObject->billing_reason === 'subscription_cycle';
148 150 if ($isSubscriptionCycle) {
149 151 if ($eventType === 'invoice.paid') {
150 - $vendorDataObject = (new API())->getStripeObject('invoices/' . $vendorDataObject->id, ['expand' => ['payment_intent']]);
152 + $vendorDataObject = (new API())->getStripeObject('invoices/' . $vendorDataObject->id, ['expand' => ['payment_intent']], StripeHelper::modeFromLivemode($eventLivemode));
151 153 $createdOrder = $this->processSubscriptionRenewal($vendorDataObject);
152 154 if ($createdOrder) {
153 155 wp_send_json([
154 156 'message' => 'Subscription renewal processed successfully. Order ID: ' . $createdOrder->id,
@@ -160,8 +162,25 @@
160 162 return false;
161 163 }
162 164 }
163 165
166 + if ($eventType === 'invoice.payment_failed') {
167 + $isSubscriptionCycle = $vendorDataObject->billing_reason === 'subscription_cycle';
168 + if ($isSubscriptionCycle) {
169 + $invoice = (new API())->getStripeObject('invoices/' . $vendorDataObject->id, [], StripeHelper::modeFromLivemode($eventLivemode));
170 + if (!is_wp_error($invoice)) {
171 + list($subscription, $parentOrder) = $this->resolveSubscriptionAndOrder($invoice);
172 +
173 + if ($subscription && $parentOrder && $subscription->current_payment_method === 'stripe') {
174 + return $parentOrder;
175 + }
176 + }
177 + }
178 +
179 + $this->unresolvedReason = __('Subscription renewal-failure invoice resolved to no order.', 'fluent-cart');
180 + return false;
181 + }
182 +
164 183 if ($eventType === 'charge.refunded' || $eventType === 'charge.succeeded') {
165 184 $paymentIntent = $vendorDataObject->payment_intent;
166 185 $orderTransaction = OrderTransaction::query()->where('vendor_charge_id', $paymentIntent)
167 186 ->where('transaction_type', 'charge')
@@ -241,9 +260,16 @@
241 260 $this->unresolvedReason = __('Event carries no reference to a local order.', 'fluent-cart');
242 261 return null;
243 262 }
244 263
245 - public function processSubscriptionRenewal($vendorInvoiceObject)
264 + /**
265 + * Resolve the local Subscription + parent Order for a Stripe invoice payload,
266 + * shared by renewal-success (invoice.paid) and renewal-failure
267 + * (invoice.payment_failed) handling.
268 + *
269 + * @return array{0: Subscription|null, 1: Order|null}
270 + */
271 + protected function resolveSubscriptionAndOrder($vendorInvoiceObject)
246 272 {
247 273 $subscription = null;
248 274 $parentOrder = null;
249 275
@@ -273,8 +299,18 @@
273 299 ->where('parent_order_id', $parentOrder->id)
274 300 ->orderBy('id', 'DESC')
275 301 ->first();
276 302 }
303 +
304 + return [$subscription, $parentOrder];
305 + }
306 +
307 + public function processSubscriptionRenewal($vendorInvoiceObject)
308 + {
309 + list($subscription, $parentOrder) = $this->resolveSubscriptionAndOrder($vendorInvoiceObject);
310 +
311 + $vendorSubscriptionId = Arr::get($vendorInvoiceObject, 'subscription', null)
312 + ?: (Arr::get($vendorInvoiceObject, 'parent.subscription_details.subscription', null) ?? null);
277 313
278 314 if (!$parentOrder || !$subscription || $subscription->current_payment_method !== 'stripe') {
279 315 fluent_cart_error_log('Stripe Webhook Error: Subscription Renewal - Order or Subscription not found.', 'Vendor Subscription ID: ' . $vendorSubscriptionId);
280 316 return false; // this is not our order