| Server IP : 144.76.79.100 / Your IP : 216.73.216.103 [ Web Server : Apache System : Linux ch05.wehostwebserver.com 5.14.0-611.5.1.el9_7.x86_64 #1 SMP PREEMPT_DYNAMIC Tue Nov 11 08:09:09 EST 2025 x86_64 User : razzlestore ( 1092) PHP Version : 8.2.29 Disable Function : NONE Domains : 343 Domains MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /proc/self/cwd/wp-content/plugins/woo-stripe-payment/includes/ |
Upload File : |
<?php
/**
* @package PaymentPlugins\Functions
*/
defined( 'ABSPATH' ) || exit();
/**
* Processes the charge via webhooks for local payment methods like P24, EPS, etc.
*
* @param \Stripe\Source $source
* @param WP_REST_Request $request
*
* @since 3.0.0
* @deprecated 3.3.73
* @package PaymentPlugins\Functions
*/
function wc_stripe_process_source_chargeable( $source, $request ) {
if ( isset( $source->metadata['order_id'] ) ) {
$order = wc_get_order( wc_stripe_filter_order_id( $source->metadata['order_id'], $source ) );
} else {
// try finding order using source.
$order = wc_stripe_get_order_from_source_id( $source->id );
}
if ( ! $order ) {
/**
* If the order ID metadata is empty, it's possible the source became chargeable before
* the plugin had a chance to update the order ID. Schedule a cron job to execute in 60 seconds
* so the plugin can update the order ID and the charge can be processed.
*/
if ( empty( $source->metadata['order_id'] ) ) {
if ( method_exists( WC(), 'queue' ) && ! doing_action( 'wc_stripe_retry_source_chargeable' ) ) {
WC()->queue()->schedule_single( time() + MINUTE_IN_SECONDS, 'wc_stripe_retry_source_chargeable', array( $source->id ) );
}
} else {
wc_stripe_log_error( sprintf( 'Could not create a charge for source %s. No order ID was found in your WordPress database.', $source->id ) );
}
return;
}
/**
*
* @var WC_Payment_Gateway_Stripe $payment_method
*/
$payment_method = WC()->payment_gateways()->payment_gateways()[ $order->get_payment_method() ];
// if the order has a transaction ID, then a charge has already been created.
if ( $payment_method->has_order_lock( $order ) || ( $transaction_id = $order->get_transaction_id() ) ) {
wc_stripe_log_info( sprintf( 'source.chargeable event received. Charge has already been created for order %s. Event exited.', $order->get_id() ) );
return;
}
$payment_method->set_order_lock( $order );
$payment_method->set_new_source_token( $source->id );
$result = $payment_method->payment_object->process_payment( $order );
if ( ! is_wp_error( $result ) && $result->complete_payment ) {
$payment_method->payment_object->payment_complete( $order, $result->charge );
}
}
/**
* When the charge has succeeded, the order should be completed.
*
* @param \Stripe\Charge $charge
* @param WP_REST_Request $request
*
* @since 3.0.5
* @deprecated 3.3.73
* @package PaymentPlugins\Functions
*/
function wc_stripe_process_charge_succeeded( $charge, $request ) {
// charges that belong to a payment intent can be skipped
// because the payment_intent.succeeded event will be called.
if ( $charge->payment_intent ) {
return;
}
$order = wc_get_order( wc_stripe_filter_order_id( $charge->metadata['order_id'], $charge ) );
if ( ! $order ) {
wc_stripe_log_error( sprintf( 'Could not complete payment for charge %s. No order ID %s was found in your WordPress database.', $charge->id, $charge->metadata['order_id'] ) );
return;
}
/**
*
* @var WC_Payment_Gateway_Stripe $payment_method
*/
$payment_method = WC()->payment_gateways()->payment_gateways()[ $order->get_payment_method() ];
/**
* Make sure the payment method is asynchronous because synchronous payments are handled via the source.chargeable event which processes the payment.
* This event is relevant for payment methods that receive a charge.succeeded event at some arbitrary amount of time
* after the source is chargeable.
*/
if ( $payment_method instanceof WC_Payment_Gateway_Stripe && ! $payment_method->synchronous ) {
// If the order's charge status is not equal to charge status from Stripe, then complete_payment.
if ( $order->get_meta( WC_Stripe_Constants::CHARGE_STATUS ) != $charge->status ) {
// want to prevent plugin from processing capture_charge since charge has already been captured.
remove_action( 'woocommerce_order_status_completed', 'wc_stripe_order_status_completed' );
if ( stripe_wc()->advanced_settings->is_fee_enabled() ) {
// retrieve the balance transaction
$balance_transaction = WC_Stripe_Gateway::load()->mode( wc_stripe_order_mode( $order ) )->balanceTransactions->retrieve( $charge->balance_transaction );
if ( ! is_wp_error( $balance_transaction ) ) {
$charge->balance_transaction = $balance_transaction;
}
}
// call payment complete so shipping, emails, etc are triggered.
$payment_method->payment_object->payment_complete( $order, $charge );
$order->add_order_note( __( 'Charge.succeeded webhook received. Payment has been completed.', 'woo-stripe-payment' ) );
}
}
}
/**
*
* @param \Stripe\PaymentIntent $intent
* @param WP_REST_Request $request
* @param \Stripe\Event $event
*
* @since 3.1.0
* @package PaymentPlugins\Functions
*/
function wc_stripe_process_payment_intent_succeeded( $intent, $request, $event ) {
$order = WC_Stripe_Utils::get_order_from_payment_intent( $intent );
if ( ! $order ) {
wc_stripe_log_info( sprintf( 'Could not complete payment_intent.succeeded event for payment_intent %s. No order ID %s was found in your WordPress database.
This typically happens when you have multiple webhooks setup for the same Stripe account. This order most likely originated from a different site.', $intent->id, isset( $intent->metadata->order_id ) ? $intent->metadata->order_id : '(No Order ID in metadata)' ) );
return;
}
/**
* @var \WC_Payment_Gateway_Stripe $payment_method
*/
$payment_method = WC()->payment_gateways()->payment_gateways()[ $order->get_payment_method() ] ?? null;
if ( $payment_method instanceof WC_Payment_Gateway_Stripe ) {
if ( $payment_method->has_order_lock( $order ) || $order->get_date_paid() ) {
wc_stripe_log_info( sprintf( 'payment_intent.succeeded event received. Intent has been completed for order %s. Event exited.', $order->get_id() ) );
return;
}
/**
* We want to defer the processing of any credit card payments to prevent race conditions. The Stripe webhook can be
* received while the checkout process is still running.
*/
if ( $payment_method->get_payment_method_type() === 'card' ) {
WC()->queue()->schedule_single( time() + 2 * MINUTE_IN_SECONDS, 'wc_stripe_process_deferred_webhook', array(
'type' => $event->type,
'order_id' => $order->get_id(),
'payment_intent' => $intent->id
) );
} else {
$payment_method->set_order_lock( $order );
$order->update_meta_data( WC_Stripe_Constants::PAYMENT_INTENT, WC_Stripe_Utils::sanitize_intent( $intent->toArray() ) );
$result = $payment_method->payment_object->process_payment( $order );
if ( ! is_wp_error( $result ) && $result->complete_payment ) {
$payment_method->payment_object->payment_complete( $order, $result->charge );
$order->add_order_note( __( 'payment_intent.succeeded webhook received. Payment has been completed.', 'woo-stripe-payment' ) );
}
}
}
}
/**
*
* @param \Stripe\Charge $charge
* @param WP_REST_Request $request
*
* @since 3.1.1
* @package PaymentPlugins\Functions
*/
function wc_stripe_process_charge_failed( $charge, $request ) {
$order = wc_get_order( wc_stripe_filter_order_id( $charge->metadata['order_id'], $charge ) );
if ( $order ) {
$payment_methods = WC()->payment_gateways()->payment_gateways();
if ( isset( $payment_methods[ $order->get_payment_method() ] ) ) {
/**
*
* @var WC_Payment_Gateway_Stripe $payment_method
*/
$payment_method = $payment_methods[ $order->get_payment_method() ];
// only update order status if this is an asynchronous payment method,
// and there is no completed date on the order. If there is a complete date it
// means payment_complete was called on the order at some point
if ( $payment_method instanceof WC_Payment_Gateway_Stripe && ! $payment_method->synchronous && ! $order->get_date_completed() ) {
$order->update_status( apply_filters( 'wc_stripe_charge_failed_status', 'failed' ), $charge->failure_message );
}
}
}
}
/**
* Function that processes the charge.refund webhook. If the refund is created in the Stripe dashboard, a
* refund will be created in the WC system to keep WC and Stripe in sync.
*
* @param \Stripe\Charge $charge
*
* @since 3.2.15
*/
function wc_stripe_process_create_refund( $charge ) {
$mode = $charge->livemode ? 'live' : 'test';
$order = null;
// get the order ID from the charge
$order = WC_Stripe_Utils::get_order_from_charge( $charge );
try {
if ( ! $order ) {
throw new Exception( sprintf( 'Could not match order with charge %s.', $charge->id ) );
}
if ( isset( $charge->metadata['cancellation_via'] ) && $charge->metadata['cancellation_via'] === 'woocommerce_admin' ) {
// This refund webhook is the result of an authorized payment intent being cancelled. Don't create a refund object.
return;
}
$response = WC_Stripe_Gateway::load( wc_stripe_order_mode( $order ) )->refunds->all( array( 'charge' => $charge->id ) );
$refunds = $response->data;
usort( $refunds, function ( $a, $b ) {
// sort so refund with most recent created timestamp is first
return $a->created < $b->created ? 1 : - 1;
} );
$refund = $refunds[0];
/**
* @var \Stripe\Refund $refund
*/
// refund was not created via WC
if ( ! isset( $refund->metadata['order_id'], $refund->metadata['created_via'] ) ) {
$args = array(
'amount' => wc_stripe_remove_number_precision( $refund->amount, $order->get_currency() ),
'order_id' => $order->get_id(),
'reason' => $refund->reason,
'refund_payment' => false
);
// if the order has been fully refunded, items should be re-stocked
if ( $order->get_total() == ( $args['amount'] + $order->get_total_refunded() ) ) {
$args['restock_items'] = true;
$line_items = array();
foreach ( $order->get_items() as $item_id => $item ) {
$line_items[ $item_id ] = array(
'qty' => $item->get_quantity()
);
}
$args['line_items'] = $line_items;
}
// create the refund
$result = wc_create_refund( $args );
// Update the refund in Stripe with metadata
if ( ! is_wp_error( $result ) ) {
$client = WC_Stripe_Gateway::load( $mode );
$order->add_order_note( sprintf( __( 'Order refunded in Stripe. Amount: %s', 'woo-stripe-payment' ), $result->get_formatted_refund_amount() ) );
$client->refunds->update( $refund->id, array(
'metadata' => array(
'order_id' => $order->get_id(),
'created_via' => 'stripe_dashboard'
)
) );
if ( stripe_wc()->advanced_settings->is_fee_enabled() ) {
// retrieve the charge but with expanded objects so fee and net can be calculated.
$charge = $client->charges->retrieve( $charge->id, array( 'expand' => array( 'balance_transaction', 'refunds.data.balance_transaction' ) ) );
if ( ! is_wp_error( $charge ) ) {
WC_Stripe_Utils::add_balance_transaction_to_order( $charge, $order, true );
}
}
} else {
throw new Exception( $result->get_error_message() );
}
}
} catch ( Exception $e ) {
wc_stripe_log_error( sprintf( 'Error processing refund webhook. Error: %s', $e->getMessage() ) );
}
}
/**
* @param $source_id
*
* @throws \Stripe\Exception\ApiErrorException
*/
function wc_stripe_retry_source_chargeable( $source_id ) {
$source = WC_Stripe_Gateway::load()->sources->retrieve( $source_id );
if ( ! is_wp_error( $source ) ) {
wc_stripe_log_info( sprintf( 'Processing source.chargeable via scheduled action. Source ID %s', $source_id ) );
wc_stripe_process_source_chargeable( $source, null );
}
}
/**
* @param Stripe\Dispute $dispute
*/
function wc_stripe_charge_dispute_created( $dispute ) {
if ( stripe_wc()->advanced_settings->is_dispute_created_enabled() ) {
$order = wc_stripe_get_order_from_transaction( $dispute->charge );
if ( ! $order ) {
wc_stripe_log_info( sprintf( 'No order found for charge %s. Dispute %s', $dispute->charge, $dispute->id ) );
} else {
$current_status = $order->get_status();
$message = sprintf( __( 'A dispute has been created for charge %1$s. Dispute status: %2$s.', 'woo-stripe-payment' ), $dispute->charge, strtoupper( $dispute->status ) );
$order->update_status( apply_filters( 'wc_stripe_dispute_created_order_status', stripe_wc()->advanced_settings->get_option( 'dispute_created_status', 'on-hold' ), $dispute, $order ),
$message );
// update the dispute with metadata that can be used later
WC_Stripe_Gateway::load( wc_stripe_order_mode( $order ) )->disputes->update( $dispute->id, array(
'metadata' => array(
'order_id' => $order->get_id(),
'prev_order_status' => $current_status
)
) );
// @todo send an email to the admin so they know a dispute was created
}
}
}
/**
* @param Stripe\Dispute $dispute
*/
function wc_stripe_charge_dispute_closed( $dispute ) {
if ( stripe_wc()->advanced_settings->is_dispute_closed_enabled() ) {
if ( isset( $dispute->metadata['order_id'] ) ) {
$order = wc_get_order( absint( $dispute->metadata['order_id'] ) );
} else {
$order = wc_stripe_get_order_from_transaction( $dispute->charge );
}
if ( ! $order ) {
return wc_stripe_log_info( sprintf( 'No order found for charge %s. Dispute %s', $dispute->charge, $dispute->id ) );
}
$message = sprintf( __( 'Dispute %1$s has been closed. Result: %2$s.', 'woo-stripe-payment' ), $dispute->id, $dispute->status );
switch ( $dispute->status ) {
case 'won':
//set the order's status back to what it was before the dispute
if ( ! empty( $dispute->metadata['prev_order_status'] ) ) {
$status = $dispute->metadata['prev_order_status'];
} else {
$status = $order->needs_processing() ? 'processing' : 'completed';
}
$order->update_status( $status, $message );
break;
case 'lost':
$order->update_status( apply_filters( 'wc_stripe_dispute_closed_order_status', 'failed', $dispute, $order ), $message );
}
}
}
/**
* @param Stripe\Review $review
*/
function wc_stripe_review_opened( $review ) {
if ( stripe_wc()->advanced_settings->is_review_opened_enabled() ) {
if ( isset( $review->charge ) ) {
$order = wc_stripe_get_order_from_transaction( $review->charge );
} else {
// In some cases, Stripe does not provide the charge ID in the Review object.
$pi = $review->payment_intent;
if ( $pi ) {
$payment_intent = WC_Stripe_Gateway::load()->mode( $review )->paymentIntents->retrieve( $pi );
if ( ! is_wp_error( $payment_intent ) && isset( $payment_intent->metadata['order_id'] ) ) {
$order = wc_get_order( $payment_intent->metadata['order_id'] );
}
}
}
if ( $order ) {
$status = $order->get_status();
$order->update_meta_data( WC_Stripe_Constants::PREV_STATUS, $status );
$message = sprintf( __( 'A review has been opened for charge %1$s. Reason: %2$s.', 'woo-stripe-payment' ), $review->charge, strtoupper( $review->reason ) );
$order->update_status( apply_filters( 'wc_stripe_review_opened_order_status', 'on-hold', $review, $order ), $message );
}
}
}
/**
* @param Stripe\Review $review
*/
function wc_stripe_review_closed( $review ) {
if ( stripe_wc()->advanced_settings->is_review_closed_enabled() ) {
if ( isset( $review->charge ) ) {
$order = wc_stripe_get_order_from_transaction( $review->charge );
} else {
// In some cases, Stripe does not provide the charge ID in the Review object.
$pi = $review->payment_intent;
if ( $pi ) {
$payment_intent = WC_Stripe_Gateway::load()->mode( $review )->paymentIntents->retrieve( $pi );
if ( ! is_wp_error( $payment_intent ) && isset( $payment_intent->metadata['order_id'] ) ) {
$order = wc_get_order( $payment_intent->metadata['order_id'] );
}
}
}
if ( $order ) {
$status = $order->get_meta( WC_Stripe_Constants::PREV_STATUS );
if ( ! $status ) {
$status = $order->needs_processing() ? 'processing' : 'completed';
}
$order->delete_meta_data( WC_Stripe_Constants::PREV_STATUS );
$message = sprintf( __( 'A review has been closed for charge %1$s. Reason: %2$s.', 'woo-stripe-payment' ), $review->charge, strtoupper( $review->reason ) );
$order->update_status( $status, $message );
}
}
}
/**
* @param \Stripe\PaymentIntent $payment_intent
*/
function wc_stripe_process_requires_action( $payment_intent ) {
if ( isset( $payment_intent->metadata['gateway_id'], $payment_intent->metadata['order_id'] ) ) {
if ( in_array( $payment_intent->metadata['gateway_id'], array( 'stripe_oxxo', 'stripe_boleto', 'stripe_konbini' ), true ) ) {
$order = WC_Stripe_Utils::get_order_from_payment_intent( $payment_intent );
if ( ! $order ) {
return;
}
/**
*
* @var WC_Payment_Gateway_Stripe $payment_method
*/
$payment_method = WC()->payment_gateways()->payment_gateways()[ $payment_intent->metadata['gateway_id'] ];
if ( $payment_method ) {
$payment_method->process_voucher_order_status( $order );
wc_stripe_log_info( sprintf( 'Order status processed for Voucher payment. Order ID %s. Payment Intent %s', $order->get_id(), $payment_intent->id ) );
}
}
}
}
/**
* @param Stripe\Charge $charge
*/
function wc_stripe_process_charge_pending( $charge ) {
if ( isset( $charge->metadata['gateway_id'], $charge->metadata['order_id'] ) ) {
$payment_methods = WC()->payment_gateways()->payment_gateways();
$payment_method = $charge->metadata['gateway_id'];
$payment_method = isset( $payment_methods[ $payment_method ] ) ? $payment_methods[ $payment_method ] : null;
if ( $payment_method && $payment_method instanceof \WC_Payment_Gateway_Stripe && ! $payment_method->synchronous ) {
$order = wc_get_order( wc_stripe_filter_order_id( $charge->metadata['order_id'], $charge ) );
if ( $order ) {
// temporary check to prevent race conditions caused by status update also occurring in
// class-wc-stripe-payment-intent.php line 89 at the same time as the webhook being received for ach payments
if ( $payment_method->id !== 'stripe_ach' && ! $payment_method->has_order_lock( $order ) ) {
$payment_method->set_order_lock( $order );
$payment_method->payment_object->payment_complete( $order, $charge );
$payment_method->release_order_lock( $order );
}
}
}
}
}