Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion includes/abstracts/abstract-wc-stripe-payment-gateway.php
Original file line number Diff line number Diff line change
Expand Up @@ -1743,7 +1743,7 @@ private function get_intent( $intent_type, $intent_id ) {
throw new Exception( "Failed to get intent of type $intent_type. Type is not allowed" );
}

$response = WC_Stripe_API::request( [], "$intent_type/$intent_id?expand[]=payment_method", 'GET' );
$response = WC_Stripe_API::request( [ 'stripe_expand' => [ 'payment_method' ] ], "$intent_type/$intent_id", 'GET' );

if ( $response && isset( $response->{ 'error' } ) ) {
$error_response_message = print_r( $response, true );
Expand Down
70 changes: 62 additions & 8 deletions includes/class-wc-stripe-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ public static function get_idempotency_key( $api, $method, $request ) {
*
* @since 3.1.0
* @version 4.0.6
* @param array $request
* @param array $request Note that there is special handling for the `stripe_expand` parameter, which is expected to be an array of field names to expand.
* @param string $api
* @param string $method
* @param bool $with_headers To get the response with headers.
Expand All @@ -217,6 +217,11 @@ public static function request( $request, $api = 'charges', $method = 'POST', $w
$headers['Idempotency-Key'] = $idempotency_key;
}

[
'request' => $request,
'expand_params' => $expand_params,
] = self::extract_expand_params( $request );

$request = apply_filters_deprecated(
'woocommerce_stripe_request_body',
[ $request, $api ],
Expand All @@ -230,13 +235,23 @@ public static function request( $request, $api = 'charges', $method = 'POST', $w
*
* @since 9.7.0
*
* @param array $request The default request body we will send to the Stripe API.
* @param string $api The Stripe API endpoint.
* @param array $request The default request body we will send to the Stripe API.
* @param string $api The Stripe API endpoint.
* @param string[] $expand_params The parameters to send as `expand[]` URL parameters in the request.
*/
$request = apply_filters( 'wc_stripe_request_body', $request, $api );
$request = apply_filters( 'wc_stripe_request_body', $request, $api, $expand_params );

$debug_params = [
'request' => $request,
];
if ( is_array( $expand_params ) ) {
$debug_params['expand_params'] = $expand_params;
}

// Log the request after the filters have been applied.
WC_Stripe_Logger::debug( "Stripe API request: {$method} {$api}", [ 'request' => $request ] );
WC_Stripe_Logger::debug( "Stripe API request: {$method} {$api}", $debug_params );

$api = self::add_expand_params_to_api( $api, $expand_params );

$response = wp_safe_remote_post(
self::ENDPOINT . $api,
Expand Down Expand Up @@ -283,9 +298,10 @@ public static function request( $request, $api = 'charges', $method = 'POST', $w
*
* @since 4.0.0
* @version 4.0.0
* @param string $api
* @param string $api The Stripe API we want to call.
* @param string[]|null $expand_params The parameters to send as `expand[]` URL parameters in the request.
*/
public static function retrieve( $api ) {
public static function retrieve( $api, $expand_params = null ) {
// If keep count of consecutive 401 errors, and it exceeds INVALID_API_KEY_ERROR_COUNT_THRESHOLD,
// we return null until the cache expires (INVALID_API_KEY_ERROR_COUNT_CACHE_TIMEOUT) or the keys are updated.
$invalid_api_key_error_count = WC_Stripe_Database_Cache::get( self::INVALID_API_KEY_ERROR_COUNT_CACHE_KEY );
Expand All @@ -300,7 +316,14 @@ public static function retrieve( $api ) {
return null;
}

WC_Stripe_Logger::debug( "Stripe API request: GET {$api}" );
$debug_params = [];
if ( is_array( $expand_params ) ) {
$debug_params['expand_params'] = $expand_params;
}

WC_Stripe_Logger::debug( "Stripe API request: GET {$api}", $debug_params );

$api = self::add_expand_params_to_api( $api, $expand_params );

$response = wp_safe_remote_get(
self::ENDPOINT . $api,
Expand Down Expand Up @@ -597,4 +620,35 @@ public function update_payment_method_configurations( $id, $payment_method_confi
);
return $response;
}

private static function extract_expand_params( array $request ): array {
if ( ! isset( $request['stripe_expand'] ) || ! is_array( $request['stripe_expand'] ) || [] === $request['stripe_expand'] ) {
return [
'request' => $request,
'expand_params' => null,
];
}

$expand_params = $request['stripe_expand'];
unset( $request['stripe_expand'] );

return [
'request' => $request,
'expand_params' => $expand_params,
];
}

private static function add_expand_params_to_api( string $api, ?array $expand_params ): string {
if ( ! is_array( $expand_params ) ) {
return $api;
}

$expand_url_param = 'expand[]=' . implode( '&expand[]=', array_map( 'rawurlencode', $expand_params ) );
// The API shouldn't include `?` already, but check just in case.
if ( str_contains( $api, '?' ) ) {
return $api . '&' . $expand_url_param;
}

return $api . '?' . $expand_url_param;
}
}
23 changes: 14 additions & 9 deletions includes/class-wc-stripe-customer.php
Original file line number Diff line number Diff line change
Expand Up @@ -714,14 +714,15 @@ public function get_payment_methods( $payment_method_type ) {
$payment_methods = get_transient( self::PAYMENT_METHODS_TRANSIENT_KEY . $payment_method_type . $this->get_id() );

if ( false === $payment_methods ) {
$params = WC_Stripe_UPE_Payment_Method_Sepa::STRIPE_ID === $payment_method_type ? '?expand[]=data.sepa_debit.generated_from.charge&expand[]=data.sepa_debit.generated_from.setup_attempt' : '';
$response = WC_Stripe_API::request(
$expand_params = WC_Stripe_UPE_Payment_Method_Sepa::STRIPE_ID === $payment_method_type ? [ 'data.sepa_debit.generated_from.charge', 'data.sepa_debit.generated_from.setup_attempt' ] : null;
$response = WC_Stripe_API::request(
[
'customer' => $this->get_id(),
'type' => $payment_method_type,
'limit' => self::PAYMENT_METHODS_API_LIMIT,
'customer' => $this->get_id(),
'type' => $payment_method_type,
'limit' => self::PAYMENT_METHODS_API_LIMIT,
'stripe_expand' => $expand_params,
],
'payment_methods' . $params,
'payment_methods',
'GET'
);

Expand Down Expand Up @@ -769,15 +770,19 @@ public function get_all_payment_methods( array $payment_method_types = [], int $

do {
$request_params = [
'customer' => $this->get_id(),
'limit' => self::PAYMENT_METHODS_API_LIMIT,
'customer' => $this->get_id(),
'limit' => self::PAYMENT_METHODS_API_LIMIT,
'stripe_expand' => [
'data.sepa_debit.generated_from.charge',
'data.sepa_debit.generated_from.setup_attempt',
],
];

if ( $last_payment_method_id ) {
$request_params['starting_after'] = $last_payment_method_id;
}

$response = WC_Stripe_API::request( $request_params, 'payment_methods?expand[]=data.sepa_debit.generated_from.charge&expand[]=data.sepa_debit.generated_from.setup_attempt', 'GET' );
$response = WC_Stripe_API::request( $request_params, 'payment_methods', 'GET' );

if ( ! empty( $response->error ) ) {
if (
Expand Down
8 changes: 4 additions & 4 deletions includes/class-wc-stripe-order-handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,8 @@ public function capture_payment( $order_id ) {
$level3_data = $this->get_level3_data_from_order( $order );
$result = WC_Stripe_API::request_with_level3_data(
[
'amount' => WC_Stripe_Helper::get_stripe_amount( $order_total ),
'expand[]' => 'charges.data.balance_transaction',
'amount' => WC_Stripe_Helper::get_stripe_amount( $order_total ),
'stripe_expand' => [ 'charges.data.balance_transaction' ],
],
'payment_intents/' . $intent->id . '/capture',
$level3_data,
Expand Down Expand Up @@ -345,8 +345,8 @@ public function capture_payment( $order_id ) {
$level3_data = $this->get_level3_data_from_order( $order );
$result = WC_Stripe_API::request_with_level3_data(
[
'amount' => WC_Stripe_Helper::get_stripe_amount( $order_total ),
'expand[]' => 'balance_transaction',
'amount' => WC_Stripe_Helper::get_stripe_amount( $order_total ),
'stripe_expand' => [ 'balance_transaction' ],
],
'charges/' . $charge . '/capture',
$level3_data,
Expand Down
13 changes: 9 additions & 4 deletions includes/payment-methods/class-wc-stripe-upe-payment-gateway.php
Original file line number Diff line number Diff line change
Expand Up @@ -1558,7 +1558,7 @@ private function is_order_associated_to_setup_intent( int $order_id, string $int
return false;
}

$intent = $this->stripe_request( 'setup_intents/' . $intent_id . '?expand[]=payment_method.billing_details' );
$intent = $this->stripe_request( 'setup_intents/' . $intent_id, [ 'stripe_expand' => [ 'payment_method.billing_details' ] ] );
if ( ! $intent ) {
return false;
}
Expand Down Expand Up @@ -1646,10 +1646,10 @@ public function process_order_for_confirmed_intent( $order, $intent_id, $save_pa

// Get payment intent to confirm status.
if ( $payment_needed ) {
$intent = $this->stripe_request( 'payment_intents/' . $intent_id . '?expand[]=payment_method' );
$intent = $this->stripe_request( 'payment_intents/' . $intent_id, [ 'stripe_expand' => [ 'payment_method' ] ] );
$error = isset( $intent->last_payment_error ) ? $intent->last_payment_error : false;
} else {
$intent = $this->stripe_request( 'setup_intents/' . $intent_id . '?expand[]=payment_method&expand[]=latest_attempt' );
$intent = $this->stripe_request( 'setup_intents/' . $intent_id, [ 'stripe_expand' => [ 'payment_method', 'latest_attempt' ] ] );
$error = isset( $intent->last_setup_error ) ? $intent->last_setup_error : false;
}

Expand Down Expand Up @@ -2166,7 +2166,7 @@ private function is_setup_intent_success_creation_redirection() {
*/
public function create_token_from_setup_intent( $setup_intent_id, $user ) {
try {
$setup_intent = $this->stripe_request( 'setup_intents/' . $setup_intent_id . '?&expand[]=latest_attempt' );
$setup_intent = $this->stripe_request( 'setup_intents/' . $setup_intent_id, [ 'stripe_expand' => [ 'latest_attempt' ] ] );
if ( ! empty( $setup_intent->last_payment_error ) ) {
throw new WC_Stripe_Exception( __( "We're not able to add this payment method. Please try again later.", 'woocommerce-gateway-stripe' ) );
}
Expand Down Expand Up @@ -2227,6 +2227,11 @@ protected function stripe_request( $path, $params = null, $order = null, $method
if ( is_null( $params ) ) {
return WC_Stripe_API::retrieve( $path );
}

if ( is_array( $params ) && [ 'stripe_expand' ] === array_keys( $params ) ) {
return WC_Stripe_API::retrieve( $path, $params['stripe_expand'] );
}

if ( ! is_null( $order ) ) {
$level3_data = $this->get_level3_data_from_order( $order );
return WC_Stripe_API::request_with_level3_data( $params, $path, $level3_data, $order );
Expand Down
5 changes: 3 additions & 2 deletions tests/phpunit/Helpers/WC_Helper_Stripe_Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,12 @@ public static function reset() {
/**
* Retrieve data. This is the equivalent mock for WC_Stripe_API::retrieve
*
* @param string data type
* @param string $key The Stripe API we want to call.
* @param string[]|null $expand_params The parameters to send as `expand[]` URL parameters in the request.
*
* @return array retrieved data mock
*/
public static function retrieve( $key = 'account' ) {
public static function retrieve( $key = 'account', $expand_params = null ) {
return self::$retrieve_response;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -954,7 +954,7 @@ public function test_process_redirect_payment_returns_valid_response() {
);
$this->mock_gateway->expects( $this->once() )
->method( 'stripe_request' )
->with( "payment_intents/$payment_intent_id?expand[]=payment_method" )
->with( "payment_intents/$payment_intent_id", [ 'stripe_expand' => [ 'payment_method' ] ] )
->will(
$this->returnValue(
$this->array_to_object( $payment_intent_mock )
Expand Down Expand Up @@ -1017,7 +1017,7 @@ public function test_process_redirect_payment_only_runs_once() {

$this->mock_gateway->expects( $this->once() )
->method( 'stripe_request' )
->with( "payment_intents/$payment_intent_id?expand[]=payment_method" )
->with( "payment_intents/$payment_intent_id", [ 'stripe_expand' => [ 'payment_method' ] ] )
->will(
$this->returnValue(
$this->array_to_object( $payment_intent_mock )
Expand Down Expand Up @@ -1102,7 +1102,7 @@ public function test_process_redirect_payment_locks_order() {
// Expect the process to bail early.
$this->mock_gateway->expects( $this->never() )
->method( 'stripe_request' )
->with( "payment_intents/$payment_intent_id?expand[]=payment_method" );
->with( "payment_intents/$payment_intent_id", [ 'stripe_expand' => [ 'payment_method' ] ] );

$this->mock_gateway->process_upe_redirect_payment( $order_id, $payment_intent_id, false );
}
Expand Down Expand Up @@ -1139,7 +1139,7 @@ public function test_checkout_without_payment_uses_setup_intents() {
);
$this->mock_gateway->expects( $this->once() )
->method( 'stripe_request' )
->with( "setup_intents/$setup_intent_id?expand[]=payment_method&expand[]=latest_attempt" )
->with( "setup_intents/$setup_intent_id", [ 'stripe_expand' => [ 'payment_method', 'latest_attempt' ] ] )
->will(
$this->returnValue(
$this->array_to_object( $setup_intent_mock )
Expand Down Expand Up @@ -1190,7 +1190,7 @@ public function test_checkout_saves_payment_method_to_order() {
);
$this->mock_gateway->expects( $this->once() )
->method( 'stripe_request' )
->with( "payment_intents/$payment_intent_id?expand[]=payment_method" )
->with( "payment_intents/$payment_intent_id", [ 'stripe_expand' => [ 'payment_method' ] ] )
->will(
$this->returnValue(
$this->array_to_object( $payment_intent_mock )
Expand Down Expand Up @@ -2280,7 +2280,7 @@ public function test_pre_order_payment_is_successful() {

$this->mock_gateway->expects( $this->once() )
->method( 'stripe_request' )
->with( "payment_intents/$payment_intent_id?expand[]=payment_method" )
->with( "payment_intents/$payment_intent_id", [ 'stripe_expand' => [ 'payment_method' ] ] )
->will(
$this->returnValue(
$this->array_to_object( $payment_intent_mock )
Expand Down Expand Up @@ -2369,7 +2369,7 @@ public function test_pre_order_without_payment_uses_setup_intents() {

$this->mock_gateway->expects( $this->once() )
->method( 'stripe_request' )
->with( "setup_intents/$setup_intent_id?expand[]=payment_method&expand[]=latest_attempt" )
->with( "setup_intents/$setup_intent_id", [ 'stripe_expand' => [ 'payment_method', 'latest_attempt' ] ] )
->will(
$this->returnValue(
$this->array_to_object( $setup_intent_mock )
Expand Down
Loading