current_payment_method !== 'stripe') { return new \WP_Error('invalid_payment_method', __('This subscription is not using Stripe as payment method.', 'fluent-cart')); } $order = $subscriptionModel->order; $vendorSubscriptionId = $subscriptionModel->vendor_subscription_id; if (!$vendorSubscriptionId) { return new \WP_Error('invalid_subscription', __('Invalid vendor subscription ID.', 'fluent-cart')); } $stripeSubscription = (new API())->getStripeObject('subscriptions/' . $vendorSubscriptionId, [ 'expand' => ['latest_invoice'] ], $order->mode); if (is_wp_error($stripeSubscription)) { return $stripeSubscription; } $invoices = (new API())->getStripeObject('invoices', [ 'subscription' => $vendorSubscriptionId, 'status' => 'paid' ], $order->mode); if (is_wp_error($invoices)) { return $invoices; } $invoices = Arr::get($invoices, 'data', []); $subscriptionUpdateData = StripeHelper::getSubscriptionUpdateData($stripeSubscription, $subscriptionModel); // reverse the array to get the latest transaction last $invoices = array_reverse($invoices); $newPayment = false; foreach ($invoices as $key => $invoice) { //$invoice is array if (Arr::get($invoice, 'amount_paid') == 0) { continue; } $transaction = OrderTransaction::query() ->whereIn('vendor_charge_id', [ Arr::get($invoice, 'payment_intent'), Arr::get($invoice, 'charge') ]) ->where('transaction_type', 'charge') ->first(); if (!$transaction) { // check local transactions missing vendor_charge_id $transaction = OrderTransaction::query() ->select(['id', 'order_id']) ->where('subscription_id', $subscriptionModel->id) ->where('vendor_charge_id', '') ->where('transaction_type', 'charge') ->where('total', (int)Arr::get($invoice, 'amount_paid')) ->first(); if ($transaction) { $transaction->update([ 'vendor_charge_id' => Arr::get($invoice, 'payment_intent') ]); continue; } $amountPaid = Arr::get($invoice, 'amount_paid'); $chargeCurrency = Arr::get($invoice, 'currency'); if ($chargeCurrency && CurrenciesHelper::isZeroDecimal($chargeCurrency)) { $amountPaid = $amountPaid * 100; } $transactionData = [ 'payment_method' => 'stripe', 'total' => (int)$amountPaid, 'vendor_charge_id' => Arr::get($invoice, 'payment_intent'), 'created_at' => ($paidAt = Arr::get($invoice, 'status_transitions.paid_at')) ? DateTime::anyTimeToGmt($paidAt)->format('Y-m-d H:i:s') : DateTime::now()->format('Y-m-d H:i:s'), ]; $paymentIntent = (new API())->getStripeObject('payment_intents/' . Arr::get($invoice, 'payment_intent'), ['expand' => ['latest_charge']], $order->mode); if (!is_wp_error($paymentIntent) && Arr::get($paymentIntent, 'latest_charge')) { $transactionData['created_at'] = DateTime::anyTimeToGmt(Arr::get($paymentIntent, 'latest_charge.created'))->format('Y-m-d H:i:s'); $paymentMethodType = Arr::get($paymentIntent, 'latest_charge.payment_method_details.type', ''); $transactionData['payment_method_type'] = $paymentMethodType; if ($paymentMethodType === 'sepa_debit') { $transactionData['card_last_4'] = Arr::get($paymentIntent, 'latest_charge.payment_method_details.sepa_debit.last4', ''); $transactionData['card_brand'] = 'sepa_debit'; } else { $transactionData['card_last_4'] = Arr::get($paymentIntent, 'latest_charge.payment_method_details.card.last4', ''); $transactionData['card_brand'] = Arr::get($paymentIntent, 'latest_charge.payment_method_details.card.brand', ''); } } else { $activePaymentMethod = $subscriptionModel->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'] = Arr::get($activePaymentMethod, 'details.brand'); } } $newPayment = true; SubscriptionService::recordRenewalPayment($transactionData, $subscriptionModel, $subscriptionUpdateData); } else { $transaction->update([ 'vendor_charge_id' => Arr::get($invoice, 'payment_intent'), 'status' => Status::TRANSACTION_SUCCEEDED, 'total' => (int)Arr::get($invoice, 'amount_paid') ]); (new StatusHelper($transaction->order))->syncOrderStatuses($transaction); } } if (!$newPayment) { $subscriptionModel = SubscriptionService::syncSubscriptionStates($subscriptionModel, $subscriptionUpdateData); } else { $subscriptionModel = Subscription::find($subscriptionModel->id); } if ($subscriptionModel->status == Status::SUBSCRIPTION_COMPLETED && $stripeSubscription['status'] === 'active') { $response = (new API)->deleteStripeObject('subscriptions/' . $vendorSubscriptionId, [], $order->mode); if (is_wp_error($response)) { fluent_cart_error_log('Stripe Subscription Deletion Error. Subscription ID: ' . $subscriptionModel->id, $response->get_error_message()); } } return $subscriptionModel; } public function cancel($vendorSubscriptionId, $args = []) { if (!$vendorSubscriptionId) { return new \WP_Error('invalid_subscription', __('Invalid vendor subscription ID.', 'fluent-cart')); } // first check if the subscription is already canceled in Stripe $response = (new API())->getStripeObject('subscriptions/' . $vendorSubscriptionId, [], Arr::get($args, 'mode', 'live')); if (is_wp_error($response)) { return $response; } $status = StripeHelper::transformSubscriptionStatus($response); if ($status == Status::SUBSCRIPTION_CANCELED) { $canceledAt = Arr::get($response, 'canceled_at'); return [ 'status' => Status::SUBSCRIPTION_CANCELED, 'canceled_at' => $canceledAt ? gmdate('Y-m-d H:i:s', $canceledAt) : NULL ]; } $response = (new API())->deleteStripeObject('subscriptions/' . $vendorSubscriptionId, [], Arr::get($args, 'mode', 'live')); if (is_wp_error($response)) { return $response; } $canceledAt = Arr::get($response, 'canceled_at'); return [ 'status' => StripeHelper::transformSubscriptionStatus($response), 'canceled_at' => $canceledAt ? gmdate('Y-m-d H:i:s', $canceledAt) : NULL ]; } public function cardUpdate($data, $subscriptionId) { (new UpdateCustomerPaymentMethod())->update($data, $subscriptionId); } public function switchPaymentMethod($data, $subscriptionId) { (new SwitchCustomerMethod())->switchPayMethod($data, $subscriptionId); } }