%1$s%2$s

%3$s


%4$s


%5$s

%6$s %7$s

%6$s %7$s

%8$s %2$s

%9$s checkout.session.completed,
charge.refunded,
charge.refund.updated,
charge.succeeded,
invoice.paid,
invoice.payment_failed,
customer.subscription.deleted,
customer.subscription.updated,

', __('Webhook URL: ', 'fluent-cart'), // %1$s $webhook_url, // %2$s (reused) __('You should configure your Stripe webhooks to get all updates of your payments remotely.', 'fluent-cart'), // %3$s __('How to configure?', 'fluent-cart'), // %4$s __('In your Stripe account:', 'fluent-cart'), // %5$s __('Go to Developers > Webhooks >', 'fluent-cart'), // %6$s __('Add endpoint', 'fluent-cart'), // %7$s __('Enter The Webhook URL:', 'fluent-cart'), // %8$s __('Select these events:', 'fluent-cart') // %9$s ); } public function processAndInsertOrderByEvent($event) { $eventType = $event->type; $metaDataEvents = [ 'invoice.paid', // Reviewed for subscription cycle 'charge.refunded', // reviewed 'charge.succeeded', // reviewed 'charge.dispute.created', 'charge.dispute.closed', 'checkout.session.completed', 'customer.subscription.deleted', 'customer.subscription.updated', ]; if (!in_array($eventType, $metaDataEvents)) { return false; } $vendorDataObject = $event->data->object; if ($eventType == 'invoice.paid') { //check if subscription billing_cycle invoice paid or failed $isSubscriptionCycle = $vendorDataObject->billing_reason === 'subscription_cycle'; if ($isSubscriptionCycle) { if ($eventType === 'invoice.paid') { $vendorDataObject = (new API())->getStripeObject('invoices/' . $vendorDataObject->id, ['expand' => ['payment_intent']]); $createdOrder = $this->processSubscriptionRenewal($vendorDataObject); if ($createdOrder) { wp_send_json([ 'message' => 'Subscription renewal processed successfully. Order ID: ' . $createdOrder->id, ], 200); } } return false; } } if ($eventType === 'charge.refunded' || $eventType === 'charge.succeeded') { $paymentIntent = $vendorDataObject->payment_intent; $orderTransaction = OrderTransaction::query()->where('vendor_charge_id', $paymentIntent) ->where('transaction_type', 'charge') ->first(); if (!$orderTransaction) { $orderTransaction = apply_filters('fluent_cart/stripe/fallback_order_transaction', null, $vendorDataObject); if (!$orderTransaction || $orderTransaction instanceof OrderTransaction) { $orderTransaction = null; } } if ($orderTransaction) { $order = Order::where('id', $orderTransaction->order_id)->first(); $order->current_transaction = $orderTransaction; return $order; } } if ($eventType === 'customer.subscription.deleted' || $eventType === 'customer.subscription.updated') { $vendorSubscriptionId = $vendorDataObject->id; $subscription = Subscription::query() ->where('vendor_subscription_id', $vendorSubscriptionId) ->first(); if ($subscription) { $order = Order::where('id', $subscription->parent_order_id)->first(); if ($order) { $order->current_subscription = $subscription; } return $order; } } if ($eventType === 'charge.dispute.created' || $eventType === 'charge.dispute.closed') { $paymentIntent = $vendorDataObject->payment_intent; $orderTransaction = OrderTransaction::query()->where('vendor_charge_id', $paymentIntent) ->first(); if ($orderTransaction) { return $orderTransaction->order; } return null; } // Handle checkout.session.completed for hosted checkout if ($eventType === 'checkout.session.completed') { $sessionId = $vendorDataObject->id; return StripeHelper::validateBySession($sessionId); } $metaData = (array)$vendorDataObject->metadata; $orderHash = Arr::get($metaData, 'fct_ref_id', false); if ($orderHash) { return Order::query()->where('uuid', $orderHash)->first(); } return null; } public function processSubscriptionRenewal($vendorInvoiceObject) { $subscription = null; $parentOrder = null; $vendorSubscriptionId = Arr::get($vendorInvoiceObject, 'subscription', null) ?: (Arr::get($vendorInvoiceObject, 'parent.subscription_details.subscription', null) ?? null); if ($vendorSubscriptionId) { $subscription = Subscription::query()->where('vendor_subscription_id', $vendorSubscriptionId) ->orderBy('id', 'DESC') ->first(); } if ($subscription) { $parentOrder = Order::query()->where('id', $subscription->parent_order_id)->first(); } if (!$parentOrder) { // let's try to find from the meta ref id $refId = Arr::get($vendorInvoiceObject, 'subscription_details.metadata.fct_ref_id', null); if ($refId) { $parentOrder = Order::query()->where('uuid', $refId)->first(); } } if ($parentOrder && !$subscription) { $subscription = Subscription::query() ->where('parent_order_id', $parentOrder->id) ->orderBy('id', 'DESC') ->first(); } if (!$parentOrder || !$subscription || $subscription->current_payment_method !== 'stripe') { fluent_cart_error_log('Stripe Webhook Error: Subscription Renewal - Order or Subscription not found.', 'Vendor Subscription ID: ' . $vendorSubscriptionId); return false; // this is not our order }; $paymentIntent = Arr::get($vendorInvoiceObject, 'payment_intent', null); if (is_array($paymentIntent)) { $paymentIntentId = Arr::get($paymentIntent, 'id', null); } else { $paymentIntentId = $paymentIntent; } if ($paymentIntent) { $alreadyRecorded = OrderTransaction::query() ->where('subscription_id', $subscription->id) ->where('vendor_charge_id', $paymentIntentId) ->exists(); if ($alreadyRecorded) { return null; // already recorded } } $amountPaid = Arr::get($vendorInvoiceObject, 'amount_paid', 0); $chargeCurrency = Arr::get($vendorInvoiceObject, 'currency', null); if ($chargeCurrency && CurrenciesHelper::isZeroDecimal($chargeCurrency)) { $amountPaid = $amountPaid * 100; } $transactionData = [ 'payment_method' => 'stripe', 'total' => $amountPaid, 'vendor_charge_id' => $paymentIntentId ]; $paymentIntent = (new API())->getStripeObject('payment_intents/' . $paymentIntentId, [ 'expand' => ['latest_charge'] ], $parentOrder->mode); if (!is_wp_error($paymentIntent)) { $transactionData['card_last_4'] = Arr::get($paymentIntent, 'latest_charge.payment_method_details.card.last4', ''); $transactionData['card_brand'] = (string)Arr::get($paymentIntent, 'latest_charge.payment_method_details.card.brand', ''); $transactionData['payment_method_type'] = (string)Arr::get($paymentIntent, 'latest_charge.payment_method_details.type', ''); } else { $activePaymentMethod = $subscription->getMeta('active_payment_method', []); if (!$activePaymentMethod || !is_array($activePaymentMethod)) { $activePaymentMethod = []; } if ($activePaymentMethod) { $transactionData['card_last_4'] = Arr::get($activePaymentMethod, 'details.last_4'); $transactionData['card_brand'] = (string)Arr::get($activePaymentMethod, 'details.brand'); $transactionData['payment_method_type'] = (string)Arr::get($activePaymentMethod, 'details.type'); } } $subscriptionUpdateData = array_filter([ 'current_payment_method' => 'stripe' ]); $stripeSubscription = (new API())->getStripeObject('subscriptions/' . $vendorSubscriptionId, [ 'expand' => ['latest_invoice'] ], $parentOrder->mode); if (!is_wp_error($stripeSubscription)) { $subscriptionUpdateData = StripeHelper::getSubscriptionUpdateData($stripeSubscription, $subscription); } $createdTransaction = SubscriptionService::recordRenewalPayment($transactionData, $subscription, $subscriptionUpdateData); $subscription = Subscription::query()->find($subscription->id); if ($subscription && $subscription->status === Status::SUBSCRIPTION_COMPLETED) { if (!is_wp_error($stripeSubscription)) { if ($stripeSubscription['status'] === 'active') { $deleted = (new API)->deleteStripeObject('subscriptions/' . $vendorSubscriptionId, [], $parentOrder->mode); if (is_wp_error($deleted)) { fluent_cart_error_log('Stripe Subscription Deletion Error. Subscription ID: ' . $subscription->id, $deleted->get_error_message()); } } } } if ($createdTransaction) { return $createdTransaction->order; } return null; } }