From 05a1284876c575da4961725f9bbd557e701e095e Mon Sep 17 00:00:00 2001
From: James Allan
Date: Mon, 26 Aug 2024 09:59:28 +1000
Subject: [PATCH 01/20] Flag when the account is connected via App and if keys
have expired (#3353)
* WIP changes
* Remove unused account connection endpoint
* Remove unused endpoint function
* Add changelog entries
---
changelog.txt | 1 +
client/settings/payment-methods/index.js | 4 +-
.../account-status-panel.js | 78 +++++++++++++++++--
...lass-wc-rest-stripe-account-controller.php | 24 +++++-
includes/connect/class-wc-stripe-connect.php | 21 +++--
readme.txt | 1 +
6 files changed, 111 insertions(+), 18 deletions(-)
diff --git a/changelog.txt b/changelog.txt
index 606d64bb2..c4a626103 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -8,6 +8,7 @@
* Fix - Clear webhook state after reconfiguring webhooks to remove outdated error and success statuses.
* Add - Log incoming webhook events and their request body.
* Add - Show UPE payment methods in saved order on block checkout page.
+* Add - Display UI elements for connection type and expired keys status for Stripe accounts linked via the WooCommerce Stripe App.
* Tweak - Delete the notice about the missing customization options on the updated checkout experience.
= 8.6.1 - 2024-08-09 =
diff --git a/client/settings/payment-methods/index.js b/client/settings/payment-methods/index.js
index 322cb9b0c..186dafe2d 100644
--- a/client/settings/payment-methods/index.js
+++ b/client/settings/payment-methods/index.js
@@ -56,8 +56,8 @@ const PaymentMethodsPanel = ( { onSaveChanges } ) => {
const { data } = useAccount();
const isTestModeEnabled = Boolean( data.testmode );
const oauthConnected = isTestModeEnabled
- ? data?.oauth_connections?.test
- : data?.oauth_connections?.live;
+ ? data?.oauth_connections?.test?.connected
+ : data?.oauth_connections?.live?.connected;
return (
<>
diff --git a/client/settings/stripe-auth-account/account-status-panel.js b/client/settings/stripe-auth-account/account-status-panel.js
index a2049d0d0..a9dc87780 100644
--- a/client/settings/stripe-auth-account/account-status-panel.js
+++ b/client/settings/stripe-auth-account/account-status-panel.js
@@ -1,6 +1,6 @@
import { __ } from '@wordpress/i18n';
import { Icon } from '@wordpress/components';
-import { help } from '@wordpress/icons';
+import { help, link, linkOff } from '@wordpress/icons';
import Chip from 'wcstripe/components/chip';
import Tooltip from 'wcstripe/components/tooltip';
import {
@@ -55,6 +55,46 @@ const unconnectedAccountTip = () => {
);
};
+/**
+ * Generates an tip for accounts connected via the WooCommerce Stripe App.
+ *
+ * @return {JSX.Element} The connected via app tip.
+ */
+const connectedViaAppTip = () => {
+ return (
+
+
+
+
+
+ );
+};
+
+/**
+ * Generates an tip for accounts connected via the WooCommerce Stripe App that has expired keys.
+ *
+ * @return {JSX.Element} The connected via app tip.
+ */
+const expiredAppKeysTip = () => {
+ return (
+
+
+
+
+
+ );
+};
+
/**
* Gets the account status.
*
@@ -76,20 +116,23 @@ const getAccountStatus = ( accountKeys, data, testMode ) => {
const publishableKey = testMode
? accountKeys.test_publishable_key
: accountKeys.publishable_key;
- const oauthConnected = testMode
- ? data?.oauth_connections?.test
- : data?.oauth_connections?.live;
- let accountStatus = 'disconnected';
+ // eslint-disable-next-line camelcase
+ const { oauth_connections } = data;
+ const oauthStatus = testMode
+ ? oauth_connections?.test
+ : oauth_connections?.live;
- if ( secretKey && publishableKey ) {
- accountStatus = oauthConnected ? 'connected' : 'unconnected';
- }
+ const hasKeys = secretKey && publishableKey;
+ const isConnected = oauthStatus?.connected;
+ const isConnectedViaApp = oauthStatus?.type === 'app';
+ const isExpired = oauthStatus?.expired;
const accountStatusMap = {
connected: {
text: __( 'Connected', 'woocommerce-gateway-stripe' ),
color: 'green',
+ icon: isConnectedViaApp ? connectedViaAppTip() : null,
},
unconnected: {
text: __( 'Incomplete', 'woocommerce-gateway-stripe' ),
@@ -100,8 +143,27 @@ const getAccountStatus = ( accountKeys, data, testMode ) => {
text: __( 'Disconnected', 'woocommerce-gateway-stripe' ),
color: 'red',
},
+ expired: {
+ text: __( 'Expired', 'woocommerce-gateway-stripe' ),
+ color: 'red',
+ icon: expiredAppKeysTip(),
+ },
};
+ if ( ! hasKeys ) {
+ return accountStatusMap.disconnected;
+ }
+
+ if ( ! isConnected ) {
+ return accountStatusMap.unconnected;
+ }
+
+ let accountStatus = 'connected';
+
+ if ( isConnectedViaApp && isExpired ) {
+ accountStatus = 'expired';
+ }
+
return accountStatusMap[ accountStatus ];
};
diff --git a/includes/admin/class-wc-rest-stripe-account-controller.php b/includes/admin/class-wc-rest-stripe-account-controller.php
index 09069c518..65a9c8e03 100644
--- a/includes/admin/class-wc-rest-stripe-account-controller.php
+++ b/includes/admin/class-wc-rest-stripe-account-controller.php
@@ -97,8 +97,8 @@ public function get_account() {
'webhook_url' => WC_Stripe_Helper::get_webhook_url(),
'configured_webhook_urls' => WC_Stripe_Webhook_State::get_configured_webhook_urls(),
'oauth_connections' => [
- 'test' => WC_Stripe::get_instance()->connect->is_connected_via_oauth( 'test' ),
- 'live' => WC_Stripe::get_instance()->connect->is_connected_via_oauth( 'live' ),
+ 'test' => $this->get_account_oauth_connection_data( 'test' ),
+ 'live' => $this->get_account_oauth_connection_data( 'live' ),
],
]
);
@@ -164,4 +164,24 @@ public function refresh_account() {
// calling the same "get" method, so that the data format is the same.
return $this->get_account();
}
+
+ /**
+ * Generates the OAuth connection data for the given mode.
+ *
+ * @param string $mode The mode. Can be 'test' or 'live'.
+ * @return array The connection data.
+ */
+ private function get_account_oauth_connection_data( $mode ) {
+ $connection = [
+ 'connected' => (bool) WC_Stripe::get_instance()->connect->is_connected_via_oauth( $mode ),
+ 'type' => WC_Stripe::get_instance()->connect->get_connection_type( $mode ),
+ ];
+
+ // If the connection is an app connection, check if the keys have expired.
+ if ( 'app' === $connection['type'] ) {
+ $connection['expired'] = $this->account->get_cached_account_data( $mode ) ? false : true; // If we have the account data, it's not expired.
+ }
+
+ return $connection;
+ }
}
diff --git a/includes/connect/class-wc-stripe-connect.php b/includes/connect/class-wc-stripe-connect.php
index 2a55fa686..7c5724799 100644
--- a/includes/connect/class-wc-stripe-connect.php
+++ b/includes/connect/class-wc-stripe-connect.php
@@ -264,10 +264,7 @@ public function is_connected_via_oauth( $mode = 'live' ) {
return false;
}
- $options = WC_Stripe_Helper::get_stripe_settings();
- $key = 'test' === $mode ? 'test_connection_type' : 'connection_type';
-
- return isset( $options[ $key ] ) && in_array( $options[ $key ], [ 'connect', 'app' ], true );
+ return in_array( $this->get_connection_type( $mode ), [ 'connect', 'app' ], true );
}
/**
@@ -285,9 +282,21 @@ public function is_connected_via_app_oauth( $mode = null ) {
if ( is_null( $mode ) ) {
$mode = isset( $options['testmode'] ) && 'yes' === $options['testmode'] ? 'test' : 'live';
}
- $key = 'test' === $mode ? 'test_connection_type' : 'connection_type';
- return isset( $options[ $key ] ) && 'app' === $options[ $key ];
+ return 'app' === $this->get_connection_type( $mode );
+ }
+
+ /**
+ * Fetches the connection type for the account.
+ *
+ * @param string $mode The account mode. 'live' or 'test'.
+ * @return string The connection type. 'connect', 'app', or ''.
+ */
+ public function get_connection_type( $mode ) {
+ $options = WC_Stripe_Helper::get_stripe_settings();
+ $key = 'test' === $mode ? 'test_connection_type' : 'connection_type';
+
+ return isset( $options[ $key ] ) ? $options[ $key ] : '';
}
/**
diff --git a/readme.txt b/readme.txt
index d4325c5c2..0ab5cf86f 100644
--- a/readme.txt
+++ b/readme.txt
@@ -136,6 +136,7 @@ If you get stuck, you can ask for help in the Plugin Forum.
* Fix - Clear webhook state after reconfiguring webhooks to remove outdated error and success statuses.
* Add - Log incoming webhook events and their request body.
* Add - Show UPE payment methods in saved order on block checkout page.
+* Add - Display UI elements for connection type and expired keys status for Stripe accounts linked via the WooCommerce Stripe App.
* Tweak - Delete the notice about the missing customization options on the updated checkout experience.
[See changelog for all versions](https://raw.githubusercontent.com/woocommerce/woocommerce-gateway-stripe/trunk/changelog.txt).
From e230f50653e0cfe4e70ed381742c059726d7070a Mon Sep 17 00:00:00 2001
From: James Allan
Date: Tue, 27 Aug 2024 11:57:03 +1000
Subject: [PATCH 02/20] Fix PHP warning caused by undefined array key when
fetching customer account with no matching results (#3376)
* Prevent warning if customer response is empty
* Add changelog entries
---
changelog.txt | 1 +
includes/class-wc-stripe-customer.php | 2 +-
readme.txt | 1 +
3 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/changelog.txt b/changelog.txt
index c4a626103..8359fbdb8 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -10,6 +10,7 @@
* Add - Show UPE payment methods in saved order on block checkout page.
* Add - Display UI elements for connection type and expired keys status for Stripe accounts linked via the WooCommerce Stripe App.
* Tweak - Delete the notice about the missing customization options on the updated checkout experience.
+* Fix - Handle undefined array key when no matching customer account is found when guest customers checkout.
= 8.6.1 - 2024-08-09 =
* Tweak - Improves the wording of the invalid Stripe keys errors, instructing merchants to click the "Configure connection" button instead of manually setting the keys.
diff --git a/includes/class-wc-stripe-customer.php b/includes/class-wc-stripe-customer.php
index cb880a49b..e5c579d04 100644
--- a/includes/class-wc-stripe-customer.php
+++ b/includes/class-wc-stripe-customer.php
@@ -238,7 +238,7 @@ public function get_existing_customer( $email, $name ) {
return [];
}
- return $search_response->data[0];
+ return $search_response->data[0] ?? [];
}
/**
diff --git a/readme.txt b/readme.txt
index 0ab5cf86f..37256be8b 100644
--- a/readme.txt
+++ b/readme.txt
@@ -138,5 +138,6 @@ If you get stuck, you can ask for help in the Plugin Forum.
* Add - Show UPE payment methods in saved order on block checkout page.
* Add - Display UI elements for connection type and expired keys status for Stripe accounts linked via the WooCommerce Stripe App.
* Tweak - Delete the notice about the missing customization options on the updated checkout experience.
+* Fix - Handle undefined array key when no matching customer account is found when guest customers checkout.
[See changelog for all versions](https://raw.githubusercontent.com/woocommerce/woocommerce-gateway-stripe/trunk/changelog.txt).
From 190e8c56b6e842a24b49769074d08d000b76fd46 Mon Sep 17 00:00:00 2001
From: Mayisha <33387139+Mayisha@users.noreply.github.com>
Date: Tue, 27 Aug 2024 14:49:30 +0600
Subject: [PATCH 03/20] Catch error when getting intent from order. (#3367)
* add try catch to prevent uncaught error
* catch `Exception`
---
changelog.txt | 1 +
.../class-wc-stripe-settings-controller.php | 18 +++++++++++-------
readme.txt | 1 +
3 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/changelog.txt b/changelog.txt
index 8359fbdb8..1240cfd99 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -10,6 +10,7 @@
* Add - Show UPE payment methods in saved order on block checkout page.
* Add - Display UI elements for connection type and expired keys status for Stripe accounts linked via the WooCommerce Stripe App.
* Tweak - Delete the notice about the missing customization options on the updated checkout experience.
+* Fix - Catch error when getting intent from order.
* Fix - Handle undefined array key when no matching customer account is found when guest customers checkout.
= 8.6.1 - 2024-08-09 =
diff --git a/includes/admin/class-wc-stripe-settings-controller.php b/includes/admin/class-wc-stripe-settings-controller.php
index cd4ef921b..22150e40a 100644
--- a/includes/admin/class-wc-stripe-settings-controller.php
+++ b/includes/admin/class-wc-stripe-settings-controller.php
@@ -68,13 +68,17 @@ public function set_stripe_gateways_in_list( $ordering ) {
* @param WC_Order $order The order that is being viewed.
*/
public function hide_refund_button_for_uncaptured_orders( $order ) {
- $intent = $this->gateway->get_intent_from_order( $order );
-
- if ( $intent && 'requires_capture' === $intent->status ) {
- $no_refunds_button = __( 'Refunding unavailable', 'woocommerce-gateway-stripe' );
- $no_refunds_tooltip = __( 'Refunding via Stripe is unavailable because funds have not been captured for this order. Process order to take payment, or cancel to remove the pre-authorization.', 'woocommerce-gateway-stripe' );
- echo '';
- echo '' . $no_refunds_button . wc_help_tip( $no_refunds_tooltip ) . '';
+ try {
+ $intent = $this->gateway->get_intent_from_order( $order );
+
+ if ( $intent && 'requires_capture' === $intent->status ) {
+ $no_refunds_button = __( 'Refunding unavailable', 'woocommerce-gateway-stripe' );
+ $no_refunds_tooltip = __( 'Refunding via Stripe is unavailable because funds have not been captured for this order. Process order to take payment, or cancel to remove the pre-authorization.', 'woocommerce-gateway-stripe' );
+ echo '';
+ echo '' . $no_refunds_button . wc_help_tip( $no_refunds_tooltip ) . '';
+ }
+ } catch ( Exception $e ) {
+ WC_Stripe_Logger::log( 'Error getting intent from order: ' . $e->getMessage() );
}
}
diff --git a/readme.txt b/readme.txt
index 37256be8b..fcd189325 100644
--- a/readme.txt
+++ b/readme.txt
@@ -138,6 +138,7 @@ If you get stuck, you can ask for help in the Plugin Forum.
* Add - Show UPE payment methods in saved order on block checkout page.
* Add - Display UI elements for connection type and expired keys status for Stripe accounts linked via the WooCommerce Stripe App.
* Tweak - Delete the notice about the missing customization options on the updated checkout experience.
+* Fix - Catch error when getting intent from order.
* Fix - Handle undefined array key when no matching customer account is found when guest customers checkout.
[See changelog for all versions](https://raw.githubusercontent.com/woocommerce/woocommerce-gateway-stripe/trunk/changelog.txt).
From d93b281c95b6a87161db77679d3aa0ac4e45b6c6 Mon Sep 17 00:00:00 2001
From: Mayisha <33387139+Mayisha@users.noreply.github.com>
Date: Tue, 27 Aug 2024 15:01:30 +0600
Subject: [PATCH 04/20] Fix error in saving settings (#3360)
---
changelog.txt | 1 +
includes/payment-methods/class-wc-stripe-payment-request.php | 4 ++--
readme.txt | 1 +
3 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/changelog.txt b/changelog.txt
index 1240cfd99..f33fab42c 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -10,6 +10,7 @@
* Add - Show UPE payment methods in saved order on block checkout page.
* Add - Display UI elements for connection type and expired keys status for Stripe accounts linked via the WooCommerce Stripe App.
* Tweak - Delete the notice about the missing customization options on the updated checkout experience.
+* Fix - Fix error in saving settings when express payment methods are disabled.
* Fix - Catch error when getting intent from order.
* Fix - Handle undefined array key when no matching customer account is found when guest customers checkout.
diff --git a/includes/payment-methods/class-wc-stripe-payment-request.php b/includes/payment-methods/class-wc-stripe-payment-request.php
index 373502b51..25217775a 100644
--- a/includes/payment-methods/class-wc-stripe-payment-request.php
+++ b/includes/payment-methods/class-wc-stripe-payment-request.php
@@ -82,6 +82,8 @@ public function __construct() {
$this->total_label = str_replace( "'", '', $this->total_label ) . apply_filters( 'wc_stripe_payment_request_total_label_suffix', ' (via WooCommerce)' );
+ add_action( 'woocommerce_stripe_updated', [ $this, 'migrate_button_size' ] );
+
// Checks if Stripe Gateway is enabled.
if ( empty( $this->stripe_settings ) || ( isset( $this->stripe_settings['enabled'] ) && 'yes' !== $this->stripe_settings['enabled'] ) ) {
return;
@@ -234,8 +236,6 @@ public function init() {
add_action( 'woocommerce_checkout_order_processed', [ $this, 'add_order_meta' ], 10, 2 );
add_filter( 'woocommerce_login_redirect', [ $this, 'get_login_redirect_url' ], 10, 3 );
add_filter( 'woocommerce_registration_redirect', [ $this, 'get_login_redirect_url' ], 10, 3 );
-
- add_action( 'woocommerce_stripe_updated', [ $this, 'migrate_button_size' ] );
}
/**
diff --git a/readme.txt b/readme.txt
index fcd189325..782bf94ea 100644
--- a/readme.txt
+++ b/readme.txt
@@ -138,6 +138,7 @@ If you get stuck, you can ask for help in the Plugin Forum.
* Add - Show UPE payment methods in saved order on block checkout page.
* Add - Display UI elements for connection type and expired keys status for Stripe accounts linked via the WooCommerce Stripe App.
* Tweak - Delete the notice about the missing customization options on the updated checkout experience.
+* Fix - Fix error in saving settings when express payment methods are disabled.
* Fix - Catch error when getting intent from order.
* Fix - Handle undefined array key when no matching customer account is found when guest customers checkout.
From ab4235e66a775386d029eeb69b7d6e5470206bd3 Mon Sep 17 00:00:00 2001
From: Faisal Alvi
Date: Tue, 27 Aug 2024 18:36:55 +0530
Subject: [PATCH 05/20] Address QIT Security test errors (#3260)
* add QIT workflow file
* add Generate ZIP workflow file
* fix QIT Security issues
* suggestions implemented
* add PHPCompat and Malware QIT tests
* suggestions implemented
* update the branches in workflow
* update allowed tag format
---
.github/workflows/generate-zip.yml | 26 +++
.github/workflows/qit.yml | 152 ++++++++++++++++++
changelog.txt | 1 +
.../class-wc-stripe-settings-controller.php | 2 +-
includes/class-wc-gateway-stripe.php | 10 +-
.../class-wc-gateway-stripe-alipay.php | 2 +-
.../class-wc-gateway-stripe-bancontact.php | 2 +-
.../class-wc-gateway-stripe-boleto.php | 2 +-
.../class-wc-gateway-stripe-eps.php | 2 +-
.../class-wc-gateway-stripe-giropay.php | 2 +-
.../class-wc-gateway-stripe-ideal.php | 2 +-
.../class-wc-gateway-stripe-multibanco.php | 2 +-
.../class-wc-gateway-stripe-oxxo.php | 2 +-
.../class-wc-gateway-stripe-p24.php | 2 +-
.../class-wc-gateway-stripe-sepa.php | 2 +-
.../class-wc-gateway-stripe-sofort.php | 2 +-
readme.txt | 1 +
.../emails/failed-preorder-authentication.php | 2 +-
18 files changed, 198 insertions(+), 18 deletions(-)
create mode 100644 .github/workflows/generate-zip.yml
create mode 100644 .github/workflows/qit.yml
diff --git a/.github/workflows/generate-zip.yml b/.github/workflows/generate-zip.yml
new file mode 100644
index 000000000..d7d766edd
--- /dev/null
+++ b/.github/workflows/generate-zip.yml
@@ -0,0 +1,26 @@
+name: Generate ZIP file
+
+on:
+ workflow_dispatch:
+ workflow_call:
+
+jobs:
+ generate-zip-file:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup node version
+ uses: actions/setup-node@v4
+ with:
+ node-version-file: '.nvmrc'
+
+ - name: Generate ZIP file
+ run: npm run build && rm -rf ./woocommerce-gateway-stripe && unzip woocommerce-gateway-stripe.zip -d ./woocommerce-gateway-stripe
+
+ - name: Use the Upload Artifact GitHub Action
+ uses: actions/upload-artifact@v4
+ with:
+ name: woocommerce-gateway-stripe
+ path: woocommerce-gateway-stripe/
diff --git a/.github/workflows/qit.yml b/.github/workflows/qit.yml
new file mode 100644
index 000000000..96a069a41
--- /dev/null
+++ b/.github/workflows/qit.yml
@@ -0,0 +1,152 @@
+name: QIT Tests
+
+on:
+ workflow_dispatch:
+ inputs:
+ test:
+ description: 'Test to run'
+ required: true
+ default: 'default'
+ type: choice
+ options:
+ - default
+ - activation
+ - api
+ - e2e
+ - phpstan
+ - phpcompat
+ - security
+ - malware
+ pull_request:
+ types: [opened, synchronize, reopened, labeled]
+ branches:
+ - trunk
+ - develop
+
+permissions:
+ contents: read
+ pull-requests: write
+
+jobs:
+ build:
+ if: "${{ ( inputs.test != '' && inputs.test != 'none' ) || contains(github.event.pull_request.labels.*.name, 'needs: qit default tests') || contains(github.event.pull_request.labels.*.name, 'needs: qit activation test') || contains(github.event.pull_request.labels.*.name, 'needs: qit api test') || contains(github.event.pull_request.labels.*.name, 'needs: qit e2e test') || contains(github.event.pull_request.labels.*.name, 'needs: qit phpstan test') || contains(github.event.pull_request.labels.*.name, 'needs: qit phpcompat test') || contains(github.event.pull_request.labels.*.name, 'needs: qit security test') || contains(github.event.pull_request.labels.*.name, 'needs: qit malware test') }}"
+ uses: woocommerce/woocommerce-gateway-stripe/.github/workflows/generate-zip.yml@fix-qit-security
+
+ test:
+ if: "${{ ( inputs.test != '' && inputs.test != 'none' ) || contains(github.event.pull_request.labels.*.name, 'needs: qit default tests') || contains(github.event.pull_request.labels.*.name, 'needs: qit activation test') || contains(github.event.pull_request.labels.*.name, 'needs: qit api test') || contains(github.event.pull_request.labels.*.name, 'needs: qit e2e test') || contains(github.event.pull_request.labels.*.name, 'needs: qit phpstan test') || contains(github.event.pull_request.labels.*.name, 'needs: qit phpcompat test') || contains(github.event.pull_request.labels.*.name, 'needs: qit security test') || contains(github.event.pull_request.labels.*.name, 'needs: qit malware test') }}"
+ needs: build
+ name: run
+ runs-on: ubuntu-latest
+
+ env:
+ NO_COLOR: 1
+ QIT_DISABLE_ONBOARDING: yes
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Download build
+ uses: actions/download-artifact@v4
+ with:
+ name: ${{ github.event.repository.name }}
+
+ - name: Build plugin zip
+ run: zip -r ${{ github.event.repository.name }}.zip ${{ github.event.repository.name }}
+
+ - name: Set PHP version
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: 7.4
+ tools: composer:v2
+ coverage: none
+
+ - name: Install QIT via composer
+ run: composer require woocommerce/qit-cli
+
+ - name: Add partner
+ run: ./vendor/bin/qit partner:add --user='${{ secrets.PARTNER_USER }}' --application_password='${{ secrets.PARTNER_SECRET }}'
+
+ - name: Run activation test
+ if: "${{ ( inputs.tests == 'default' || inputs.tests == 'activation' ) || contains(github.event.pull_request.labels.*.name, 'needs: qit default tests') || contains(github.event.pull_request.labels.*.name, 'needs: qit activation test') }}"
+ id: run-activation-test
+ run: ./vendor/bin/qit run:activation ${{ github.event.repository.name }} --zip=${{ github.event.repository.name }}.zip --wait > activation-result.txt
+
+ - uses: marocchino/sticky-pull-request-comment@v2
+ if: ${{ failure() && steps.run-activation-test.conclusion == 'failure' }}
+ with:
+ header: QIT activation result
+ recreate: true
+ path: activation-result.txt
+
+ - name: Run API test
+ if: "${{ ( ( inputs.tests == 'default' || inputs.tests == 'api' ) || contains(github.event.pull_request.labels.*.name, 'needs: qit default tests') || contains(github.event.pull_request.labels.*.name, 'needs: qit api test') ) && ( success() || failure() ) }}"
+ id: run-api-test
+ run: ./vendor/bin/qit run:woo-api ${{ github.event.repository.name }} --zip=${{ github.event.repository.name }}.zip --wait > api-result.txt
+
+ - uses: marocchino/sticky-pull-request-comment@v2
+ if: ${{ failure() && steps.run-api-test.conclusion == 'failure' }}
+ with:
+ header: QIT API result
+ recreate: true
+ path: api-result.txt
+
+ - name: Run E2E test
+ if: "${{ ( ( inputs.tests == 'default' || inputs.tests == 'e2e' ) || contains(github.event.pull_request.labels.*.name, 'needs: qit default tests') || contains(github.event.pull_request.labels.*.name, 'needs: qit e2e test') ) && ( success() || failure() ) }}"
+ id: run-e2e-test
+ run: ./vendor/bin/qit run:woo-e2e ${{ github.event.repository.name }} --zip=${{ github.event.repository.name }}.zip --wait > e2e-result.txt
+
+ - uses: marocchino/sticky-pull-request-comment@v2
+ if: ${{ failure() && steps.run-e2e-test.conclusion == 'failure' }}
+ with:
+ header: QIT E2E result
+ recreate: true
+ path: e2e-result.txt
+
+ - name: Run PHPStan test
+ if: "${{ inputs.tests == 'phpstan' || contains(github.event.pull_request.labels.*.name, 'needs: qit phpstan test') && ( success() || failure() ) }}"
+ id: run-phpstan-test
+ run: ./vendor/bin/qit run:phpstan ${{ github.event.repository.name }} --zip=${{ github.event.repository.name }}.zip --wait > phpstan-result.txt
+
+ - uses: marocchino/sticky-pull-request-comment@v2
+ if: ${{ failure() && steps.run-phpstan-test.conclusion == 'failure' }}
+ with:
+ header: QIT PHPStan result
+ recreate: true
+ path: phpstan-result.txt
+
+ - name: Run PHPCompat test
+ if: "${{ inputs.tests == 'phpcompat' || contains(github.event.pull_request.labels.*.name, 'needs: qit phpcompat test') && ( success() || failure() ) }}"
+ id: run-phpcompat-test
+ run: ./vendor/bin/qit run:phpcompatibility ${{ github.event.repository.name }} --zip=${{ github.event.repository.name }}.zip --wait > phpcompat-result.txt
+
+ - uses: marocchino/sticky-pull-request-comment@v2
+ if: ${{ failure() && steps.run-phpcompat-test.conclusion == 'failure' }}
+ with:
+ header: QIT PHPCompat result
+ recreate: true
+ path: phpcompat-result.txt
+
+ - name: Run security test
+ if: "${{ inputs.tests == 'security' || contains(github.event.pull_request.labels.*.name, 'needs: qit security test') && ( success() || failure() ) }}"
+ id: run-security-test
+ run: ./vendor/bin/qit run:security ${{ github.event.repository.name }} --zip=${{ github.event.repository.name }}.zip --wait > security-result.txt
+
+ - uses: marocchino/sticky-pull-request-comment@v2
+ if: ${{ failure() && steps.run-security-test.conclusion == 'failure' }}
+ with:
+ header: QIT security result
+ recreate: true
+ path: security-result.txt
+
+ - name: Run malware test
+ if: "${{ inputs.tests == 'malware' || contains(github.event.pull_request.labels.*.name, 'needs: qit malware test') && ( success() || failure() ) }}"
+ id: run-malware-test
+ run: ./vendor/bin/qit run:malware ${{ github.event.repository.name }} --zip=${{ github.event.repository.name }}.zip --wait > malware-result.txt
+
+ - uses: marocchino/sticky-pull-request-comment@v2
+ if: ${{ failure() && steps.run-malware-test.conclusion == 'failure' }}
+ with:
+ header: QIT malware result
+ recreate: true
+ path: malware-result.txt
diff --git a/changelog.txt b/changelog.txt
index f33fab42c..6dc2df6eb 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -13,6 +13,7 @@
* Fix - Fix error in saving settings when express payment methods are disabled.
* Fix - Catch error when getting intent from order.
* Fix - Handle undefined array key when no matching customer account is found when guest customers checkout.
+* Fix - Address QIT Security test errors.
= 8.6.1 - 2024-08-09 =
* Tweak - Improves the wording of the invalid Stripe keys errors, instructing merchants to click the "Configure connection" button instead of manually setting the keys.
diff --git a/includes/admin/class-wc-stripe-settings-controller.php b/includes/admin/class-wc-stripe-settings-controller.php
index 22150e40a..6bd925241 100644
--- a/includes/admin/class-wc-stripe-settings-controller.php
+++ b/includes/admin/class-wc-stripe-settings-controller.php
@@ -75,7 +75,7 @@ public function hide_refund_button_for_uncaptured_orders( $order ) {
$no_refunds_button = __( 'Refunding unavailable', 'woocommerce-gateway-stripe' );
$no_refunds_tooltip = __( 'Refunding via Stripe is unavailable because funds have not been captured for this order. Process order to take payment, or cancel to remove the pre-authorization.', 'woocommerce-gateway-stripe' );
echo '';
- echo '' . $no_refunds_button . wc_help_tip( $no_refunds_tooltip ) . '';
+ echo '' . esc_html( $no_refunds_button ) . wc_help_tip( $no_refunds_tooltip ) . '';
}
} catch ( Exception $e ) {
WC_Stripe_Logger::log( 'Error getting intent from order: ' . $e->getMessage() );
diff --git a/includes/class-wc-gateway-stripe.php b/includes/class-wc-gateway-stripe.php
index ded4dbada..d1ffb2bbe 100644
--- a/includes/class-wc-gateway-stripe.php
+++ b/includes/class-wc-gateway-stripe.php
@@ -245,7 +245,7 @@ public function payment_fields() {
$description = trim( $description );
- echo apply_filters( 'wc_stripe_description', wpautop( wp_kses_post( $description ) ), $this->id ); // wpcs: xss ok.
+ echo wp_kses_post( apply_filters( 'wc_stripe_description', wpautop( $description ), $this->id ) );
if ( $display_tokenization ) {
$this->tokenization_script();
@@ -560,7 +560,7 @@ public function display_order_fee( $order_id ) {
|
- - $currency ] ); // wpcs: xss ok. ?>
+ - $currency ] ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
@@ -597,7 +597,7 @@ public function display_order_payout( $order_id ) {
|
- $currency ] ); // wpcs: xss ok. ?>
+ $currency ] ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
@@ -1116,11 +1116,11 @@ public function needs_setup() {
* @return array
*/
public function update_onboarding_settings( $settings ) {
- if ( ! isset( $_SERVER['HTTP_REFERER'] ) ) {
+ if ( ! isset( $_SERVER['HTTP_REFERER'] ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
return;
}
- parse_str( wp_parse_url( $_SERVER['HTTP_REFERER'], PHP_URL_QUERY ), $queries ); // phpcs:ignore sanitization ok.
+ parse_str( wp_parse_url( wp_unslash( $_SERVER['HTTP_REFERER'] ), PHP_URL_QUERY ), $queries ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
// Determine if merchant is onboarding (page='wc-admin' and task='payments').
if (
diff --git a/includes/payment-methods/class-wc-gateway-stripe-alipay.php b/includes/payment-methods/class-wc-gateway-stripe-alipay.php
index f8abb1827..5bd84ee1f 100644
--- a/includes/payment-methods/class-wc-gateway-stripe-alipay.php
+++ b/includes/payment-methods/class-wc-gateway-stripe-alipay.php
@@ -206,7 +206,7 @@ public function payment_fields() {
data-currency="' . esc_attr( strtolower( get_woocommerce_currency() ) ) . '">';
if ( $description ) {
- echo wpautop( esc_html( apply_filters( 'wc_stripe_description', wp_kses_post( $description ), $this->id ) ) );
+ echo wp_kses_post( wpautop( apply_filters( 'wc_stripe_description', $description, $this->id ) ) );
}
echo '';
diff --git a/includes/payment-methods/class-wc-gateway-stripe-bancontact.php b/includes/payment-methods/class-wc-gateway-stripe-bancontact.php
index a035efd2d..7df77c73c 100644
--- a/includes/payment-methods/class-wc-gateway-stripe-bancontact.php
+++ b/includes/payment-methods/class-wc-gateway-stripe-bancontact.php
@@ -193,7 +193,7 @@ public function payment_fields() {
data-currency="' . esc_attr( strtolower( get_woocommerce_currency() ) ) . '">';
if ( $description ) {
- echo wpautop( esc_html( apply_filters( 'wc_stripe_description', wp_kses_post( $description ), $this->id ) ) );
+ echo wp_kses_post( wpautop( apply_filters( 'wc_stripe_description', $description, $this->id ) ) );
}
echo '';
diff --git a/includes/payment-methods/class-wc-gateway-stripe-boleto.php b/includes/payment-methods/class-wc-gateway-stripe-boleto.php
index 931859226..0fb33f021 100644
--- a/includes/payment-methods/class-wc-gateway-stripe-boleto.php
+++ b/includes/payment-methods/class-wc-gateway-stripe-boleto.php
@@ -145,7 +145,7 @@ public function payment_fields() {
-
+ [] ] ); ?>
';
if ( $description ) {
- echo wpautop( esc_html( apply_filters( 'wc_stripe_description', wp_kses_post( $description ), $this->id ) ) );
+ echo wp_kses_post( wpautop( apply_filters( 'wc_stripe_description', $description, $this->id ) ) );
}
echo '';
diff --git a/includes/payment-methods/class-wc-gateway-stripe-giropay.php b/includes/payment-methods/class-wc-gateway-stripe-giropay.php
index 13c1a01ea..2505f7f49 100644
--- a/includes/payment-methods/class-wc-gateway-stripe-giropay.php
+++ b/includes/payment-methods/class-wc-gateway-stripe-giropay.php
@@ -189,7 +189,7 @@ public function payment_fields() {
data-currency="' . esc_attr( strtolower( get_woocommerce_currency() ) ) . '">';
if ( $description ) {
- echo wpautop( esc_html( apply_filters( 'wc_stripe_description', wp_kses_post( $description ), $this->id ) ) );
+ echo wp_kses_post( wpautop( apply_filters( 'wc_stripe_description', $description, $this->id ) ) );
}
echo '';
diff --git a/includes/payment-methods/class-wc-gateway-stripe-ideal.php b/includes/payment-methods/class-wc-gateway-stripe-ideal.php
index 8e499e0f2..ebfb5428c 100644
--- a/includes/payment-methods/class-wc-gateway-stripe-ideal.php
+++ b/includes/payment-methods/class-wc-gateway-stripe-ideal.php
@@ -193,7 +193,7 @@ public function payment_fields() {
data-currency="' . esc_attr( strtolower( get_woocommerce_currency() ) ) . '">';
if ( $description ) {
- echo wpautop( esc_html( apply_filters( 'wc_stripe_description', wp_kses_post( $description ), $this->id ) ) );
+ echo wp_kses_post( wpautop( apply_filters( 'wc_stripe_description', $description, $this->id ) ) );
}
echo '';
diff --git a/includes/payment-methods/class-wc-gateway-stripe-multibanco.php b/includes/payment-methods/class-wc-gateway-stripe-multibanco.php
index 099ca060c..ad9a3ac34 100644
--- a/includes/payment-methods/class-wc-gateway-stripe-multibanco.php
+++ b/includes/payment-methods/class-wc-gateway-stripe-multibanco.php
@@ -197,7 +197,7 @@ public function payment_fields() {
data-currency="' . esc_attr( strtolower( get_woocommerce_currency() ) ) . '">';
if ( $description ) {
- echo wpautop( esc_html( apply_filters( 'wc_stripe_description', $description, $this->id ) ) );
+ echo wp_kses( wpautop( apply_filters( 'wc_stripe_description', $description, $this->id ) ), [ 'p' => [] ] );
}
echo '';
diff --git a/includes/payment-methods/class-wc-gateway-stripe-oxxo.php b/includes/payment-methods/class-wc-gateway-stripe-oxxo.php
index 6d9e7842e..f0e2dbf53 100644
--- a/includes/payment-methods/class-wc-gateway-stripe-oxxo.php
+++ b/includes/payment-methods/class-wc-gateway-stripe-oxxo.php
@@ -82,7 +82,7 @@ public function payment_fields() {
?>
-
+ [] ] ); ?>
';
if ( $description ) {
- echo wpautop( esc_html( apply_filters( 'wc_stripe_description', wp_kses_post( $description ), $this->id ) ) );
+ echo wp_kses_post( wpautop( apply_filters( 'wc_stripe_description', $description, $this->id ) ) );
}
echo '';
diff --git a/includes/payment-methods/class-wc-gateway-stripe-sepa.php b/includes/payment-methods/class-wc-gateway-stripe-sepa.php
index f55555bff..7a985847b 100644
--- a/includes/payment-methods/class-wc-gateway-stripe-sepa.php
+++ b/includes/payment-methods/class-wc-gateway-stripe-sepa.php
@@ -250,7 +250,7 @@ public function payment_fields() {
$description = trim( $description );
- echo wpautop( esc_html( apply_filters( 'wc_stripe_description', wp_kses_post( $description ), $this->id ) ) );
+ echo wp_kses_post( wpautop( apply_filters( 'wc_stripe_description', $description, $this->id ) ) );
if ( $display_tokenization ) {
$this->tokenization_script();
diff --git a/includes/payment-methods/class-wc-gateway-stripe-sofort.php b/includes/payment-methods/class-wc-gateway-stripe-sofort.php
index 6ce41adec..3dfe21109 100644
--- a/includes/payment-methods/class-wc-gateway-stripe-sofort.php
+++ b/includes/payment-methods/class-wc-gateway-stripe-sofort.php
@@ -193,7 +193,7 @@ public function payment_fields() {
data-currency="' . esc_attr( strtolower( get_woocommerce_currency() ) ) . '">';
if ( $description ) {
- echo wpautop( esc_html( apply_filters( 'wc_stripe_description', wp_kses_post( $description ), $this->id ) ) );
+ echo wp_kses_post( wpautop( apply_filters( 'wc_stripe_description', $description, $this->id ) ) );
}
echo '';
diff --git a/readme.txt b/readme.txt
index 782bf94ea..29f685f25 100644
--- a/readme.txt
+++ b/readme.txt
@@ -141,5 +141,6 @@ If you get stuck, you can ask for help in the Plugin Forum.
* Fix - Fix error in saving settings when express payment methods are disabled.
* Fix - Catch error when getting intent from order.
* Fix - Handle undefined array key when no matching customer account is found when guest customers checkout.
+* Fix - Address QIT Security test errors.
[See changelog for all versions](https://raw.githubusercontent.com/woocommerce/woocommerce-gateway-stripe/trunk/changelog.txt).
diff --git a/templates/emails/failed-preorder-authentication.php b/templates/emails/failed-preorder-authentication.php
index a704a7613..bf53e1c58 100644
--- a/templates/emails/failed-preorder-authentication.php
+++ b/templates/emails/failed-preorder-authentication.php
@@ -25,7 +25,7 @@
get_custom_message() ) : ?>
- get_custom_message() ) ) ); ?>
+ get_custom_message() ) ), [ 'p' => [] ] ); ?>
Date: Tue, 27 Aug 2024 23:11:08 +0530
Subject: [PATCH 06/20] Address QIT PHPStan test errors (#3268)
* add QIT workflow file
* add Generate ZIP workflow file
* fix QIT Security issues
* suggestions implemented
* add PHPCompat and Malware QIT tests
* suggestions implemented
* update the branches in workflow
* Address QIT PHPStan test errors
* update allowed tag format
* remove ignore stats from WC_Stripe and add reasons to the rest
* fix grammer
* remove rest of the WC_Stripe ignore statements
* handle the null ->retry
---
changelog.txt | 1 +
...ract-wc-stripe-connect-rest-controller.php | 6 ++--
.../abstract-wc-stripe-payment-gateway.php | 28 ++++++++---------
.../admin/class-wc-stripe-admin-notices.php | 4 +--
includes/admin/class-wc-stripe-privacy.php | 10 ++++--
includes/class-wc-gateway-stripe.php | 5 +++
includes/class-wc-stripe-blocks-support.php | 6 ++--
includes/class-wc-stripe-helper.php | 4 +--
includes/class-wc-stripe-payment-tokens.php | 2 +-
...ripe-email-failed-authentication-retry.php | 4 +--
...pe-email-failed-renewal-authentication.php | 9 ++++--
.../compat/trait-wc-stripe-pre-orders.php | 24 +++++++-------
...rait-wc-stripe-subscriptions-utilities.php | 14 +++++++--
.../compat/trait-wc-stripe-subscriptions.php | 31 +++++++++++--------
.../class-wc-gateway-stripe-sepa.php | 1 -
.../class-wc-stripe-payment-request.php | 17 +++++-----
.../class-wc-stripe-upe-payment-method.php | 8 ++---
readme.txt | 1 +
...ailed-renewal-authentication-requested.php | 2 +-
...ailed-renewal-authentication-requested.php | 2 +-
20 files changed, 106 insertions(+), 73 deletions(-)
diff --git a/changelog.txt b/changelog.txt
index 6dc2df6eb..6e942cd6f 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -14,6 +14,7 @@
* Fix - Catch error when getting intent from order.
* Fix - Handle undefined array key when no matching customer account is found when guest customers checkout.
* Fix - Address QIT Security test errors.
+* Fix - Address QIT PHPStan test errors.
= 8.6.1 - 2024-08-09 =
* Tweak - Improves the wording of the invalid Stripe keys errors, instructing merchants to click the "Configure connection" button instead of manually setting the keys.
diff --git a/includes/abstracts/abstract-wc-stripe-connect-rest-controller.php b/includes/abstracts/abstract-wc-stripe-connect-rest-controller.php
index e67baa98e..c0da244f4 100644
--- a/includes/abstracts/abstract-wc-stripe-connect-rest-controller.php
+++ b/includes/abstracts/abstract-wc-stripe-connect-rest-controller.php
@@ -94,7 +94,7 @@ public function get_internal( $request ) {
$this->prevent_route_caching();
- return $this->get( $request );
+ return $this->get( $request ); // @phpstan-ignore-line (get method is defined in classes that use this class)
}
/**
@@ -108,7 +108,7 @@ public function post_internal( $request ) {
$this->prevent_route_caching();
- return $this->post( $request );
+ return $this->post( $request ); // @phpstan-ignore-line (post method is defined in classes that use this class)
}
/**
@@ -122,7 +122,7 @@ public function delete_internal( $request ) {
$this->prevent_route_caching();
- return $this->delete( $request );
+ return $this->delete( $request ); // @phpstan-ignore-line (delete method is defined in classes that use this class)
}
/**
diff --git a/includes/abstracts/abstract-wc-stripe-payment-gateway.php b/includes/abstracts/abstract-wc-stripe-payment-gateway.php
index 2ae68fccb..4d0743aaa 100644
--- a/includes/abstracts/abstract-wc-stripe-payment-gateway.php
+++ b/includes/abstracts/abstract-wc-stripe-payment-gateway.php
@@ -265,12 +265,12 @@ public function are_keys_set() {
// NOTE: updates to this function should be added to are_keys_set()
// in includes/payment-methods/class-wc-stripe-payment-request.php
- if ( $this->testmode ) {
- return preg_match( '/^pk_test_/', $this->publishable_key )
- && preg_match( '/^[rs]k_test_/', $this->secret_key );
+ if ( $this->testmode ) { // @phpstan-ignore-line (testmode is defined in the classes that use this class)
+ return preg_match( '/^pk_test_/', $this->publishable_key ) // @phpstan-ignore-line (publishable_key is defined in the classes that use this class)
+ && preg_match( '/^[rs]k_test_/', $this->secret_key ); // @phpstan-ignore-line (secret_key is defined in the classes that use this class)
} else {
- return preg_match( '/^pk_live_/', $this->publishable_key )
- && preg_match( '/^[rs]k_live_/', $this->secret_key );
+ return preg_match( '/^pk_live_/', $this->publishable_key ) // @phpstan-ignore-line (publishable_key is defined in the classes that use this class)
+ && preg_match( '/^[rs]k_live_/', $this->secret_key ); // @phpstan-ignore-line (secret_key is defined in the classes that use this class)
}
}
@@ -379,7 +379,7 @@ public function validate_minimum_order_amount( $order ) {
* @version 4.0.0
*/
public function get_transaction_url( $order ) {
- if ( $this->testmode ) {
+ if ( $this->testmode ) { // @phpstan-ignore-line (testmode is defined in the classes that use this class)
$this->view_transaction_url = 'https://dashboard.stripe.com/test/payments/%s';
} else {
$this->view_transaction_url = 'https://dashboard.stripe.com/payments/%s';
@@ -874,7 +874,7 @@ public function prepare_source( $user_id, $force_save_source = false, $existing_
$maybe_saved_card = isset( $_POST[ 'wc-' . $payment_method . '-new-payment-method' ] ) && ! empty( $_POST[ 'wc-' . $payment_method . '-new-payment-method' ] );
// This is true if the user wants to store the card to their account.
- if ( ( $user_id && $this->saved_cards && $maybe_saved_card ) || $force_save_source ) {
+ if ( ( $user_id && $this->saved_cards && $maybe_saved_card ) || $force_save_source ) { // @phpstan-ignore-line (saved_cards is defined in the classes that use this class)
$response = $customer->attach_source( $stripe_token );
if ( ! empty( $response->error ) ) {
@@ -1059,7 +1059,7 @@ public function update_fees( $order, $balance_transaction_id ) {
* @param int $order_id
* @param float $amount
*
- * @return bool
+ * @return bool True or false based on success.
* @throws Exception Throws exception when charge wasn't captured.
*/
public function process_refund( $order_id, $amount = null, $reason = '' ) {
@@ -1146,7 +1146,7 @@ public function process_refund( $order_id, $amount = null, $reason = '' ) {
);
}
- if ( ! empty( $response->error ) ) {
+ if ( ! empty( $response->error ) ) { // @phpstan-ignore-line (return statement is added)
WC_Stripe_Logger::log( 'Error: ' . $response->error->message );
return new WP_Error(
@@ -1319,7 +1319,7 @@ public function generate_create_intent_request( $order, $prepared_source ) {
$payment_method_types = [ 'card' ];
if ( WC_Stripe_Feature_Flags::is_upe_checkout_enabled() ) {
- $payment_method_types = $this->get_upe_enabled_at_checkout_payment_method_ids();
+ $payment_method_types = $this->get_upe_enabled_at_checkout_payment_method_ids(); // @phpstan-ignore-line (get_upe_enabled_at_checkout_payment_method_ids is defined in the classes that use this class)
} elseif ( isset( $prepared_source->source_object->type ) ) {
$payment_method_types = [ $prepared_source->source_object->type ];
}
@@ -1936,7 +1936,7 @@ public function payment_scripts() {
&& ! $this->is_valid_pay_for_order_endpoint()
&& ! is_add_payment_method_page()
&& ! isset( $_GET['change_payment_method'] ) // wpcs: csrf ok.
- && ! ( ! empty( get_query_var( 'view-subscription' ) ) && is_callable( 'WCS_Early_Renewal_Manager::is_early_renewal_via_modal_enabled' ) && WCS_Early_Renewal_Manager::is_early_renewal_via_modal_enabled() )
+ && ! ( ! empty( get_query_var( 'view-subscription' ) ) && is_callable( 'WCS_Early_Renewal_Manager::is_early_renewal_via_modal_enabled' ) && WCS_Early_Renewal_Manager::is_early_renewal_via_modal_enabled() ) // @phpstan-ignore-line (Class WCS_Early_Renewal_Manager is checked already)
|| ( is_order_received_page() )
) {
return;
@@ -2021,7 +2021,7 @@ public function javascript_params() {
$stripe_params = [
'title' => $this->title,
- 'key' => $this->publishable_key,
+ 'key' => $this->publishable_key, // @phpstan-ignore-line (publishable_key is defined in the classes that use this class)
'i18n_terms' => __( 'Please accept the terms and conditions first', 'woocommerce-gateway-stripe' ),
'i18n_required_fields' => __( 'Please fill in required checkout fields first', 'woocommerce-gateway-stripe' ),
'updateFailedOrderNonce' => wp_create_nonce( 'wc_stripe_update_failed_order_nonce' ),
@@ -2068,7 +2068,7 @@ public function javascript_params() {
$stripe_params['return_url'] = $this->get_stripe_return_url();
$stripe_params['ajaxurl'] = WC_AJAX::get_endpoint( '%%endpoint%%' );
$stripe_params['stripe_nonce'] = wp_create_nonce( '_wc_stripe_nonce' );
- $stripe_params['statement_descriptor'] = $this->statement_descriptor;
+ $stripe_params['statement_descriptor'] = $this->statement_descriptor; // @phpstan-ignore-line (statement_descriptor is defined in the classes that use this class)
$stripe_params['elements_options'] = apply_filters( 'wc_stripe_elements_options', [] );
$stripe_params['sepa_elements_options'] = $sepa_elements_options;
$stripe_params['invalid_owner_name'] = __( 'Billing First Name and Last Name are required.', 'woocommerce-gateway-stripe' );
@@ -2136,7 +2136,7 @@ private function get_source_object_from_request() {
* @return bool True if SSL is needed but not set.
*/
private function needs_ssl_setup() {
- return ! $this->testmode && ! is_ssl();
+ return ! $this->testmode && ! is_ssl(); // @phpstan-ignore-line (testmode is defined in the classes that use this class)
}
/**
diff --git a/includes/admin/class-wc-stripe-admin-notices.php b/includes/admin/class-wc-stripe-admin-notices.php
index 731f46303..5486545fa 100644
--- a/includes/admin/class-wc-stripe-admin-notices.php
+++ b/includes/admin/class-wc-stripe-admin-notices.php
@@ -93,11 +93,11 @@ public function get_payment_methods() {
return [
'alipay' => 'WC_Gateway_Stripe_Alipay',
'bancontact' => 'WC_Gateway_Stripe_Bancontact',
- 'eps' => 'WC_Gateway_Stripe_EPS',
+ 'eps' => 'WC_Gateway_Stripe_Eps',
'giropay' => 'WC_Gateway_Stripe_Giropay',
'ideal' => 'WC_Gateway_Stripe_Ideal',
'multibanco' => 'WC_Gateway_Stripe_Multibanco',
- 'p24' => 'WC_Gateway_Stripe_p24',
+ 'p24' => 'WC_Gateway_Stripe_P24',
'sepa' => 'WC_Gateway_Stripe_Sepa',
'sofort' => 'WC_Gateway_Stripe_Sofort',
'boleto' => 'WC_Gateway_Stripe_Boleto',
diff --git a/includes/admin/class-wc-stripe-privacy.php b/includes/admin/class-wc-stripe-privacy.php
index 6b150061c..35eb1d528 100644
--- a/includes/admin/class-wc-stripe-privacy.php
+++ b/includes/admin/class-wc-stripe-privacy.php
@@ -177,7 +177,7 @@ public function subscriptions_data_exporter( $email_address, $page = 1 ) {
'meta_query' => $meta_query,
];
- $subscriptions = wcs_get_subscriptions( $subscription_query );
+ $subscriptions = function_exists( 'wcs_get_subscriptions' ) ? wcs_get_subscriptions( $subscription_query ) : [];
$done = true;
@@ -332,7 +332,11 @@ protected function maybe_handle_subscription( $order ) {
return [ false, false, [] ];
}
- if ( ! wcs_order_contains_subscription( $order ) ) {
+ if ( function_exists( 'wcs_order_contains_subscription' ) && ! wcs_order_contains_subscription( $order ) ) {
+ return [ false, false, [] ];
+ }
+
+ if ( ! function_exists( 'wcs_get_subscriptions_for_order' ) ) {
return [ false, false, [] ];
}
@@ -354,7 +358,7 @@ protected function maybe_handle_subscription( $order ) {
return [ false, true, [ sprintf( __( 'Order ID %d contains an active Subscription. Personal data retained. (Stripe)', 'woocommerce-gateway-stripe' ), $order->get_id() ) ] ];
}
- $renewal_orders = WC_Subscriptions_Renewal_Order::get_renewal_orders( $order->get_id(), 'WC_Order' );
+ $renewal_orders = class_exists( 'WC_Subscriptions_Renewal_Order' ) ? WC_Subscriptions_Renewal_Order::get_renewal_orders( $order->get_id(), 'WC_Order' ) : [];
foreach ( $renewal_orders as $renewal_order ) {
$renewal_order->delete_meta_data( '_stripe_source_id' );
diff --git a/includes/class-wc-gateway-stripe.php b/includes/class-wc-gateway-stripe.php
index d1ffb2bbe..ad59c91d2 100644
--- a/includes/class-wc-gateway-stripe.php
+++ b/includes/class-wc-gateway-stripe.php
@@ -68,6 +68,11 @@ class WC_Gateway_Stripe extends WC_Stripe_Payment_Gateway {
*/
public $inline_cc_form;
+ /**
+ * Order pay intent
+ */
+ private $order_pay_intent;
+
/**
* Constructor
*/
diff --git a/includes/class-wc-stripe-blocks-support.php b/includes/class-wc-stripe-blocks-support.php
index 2f8788418..29f4d70e5 100644
--- a/includes/class-wc-stripe-blocks-support.php
+++ b/includes/class-wc-stripe-blocks-support.php
@@ -1,7 +1,7 @@
wp_create_nonce( 'wc_stripe_confirm_pi' ),
'redirect_to' => rawurlencode( $result->redirect_url ),
],
- home_url() . \WC_Ajax::get_endpoint( 'wc_stripe_verify_intent' )
+ home_url() . \WC_AJAX::get_endpoint( 'wc_stripe_verify_intent' )
);
if ( ! empty( $payment_details['save_payment_method'] ) ) {
diff --git a/includes/class-wc-stripe-helper.php b/includes/class-wc-stripe-helper.php
index 21049d1ff..74fd537ee 100644
--- a/includes/class-wc-stripe-helper.php
+++ b/includes/class-wc-stripe-helper.php
@@ -410,12 +410,12 @@ public static function get_legacy_payment_method_classes() {
WC_Gateway_Stripe_Alipay::class,
WC_Gateway_Stripe_Bancontact::class,
WC_Gateway_Stripe_Boleto::class,
- WC_Gateway_Stripe_EPS::class,
+ WC_Gateway_Stripe_Eps::class,
WC_Gateway_Stripe_Giropay::class,
WC_Gateway_Stripe_Ideal::class,
WC_Gateway_Stripe_Multibanco::class,
WC_Gateway_Stripe_Oxxo::class,
- WC_Gateway_Stripe_p24::class,
+ WC_Gateway_Stripe_P24::class,
WC_Gateway_Stripe_Sepa::class,
];
diff --git a/includes/class-wc-stripe-payment-tokens.php b/includes/class-wc-stripe-payment-tokens.php
index f09d56487..ac36cd1ca 100644
--- a/includes/class-wc-stripe-payment-tokens.php
+++ b/includes/class-wc-stripe-payment-tokens.php
@@ -610,7 +610,7 @@ public static function update_token_from_method_details( $user_id, $payment_meth
* @return array Filtered item
*/
public function get_account_saved_payment_methods_list_item_sepa( $item, $payment_token ) {
- __deprecated_function( __METHOD__, '8.4.0', 'WC_Stripe_Payment_Tokens::get_account_saved_payment_methods_list_item' );
+ _deprecated_function( __METHOD__, '8.4.0', 'WC_Stripe_Payment_Tokens::get_account_saved_payment_methods_list_item' );
return $this->get_account_saved_payment_methods_list_item( $item, $payment_token );
}
}
diff --git a/includes/compat/class-wc-stripe-email-failed-authentication-retry.php b/includes/compat/class-wc-stripe-email-failed-authentication-retry.php
index 4920a3d9d..6e9a27828 100644
--- a/includes/compat/class-wc-stripe-email-failed-authentication-retry.php
+++ b/includes/compat/class-wc-stripe-email-failed-authentication-retry.php
@@ -71,8 +71,8 @@ public function trigger( $order_id, $order = null ) {
$this->find['retry-time'] = '{retry_time}';
if ( class_exists( 'WCS_Retry_Manager' ) && function_exists( 'wcs_get_human_time_diff' ) ) {
- $this->retry = WCS_Retry_Manager::store()->get_last_retry_for_order( wcs_get_objects_property( $order, 'id' ) );
- $this->replace['retry-time'] = wcs_get_human_time_diff( $this->retry->get_time() );
+ $this->retry = function_exists( 'wcs_get_objects_property' ) ? WCS_Retry_Manager::store()->get_last_retry_for_order( wcs_get_objects_property( $order, 'id' ) ) : null;
+ $this->replace['retry-time'] = null !== $this->retry ? wcs_get_human_time_diff( $this->retry->get_time() ) : '';
} else {
WC_Stripe_Logger::log( 'WCS_Retry_Manager class or does not exist. Not able to send admnin email about customer notification for authentication required for renewal payment.' );
return;
diff --git a/includes/compat/class-wc-stripe-email-failed-renewal-authentication.php b/includes/compat/class-wc-stripe-email-failed-renewal-authentication.php
index 64c9f158f..68c6f827f 100644
--- a/includes/compat/class-wc-stripe-email-failed-renewal-authentication.php
+++ b/includes/compat/class-wc-stripe-email-failed-renewal-authentication.php
@@ -41,7 +41,11 @@ public function __construct( $email_classes = [] ) {
* @param WC_Order $order The order that is being paid.
*/
public function trigger( $order ) {
- if ( function_exists( 'wcs_order_contains_subscription' ) && ( wcs_order_contains_subscription( $order->get_id() ) || wcs_is_subscription( $order->get_id() ) || wcs_order_contains_renewal( $order->get_id() ) ) ) {
+ if ( function_exists( 'wcs_order_contains_subscription' )
+ && function_exists( 'wcs_is_subscription' )
+ && function_exists( 'wcs_order_contains_renewal' )
+ && ( wcs_order_contains_subscription( $order->get_id() ) || wcs_is_subscription( $order->get_id() ) || wcs_order_contains_renewal( $order->get_id() ) )
+ ) {
parent::trigger( $order );
// Prevent the renewal email from WooCommerce Subscriptions from being sent.
@@ -85,7 +89,7 @@ public function get_default_heading() {
* @return array
*/
public function prevent_retry_notification_email( $rule_array, $retry_number, $order_id ) {
- if ( wcs_get_objects_property( $this->object, 'id' ) === $order_id ) {
+ if ( function_exists( 'wcs_get_objects_property' ) && wcs_get_objects_property( $this->object, 'id' ) === $order_id ) {
$rule_array['email_template_customer'] = '';
}
@@ -102,6 +106,7 @@ public function prevent_retry_notification_email( $rule_array, $retry_number, $o
*/
public function set_store_owner_custom_email( $rule_array, $retry_number, $order_id ) {
if (
+ function_exists( 'wcs_get_objects_property' ) &&
wcs_get_objects_property( $this->object, 'id' ) === $order_id &&
'' !== $rule_array['email_template_admin'] // Only send our email if a retry admin email was already going to be sent.
) {
diff --git a/includes/compat/trait-wc-stripe-pre-orders.php b/includes/compat/trait-wc-stripe-pre-orders.php
index 8b6a830cd..877bbf16f 100644
--- a/includes/compat/trait-wc-stripe-pre-orders.php
+++ b/includes/compat/trait-wc-stripe-pre-orders.php
@@ -27,15 +27,15 @@ public function maybe_init_pre_orders() {
return;
}
- $this->supports[] = 'pre-orders';
+ $this->supports[] = 'pre-orders'; // @phpstan-ignore-line (supports is defined in the classes that use this trait)
- add_action( 'wc_pre_orders_process_pre_order_completion_payment_' . $this->id, [ $this, 'process_pre_order_release_payment' ] );
+ add_action( 'wc_pre_orders_process_pre_order_completion_payment_' . $this->id, [ $this, 'process_pre_order_release_payment' ] ); // @phpstan-ignore-line (id is defined in the classes that use this trait)
/**
* The callbacks attached below only need to be attached once. We don't need each gateway instance to have its own callback.
* Therefore we only attach them once on the main `stripe` gateway and store a flag to indicate that they have been attached.
*/
- if ( self::$has_attached_pre_order_integration_hooks || WC_Gateway_Stripe::ID !== $this->id ) {
+ if ( self::$has_attached_pre_order_integration_hooks || WC_Gateway_Stripe::ID !== $this->id ) { // @phpstan-ignore-line (id is defined in the classes that use this trait)
return;
}
@@ -147,6 +147,7 @@ public function is_pre_order_product_charged_upfront( $product ) {
public function maybe_process_pre_orders( $order_id ) {
return (
$this->has_pre_order( $order_id ) &&
+ class_exists( 'WC_Pre_Orders_Order' ) &&
WC_Pre_Orders_Order::order_requires_payment_tokenization( $order_id )
);
}
@@ -187,9 +188,9 @@ public function process_pre_order( $order_id ) {
$order = wc_get_order( $order_id );
// This will throw exception if not valid.
- $this->validate_minimum_order_amount( $order );
+ $this->validate_minimum_order_amount( $order ); // @phpstan-ignore-line (minimum amount is defined in the classes that use this trait)
- $prepared_source = $this->prepare_source( get_current_user_id(), true );
+ $prepared_source = $this->prepare_source( get_current_user_id(), true ); // @phpstan-ignore-line (prepare_source is defined in the classes that use this trait)
// We need a source on file to continue.
if ( empty( $prepared_source->customer ) || empty( $prepared_source->source ) ) {
@@ -199,13 +200,14 @@ public function process_pre_order( $order_id ) {
// Setup the response early to allow later modifications.
$response = [
'result' => 'success',
+ // @phpstan-ignore-next-line (get_return_url is defined in the classes that use this trait)
'redirect' => $this->get_return_url( $order ),
];
- $this->save_source_to_order( $order, $prepared_source );
+ $this->save_source_to_order( $order, $prepared_source ); // @phpstan-ignore-line (save_source_to_order is defined in the classes that use this trait)
// Try setting up a payment intent.
- $intent_secret = $this->setup_intent( $order, $prepared_source );
+ $intent_secret = $this->setup_intent( $order, $prepared_source ); // @phpstan-ignore-line (setup_intent is defined in the classes that use this trait)
if ( ! empty( $intent_secret ) ) {
$response['setup_intent_secret'] = $intent_secret;
return $response;
@@ -240,10 +242,10 @@ public function process_pre_order( $order_id ) {
*/
public function process_pre_order_release_payment( $order, $retry = true ) {
try {
- $source = $this->prepare_order_source( $order );
- $response = $this->create_and_confirm_intent_for_off_session( $order, $source );
+ $source = $this->prepare_order_source( $order ); // @phpstan-ignore-line (prepare_order_source is defined in the classes that use this trait)
+ $response = $this->create_and_confirm_intent_for_off_session( $order, $source ); // @phpstan-ignore-line (create_and_confirm_intent_for_off_session is defined in the classes that use this trait)
- $is_authentication_required = $this->is_authentication_required_for_payment( $response );
+ $is_authentication_required = $this->is_authentication_required_for_payment( $response ); // @phpstan-ignore-line (is_authentication_required_for_payment is defined in the classes that use this trait)
if ( ! empty( $response->error ) && ! $is_authentication_required ) {
if ( ! $retry ) {
@@ -269,7 +271,7 @@ public function process_pre_order_release_payment( $order, $retry = true ) {
throw new WC_Stripe_Exception( print_r( $response, true ), $response->error->message );
} else {
// Successful
- $this->process_response( $this->get_latest_charge_from_intent( $response ), $order );
+ $this->process_response( $this->get_latest_charge_from_intent( $response ), $order ); // @phpstan-ignore-line (process_response is defined in the classes that use this trait)
}
} catch ( Exception $e ) {
$error_message = is_callable( [ $e, 'getLocalizedMessage' ] ) ? $e->getLocalizedMessage() : $e->getMessage();
diff --git a/includes/compat/trait-wc-stripe-subscriptions-utilities.php b/includes/compat/trait-wc-stripe-subscriptions-utilities.php
index 011b874d6..89d691653 100644
--- a/includes/compat/trait-wc-stripe-subscriptions-utilities.php
+++ b/includes/compat/trait-wc-stripe-subscriptions-utilities.php
@@ -31,7 +31,12 @@ public function is_subscriptions_enabled() {
* @return boolean
*/
public function has_subscription( $order_id ) {
- return ( function_exists( 'wcs_order_contains_subscription' ) && ( wcs_order_contains_subscription( $order_id ) || wcs_is_subscription( $order_id ) || wcs_order_contains_renewal( $order_id ) ) );
+ return (
+ function_exists( 'wcs_order_contains_subscription' )
+ && function_exists( 'wcs_is_subscription' )
+ && function_exists( 'wcs_order_contains_renewal' )
+ && ( wcs_order_contains_subscription( $order_id ) || wcs_is_subscription( $order_id ) || wcs_order_contains_renewal( $order_id ) )
+ );
}
/**
@@ -79,7 +84,10 @@ public function is_payment_recurring( $order_id ) {
* @return bool Indicates whether the save payment method checkbox should be displayed or not.
*/
public function display_save_payment_method_checkbox( $display ) {
- if ( WC_Subscriptions_Cart::cart_contains_subscription() || $this->is_changing_payment_method_for_subscription() ) {
+ if (
+ ( class_exists( 'WC_Subscriptions_Cart' ) && WC_Subscriptions_Cart::cart_contains_subscription() )
+ || $this->is_changing_payment_method_for_subscription()
+ ) {
return false;
}
// Only render the "Save payment method" checkbox if there are no subscription products in the cart.
@@ -96,7 +104,7 @@ public function display_save_payment_method_checkbox( $display ) {
*/
public function is_subscription_item_in_cart() {
if ( $this->is_subscriptions_enabled() ) {
- return WC_Subscriptions_Cart::cart_contains_subscription() || $this->cart_contains_renewal();
+ return ( class_exists( 'WC_Subscriptions_Cart' ) && WC_Subscriptions_Cart::cart_contains_subscription() ) || $this->cart_contains_renewal();
}
return false;
}
diff --git a/includes/compat/trait-wc-stripe-subscriptions.php b/includes/compat/trait-wc-stripe-subscriptions.php
index 8256ffff0..69dfa7fd3 100644
--- a/includes/compat/trait-wc-stripe-subscriptions.php
+++ b/includes/compat/trait-wc-stripe-subscriptions.php
@@ -99,7 +99,7 @@ public function display_update_subs_payment_checkout() {
$subs_statuses = apply_filters( 'wc_stripe_update_subs_payment_method_card_statuses', [ 'active' ] );
if (
apply_filters( 'wc_stripe_display_update_subs_payment_method_card_checkbox', true ) &&
- wcs_user_has_subscription( get_current_user_id(), '', $subs_statuses ) &&
+ ( function_exists( 'wcs_user_has_subscription' ) && wcs_user_has_subscription( get_current_user_id(), '', $subs_statuses ) ) &&
is_add_payment_method_page()
) {
$label = esc_html( apply_filters( 'wc_stripe_save_to_subs_text', __( 'Update the Payment Method used for all of my active subscriptions.', 'woocommerce-gateway-stripe' ) ) );
@@ -125,13 +125,13 @@ public function display_update_subs_payment_checkout() {
*/
public function handle_add_payment_method_success( $source_id, $source_object ) {
if ( isset( $_POST[ 'wc-' . $this->id . '-update-subs-payment-method-card' ] ) ) {
- $all_subs = wcs_get_users_subscriptions();
+ $all_subs = function_exists( 'wcs_get_users_subscriptions' ) ? wcs_get_users_subscriptions() : [];
$subs_statuses = apply_filters( 'wc_stripe_update_subs_payment_method_card_statuses', [ 'active' ] );
$stripe_customer = new WC_Stripe_Customer( get_current_user_id() );
if ( ! empty( $all_subs ) ) {
foreach ( $all_subs as $sub ) {
- if ( $sub->has_status( $subs_statuses ) ) {
+ if ( $sub->has_status( $subs_statuses ) && class_exists( 'WC_Subscriptions_Change_Payment_Gateway' ) ) {
WC_Subscriptions_Change_Payment_Gateway::update_payment_method(
$sub,
$this->id,
@@ -317,7 +317,7 @@ public function process_subscription_payment( $amount, $renewal_order, $retry =
if ( $this->is_retryable_error( $response->error ) ) {
if ( $retry ) {
// Don't do anymore retries after this.
- if ( 5 <= $this->retry_interval ) {
+ if ( 5 <= $this->retry_interval ) { // @phpstan-ignore-line (retry_interval is defined in classes using this class)
return $this->process_subscription_payment( $amount, $renewal_order, false, $response->error );
}
@@ -433,9 +433,9 @@ public function maybe_update_source_on_subscription_order( $order, $source, $pay
// Also store it on the subscriptions being purchased or paid for in the order
if ( function_exists( 'wcs_order_contains_subscription' ) && wcs_order_contains_subscription( $order_id ) ) {
- $subscriptions = wcs_get_subscriptions_for_order( $order_id );
+ $subscriptions = function_exists( 'wcs_get_subscriptions_for_order' ) ? wcs_get_subscriptions_for_order( $order_id ) : [];
} elseif ( function_exists( 'wcs_order_contains_renewal' ) && wcs_order_contains_renewal( $order_id ) ) {
- $subscriptions = wcs_get_subscriptions_for_renewal_order( $order_id );
+ $subscriptions = function_exists( 'wcs_get_subscriptions_for_renewal_order' ) ? wcs_get_subscriptions_for_renewal_order( $order_id ) : [];
} else {
$subscriptions = [];
}
@@ -552,7 +552,6 @@ public function add_subscription_payment_meta( $payment_meta, $subscription ) {
*
* @param string $payment_method_id The ID of the payment method to validate
* @param array $payment_meta associative array of meta data required for automatic payments
- * @return array
*/
public function validate_subscription_payment_meta( $payment_method_id, $payment_meta ) {
if ( $this->id === $payment_method_id ) {
@@ -605,7 +604,7 @@ public function add_subscription_information_to_intent( $request, $order, $prepa
return $request;
}
- $subscriptions_for_renewal_order = wcs_get_subscriptions_for_renewal_order( $order );
+ $subscriptions_for_renewal_order = function_exists( 'wcs_get_subscriptions_for_renewal_order' ) ? wcs_get_subscriptions_for_renewal_order( $order ) : [];
// Check if mandate already exists.
if ( 1 === count( $subscriptions_for_renewal_order ) ) {
@@ -676,7 +675,7 @@ private function create_mandate_options_for_order( $order, $subscriptions ) {
// If this is the first order, not a renewal, then get the subscriptions for the parent order.
if ( empty( $subscriptions ) ) {
- $subscriptions = wcs_get_subscriptions_for_order( $order );
+ $subscriptions = function_exists( 'wcs_get_subscriptions_for_order' ) ? wcs_get_subscriptions_for_order( $order ) : [];
}
// If there are no subscriptions we just return since mandates aren't required.
@@ -834,7 +833,7 @@ public function maybe_render_subscription_payment_method( $payment_method_to_dis
public function remove_order_pay_var() {
global $wp;
if ( isset( $_GET['wc-stripe-confirmation'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
- $this->order_pay_var = $wp->query_vars['order-pay'];
+ $this->order_pay_var = $wp->query_vars['order-pay']; // @phpstan-ignore-line (order_pay_var is defined in classes using this class)
$wp->query_vars['order-pay'] = null;
}
}
@@ -911,8 +910,12 @@ public function redirect_after_early_renewal( $url ) {
*/
protected function maybe_process_subscription_early_renewal_success( $order, $intent ) {
if ( $this->is_subscriptions_enabled() && isset( $_GET['early_renewal'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
- wcs_update_dates_after_early_renewal( wcs_get_subscription( $order->get_meta( '_subscription_renewal' ) ), $order );
- wc_add_notice( __( 'Your early renewal order was successful.', 'woocommerce-gateway-stripe' ), 'success' );
+ if ( function_exists( 'wcs_update_dates_after_early_renewal' ) && function_exists( 'wcs_get_subscription' ) ) {
+ wcs_update_dates_after_early_renewal( wcs_get_subscription( $order->get_meta( '_subscription_renewal' ) ), $order );
+ }
+ if ( function_exists( 'wc_add_notice' ) ) {
+ wc_add_notice( __( 'Your early renewal order was successful.', 'woocommerce-gateway-stripe' ), 'success' );
+ }
}
}
@@ -926,7 +929,9 @@ protected function maybe_process_subscription_early_renewal_failure( $order, $in
if ( $this->is_subscriptions_enabled() && isset( $_GET['early_renewal'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$order->delete( true );
wc_add_notice( __( 'Payment authorization for the renewal order was unsuccessful, please try again.', 'woocommerce-gateway-stripe' ), 'error' );
- $renewal_url = wcs_get_early_renewal_url( wcs_get_subscription( $order->get_meta( '_subscription_renewal' ) ) );
+ $renewal_url = ( function_exists( 'wcs_get_early_renewal_url' ) && function_exists( 'wcs_get_subscription' ) )
+ ? wcs_get_early_renewal_url( wcs_get_subscription( $order->get_meta( '_subscription_renewal' ) ) )
+ : '';
wp_safe_redirect( $renewal_url );
exit;
}
diff --git a/includes/payment-methods/class-wc-gateway-stripe-sepa.php b/includes/payment-methods/class-wc-gateway-stripe-sepa.php
index 7a985847b..ffd615d0d 100644
--- a/includes/payment-methods/class-wc-gateway-stripe-sepa.php
+++ b/includes/payment-methods/class-wc-gateway-stripe-sepa.php
@@ -183,7 +183,6 @@ public function init_form_fields() {
*
* @since 4.0.0
* @version 4.0.0
- * @return string
*/
public function mandate_display() {
/* translators: statement descriptor */
diff --git a/includes/payment-methods/class-wc-stripe-payment-request.php b/includes/payment-methods/class-wc-stripe-payment-request.php
index 25217775a..669167fb7 100644
--- a/includes/payment-methods/class-wc-stripe-payment-request.php
+++ b/includes/payment-methods/class-wc-stripe-payment-request.php
@@ -1319,12 +1319,12 @@ public function update_shipping_method( $shipping_methods ) {
*
* @since 4.0.0
* @version 4.0.0
- * @return array $data
+ * @return array $data The selected product data.
*/
public function ajax_get_selected_product_data() {
check_ajax_referer( 'wc-stripe-get-selected-product-data', 'security' );
- try {
+ try { // @phpstan-ignore-line (return statement is added)
$product_id = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : 0;
$qty = ! isset( $_POST['qty'] ) ? 1 : apply_filters( 'woocommerce_add_to_cart_quantity', absint( $_POST['qty'] ), $product_id );
$addon_value = isset( $_POST['addon_value'] ) ? max( floatval( $_POST['addon_value'] ), 0 ) : 0;
@@ -1417,7 +1417,7 @@ public function ajax_get_selected_product_data() {
*
* @since 4.0.0
* @version 4.0.0
- * @return array $data
+ * @return array $data Results of adding the product to the cart.
*/
public function ajax_add_to_cart() {
check_ajax_referer( 'wc-stripe-add-to-cart', 'security' );
@@ -1455,6 +1455,7 @@ public function ajax_add_to_cart() {
$data += $this->build_display_items();
$data['result'] = 'success';
+ // @phpstan-ignore-next-line (return statement is added)
wp_send_json( $data );
}
@@ -2052,11 +2053,13 @@ private function maybe_restore_recurring_chosen_shipping_methods( $previous_chos
foreach ( WC()->cart->recurring_carts as $recurring_cart_key => $recurring_cart ) {
foreach ( $recurring_cart->get_shipping_packages() as $recurring_cart_package_index => $recurring_cart_package ) {
- $package_key = WC_Subscriptions_Cart::get_recurring_shipping_package_key( $recurring_cart_key, $recurring_cart_package_index );
+ if ( class_exists( 'WC_Subscriptions_Cart' ) ) {
+ $package_key = WC_Subscriptions_Cart::get_recurring_shipping_package_key( $recurring_cart_key, $recurring_cart_package_index );
- // If the recurring cart package key is found in the previous chosen methods, but not in the current chosen methods, restore it.
- if ( isset( $previous_chosen_methods[ $package_key ] ) && ! isset( $chosen_shipping_methods[ $package_key ] ) ) {
- $chosen_shipping_methods[ $package_key ] = $previous_chosen_methods[ $package_key ];
+ // If the recurring cart package key is found in the previous chosen methods, but not in the current chosen methods, restore it.
+ if ( isset( $previous_chosen_methods[ $package_key ] ) && ! isset( $chosen_shipping_methods[ $package_key ] ) ) {
+ $chosen_shipping_methods[ $package_key ] = $previous_chosen_methods[ $package_key ];
+ }
}
}
}
diff --git a/includes/payment-methods/class-wc-stripe-upe-payment-method.php b/includes/payment-methods/class-wc-stripe-upe-payment-method.php
index 91ec548f9..1fddc6220 100644
--- a/includes/payment-methods/class-wc-stripe-upe-payment-method.php
+++ b/includes/payment-methods/class-wc-stripe-upe-payment-method.php
@@ -112,8 +112,8 @@ public function __construct() {
$main_settings = WC_Stripe_Helper::get_stripe_settings();
$is_stripe_enabled = ! empty( $main_settings['enabled'] ) && 'yes' === $main_settings['enabled'];
- $this->enabled = $is_stripe_enabled && in_array( static::STRIPE_ID, $this->get_option( 'upe_checkout_experience_accepted_payments', [ 'card' ] ), true ) ? 'yes' : 'no';
- $this->id = WC_Gateway_Stripe::ID . '_' . static::STRIPE_ID;
+ $this->enabled = $is_stripe_enabled && in_array( static::STRIPE_ID, $this->get_option( 'upe_checkout_experience_accepted_payments', [ 'card' ] ), true ) ? 'yes' : 'no'; // @phpstan-ignore-line (STRIPE_ID is defined in classes using this class)
+ $this->id = WC_Gateway_Stripe::ID . '_' . static::STRIPE_ID; // @phpstan-ignore-line (STRIPE_ID is defined in classes using this class)
$this->has_fields = true;
$this->testmode = ! empty( $main_settings['testmode'] ) && 'yes' === $main_settings['testmode'];
$this->supports = [ 'products', 'refunds' ];
@@ -350,7 +350,7 @@ public function get_capabilities_response() {
* to query to retrieve saved payment methods from Stripe.
*/
public function get_retrievable_type() {
- return $this->is_reusable() ? WC_Stripe_UPE_Payment_Method_Sepa::STRIPE_ID : static::STRIPE_ID;
+ return $this->is_reusable() ? WC_Stripe_UPE_Payment_Method_Sepa::STRIPE_ID : static::STRIPE_ID; // @phpstan-ignore-line (STRIPE_ID is defined in classes using this class)
}
/**
@@ -379,7 +379,7 @@ public function create_payment_token_for_user( $user_id, $payment_method ) {
*/
public function get_supported_currencies() {
return apply_filters(
- 'wc_stripe_' . static::STRIPE_ID . '_upe_supported_currencies',
+ 'wc_stripe_' . static::STRIPE_ID . '_upe_supported_currencies', // @phpstan-ignore-line (STRIPE_ID is defined in classes using this class)
$this->supported_currencies
);
}
diff --git a/readme.txt b/readme.txt
index 29f685f25..4b4464c18 100644
--- a/readme.txt
+++ b/readme.txt
@@ -142,5 +142,6 @@ If you get stuck, you can ask for help in the Plugin Forum.
* Fix - Catch error when getting intent from order.
* Fix - Handle undefined array key when no matching customer account is found when guest customers checkout.
* Fix - Address QIT Security test errors.
+* Fix - Address QIT PHPStan test errors.
[See changelog for all versions](https://raw.githubusercontent.com/woocommerce/woocommerce-gateway-stripe/trunk/changelog.txt).
diff --git a/templates/emails/failed-renewal-authentication-requested.php b/templates/emails/failed-renewal-authentication-requested.php
index ad221a7aa..c8c538492 100644
--- a/templates/emails/failed-renewal-authentication-requested.php
+++ b/templates/emails/failed-renewal-authentication-requested.php
@@ -27,7 +27,7 @@
),
$order->get_order_number(),
$order->get_formatted_billing_full_name(),
- wcs_get_human_time_diff( $retry->get_time() )
+ function_exists( 'wcs_get_human_time_diff' ) ? wcs_get_human_time_diff( $retry->get_time() ) : ''
)
);
?>
diff --git a/templates/emails/plain/failed-renewal-authentication-requested.php b/templates/emails/plain/failed-renewal-authentication-requested.php
index 9c1754523..5e61b515a 100644
--- a/templates/emails/plain/failed-renewal-authentication-requested.php
+++ b/templates/emails/plain/failed-renewal-authentication-requested.php
@@ -21,7 +21,7 @@
),
esc_html( $order->get_order_number() ),
esc_html( $order->get_formatted_billing_full_name() ),
- esc_html( wcs_get_human_time_diff( $retry->get_time() ) )
+ function_exists( 'wcs_get_human_time_diff' ) ? esc_html( wcs_get_human_time_diff( $retry->get_time() ) ) : ''
) . "\n\n";
printf( esc_html__( 'The renewal order is as follows:', 'woocommerce-gateway-stripe' ) ) . "\n\n";
From 36ea8ad1600262b68efa5308b0277406d20fbfd9 Mon Sep 17 00:00:00 2001
From: James Allan
Date: Wed, 28 Aug 2024 16:05:04 +1000
Subject: [PATCH 07/20] Fix fatal error when canceling uncaptured orders due to
non-expanded refunds in Stripe API response (#3377)
* Fetch refunds in a way that's compatible with newer API versions
* Avoid error if charge response includes no refunds
* Add comment to explain why we're refunding a uncaptured charge
* Add changelog entries
* Use correct format for refunds expanding
---
changelog.txt | 1 +
includes/abstracts/abstract-wc-stripe-payment-gateway.php | 7 +++++--
includes/class-wc-stripe-order-handler.php | 2 ++
readme.txt | 1 +
4 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/changelog.txt b/changelog.txt
index 6e942cd6f..82f399f9b 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -10,6 +10,7 @@
* Add - Show UPE payment methods in saved order on block checkout page.
* Add - Display UI elements for connection type and expired keys status for Stripe accounts linked via the WooCommerce Stripe App.
* Tweak - Delete the notice about the missing customization options on the updated checkout experience.
+* Fix - Prevent fatal error when canceling uncaptured orders by ensuring refunds array is expanded in Stripe API response.
* Fix - Fix error in saving settings when express payment methods are disabled.
* Fix - Catch error when getting intent from order.
* Fix - Handle undefined array key when no matching customer account is found when guest customers checkout.
diff --git a/includes/abstracts/abstract-wc-stripe-payment-gateway.php b/includes/abstracts/abstract-wc-stripe-payment-gateway.php
index 4d0743aaa..5e424af45 100644
--- a/includes/abstracts/abstract-wc-stripe-payment-gateway.php
+++ b/includes/abstracts/abstract-wc-stripe-payment-gateway.php
@@ -1124,8 +1124,11 @@ public function process_refund( $order_id, $amount = null, $reason = '' ) {
if ( ! empty( $result->error ) ) {
$response = $result;
} else {
- $charge = $this->get_latest_charge_from_intent( $result );
- $response = end( $charge->refunds->data );
+ $charge = $this->get_charge_object( $result->latest_charge, [ 'expand' => [ 'refunds' ] ] );
+
+ if ( isset( $charge->refunds->data ) ) {
+ $response = end( $charge->refunds->data );
+ }
}
}
}
diff --git a/includes/class-wc-stripe-order-handler.php b/includes/class-wc-stripe-order-handler.php
index 8bb3d006e..616f9c381 100644
--- a/includes/class-wc-stripe-order-handler.php
+++ b/includes/class-wc-stripe-order-handler.php
@@ -342,7 +342,9 @@ public function cancel_payment( $order_id ) {
if ( WC_Stripe_Helper::payment_method_allows_manual_capture( $order->get_payment_method() ) ) {
$captured = $order->get_meta( '_stripe_charge_captured', true );
+
if ( 'no' === $captured ) {
+ // To cancel a pre-auth, we need to refund the charge.
$this->process_refund( $order_id );
}
diff --git a/readme.txt b/readme.txt
index 4b4464c18..c989e0c99 100644
--- a/readme.txt
+++ b/readme.txt
@@ -138,6 +138,7 @@ If you get stuck, you can ask for help in the Plugin Forum.
* Add - Show UPE payment methods in saved order on block checkout page.
* Add - Display UI elements for connection type and expired keys status for Stripe accounts linked via the WooCommerce Stripe App.
* Tweak - Delete the notice about the missing customization options on the updated checkout experience.
+* Fix - Prevent fatal error when canceling uncaptured orders by ensuring refunds array is expanded in Stripe API response.
* Fix - Fix error in saving settings when express payment methods are disabled.
* Fix - Catch error when getting intent from order.
* Fix - Handle undefined array key when no matching customer account is found when guest customers checkout.
From 3ceecdf8ecdbd90bd622e27d7adc188f6f3aec26 Mon Sep 17 00:00:00 2001
From: Anne Mirasol
Date: Wed, 28 Aug 2024 07:52:07 -0500
Subject: [PATCH 08/20] Re-enable Stripe Link for shortcode checkout (#3380)
* Add code to reenable Stripe Link for shortcode checkout
* Add readme and changelog entries
---
changelog.txt | 1 +
client/classic/upe/deferred-intent.js | 67 ++++++++++++++++++++++--
client/classic/upe/payment-processing.js | 3 ++
readme.txt | 1 +
4 files changed, 68 insertions(+), 4 deletions(-)
diff --git a/changelog.txt b/changelog.txt
index 82f399f9b..e5548a17f 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,6 +1,7 @@
*** Changelog ***
= 8.7.0 - xxxx-xx-xx =
+* Fix - Add back support for Stripe Link autofill for shortcode checkout.
* Fix - Fix undefined method error caused by settings refactor when connecting Stripe account.
* Fix - Fix multiple compatibility issues and deprecation warnings when running the extension on PHP 8.1.
* Fix - Re-connect promotional surface blinking after disappearing for merchants that have already connected their Stripe account.
diff --git a/client/classic/upe/deferred-intent.js b/client/classic/upe/deferred-intent.js
index 00d08d7ad..f1422db1e 100644
--- a/client/classic/upe/deferred-intent.js
+++ b/client/classic/upe/deferred-intent.js
@@ -2,6 +2,7 @@ import jQuery from 'jquery';
import WCStripeAPI from '../../api';
import {
generateCheckoutEventNames,
+ getPaymentMethodTypes,
getSelectedUPEGatewayPaymentMethod,
getStripeServerData,
isPaymentMethodRestrictedToLocation,
@@ -10,12 +11,13 @@ import {
} from '../../stripe-utils';
import './style.scss';
import {
- processPayment,
- mountStripePaymentElement,
- createAndConfirmSetupIntent,
confirmVoucherPayment,
confirmWalletPayment,
+ createAndConfirmSetupIntent,
+ mountStripePaymentElement,
+ processPayment,
} from './payment-processing';
+import enableStripeLinkPaymentMethod from 'wcstripe/stripe-link';
jQuery( function ( $ ) {
// Create an API object, which will be used throughout the checkout.
@@ -87,12 +89,69 @@ jQuery( function ( $ ) {
for ( const upeElement of $(
'.wc-stripe-upe-element'
).toArray() ) {
- await mountStripePaymentElement( api, upeElement );
+ const component = await mountStripePaymentElement(
+ api,
+ upeElement
+ );
restrictPaymentMethodToLocation( upeElement );
+ maybeEnableStripeLinkPaymentMethod(
+ component.elements,
+ upeElement.dataset.paymentMethodType
+ );
}
}
}
+ function maybeEnableStripeLinkPaymentMethod( elements, paymentMethodType ) {
+ const isCheckout = getStripeServerData()?.isCheckout;
+ if ( ! isCheckout ) {
+ return;
+ }
+
+ if ( paymentMethodType !== 'card' ) {
+ return;
+ }
+
+ const isStripeLinkEnabled = getPaymentMethodTypes(
+ paymentMethodType
+ ).includes( 'link' );
+ if ( ! isStripeLinkEnabled ) {
+ return;
+ }
+
+ enableStripeLinkPaymentMethod( {
+ api,
+ elements,
+ emailId: 'billing_email_field',
+ complete_billing: () => {
+ return document.getElementById( 'billing_address_1' ) !== null;
+ },
+ complete_shipping: () => {
+ return document.getElementById( 'shipping_address_1' ) !== null;
+ },
+ shipping_fields: {
+ line1: 'shipping_address_1',
+ line2: 'shipping_address_2',
+ city: 'shipping_city',
+ state: 'shipping_state',
+ postal_code: 'shipping_postcode',
+ country: 'shipping_country',
+ first_name: 'shipping_first_name',
+ last_name: 'shipping_last_name',
+ },
+ billing_fields: {
+ line1: 'billing_address_1',
+ line2: 'billing_address_2',
+ city: 'billing_city',
+ state: 'billing_state',
+ postal_code: 'billing_postcode',
+ country: 'billing_country',
+ first_name: 'billing_first_name',
+ last_name: 'billing_last_name',
+ },
+ } );
+ }
+
function restrictPaymentMethodToLocation( upeElement ) {
if ( isPaymentMethodRestrictedToLocation( upeElement ) ) {
togglePaymentMethodForCountry( upeElement );
diff --git a/client/classic/upe/payment-processing.js b/client/classic/upe/payment-processing.js
index 546f10964..4611eda5b 100644
--- a/client/classic/upe/payment-processing.js
+++ b/client/classic/upe/payment-processing.js
@@ -166,6 +166,7 @@ function createStripePaymentMethod(
*
* @param {Object} api The API object.
* @param {string} domElement The selector of the DOM element of particular payment method to mount the UPE element to.
+ * @return {Object} An object containing the Stripe Elements object and the Stripe Payment Element.
**/
export async function mountStripePaymentElement( api, domElement ) {
/*
@@ -194,6 +195,8 @@ export async function mountStripePaymentElement( api, domElement ) {
gatewayUPEComponents[ paymentMethodType ].upeElement ||
( await createStripePaymentElement( api, paymentMethodType ) );
upeElement.mount( domElement );
+
+ return gatewayUPEComponents[ paymentMethodType ];
}
/**
diff --git a/readme.txt b/readme.txt
index c989e0c99..50fad06fe 100644
--- a/readme.txt
+++ b/readme.txt
@@ -129,6 +129,7 @@ If you get stuck, you can ask for help in the Plugin Forum.
== Changelog ==
= 8.7.0 - xxxx-xx-xx =
+* Fix - Add back support for Stripe Link autofill for shortcode checkout.
* Fix - Fix undefined method error caused by settings refactor when connecting Stripe account.
* Fix - Fix multiple compatibility issues and deprecation warnings when running the extension on PHP 8.1.
* Fix - Re-connect promotional surface blinking after disappearing for merchants that have already connected their Stripe account.
From ad3eafbaa4d7931da8bd9779a7a63a25ec5ac643 Mon Sep 17 00:00:00 2001
From: Wesley Rosa
Date: Wed, 28 Aug 2024 18:29:45 -0300
Subject: [PATCH 09/20] Fix subscription processing with mandates (#3359)
* Disable subscription edit for Indian subscriptions with mandates
* Draft for the possible mandate fix
* Implementation for the specific logic for creating mandates when switching subscriptions
* Reverting unnecessary changes
* Adding entries to changelog and readme files
* Considering currency when summing subscription price
* Fix lint issues
---
changelog.txt | 1 +
.../compat/trait-wc-stripe-subscriptions.php | 120 ++++++++++++------
readme.txt | 1 +
3 files changed, 85 insertions(+), 37 deletions(-)
diff --git a/changelog.txt b/changelog.txt
index e5548a17f..386962258 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,6 +1,7 @@
*** Changelog ***
= 8.7.0 - xxxx-xx-xx =
+* Fix - Fix Indian subscription processing by forcing the recreation of mandates during switches (upgrading/downgrading).
* Fix - Add back support for Stripe Link autofill for shortcode checkout.
* Fix - Fix undefined method error caused by settings refactor when connecting Stripe account.
* Fix - Fix multiple compatibility issues and deprecation warnings when running the extension on PHP 8.1.
diff --git a/includes/compat/trait-wc-stripe-subscriptions.php b/includes/compat/trait-wc-stripe-subscriptions.php
index 69dfa7fd3..d236e01fe 100644
--- a/includes/compat/trait-wc-stripe-subscriptions.php
+++ b/includes/compat/trait-wc-stripe-subscriptions.php
@@ -87,6 +87,9 @@ public function maybe_init_subscriptions() {
*/
add_action( 'template_redirect', [ $this, 'remove_order_pay_var' ], 99 );
add_action( 'template_redirect', [ $this, 'restore_order_pay_var' ], 101 );
+
+ // Disable editing for Indian subscriptions with mandates. Those need to be recreated as mandates does not support upgrades (due fixed amounts).
+ add_filter( 'wc_order_is_editable', [ $this, 'disable_subscription_edit_for_india' ], 10, 2 );
}
/**
@@ -593,30 +596,35 @@ public function add_subscription_information_to_intent( $request, $order, $prepa
return $request;
}
- // TODO: maybe this isn't necessary since this function should really only be called
- // when creating the intent? It's called in process_subscription_payment though
- // so it's probably needed here too?
- // If we've already created a mandate for this order; use that.
- $mandate = $order->get_meta( '_stripe_mandate_id', true );
- if ( isset( $request['confirm'] ) && filter_var( $request['confirm'], FILTER_VALIDATE_BOOL ) && ! empty( $mandate ) ) {
- $request['mandate'] = $mandate;
- unset( $request['setup_future_usage'] );
- return $request;
- }
-
- $subscriptions_for_renewal_order = function_exists( 'wcs_get_subscriptions_for_renewal_order' ) ? wcs_get_subscriptions_for_renewal_order( $order ) : [];
-
- // Check if mandate already exists.
- if ( 1 === count( $subscriptions_for_renewal_order ) ) {
- $subscription_order = reset( $subscriptions_for_renewal_order );
- $mandate = $this->get_mandate_for_subscription( $subscription_order, isset( $request['payment_method'] ) ? $request['payment_method'] : '' );
+ $subscriptions_for_renewal_order = [];
- if ( ! empty( $mandate ) ) {
- $request['confirm'] = 'true';
+ // Check if this is not a subscription switch. When switching we will force the creation of mandates to update the amount
+ if ( ! WC_Subscriptions_Switcher::cart_contains_switches() ) {
+ // TODO: maybe this isn't necessary since this function should really only be called
+ // when creating the intent? It's called in process_subscription_payment though
+ // so it's probably needed here too?
+ // If we've already created a mandate for this order; use that.
+ $mandate = $order->get_meta( '_stripe_mandate_id', true );
+ if ( isset( $request['confirm'] ) && filter_var( $request['confirm'], FILTER_VALIDATE_BOOL ) && ! empty( $mandate ) ) {
$request['mandate'] = $mandate;
unset( $request['setup_future_usage'] );
return $request;
}
+
+ $subscriptions_for_renewal_order = function_exists( 'wcs_get_subscriptions_for_renewal_order' ) ? wcs_get_subscriptions_for_renewal_order( $order ) : [];
+
+ // Check if mandate already exists.
+ if ( 1 === count( $subscriptions_for_renewal_order ) ) {
+ $subscription_order = reset( $subscriptions_for_renewal_order );
+ $mandate = $this->get_mandate_for_subscription( $subscription_order, isset( $request['payment_method'] ) ? $request['payment_method'] : '' );
+
+ if ( ! empty( $mandate ) ) {
+ $request['confirm'] = 'true';
+ $request['mandate'] = $mandate;
+ unset( $request['setup_future_usage'] );
+ return $request;
+ }
+ }
}
// Add mandate options to request to create new mandate if mandate id does not already exist in a previous renewal or parent order.
@@ -661,7 +669,7 @@ private function get_mandate_for_subscription( $order, $payment_method ) {
* Create mandate options for a subscription order to be added to the payment intent request.
*
* @param WC_Order $order The renewal order.
- * @param WC_Order $subscriptions Subscriptions for the renewal order.
+ * @param WC_Subscription[] $subscriptions Subscriptions for the renewal order.
* @return array the mandate_options for the subscription order.
*/
private function create_mandate_options_for_order( $order, $subscriptions ) {
@@ -673,19 +681,41 @@ private function create_mandate_options_for_order( $order, $subscriptions ) {
return [];
}
- // If this is the first order, not a renewal, then get the subscriptions for the parent order.
- if ( empty( $subscriptions ) ) {
- $subscriptions = function_exists( 'wcs_get_subscriptions_for_order' ) ? wcs_get_subscriptions_for_order( $order ) : [];
- }
+ $sub_amount = 0;
- // If there are no subscriptions we just return since mandates aren't required.
- if ( 0 === count( $subscriptions ) ) {
- return [];
- }
+ // If this is a switch order we set the mandate options based on the new subscription.
+ $cart_contain_switches = WC_Subscriptions_Switcher::cart_contains_switches();
+ if ( $cart_contain_switches ) {
+ foreach ( WC()->cart->cart_contents as $cart_item ) {
+ $subscription_price = WC_Subscriptions_Product::get_price( $cart_item['data'] );
+ $sub_amount += (int) WC_Stripe_Helper::get_stripe_amount( $subscription_price, $currency );
+ }
- $sub_amount = 0;
- foreach ( $subscriptions as $sub ) {
- $sub_amount += WC_Stripe_Helper::get_stripe_amount( $sub->get_total() );
+ // Get the first cart item associated with this order.
+ $cart_item = reset( WC()->cart->cart_contents );
+
+ $sub_billing_period = WC_Subscriptions_Product::get_period( $cart_item['data'] );
+ $sub_billing_interval = absint( WC_Subscriptions_Product::get_interval( $cart_item['data'] ) );
+ } else {
+ // If this is the first order, not a renewal, then get the subscriptions for the parent order.
+ if ( empty( $subscriptions ) ) {
+ $subscriptions = function_exists( 'wcs_get_subscriptions_for_order' ) ? wcs_get_subscriptions_for_order( $order ) : [];
+ }
+
+ // If there are no subscriptions we just return since mandates aren't required.
+ if ( 0 === count( $subscriptions ) ) {
+ return [];
+ }
+
+ foreach ( $subscriptions as $sub ) {
+ $sub_amount += WC_Stripe_Helper::get_stripe_amount( $sub->get_total(), $currency );
+ }
+
+ // Get the first subscription associated with this order.
+ $sub = reset( $subscriptions );
+
+ $sub_billing_period = strtolower( $sub->get_billing_period() );
+ $sub_billing_interval = $sub->get_billing_interval();
}
// If the amount is 0 we don't need to create a mandate since we won't be charging anything.
@@ -694,13 +724,10 @@ private function create_mandate_options_for_order( $order, $subscriptions ) {
return [];
}
- // Get the first subscription associated with this order.
- $sub = reset( $subscriptions );
-
- if ( 1 === count( $subscriptions ) ) {
+ if ( 1 === count( $subscriptions ) || $cart_contain_switches ) {
$mandate_options['amount_type'] = 'fixed';
- $mandate_options['interval'] = strtolower( $sub->get_billing_period() );
- $mandate_options['interval_count'] = $sub->get_billing_interval();
+ $mandate_options['interval'] = $sub_billing_period;
+ $mandate_options['interval_count'] = $sub_billing_interval;
} else {
// If there are multiple subscriptions the amount_type becomes 'maximum' so we can charge anything
// less than the order total, and the interval is sporadic so we don't have to follow a set interval.
@@ -967,4 +994,23 @@ public function update_subscription_payment_method_from_order( $order, $payment_
$subscription->save();
}
}
+
+ /**
+ * Disables the ability to edit a subscription for orders with mandates.
+ *
+ * @param $editable boolean The current editability of the subscription.
+ * @param $order WC_Order The order object.
+ * @return boolean true if the subscription can be edited, false otherwise.
+ */
+ public function disable_subscription_edit_for_india( $editable, $order ) {
+ $parent_order = wc_get_order( $order->get_parent_id() );
+ if ( $this->is_subscriptions_enabled()
+ && $this->is_subscription( $order )
+ && $parent_order
+ && ! empty( $parent_order->get_meta( '_stripe_mandate_id', true ) ) ) {
+ $editable = false;
+ }
+
+ return $editable;
+ }
}
diff --git a/readme.txt b/readme.txt
index 50fad06fe..08cced88a 100644
--- a/readme.txt
+++ b/readme.txt
@@ -129,6 +129,7 @@ If you get stuck, you can ask for help in the Plugin Forum.
== Changelog ==
= 8.7.0 - xxxx-xx-xx =
+* Fix - Fix Indian subscription processing by forcing the recreation of mandates during switches (upgrading/downgrading).
* Fix - Add back support for Stripe Link autofill for shortcode checkout.
* Fix - Fix undefined method error caused by settings refactor when connecting Stripe account.
* Fix - Fix multiple compatibility issues and deprecation warnings when running the extension on PHP 8.1.
From 7b004194e8523bd0ffaeaf4e7aa634ed48b2bda1 Mon Sep 17 00:00:00 2001
From: Mayisha <33387139+Mayisha@users.noreply.github.com>
Date: Thu, 29 Aug 2024 13:12:56 +0600
Subject: [PATCH 10/20] Update capabilities to payment methods mapping (#3375)
* update capability to payment method mapping
- consider `pm` and `pm_payments` both type of keys to check capabilities
* remove capability check from frontend
- payment methods are already filtered in the backend in 'filter_payment_methods_with_capabilities' method
* consider `legacy_payments` capability for card method.
* refactor and add comment
* isset check
---
changelog.txt | 1 +
.../payment-methods-list.js | 22 ++++---------------
includes/class-wc-stripe-helper.php | 13 +++++++++--
readme.txt | 1 +
4 files changed, 17 insertions(+), 20 deletions(-)
diff --git a/changelog.txt b/changelog.txt
index 386962258..14bc00208 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -16,6 +16,7 @@
* Fix - Fix error in saving settings when express payment methods are disabled.
* Fix - Catch error when getting intent from order.
* Fix - Handle undefined array key when no matching customer account is found when guest customers checkout.
+* Tweak - Update capabilities to payment methods mapping.
* Fix - Address QIT Security test errors.
* Fix - Address QIT PHPStan test errors.
diff --git a/client/settings/general-settings-section/payment-methods-list.js b/client/settings/general-settings-section/payment-methods-list.js
index 560c3768c..6286c1960 100644
--- a/client/settings/general-settings-section/payment-methods-list.js
+++ b/client/settings/general-settings-section/payment-methods-list.js
@@ -1,11 +1,10 @@
import { __, sprintf } from '@wordpress/i18n';
-import React, { useContext, useState } from 'react';
+import React, { useState } from 'react';
import styled from '@emotion/styled';
import classnames from 'classnames';
import { Button } from '@wordpress/components';
import { Icon as IconComponent, dragHandle } from '@wordpress/icons';
import { Reorder } from 'framer-motion';
-import UpeToggleContext from '../upe-toggle/context';
import PaymentMethodsMap from '../../payment-methods-map';
import PaymentMethodDescription from './payment-method-description';
import CustomizePaymentMethod from './customize-payment-method';
@@ -15,7 +14,7 @@ import {
useGetOrderedPaymentMethodIds,
useManualCapture,
} from 'wcstripe/data';
-import { useAccount, useGetCapabilities } from 'wcstripe/data/account';
+import { useAccount } from 'wcstripe/data/account';
import PaymentMethodFeesPill from 'wcstripe/components/payment-method-fees-pill';
const List = styled.ul`
@@ -183,9 +182,7 @@ const GeneralSettingsSection = ( {
isChangingDisplayOrder,
onSaveChanges,
} ) => {
- const { isUpeEnabled } = useContext( UpeToggleContext );
const [ customizationStatus, setCustomizationStatus ] = useState( {} );
- const capabilities = useGetCapabilities();
const [ isManualCaptureEnabled ] = useManualCapture();
const [ enabledPaymentMethodIds ] = useEnabledPaymentMethodIds();
const {
@@ -193,19 +190,8 @@ const GeneralSettingsSection = ( {
setOrderedPaymentMethodIds,
} = useGetOrderedPaymentMethodIds();
const { data } = useAccount();
- const isTestModeEnabled = Boolean( data.testmode );
-
- // Hide payment methods that are not part of the account capabilities if UPE is enabled in live mode.
- // Show all methods in test mode.
- const availablePaymentMethods = isUpeEnabled
- ? orderedPaymentMethodIds
- .filter(
- ( method ) =>
- isTestModeEnabled ||
- capabilities.hasOwnProperty( `${ method }_payments` )
- )
- .filter( ( id ) => id !== 'link' )
- : orderedPaymentMethodIds;
+
+ const availablePaymentMethods = orderedPaymentMethodIds;
// Remove Sofort if it's not enabled. Hide from the new merchants and keep it for the old ones who are already using this gateway, until we remove it completely.
// Stripe is deprecating Sofort https://support.stripe.com/questions/sofort-is-being-deprecated-as-a-standalone-payment-method.
diff --git a/includes/class-wc-stripe-helper.php b/includes/class-wc-stripe-helper.php
index 74fd537ee..14e0220bc 100644
--- a/includes/class-wc-stripe-helper.php
+++ b/includes/class-wc-stripe-helper.php
@@ -726,12 +726,21 @@ public static function filter_payment_methods_with_capabilities( $payment_method
return [];
}
+ // Return all payment methods if in test mode.
+ if ( $testmode ) {
+ return $payment_method_ids;
+ }
+
$payment_method_ids_with_capability = [];
foreach ( $payment_method_ids as $payment_method_id ) {
$key = $payment_method_id . '_payments';
- $has_capability = isset( $data['capabilities'][ $key ] );
- if ( $has_capability || $testmode ) {
+ // Check if the payment method has capabilities set in the account data.
+ // Generally the key is the payment method id appended with '_payments' (i.e. 'card_payments', 'sepa_debit_payments', 'klarna_payments').
+ // In some cases, the Stripe account might have the legacy key set. For example, for Klarna, the legacy key is 'klarna'.
+ // For card, the legacy key is 'legacy_payments'.
+ $has_capability = isset( $data['capabilities'][ $key ] ) || isset( $data['capabilities'][ $payment_method_id ] ) || ( 'card' === $payment_method_id && isset( $data['capabilities']['legacy_payments'] ) );
+ if ( $has_capability ) {
$payment_method_ids_with_capability[] = $payment_method_id;
}
}
diff --git a/readme.txt b/readme.txt
index 08cced88a..f4b701012 100644
--- a/readme.txt
+++ b/readme.txt
@@ -144,6 +144,7 @@ If you get stuck, you can ask for help in the Plugin Forum.
* Fix - Fix error in saving settings when express payment methods are disabled.
* Fix - Catch error when getting intent from order.
* Fix - Handle undefined array key when no matching customer account is found when guest customers checkout.
+* Tweak - Update capabilities to payment methods mapping.
* Fix - Address QIT Security test errors.
* Fix - Address QIT PHPStan test errors.
From 6d8f2553b671096d2f1a4b365d7a665df6d579c2 Mon Sep 17 00:00:00 2001
From: Diego Curbelo
Date: Thu, 29 Aug 2024 10:46:21 -0300
Subject: [PATCH 11/20] Fix E2E test suite compatibility with Woo 9.2 (#3390)
* Fix github action name
* Update country/state selector to use selectOption instead of fill and click on the first result
---------
Co-authored-by: Mayisha <33387139+Mayisha@users.noreply.github.com>
---
.github/workflows/e2e-tests.yml | 2 +-
tests/e2e/utils/payments.js | 15 +++------------
2 files changed, 4 insertions(+), 13 deletions(-)
diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml
index 9a0f101c6..8392a956a 100644
--- a/.github/workflows/e2e-tests.yml
+++ b/.github/workflows/e2e-tests.yml
@@ -16,7 +16,7 @@ jobs:
matrix:
checkout: [ 'Default', 'Legacy' ]
- name: ${{ matrix.checkout }} WP=latest, WC=latest, PHP=7.4"
+ name: ${{ matrix.checkout }} WP=latest, WC=latest, PHP=7.4
steps:
- name: Checkout repo
uses: actions/checkout@v4
diff --git a/tests/e2e/utils/payments.js b/tests/e2e/utils/payments.js
index 87228e0dd..b6efdb4a9 100644
--- a/tests/e2e/utils/payments.js
+++ b/tests/e2e/utils/payments.js
@@ -227,21 +227,12 @@ export async function setupBlocksCheckout( page, billingDetails = null ) {
if ( billingDetails ) {
await page
.getByLabel( 'Country/Region' )
- .fill( billingDetails[ 'country' ] );
- await page
- .locator(
- '.components-form-token-field__suggestions-list > li:first-child'
- )
- .click();
+ .selectOption( { label: billingDetails[ 'country' ] } );
await page
.getByLabel( 'State', { exact: true } )
- .fill( billingDetails[ 'state' ] );
- await page
- .locator(
- '.components-form-token-field__suggestions-list > li:first-child'
- )
- .click();
+ .selectOption( { label: billingDetails[ 'state' ] } );
+
// Expand the address 2 field.
await page
.locator( '.wc-block-components-address-form__address_2-toggle' )
From a5d3ce01c1eec536a1b3f8b0468d82ffa337bc4a Mon Sep 17 00:00:00 2001
From: Anne Mirasol
Date: Thu, 29 Aug 2024 11:04:23 -0500
Subject: [PATCH 12/20] Set transaction URL for Stripe APMs (#3383)
* Set transaction URL for Stripe APMs
* Add readme and changelog entries
* Refactor: move common logic to helper method
---
changelog.txt | 1 +
.../abstract-wc-stripe-payment-gateway.php | 6 +-----
includes/class-wc-stripe-helper.php | 8 ++++++++
.../class-wc-stripe-upe-payment-method.php | 13 +++++++++++++
readme.txt | 1 +
5 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/changelog.txt b/changelog.txt
index 14bc00208..908c9da19 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,6 +1,7 @@
*** Changelog ***
= 8.7.0 - xxxx-xx-xx =
+* Fix - Link APM charge IDs in Order Details page to their Stripe dashboard payments page.
* Fix - Fix Indian subscription processing by forcing the recreation of mandates during switches (upgrading/downgrading).
* Fix - Add back support for Stripe Link autofill for shortcode checkout.
* Fix - Fix undefined method error caused by settings refactor when connecting Stripe account.
diff --git a/includes/abstracts/abstract-wc-stripe-payment-gateway.php b/includes/abstracts/abstract-wc-stripe-payment-gateway.php
index 5e424af45..a2798379c 100644
--- a/includes/abstracts/abstract-wc-stripe-payment-gateway.php
+++ b/includes/abstracts/abstract-wc-stripe-payment-gateway.php
@@ -379,11 +379,7 @@ public function validate_minimum_order_amount( $order ) {
* @version 4.0.0
*/
public function get_transaction_url( $order ) {
- if ( $this->testmode ) { // @phpstan-ignore-line (testmode is defined in the classes that use this class)
- $this->view_transaction_url = 'https://dashboard.stripe.com/test/payments/%s';
- } else {
- $this->view_transaction_url = 'https://dashboard.stripe.com/payments/%s';
- }
+ $this->view_transaction_url = WC_Stripe_Helper::get_transaction_url( $this->testmode );
return parent::get_transaction_url( $order );
}
diff --git a/includes/class-wc-stripe-helper.php b/includes/class-wc-stripe-helper.php
index 14e0220bc..cec6f152d 100644
--- a/includes/class-wc-stripe-helper.php
+++ b/includes/class-wc-stripe-helper.php
@@ -1525,4 +1525,12 @@ public static function is_webhook_url( $url, $webhook_url = '' ) {
return $url_host === $webhook_host && $url_path === $webhook_path;
}
+
+ public static function get_transaction_url( $is_test_mode = false ) {
+ if ( $is_test_mode ) {
+ return 'https://dashboard.stripe.com/test/payments/%s';
+ }
+
+ return 'https://dashboard.stripe.com/payments/%s';
+ }
}
diff --git a/includes/payment-methods/class-wc-stripe-upe-payment-method.php b/includes/payment-methods/class-wc-stripe-upe-payment-method.php
index 1fddc6220..bdc572ff9 100644
--- a/includes/payment-methods/class-wc-stripe-upe-payment-method.php
+++ b/includes/payment-methods/class-wc-stripe-upe-payment-method.php
@@ -661,4 +661,17 @@ public function save_payment_method_checkbox( $force_checked = false ) {
view_transaction_url = WC_Stripe_Helper::get_transaction_url( $this->testmode );
+
+ return parent::get_transaction_url( $order );
+ }
}
diff --git a/readme.txt b/readme.txt
index f4b701012..d116c949b 100644
--- a/readme.txt
+++ b/readme.txt
@@ -129,6 +129,7 @@ If you get stuck, you can ask for help in the Plugin Forum.
== Changelog ==
= 8.7.0 - xxxx-xx-xx =
+* Fix - Link APM charge IDs in Order Details page to their Stripe dashboard payments page.
* Fix - Fix Indian subscription processing by forcing the recreation of mandates during switches (upgrading/downgrading).
* Fix - Add back support for Stripe Link autofill for shortcode checkout.
* Fix - Fix undefined method error caused by settings refactor when connecting Stripe account.
From 019e3981ded5eca05f7701ba77217ee690c584cc Mon Sep 17 00:00:00 2001
From: James Allan
Date: Fri, 30 Aug 2024 11:52:28 +1000
Subject: [PATCH 13/20] Ensure payment methods aren't detached on local or
staging sites when the new checkout experience is enabled (#3370)
* Ensure pms aren't detached on local or staging sites when the new checkout experience is enabled
* Use single function for detaching payment methods
* Add changelog entries
* Use the token's user ID rather than the current user when a token is deleted
* Revert "Use the token's user ID rather than the current user when a token is deleted"
This reverts commit 524752e33cff1283c64c37c523208ee5f794cf33.
---------
Co-authored-by: Mayisha <33387139+Mayisha@users.noreply.github.com>
---
changelog.txt | 1 +
includes/class-wc-stripe-customer.php | 2 +-
readme.txt | 1 +
3 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/changelog.txt b/changelog.txt
index 908c9da19..ce43adb16 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -9,6 +9,7 @@
* Fix - Re-connect promotional surface blinking after disappearing for merchants that have already connected their Stripe account.
* Fix - Fix possible fatal errors when Stripe settings format is invalid during account connection.
* Fix - Clear webhook state after reconfiguring webhooks to remove outdated error and success statuses.
+* Fix - Prevent payment methods from being detached from Stripe customers on non-production sites when a WP user is deleted with the new checkout experience enabled.
* Add - Log incoming webhook events and their request body.
* Add - Show UPE payment methods in saved order on block checkout page.
* Add - Display UI elements for connection type and expired keys status for Stripe accounts linked via the WooCommerce Stripe App.
diff --git a/includes/class-wc-stripe-customer.php b/includes/class-wc-stripe-customer.php
index e5c579d04..3610b41ed 100644
--- a/includes/class-wc-stripe-customer.php
+++ b/includes/class-wc-stripe-customer.php
@@ -567,7 +567,7 @@ public function detach_payment_method( $payment_method_id ) {
return false;
}
- $response = WC_Stripe_API::request( [], "payment_methods/$payment_method_id/detach", 'POST' );
+ $response = WC_Stripe_API::detach_payment_method_from_customer( $this->get_id(), $payment_method_id );
$this->clear_cache();
diff --git a/readme.txt b/readme.txt
index d116c949b..bdd3d16b1 100644
--- a/readme.txt
+++ b/readme.txt
@@ -137,6 +137,7 @@ If you get stuck, you can ask for help in the Plugin Forum.
* Fix - Re-connect promotional surface blinking after disappearing for merchants that have already connected their Stripe account.
* Fix - Fix possible fatal errors when Stripe settings format is invalid during account connection.
* Fix - Clear webhook state after reconfiguring webhooks to remove outdated error and success statuses.
+* Fix - Prevent payment methods from being detached from Stripe customers on non-production sites when a WP user is deleted with the new checkout experience enabled.
* Add - Log incoming webhook events and their request body.
* Add - Show UPE payment methods in saved order on block checkout page.
* Add - Display UI elements for connection type and expired keys status for Stripe accounts linked via the WooCommerce Stripe App.
From 5934d4a269c6de15d4b588b98f03761b85f56bde Mon Sep 17 00:00:00 2001
From: James Allan
Date: Fri, 30 Aug 2024 19:57:49 +1000
Subject: [PATCH 14/20] Ensure tokens are deleted when a user is deleted and
the admin doesn't have a Stripe Account (#3396)
* Use the token's user ID rather than the current user when a token is deleted
* Add changelog entries
---
changelog.txt | 1 +
includes/class-wc-stripe-payment-tokens.php | 7 +++++--
readme.txt | 1 +
3 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/changelog.txt b/changelog.txt
index ce43adb16..682373097 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -21,6 +21,7 @@
* Tweak - Update capabilities to payment methods mapping.
* Fix - Address QIT Security test errors.
* Fix - Address QIT PHPStan test errors.
+* Fix - Ensure payment tokens are detached from Stripe when a user is deleted, regardless of if the admin user has a Stripe account.
= 8.6.1 - 2024-08-09 =
* Tweak - Improves the wording of the invalid Stripe keys errors, instructing merchants to click the "Configure connection" button instead of manually setting the keys.
diff --git a/includes/class-wc-stripe-payment-tokens.php b/includes/class-wc-stripe-payment-tokens.php
index ac36cd1ca..e975fa1f8 100644
--- a/includes/class-wc-stripe-payment-tokens.php
+++ b/includes/class-wc-stripe-payment-tokens.php
@@ -400,13 +400,16 @@ public function get_account_saved_payment_methods_list_item( $item, $payment_tok
}
/**
- * Delete token from Stripe.
+ * Deletes a token from Stripe.
*
* @since 3.1.0
* @version 4.0.0
+ *
+ * @param int $token_id The WooCommerce token ID.
+ * @param WC_Payment_Token $token The WC_Payment_Token object.
*/
public function woocommerce_payment_token_deleted( $token_id, $token ) {
- $stripe_customer = new WC_Stripe_Customer( get_current_user_id() );
+ $stripe_customer = new WC_Stripe_Customer( $token->get_user_id() );
try {
if ( WC_Stripe_Feature_Flags::is_upe_checkout_enabled() ) {
if ( in_array( $token->get_gateway_id(), self::UPE_REUSABLE_GATEWAYS_BY_PAYMENT_METHOD, true ) ) {
diff --git a/readme.txt b/readme.txt
index bdd3d16b1..529875e2d 100644
--- a/readme.txt
+++ b/readme.txt
@@ -149,5 +149,6 @@ If you get stuck, you can ask for help in the Plugin Forum.
* Tweak - Update capabilities to payment methods mapping.
* Fix - Address QIT Security test errors.
* Fix - Address QIT PHPStan test errors.
+* Fix - Ensure payment tokens are detached from Stripe when a user is deleted, regardless of if the admin user has a Stripe account.
[See changelog for all versions](https://raw.githubusercontent.com/woocommerce/woocommerce-gateway-stripe/trunk/changelog.txt).
From 10fee72bb123b5f8eebdd0f628ef3a5171b5a1f9 Mon Sep 17 00:00:00 2001
From: Diego Curbelo
Date: Sat, 31 Aug 2024 20:18:01 -0300
Subject: [PATCH 15/20] Add scheduled workflow to auto-label issues (#3245)
* Add issue gardening workflow
---
.github/workflows/issue-gardening.yml | 50 +++++++++++++++++++++++++++
1 file changed, 50 insertions(+)
create mode 100644 .github/workflows/issue-gardening.yml
diff --git a/.github/workflows/issue-gardening.yml b/.github/workflows/issue-gardening.yml
new file mode 100644
index 000000000..f788c6f02
--- /dev/null
+++ b/.github/workflows/issue-gardening.yml
@@ -0,0 +1,50 @@
+name: 'Issue Gardening'
+
+on:
+ schedule:
+ - cron: '0 0 * * *'
+
+jobs:
+ issue-gardening:
+ name: ${{ matrix.name }}
+ runs-on: ubuntu-latest
+ if: ${{ github.repository == 'woocommerce/woocommerce-gateway-stripe' }}
+ strategy:
+ matrix:
+ include:
+
+ - name: 'Issues that require more info'
+ message: 'Help us move this issue forward. This issue is being marked stale since it has no activity after 15 days of requesting more information. Please add info requested so we can help move the issue forward.'
+ days-before-stale: 15
+ days-before-close: -1
+ only-labels: 'status: needs more info'
+ remove-stale-when-updated: true
+ stale-issue-label: 'status: stale'
+
+ - name: 'Issues without activity for 5 months'
+ message: "Hi,\nThis issue has gone 150 days (5 months) without any activity. This means it is time for a check-in to make sure it is still relevant. If you are still experiencing this issue with the latest version, you can help the project by responding to confirm the problem and by providing any updated reproduction steps.\nThanks for helping out."
+ days-before-stale: 150
+ days-before-close: -1
+ only-labels: ''
+ remove-stale-when-updated: true
+ stale-issue-label: 'status: needs confirmation'
+
+ - name: 'Issues without activity for 6 months'
+ message: 'This issue has gone 180 days (6 months) without any activity.'
+ days-before-stale: 30
+ days-before-close: -1
+ only-labels: 'status: needs confirmation'
+ remove-stale-when-updated: true
+ stale-issue-label: 'status: stale'
+
+ steps:
+ - name: Update issues
+ uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9.0.0
+ with:
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
+ stale-issue-message: ${{ matrix.message }}
+ days-before-stale: ${{ matrix.days-before-stale }}
+ days-before-close: ${{ matrix.days-before-close }}
+ only-labels: ${{ matrix.only-labels }}
+ remove-stale-when-updated: ${{ matrix.remove-stale-when-updated }}
+ stale-issue-label: ${{ matrix.stale-issue-label }}
From cebe0cb323c59d2de06d2d0aa388533a5339e0b1 Mon Sep 17 00:00:00 2001
From: James Allan
Date: Mon, 2 Sep 2024 11:02:46 +1000
Subject: [PATCH 16/20] Define the Stripe API version we use in the JS Stripe
instance (#3392)
* Define the Stripe JS API version we use
* Add changelog entries
---------
Co-authored-by: Diego Curbelo
---
changelog.txt | 1 +
client/api/index.js | 5 ++++-
.../payment-methods/class-wc-stripe-upe-payment-gateway.php | 1 +
readme.txt | 1 +
4 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/changelog.txt b/changelog.txt
index 682373097..702a424ae 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -21,6 +21,7 @@
* Tweak - Update capabilities to payment methods mapping.
* Fix - Address QIT Security test errors.
* Fix - Address QIT PHPStan test errors.
+* Update - Specify the JS Stripe API version as 2024-06-20.
* Fix - Ensure payment tokens are detached from Stripe when a user is deleted, regardless of if the admin user has a Stripe account.
= 8.6.1 - 2024-08-09 =
diff --git a/client/api/index.js b/client/api/index.js
index f7817f0c6..3f837cc3d 100644
--- a/client/api/index.js
+++ b/client/api/index.js
@@ -78,7 +78,10 @@ export default class WCStripeAPI {
}
createStripe( key, locale, betas = [] ) {
- const options = { locale };
+ const options = {
+ locale,
+ apiVersion: this.options.apiVersion,
+ };
if ( betas.length ) {
options.betas = betas;
diff --git a/includes/payment-methods/class-wc-stripe-upe-payment-gateway.php b/includes/payment-methods/class-wc-stripe-upe-payment-gateway.php
index 46e0d4f0e..1be33b4bc 100644
--- a/includes/payment-methods/class-wc-stripe-upe-payment-gateway.php
+++ b/includes/payment-methods/class-wc-stripe-upe-payment-gateway.php
@@ -375,6 +375,7 @@ public function javascript_params() {
'isUPEEnabled' => true,
'key' => $this->publishable_key,
'locale' => WC_Stripe_Helper::convert_wc_locale_to_stripe_locale( get_locale() ),
+ 'apiVersion' => WC_Stripe_API::STRIPE_API_VERSION,
];
$enabled_billing_fields = [];
diff --git a/readme.txt b/readme.txt
index 529875e2d..232c6884b 100644
--- a/readme.txt
+++ b/readme.txt
@@ -149,6 +149,7 @@ If you get stuck, you can ask for help in the Plugin Forum.
* Tweak - Update capabilities to payment methods mapping.
* Fix - Address QIT Security test errors.
* Fix - Address QIT PHPStan test errors.
+* Update - Specify the JS Stripe API version as 2024-06-20.
* Fix - Ensure payment tokens are detached from Stripe when a user is deleted, regardless of if the admin user has a Stripe account.
[See changelog for all versions](https://raw.githubusercontent.com/woocommerce/woocommerce-gateway-stripe/trunk/changelog.txt).
From bf88cd5190126e46fe94328b5152fbc3d0c857e7 Mon Sep 17 00:00:00 2001
From: Anne Mirasol
Date: Tue, 3 Sep 2024 12:00:19 -0500
Subject: [PATCH 17/20] Support custom name and description for Afterpay
(#3399)
* Support custom name and description for Afterpay
* Add changelog and readme entries
* Add unit test
---
changelog.txt | 1 +
...e-upe-payment-method-afterpay-clearpay.php | 23 ++---------
readme.txt | 1 +
...est-class-wc-stripe-upe-payment-method.php | 38 +++++++++++++++++++
4 files changed, 44 insertions(+), 19 deletions(-)
diff --git a/changelog.txt b/changelog.txt
index 702a424ae..9388d340e 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,6 +1,7 @@
*** Changelog ***
= 8.7.0 - xxxx-xx-xx =
+* Fix - Support custom name and description for Afterpay.
* Fix - Link APM charge IDs in Order Details page to their Stripe dashboard payments page.
* Fix - Fix Indian subscription processing by forcing the recreation of mandates during switches (upgrading/downgrading).
* Fix - Add back support for Stripe Link autofill for shortcode checkout.
diff --git a/includes/payment-methods/class-wc-stripe-upe-payment-method-afterpay-clearpay.php b/includes/payment-methods/class-wc-stripe-upe-payment-method-afterpay-clearpay.php
index a398b7574..84bd30cc4 100644
--- a/includes/payment-methods/class-wc-stripe-upe-payment-method-afterpay-clearpay.php
+++ b/includes/payment-methods/class-wc-stripe-upe-payment-method-afterpay-clearpay.php
@@ -70,27 +70,12 @@ public function __construct() {
*/
public function get_title( $payment_details = false ) {
if ( $this->is_gb_country() ) {
- return __( 'Clearpay', 'woocommerce-gateway-stripe' );
+ $this->title = __( 'Clearpay', 'woocommerce-gateway-stripe' );
+ } else {
+ $this->title = __( 'Afterpay', 'woocommerce-gateway-stripe' );
}
- return __( 'Afterpay', 'woocommerce-gateway-stripe' );
- }
- /**
- * Return the gateway's description.
- *
- * @return string
- */
- public function get_description( $payment_details = false ) {
- if ( $this->is_gb_country() ) {
- return __(
- 'Allow customers to pay over time with Clearpay.',
- 'woocommerce-gateway-stripe'
- );
- }
- return __(
- 'Allow customers to pay over time with Afterpay.',
- 'woocommerce-gateway-stripe'
- );
+ return parent::get_title( $payment_details );
}
/**
diff --git a/readme.txt b/readme.txt
index 232c6884b..6636043a7 100644
--- a/readme.txt
+++ b/readme.txt
@@ -129,6 +129,7 @@ If you get stuck, you can ask for help in the Plugin Forum.
== Changelog ==
= 8.7.0 - xxxx-xx-xx =
+* Fix - Support custom name and description for Afterpay.
* Fix - Link APM charge IDs in Order Details page to their Stripe dashboard payments page.
* Fix - Fix Indian subscription processing by forcing the recreation of mandates during switches (upgrading/downgrading).
* Fix - Add back support for Stripe Link autofill for shortcode checkout.
diff --git a/tests/phpunit/test-class-wc-stripe-upe-payment-method.php b/tests/phpunit/test-class-wc-stripe-upe-payment-method.php
index 0b8fd5d34..1798ea850 100644
--- a/tests/phpunit/test-class-wc-stripe-upe-payment-method.php
+++ b/tests/phpunit/test-class-wc-stripe-upe-payment-method.php
@@ -615,6 +615,44 @@ public function test_payment_methods_are_reusable_if_cart_contains_subscription(
}
}
+ public function test_payment_methods_support_custom_name_and_description() {
+ $payment_method_ids = [
+ 'card',
+ 'klarna',
+ 'afterpay_clearpay',
+ 'affirm',
+ 'p24',
+ 'eps',
+ 'sepa_debit',
+ 'sofort',
+ 'bancontact',
+ 'ideal',
+ 'boleto',
+ 'multibanco',
+ 'oxxo',
+ 'wechat_pay',
+ ];
+
+ foreach ( $payment_method_ids as $payment_method_id ) {
+ $payment_method = $this->mock_payment_methods[ $payment_method_id ];
+
+ // Update the payment method settings to have a custom name and description.
+ $original_payment_settings = get_option( 'woocommerce_stripe_' . $payment_method_id . '_settings', [] );
+ $updated_payment_settings = $original_payment_settings;
+ $custom_name = 'Custom Name for ' . $payment_method_id;
+ $custom_description = 'Custom description for ' . $payment_method_id;
+ $updated_payment_settings['title'] = $custom_name;
+ $updated_payment_settings['description'] = $custom_description;
+ update_option( 'woocommerce_stripe_' . $payment_method_id . '_settings', $updated_payment_settings );
+
+ $this->assertEquals( $custom_name, $payment_method->get_title() );
+ $this->assertEquals( $custom_description, $payment_method->get_description() );
+
+ // Restore original settings.
+ update_option( 'woocommerce_stripe_' . $payment_method_id . '_settings', $original_payment_settings );
+ }
+ }
+
/**
* Test the type of payment token created for the user.
*/
From 849b8b57e1161c62ccd6c6fad4179e6423638002 Mon Sep 17 00:00:00 2001
From: Mayisha <33387139+Mayisha@users.noreply.github.com>
Date: Wed, 4 Sep 2024 12:59:59 +0600
Subject: [PATCH 18/20] Add 'get_supported_currencies' function for klarna
(#3378)
* add 'get_supported_currencies' function for klarna
* add comment
* add safety check
---
changelog.txt | 1 +
...ss-wc-stripe-upe-payment-method-klarna.php | 33 +++++++++++++++++++
readme.txt | 1 +
...est-class-wc-stripe-upe-payment-method.php | 14 ++++++++
4 files changed, 49 insertions(+)
diff --git a/changelog.txt b/changelog.txt
index 9388d340e..2daf997b7 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -24,6 +24,7 @@
* Fix - Address QIT PHPStan test errors.
* Update - Specify the JS Stripe API version as 2024-06-20.
* Fix - Ensure payment tokens are detached from Stripe when a user is deleted, regardless of if the admin user has a Stripe account.
+* Fix - Address Klarna availability based on correct presentment currency rules.
= 8.6.1 - 2024-08-09 =
* Tweak - Improves the wording of the invalid Stripe keys errors, instructing merchants to click the "Configure connection" button instead of manually setting the keys.
diff --git a/includes/payment-methods/class-wc-stripe-upe-payment-method-klarna.php b/includes/payment-methods/class-wc-stripe-upe-payment-method-klarna.php
index 85d1d94a2..248dfa0ec 100644
--- a/includes/payment-methods/class-wc-stripe-upe-payment-method-klarna.php
+++ b/includes/payment-methods/class-wc-stripe-upe-payment-method-klarna.php
@@ -82,6 +82,39 @@ public function get_available_billing_countries() {
return parent::get_available_billing_countries();
}
+ /**
+ * Returns the currencies this UPE method supports for the Stripe account.
+ *
+ * Klarna has unique requirements for domestic transactions. The customer must be located in the same country as the merchant's Stripe account and the currency must match.
+ * - Stores connected to US account and presenting USD can only transact with customers located in the US.
+ * - Stores connected to US account and presenting non-USD currency can not transact with customers irrespective of their location.
+ *
+ * Additionally, if the merchant is in the EEA, the country they can transact with depends on the presentment currency.
+ * EUR stores can transact with other EUR countries. Stores with currencies like GBP, CHF, etc. can only transact with customers located in those countries.
+ * This creates the following unique situations:
+ * - Stores presenting EUR, with a Stripe account in any EEA country including Switzerland or the UK can transact with countries where Euros are the standard currency: AT, BE, FI, FR, GR, DE, IE, IT, NL, PT, ES.
+ * - Stores presenting GBP with a Stripe account in any EEA country including Switzerland or the UK can transact with: GB.
+ * - Stores presenting NOK with a Stripe account in France, for example, cannot sell into France. They can only sell into Norway.
+ *
+ * @return array Supported currencies.
+ */
+ public function get_supported_currencies() {
+ $account = WC_Stripe::get_instance()->account->get_cached_account_data();
+ $account_country = strtoupper( $account['country'] ?? '' );
+
+ // Countries in the EEA + UK and Switzerland can transact across all other EEA countries as long as the currency matches.
+ $eea_countries = array_merge( WC_Stripe_Helper::get_european_economic_area_countries(), [ 'CH', 'GB' ] );
+
+ // Countries outside the EEA can only transact with customers in their own currency.
+ if ( ! in_array( $account_country, $eea_countries, true ) ) {
+ return [ strtoupper( $account['default_currency'] ?? '' ) ];
+ }
+
+ // Stripe account in EEA + UK and Switzerland can present the following as store currencies.
+ // EEA currencies can only transact with countries where that currency is the standard currency.
+ return [ 'CHF', 'CZK', 'DKK', 'EUR', 'GBP', 'NOK', 'PLN', 'SEK' ];
+ }
+
/**
* Returns whether the payment method is available for the Stripe account's country.
*
diff --git a/readme.txt b/readme.txt
index 6636043a7..be3d7273b 100644
--- a/readme.txt
+++ b/readme.txt
@@ -152,5 +152,6 @@ If you get stuck, you can ask for help in the Plugin Forum.
* Fix - Address QIT PHPStan test errors.
* Update - Specify the JS Stripe API version as 2024-06-20.
* Fix - Ensure payment tokens are detached from Stripe when a user is deleted, regardless of if the admin user has a Stripe account.
+* Fix - Address Klarna availability based on correct presentment currency rules.
[See changelog for all versions](https://raw.githubusercontent.com/woocommerce/woocommerce-gateway-stripe/trunk/changelog.txt).
diff --git a/tests/phpunit/test-class-wc-stripe-upe-payment-method.php b/tests/phpunit/test-class-wc-stripe-upe-payment-method.php
index 1798ea850..1fa49c7eb 100644
--- a/tests/phpunit/test-class-wc-stripe-upe-payment-method.php
+++ b/tests/phpunit/test-class-wc-stripe-upe-payment-method.php
@@ -525,6 +525,20 @@ public function test_payment_methods_with_domestic_restrictions_are_disabled_on_
*/
public function test_payment_methods_with_domestic_restrictions_are_enabled_on_currency_match() {
WC_Stripe_Helper::update_main_stripe_settings( [ 'testmode' => 'yes' ] );
+ WC_Stripe::get_instance()->account = $this->getMockBuilder( 'WC_Stripe_Account' )
+ ->disableOriginalConstructor()
+ ->setMethods(
+ [
+ 'get_cached_account_data',
+ ]
+ )
+ ->getMock();
+ WC_Stripe::get_instance()->account->method( 'get_cached_account_data' )->willReturn(
+ [
+ 'country' => 'US',
+ 'default_currency' => 'USD',
+ ]
+ );
$this->set_mock_payment_method_return_value( 'get_woocommerce_currency', 'USD', true );
From eb0810c8cd395b26ef25989dfcbb2bfeccf3b4dd Mon Sep 17 00:00:00 2001
From: Mayisha <33387139+Mayisha@users.noreply.github.com>
Date: Wed, 4 Sep 2024 13:24:37 +0600
Subject: [PATCH 19/20] Use custom order IDs in create intent request (#3398)
* use 'order_id' from 'get_order_number' in stripe intent metadata
---
changelog.txt | 1 +
.../payment-methods/class-wc-stripe-upe-payment-gateway.php | 2 +-
readme.txt | 1 +
3 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/changelog.txt b/changelog.txt
index 2daf997b7..9941fa871 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -23,6 +23,7 @@
* Fix - Address QIT Security test errors.
* Fix - Address QIT PHPStan test errors.
* Update - Specify the JS Stripe API version as 2024-06-20.
+* Tweak - Use order ID from 'get_order_number' in stripe intent metadata.
* Fix - Ensure payment tokens are detached from Stripe when a user is deleted, regardless of if the admin user has a Stripe account.
* Fix - Address Klarna availability based on correct presentment currency rules.
diff --git a/includes/payment-methods/class-wc-stripe-upe-payment-gateway.php b/includes/payment-methods/class-wc-stripe-upe-payment-gateway.php
index 1be33b4bc..130a8f450 100644
--- a/includes/payment-methods/class-wc-stripe-upe-payment-gateway.php
+++ b/includes/payment-methods/class-wc-stripe-upe-payment-gateway.php
@@ -1730,7 +1730,7 @@ public function get_metadata_from_order( $order ) {
'customer_name' => $name,
'customer_email' => $email,
'site_url' => esc_url( get_site_url() ),
- 'order_id' => $order->get_id(),
+ 'order_id' => $order->get_order_number(),
'order_key' => $order->get_order_key(),
'payment_type' => $payment_type,
];
diff --git a/readme.txt b/readme.txt
index be3d7273b..14a403e41 100644
--- a/readme.txt
+++ b/readme.txt
@@ -151,6 +151,7 @@ If you get stuck, you can ask for help in the Plugin Forum.
* Fix - Address QIT Security test errors.
* Fix - Address QIT PHPStan test errors.
* Update - Specify the JS Stripe API version as 2024-06-20.
+* Tweak - Use order ID from 'get_order_number' in stripe intent metadata.
* Fix - Ensure payment tokens are detached from Stripe when a user is deleted, regardless of if the admin user has a Stripe account.
* Fix - Address Klarna availability based on correct presentment currency rules.
From 9b93daea3bc11b53452ba496754ca1a5b92ed41d Mon Sep 17 00:00:00 2001
From: Alex Florisca
Date: Wed, 4 Sep 2024 16:40:40 +0100
Subject: [PATCH 20/20] Add title, description and gatewayId for express
payment methods (#3415)
* Add title, description and gatewayId for express payment methods
* Add missing domain from translation function
---
client/blocks/payment-request/index.js | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/client/blocks/payment-request/index.js b/client/blocks/payment-request/index.js
index a19c8552e..ad0c903bf 100644
--- a/client/blocks/payment-request/index.js
+++ b/client/blocks/payment-request/index.js
@@ -1,4 +1,5 @@
import { getSetting } from '@woocommerce/settings';
+import { __ } from '@wordpress/i18n';
import { PAYMENT_METHOD_NAME } from './constants';
import { PaymentRequestExpress } from './payment-request-express';
import { applePayImage } from './apple-pay-preview';
@@ -14,6 +15,12 @@ const componentStripePromise = loadStripe();
const paymentRequestPaymentMethod = {
name: PAYMENT_METHOD_NAME,
+ title: 'Stripe',
+ description: __(
+ 'This will show users the ApplePay, GooglePay, or Stripe Link button depending on their browser and logged in status.',
+ 'woocommerce-gateway-stripe'
+ ),
+ gatewayId: 'stripe',
content: ,
edit: ,
canMakePayment: ( cartData ) => {