-
-
- { createInterpolateElement(
- __(
- 'You must
capture this charge within the next',
- 'woocommerce-payments'
- ),
- {
- a: (
- // eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-no-target-blank
-
- ),
+
-
- { moment
- .utc( authorization.created )
- .add( 7, 'days' )
- .fromNow( true ) }
-
-
- { isFraudOutcomeReview &&
- `. ${ __(
- 'Approving this transaction will capture the charge.',
- 'woocommerce-payments'
- ) }` }
-
-
- { ! isFraudOutcomeReview && (
-
-
{
- wcpayTracks.recordEvent(
- 'payments_transactions_details_capture_charge_button_click',
- {
- payment_intent_id:
- charge.payment_intent,
- }
- );
- } }
+ buttonIsPrimary={ true }
+ buttonIsSmall={ false }
+ onClick={ () => {
+ wcpayTracks.recordEvent(
+ 'payments_transactions_details_capture_charge_button_click',
+ {
+ payment_intent_id:
+ charge.payment_intent,
+ }
+ );
+ } }
+ />
+ ) : (
+ <>>
+ )
+ }
+ >
+ { createInterpolateElement(
+ __(
+ 'You must capture this charge within the next',
+ 'woocommerce-payments'
+ ),
+ {
+ a: (
+ // eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-no-target-blank
+
-
+ ),
+ }
+ ) }{ ' ' }
+
-
+ >
+
+ { moment
+ .utc( authorization.created )
+ .add( 7, 'days' )
+ .fromNow( true ) }
+
+
+ { isFraudOutcomeReview &&
+ `. ${ __(
+ 'Approving this transaction will capture the charge.',
+ 'woocommerce-payments'
+ ) }` }
+
) }
diff --git a/client/payment-details/summary/test/__snapshots__/index.test.tsx.snap b/client/payment-details/summary/test/__snapshots__/index.test.tsx.snap
index 02f35f6c1db..30c5c237e49 100644
--- a/client/payment-details/summary/test/__snapshots__/index.test.tsx.snap
+++ b/client/payment-details/summary/test/__snapshots__/index.test.tsx.snap
@@ -244,15 +244,15 @@ exports[`PaymentDetailsSummary capture notification and fraud buttons renders ca
@@ -2238,11 +2238,11 @@ exports[`PaymentDetailsSummary renders partially refunded information for a char
>
Refunded:
- $-12.00
+ -$12.00
Fees:
- $-0.70
+ -$0.70
@@ -2502,7 +2502,7 @@ exports[`PaymentDetailsSummary renders the Tap to Pay channel from metadata 1`]
Fees:
- $-0.70
+ -$0.70
@@ -2762,7 +2762,7 @@ exports[`PaymentDetailsSummary renders the information of a dispute-reversal cha
Fees:
- $-0.70
+ -$0.70
diff --git a/client/payment-details/summary/test/index.test.tsx b/client/payment-details/summary/test/index.test.tsx
index 58de0645616..522c613d5ff 100755
--- a/client/payment-details/summary/test/index.test.tsx
+++ b/client/payment-details/summary/test/index.test.tsx
@@ -251,7 +251,7 @@ describe( 'PaymentDetailsSummary', () => {
} );
const container = renderCharge( charge );
- screen.getByText( /Refunded: \$-20.00/i );
+ screen.getByText( /Refunded: -\$20.00/i );
expect( container ).toMatchSnapshot();
} );
diff --git a/client/payment-details/timeline/test/__snapshots__/index.js.snap b/client/payment-details/timeline/test/__snapshots__/index.js.snap
index df78052123c..e4753b57f06 100644
--- a/client/payment-details/timeline/test/__snapshots__/index.js.snap
+++ b/client/payment-details/timeline/test/__snapshots__/index.js.snap
@@ -1494,7 +1494,7 @@ exports[`PaymentDetailsTimeline renders subscription fee correctly 1`] = `
>
- Fee (3.9% + $0.30): $-0.34
+ Fee (3.9% + $0.30): -$0.34
@@ -412,7 +412,7 @@ Array [
Variable fee: -4.9%
- Fixed fee: £-0.20
+ Fixed fee: -£0.20
@@ -455,7 +455,7 @@ Array [
Object {
"body": Array [
undefined,
- "Base fee (1.95% + $0.15): $-3.50",
+ "Base fee (1.95% + $0.15): -$3.50",
undefined,
"Net deposit: $59.50 USD",
],
@@ -695,7 +695,7 @@ Array [
Object {
"body": Array [
undefined,
- "Fee (2.6% + $0.20): $-0.61",
+ "Fee (2.6% + $0.20): -$0.61",
@@ -745,7 +745,7 @@ Array [
Object {
"body": Array [
undefined,
- "Fee (1.95% + $0.15): $-3.50",
+ "Fee (1.95% + $0.15): -$3.50",
undefined,
"Net deposit: $59.50 USD",
],
diff --git a/client/transactions/list/test/__snapshots__/index.tsx.snap b/client/transactions/list/test/__snapshots__/index.tsx.snap
index c7bfca77b45..3e5c77a9a7a 100644
--- a/client/transactions/list/test/__snapshots__/index.tsx.snap
+++ b/client/transactions/list/test/__snapshots__/index.tsx.snap
@@ -542,7 +542,7 @@ exports[`Transactions list renders correctly when can filter by several currenci
href="admin.php?page=wc-admin&path=%2Fpayments%2Ftransactions%2Fdetails&id=pi_mock&transaction_id=txn_j23jda9JJa&transaction_type=refund"
tabindex="-1"
>
- $-0.50
+ -$0.50
- $-0.50
+ -$0.50
- $-0.75
+ -$0.75
- $-0.50
+ -$0.50
- $-0.50
+ -$0.50
- $-0.75
+ -$0.75
- $-0.50
+ -$0.50
- $-0.50
+ -$0.50
- $-0.50
+ -$0.50
- $-0.75
+ -$0.75
- $-0.50
+ -$0.50
- $-0.50
+ -$0.50
- $-0.75
+ -$0.75
- $-0.50
+ -$0.50
- $-0.50
+ -$0.50
- $-0.75
+ -$0.75
= 0 ) {
- return $formatted;
- }
-
- // Handle the subtle display difference for the negative amount between PHP wc_price `-$0.74` vs JavaScript formatCurrency `$-0.74` for the same input.
- // Remove the minus sign, and then move it right before the number.
- $formatted = str_replace( '-', '', $formatted );
-
- return preg_replace( '/([0-9,\.]+)/', '-$1', $formatted );
+ return $formatted;
}
/**
diff --git a/tests/fixtures/captured-payments/discount.json b/tests/fixtures/captured-payments/discount.json
index 939a6b7bb8d..af1b0f8cf77 100644
--- a/tests/fixtures/captured-payments/discount.json
+++ b/tests/fixtures/captured-payments/discount.json
@@ -61,7 +61,7 @@
"discount": {
"label": "Discount",
"variable": "Variable fee: -4.9%",
- "fixed": "Fixed fee: $-0.30"
+ "fixed": "Fixed fee: -$0.30"
}
},
"netString": "Net deposit: $105.48 USD"
diff --git a/tests/fixtures/captured-payments/foreign-card.json b/tests/fixtures/captured-payments/foreign-card.json
index 8f5f7f214c6..9a121e3a7ed 100644
--- a/tests/fixtures/captured-payments/foreign-card.json
+++ b/tests/fixtures/captured-payments/foreign-card.json
@@ -49,7 +49,7 @@
},
"expectation": {
"fxString": "1.00 CAD → 0.774692 USD: $100.71 USD",
- "feeString": "Fee (4.9% + $0.30): $-5.24",
+ "feeString": "Fee (4.9% + $0.30): -$5.24",
"feeBreakdown": {
"base": "Base fee: 2.9% + $0.30",
"additional-international": "International card fee: 1%",
diff --git a/tests/fixtures/captured-payments/fx-decimal.json b/tests/fixtures/captured-payments/fx-decimal.json
index 0088ab63680..77a136924f8 100644
--- a/tests/fixtures/captured-payments/fx-decimal.json
+++ b/tests/fixtures/captured-payments/fx-decimal.json
@@ -42,7 +42,7 @@
},
"expectation": {
"fxString": "1.00 EUR → 1.0504 USD: $105.04 USD",
- "feeString": "Fee (3.9% + $0.30): $-4.39",
+ "feeString": "Fee (3.9% + $0.30): -$4.39",
"feeBreakdown": {
"base": "Base fee: 2.9% + $0.30",
"additional-fx": "Foreign exchange fee: 1%"
diff --git a/tests/fixtures/captured-payments/fx-foreign-card.json b/tests/fixtures/captured-payments/fx-foreign-card.json
index 7d9ea59e557..9b26ad48fc1 100644
--- a/tests/fixtures/captured-payments/fx-foreign-card.json
+++ b/tests/fixtures/captured-payments/fx-foreign-card.json
@@ -42,7 +42,7 @@
}
},
"expectation": {
- "feeString": "Fee (3.9% + $0.30): $-3.20",
+ "feeString": "Fee (3.9% + $0.30): -$3.20",
"feeBreakdown": {
"base": "Base fee: 2.9% + $0.30",
"additional-international": "International card fee: 1%"
diff --git a/tests/fixtures/captured-payments/fx-with-capped-fee.json b/tests/fixtures/captured-payments/fx-with-capped-fee.json
index 1eaecc3e9d7..23c3cbf1387 100644
--- a/tests/fixtures/captured-payments/fx-with-capped-fee.json
+++ b/tests/fixtures/captured-payments/fx-with-capped-fee.json
@@ -51,7 +51,7 @@
},
"expectation": {
"fxString": "1.00 EUR → 1.05483 USD: $1,002.09 USD",
- "feeString": "Fee (2.5% + $6.00): $-31.05",
+ "feeString": "Fee (2.5% + $6.00): -$31.05",
"feeBreakdown": {
"base": "Base fee: capped at $6.00",
"additional-international": "International card fee: 1.5%",
diff --git a/tests/fixtures/captured-payments/fx.json b/tests/fixtures/captured-payments/fx.json
index 9dfe492153b..166deab4a86 100644
--- a/tests/fixtures/captured-payments/fx.json
+++ b/tests/fixtures/captured-payments/fx.json
@@ -43,7 +43,7 @@
},
"expectation": {
"fxString": "1 VND → 0.000044 USD: $100.04 USD",
- "feeString": "Fee (3.9% + $0.30): $-4.20",
+ "feeString": "Fee (3.9% + $0.30): -$4.20",
"feeBreakdown": {
"base": "Base fee: 2.9% + $0.30",
"additional-fx": "Foreign exchange fee: 1%"
diff --git a/tests/fixtures/captured-payments/jpy-payment.json b/tests/fixtures/captured-payments/jpy-payment.json
index 50af38dd483..c5bc6eb7dd6 100644
--- a/tests/fixtures/captured-payments/jpy-payment.json
+++ b/tests/fixtures/captured-payments/jpy-payment.json
@@ -50,7 +50,7 @@
},
"expectation": {
"fxString": "1.00 EUR → 159.13333 JPY: ¥4,774 JPY",
- "feeString": "Fee (7.6% + ¥0): ¥-267",
+ "feeString": "Fee (7.6% + ¥0): -¥267",
"feeBreakdown": {
"base": "Base fee: 3.6%",
"additional-international": "International card fee: 2%",
diff --git a/tests/fixtures/captured-payments/only-base-fee.json b/tests/fixtures/captured-payments/only-base-fee.json
index 39a3dfccdd4..0385bd61c6f 100644
--- a/tests/fixtures/captured-payments/only-base-fee.json
+++ b/tests/fixtures/captured-payments/only-base-fee.json
@@ -34,7 +34,7 @@
}
},
"expectation": {
- "feeString": "Base fee (2.9% + $0.30): $-0.74",
+ "feeString": "Base fee (2.9% + $0.30): -$0.74",
"netString": "Net deposit: $14.26 USD"
}
}
diff --git a/tests/fixtures/captured-payments/subscription.json b/tests/fixtures/captured-payments/subscription.json
index 1ee34195c2a..a9a4d01eae4 100644
--- a/tests/fixtures/captured-payments/subscription.json
+++ b/tests/fixtures/captured-payments/subscription.json
@@ -50,7 +50,7 @@
},
"expectation": {
"fxString": "1.00 EUR → 1.05491 USD: $55.91 USD",
- "feeString": "Fee (4.9% + $0.30): $-3.04",
+ "feeString": "Fee (4.9% + $0.30): -$3.04",
"feeBreakdown": {
"base": "Base fee: 2.9% + $0.30",
"additional-fx": "Foreign exchange fee: 1%",
diff --git a/tests/unit/test-class-wc-payments-utils.php b/tests/unit/test-class-wc-payments-utils.php
index f9ed09117f6..0248b757f3b 100644
--- a/tests/unit/test-class-wc-payments-utils.php
+++ b/tests/unit/test-class-wc-payments-utils.php
@@ -518,7 +518,7 @@ public function test_format_currency( float $amount, string $currency, string $e
public function provider_format_currency(): array {
return [
'US dollar' => [ 123.456, 'USD', '$123.46' ],
- 'US dollar with negative amount' => [ -123.456, 'USD', '$-123.46' ],
+ 'US dollar with negative amount' => [ -123.456, 'USD', '-$123.46' ],
'Euro' => [ 12000, 'EUR', '12.000,00 €' ],
'CHF - no currency symbol' => [ 123, 'CHF', 'CHF 123.00' ],
'VND - decimal currency' => [ 123456, 'VND', '123.456 ₫' ],
From f1cabba6355e295727cffc74ba0d7f138ecc26e7 Mon Sep 17 00:00:00 2001
From: Timur Karimov
Date: Wed, 20 Dec 2023 20:47:57 +0100
Subject: [PATCH 40/56] Add empty file to avoid fatals (#7936)
Co-authored-by: Timur Karimov
Co-authored-by: Brett Shumaker
---
changelog/revert-file-needed-for-plugin-update | 5 +++++
.../class-wc-rest-upe-flag-toggle-controller.php | 16 ++++++++++++++++
2 files changed, 21 insertions(+)
create mode 100644 changelog/revert-file-needed-for-plugin-update
create mode 100644 includes/admin/class-wc-rest-upe-flag-toggle-controller.php
diff --git a/changelog/revert-file-needed-for-plugin-update b/changelog/revert-file-needed-for-plugin-update
new file mode 100644
index 00000000000..f4e5d1e3224
--- /dev/null
+++ b/changelog/revert-file-needed-for-plugin-update
@@ -0,0 +1,5 @@
+Significance: patch
+Type: dev
+Comment: This is the file revert to avoid failures on plugin update. This is a temporary solution. Both removal & revert happen on develop meaning there is no change to the outside world.
+
+
diff --git a/includes/admin/class-wc-rest-upe-flag-toggle-controller.php b/includes/admin/class-wc-rest-upe-flag-toggle-controller.php
new file mode 100644
index 00000000000..bc476de7731
--- /dev/null
+++ b/includes/admin/class-wc-rest-upe-flag-toggle-controller.php
@@ -0,0 +1,16 @@
+
Date: Thu, 21 Dec 2023 11:12:39 +1000
Subject: [PATCH 41/56] Updates WooPayments with the latest from Subscriptions
Core library (6.6.0) (#7934)
Co-authored-by: Matt Allan
---
changelog/subscriptions-6.6.0-1 | 4 ++++
changelog/subscriptions-6.6.0-2 | 4 ++++
changelog/subscriptions-core-6.6.0 | 4 ++++
changelog/subscriptions-core-6.6.0-3 | 4 ++++
changelog/subscriptions-core-6.6.0-4 | 4 ++++
changelog/subscriptions-core-6.6.0-5 | 4 ++++
changelog/subscriptions-core-6.6.0-6 | 4 ++++
changelog/subscriptions-core-6.6.0-7 | 4 ++++
changelog/subscriptions-core-6.6.0-8 | 4 ++++
composer.json | 2 +-
composer.lock | 16 ++++++++--------
11 files changed, 45 insertions(+), 9 deletions(-)
create mode 100644 changelog/subscriptions-6.6.0-1
create mode 100644 changelog/subscriptions-6.6.0-2
create mode 100644 changelog/subscriptions-core-6.6.0
create mode 100644 changelog/subscriptions-core-6.6.0-3
create mode 100644 changelog/subscriptions-core-6.6.0-4
create mode 100644 changelog/subscriptions-core-6.6.0-5
create mode 100644 changelog/subscriptions-core-6.6.0-6
create mode 100644 changelog/subscriptions-core-6.6.0-7
create mode 100644 changelog/subscriptions-core-6.6.0-8
diff --git a/changelog/subscriptions-6.6.0-1 b/changelog/subscriptions-6.6.0-1
new file mode 100644
index 00000000000..9c70ea3d4ce
--- /dev/null
+++ b/changelog/subscriptions-6.6.0-1
@@ -0,0 +1,4 @@
+Significance: minor
+Type: dev
+
+Deprecate the WC_Subscriptions_Synchroniser::add_to_recurring_cart_key(). Use WC_Subscriptions_Synchroniser::add_to_recurring_product_grouping_key() instead.
diff --git a/changelog/subscriptions-6.6.0-2 b/changelog/subscriptions-6.6.0-2
new file mode 100644
index 00000000000..98a24e2a8d8
--- /dev/null
+++ b/changelog/subscriptions-6.6.0-2
@@ -0,0 +1,4 @@
+Significance: minor
+Type: dev
+
+Introduce a new wcs_get_subscription_grouping_key() function to generate a unique key for a subscription based on its billing schedule. This function uses the existing recurring cart key concept.
diff --git a/changelog/subscriptions-core-6.6.0 b/changelog/subscriptions-core-6.6.0
new file mode 100644
index 00000000000..192de7697f3
--- /dev/null
+++ b/changelog/subscriptions-core-6.6.0
@@ -0,0 +1,4 @@
+Significance: minor
+Type: dev
+
+Updated subscriptions-core to version 6.6.0
diff --git a/changelog/subscriptions-core-6.6.0-3 b/changelog/subscriptions-core-6.6.0-3
new file mode 100644
index 00000000000..39e3728713e
--- /dev/null
+++ b/changelog/subscriptions-core-6.6.0-3
@@ -0,0 +1,4 @@
+Significance: minor
+Type: fix
+
+Fetch and update the `_cancelled_email_sent` meta in a HPOS compatibile way.
diff --git a/changelog/subscriptions-core-6.6.0-4 b/changelog/subscriptions-core-6.6.0-4
new file mode 100644
index 00000000000..adf5488ac54
--- /dev/null
+++ b/changelog/subscriptions-core-6.6.0-4
@@ -0,0 +1,4 @@
+Significance: minor
+Type: fix
+
+Ensure proper backfilling of subscription metadata (i.e. dates and cache) to the postmeta table when HPOS is enabled and compatibility mode (data syncing) is turned on.
diff --git a/changelog/subscriptions-core-6.6.0-5 b/changelog/subscriptions-core-6.6.0-5
new file mode 100644
index 00000000000..fc15acdb576
--- /dev/null
+++ b/changelog/subscriptions-core-6.6.0-5
@@ -0,0 +1,4 @@
+Significance: minor
+Type: fix
+
+Resolved an issue that would cause undefined $current_page, $max_num_pages, and $paginate variable errors when viewing a page with the subscriptions-shortcode.
diff --git a/changelog/subscriptions-core-6.6.0-6 b/changelog/subscriptions-core-6.6.0-6
new file mode 100644
index 00000000000..df965094736
--- /dev/null
+++ b/changelog/subscriptions-core-6.6.0-6
@@ -0,0 +1,4 @@
+Significance: minor
+Type: fix
+
+When HPOS is enabled and data compatibility mode is turned on, make sure subscription date changes made to postmeta are synced to orders_meta table.
diff --git a/changelog/subscriptions-core-6.6.0-7 b/changelog/subscriptions-core-6.6.0-7
new file mode 100644
index 00000000000..96c2cae1f2c
--- /dev/null
+++ b/changelog/subscriptions-core-6.6.0-7
@@ -0,0 +1,4 @@
+Significance: minor
+Type: fix
+
+Prevents a PHP fatal error that occurs when the cart contains a renewal order item that no longer exists.
diff --git a/changelog/subscriptions-core-6.6.0-8 b/changelog/subscriptions-core-6.6.0-8
new file mode 100644
index 00000000000..a2ffa0feb0c
--- /dev/null
+++ b/changelog/subscriptions-core-6.6.0-8
@@ -0,0 +1,4 @@
+Significance: minor
+Type: fix
+
+When using the checkout block to pay for renewal orders, ensure the order's cart hash is updated to make sure the existing order can be used.
diff --git a/composer.json b/composer.json
index 01444821e33..0b2890b6228 100644
--- a/composer.json
+++ b/composer.json
@@ -27,7 +27,7 @@
"automattic/jetpack-autoloader": "2.11.18",
"automattic/jetpack-identity-crisis": "0.8.43",
"automattic/jetpack-sync": "1.47.7",
- "woocommerce/subscriptions-core": "6.4.0"
+ "woocommerce/subscriptions-core": "6.6.0"
},
"require-dev": {
"composer/installers": "1.10.0",
diff --git a/composer.lock b/composer.lock
index 54c7ccceb4e..686f8f9aa92 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "9dfc107cbaa90afb69bed66432c8cf70",
+ "content-hash": "2f207d4579d3db832302089bb6f3a11f",
"packages": [
{
"name": "automattic/jetpack-a8c-mc-stats",
@@ -940,16 +940,16 @@
},
{
"name": "woocommerce/subscriptions-core",
- "version": "6.4.0",
+ "version": "6.6.0",
"source": {
"type": "git",
"url": "https://github.com/Automattic/woocommerce-subscriptions-core.git",
- "reference": "a94c9aab6d47f32461974ed09a4d3cad590f25b0"
+ "reference": "5abcf9aac4e53ad9bdcf3752a34a04ae42261bac"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Automattic/woocommerce-subscriptions-core/zipball/a94c9aab6d47f32461974ed09a4d3cad590f25b0",
- "reference": "a94c9aab6d47f32461974ed09a4d3cad590f25b0",
+ "url": "https://api.github.com/repos/Automattic/woocommerce-subscriptions-core/zipball/5abcf9aac4e53ad9bdcf3752a34a04ae42261bac",
+ "reference": "5abcf9aac4e53ad9bdcf3752a34a04ae42261bac",
"shasum": ""
},
"require": {
@@ -960,7 +960,7 @@
"dave-liddament/sarb": "^1.1",
"phpunit/phpunit": "9.5.14",
"woocommerce/woocommerce-sniffs": "0.1.0",
- "yoast/phpunit-polyfills": "1.0.3"
+ "yoast/phpunit-polyfills": "1.1.0"
},
"type": "wordpress-plugin",
"extra": {
@@ -990,10 +990,10 @@
"description": "Sell products and services with recurring payments in your WooCommerce Store.",
"homepage": "https://github.com/Automattic/woocommerce-subscriptions-core",
"support": {
- "source": "https://github.com/Automattic/woocommerce-subscriptions-core/tree/6.4.0",
+ "source": "https://github.com/Automattic/woocommerce-subscriptions-core/tree/6.6.0",
"issues": "https://github.com/Automattic/woocommerce-subscriptions-core/issues"
},
- "time": "2023-10-18T03:32:50+00:00"
+ "time": "2023-12-20T07:19:09+00:00"
}
],
"packages-dev": [
From f73f0df93f336101ffe995ec47849c0a8a60b589 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?K=C4=81rlis=20Janisels?=
Date: Thu, 21 Dec 2023 09:09:35 +0200
Subject: [PATCH 42/56] Refund transaction from details page (#7742)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Kārlis Janisels
Co-authored-by: Vladimir Reznichenko
Co-authored-by: Miguel Gasca
---
...-7248-refund-transaction-from-details-page | 4 +
client/data/payment-intents/actions.ts | 63 +++++
client/data/payment-intents/hooks.ts | 20 +-
client/data/payment-intents/test/hooks.ts | 13 ++
.../test/__snapshots__/index.test.tsx.snap | 3 +
client/payment-details/summary/index.tsx | 116 +++++++++-
.../summary/missing-order-notice/index.tsx | 136 +++--------
.../test/__snapshots__/index.test.tsx.snap | 34 +++
.../missing-order-notice/test/index.test.tsx | 39 ++++
.../summary/refund-modal/index.tsx | 127 ++++++++++
.../test/__snapshots__/index.test.tsx.snap | 7 +
.../summary/refund-modal/test/index.test.tsx | 92 ++++++++
client/payment-details/summary/style.scss | 10 +
.../test/__snapshots__/index.test.tsx.snap | 218 +++++++++++++++++-
.../test/__snapshots__/index.test.tsx.snap | 74 ++++++
client/payment-details/types.ts | 1 +
client/settings/wcpay-settings-context.js | 1 -
...ss-wc-rest-payments-refunds-controller.php | 80 +++++++
includes/class-wc-payment-gateway-wcpay.php | 4 +
includes/class-wc-payments.php | 4 +
.../server/request/class-refund-charge.php | 27 +++
...ss-wc-rest-payments-refunds-controller.php | 73 ++++++
tests/unit/bootstrap.php | 1 +
23 files changed, 1023 insertions(+), 124 deletions(-)
create mode 100644 changelog/add-7248-refund-transaction-from-details-page
create mode 100644 client/payment-details/summary/missing-order-notice/test/__snapshots__/index.test.tsx.snap
create mode 100644 client/payment-details/summary/missing-order-notice/test/index.test.tsx
create mode 100644 client/payment-details/summary/refund-modal/index.tsx
create mode 100644 client/payment-details/summary/refund-modal/test/__snapshots__/index.test.tsx.snap
create mode 100644 client/payment-details/summary/refund-modal/test/index.test.tsx
create mode 100644 includes/admin/class-wc-rest-payments-refunds-controller.php
create mode 100644 tests/unit/admin/test-class-wc-rest-payments-refunds-controller.php
diff --git a/changelog/add-7248-refund-transaction-from-details-page b/changelog/add-7248-refund-transaction-from-details-page
new file mode 100644
index 00000000000..bfd753860e8
--- /dev/null
+++ b/changelog/add-7248-refund-transaction-from-details-page
@@ -0,0 +1,4 @@
+Significance: minor
+Type: add
+
+Add refund controls to transaction details view
diff --git a/client/data/payment-intents/actions.ts b/client/data/payment-intents/actions.ts
index ea74c5036bb..ceae8ef6efa 100644
--- a/client/data/payment-intents/actions.ts
+++ b/client/data/payment-intents/actions.ts
@@ -1,5 +1,12 @@
/** @format */
+/**
+ * External dependencies
+ */
+import { apiFetch } from '@wordpress/data-controls';
+import { controls } from '@wordpress/data';
+import { __, sprintf } from '@wordpress/i18n';
+
/**
* Internal Dependencies
*/
@@ -10,6 +17,8 @@ import {
UpdateErrorForPaymentIntentAction,
UpdatePaymentIntentAction,
} from './types';
+import { Charge } from 'wcpay/types/charges';
+import { STORE_NAME } from 'wcpay/data/constants';
export function updatePaymentIntent(
id: string,
@@ -32,3 +41,57 @@ export function updateErrorForPaymentIntent(
error,
};
}
+
+export function* refundCharge(
+ charge: Charge,
+ reason: string | null
+): Generator {
+ const paymentIntentId = charge.payment_intent;
+ try {
+ yield apiFetch( {
+ path: `/wc/v3/payments/refund/`,
+ method: 'post',
+ data: {
+ charge_id: charge.id,
+ amount: charge.amount,
+ reason: reason,
+ order_id: charge?.order?.number,
+ },
+ } );
+
+ yield controls.dispatch(
+ STORE_NAME,
+ 'invalidateResolutionForStoreSelector',
+ 'getTimeline'
+ );
+
+ yield controls.dispatch(
+ STORE_NAME,
+ 'invalidateResolutionForStoreSelector',
+ 'getPaymentIntent'
+ );
+
+ yield controls.dispatch(
+ 'core/notices',
+ 'createSuccessNotice',
+ sprintf(
+ // translators: %s payment intent id
+ __( 'Refunded payment #%s.', 'woocommerce-payments' ),
+ paymentIntentId
+ )
+ );
+ } catch ( error ) {
+ yield controls.dispatch(
+ 'core/notices',
+ 'createErrorNotice',
+ sprintf(
+ // translators: %s payment intent id
+ __(
+ 'There has been an error refunding the payment #%s. Please try again later.',
+ 'woocommerce-payments'
+ ),
+ paymentIntentId
+ )
+ );
+ }
+}
diff --git a/client/data/payment-intents/hooks.ts b/client/data/payment-intents/hooks.ts
index 61f51442fd1..330365219ad 100644
--- a/client/data/payment-intents/hooks.ts
+++ b/client/data/payment-intents/hooks.ts
@@ -2,19 +2,20 @@
/**
* External dependencies
*/
-import { useSelect } from '@wordpress/data';
+import { useDispatch, useSelect } from '@wordpress/data';
import { PaymentIntent } from '../../types/payment-intents';
import { getChargeData } from '../charges';
import { PaymentChargeDetailsResponse } from '../../payment-details/types';
import { STORE_NAME } from '../constants';
+import { Charge } from 'wcpay/types/charges';
export const getIsChargeId = ( id: string ): boolean =>
-1 !== id.indexOf( 'ch_' ) || -1 !== id.indexOf( 'py_' );
export const usePaymentIntentWithChargeFallback = (
id: string
-): PaymentChargeDetailsResponse =>
- useSelect(
+): PaymentChargeDetailsResponse => {
+ const { data, error, isLoading } = useSelect(
( select ) => {
const selectors = select( STORE_NAME );
const isChargeId = getIsChargeId( id );
@@ -52,3 +53,16 @@ export const usePaymentIntentWithChargeFallback = (
},
[ id ]
);
+
+ const { refundCharge } = useDispatch( STORE_NAME );
+
+ const doRefund = ( charge: Charge, reason: string | null ) =>
+ refundCharge( charge, reason );
+
+ return {
+ data,
+ error,
+ isLoading,
+ doRefund,
+ };
+};
diff --git a/client/data/payment-intents/test/hooks.ts b/client/data/payment-intents/test/hooks.ts
index 370816ac23a..e2631e291f2 100644
--- a/client/data/payment-intents/test/hooks.ts
+++ b/client/data/payment-intents/test/hooks.ts
@@ -110,6 +110,16 @@ describe( 'Payment Intent hooks', () => {
( useSelect as jest.Mock ).mockImplementation(
( cb: ( callback: any ) => jest.Mock ) => cb( selectMock )
);
+
+ jest.spyOn(
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
+ require( '@wordpress/data' ),
+ 'useDispatch'
+ ).mockReturnValue( () => {
+ return {
+ refundCharge: jest.fn(), // Mock the refundCharge function
+ };
+ } );
} );
describe( 'usePaymentIntentWithChargeFallback', () => {
@@ -133,6 +143,7 @@ describe( 'Payment Intent hooks', () => {
expect( result ).toEqual( {
data: paymentIntentMock.charge,
+ doRefund: expect.any( Function ),
error: {},
isLoading: false,
} );
@@ -158,6 +169,7 @@ describe( 'Payment Intent hooks', () => {
expect( result ).toEqual( {
data: paymentIntentMock,
+ doRefund: expect.any( Function ),
error: {},
isLoading: false,
} );
@@ -181,6 +193,7 @@ describe( 'Payment Intent hooks', () => {
expect( result ).toEqual( {
data: {},
+ doRefund: expect.any( Function ),
error: {},
isLoading: true,
} );
diff --git a/client/payment-details/order-details/test/__snapshots__/index.test.tsx.snap b/client/payment-details/order-details/test/__snapshots__/index.test.tsx.snap
index d02d14d3476..f28176053a7 100644
--- a/client/payment-details/order-details/test/__snapshots__/index.test.tsx.snap
+++ b/client/payment-details/order-details/test/__snapshots__/index.test.tsx.snap
@@ -66,6 +66,9 @@ exports[`Order details page should match the snapshot - Charge without payment i
+
= ( {
charge.currency && balance.currency !== charge.currency;
const {
- featureFlags: { isAuthAndCaptureEnabled, isRefundControlsEnabled },
+ featureFlags: { isAuthAndCaptureEnabled },
} = useContext( WCPaySettingsContext );
// We should only fetch the authorization data if the payment is marked for manual capture and it is not already captured.
@@ -225,6 +239,7 @@ const PaymentDetailsSummary: React.FC< PaymentDetailsSummaryProps > = ( {
balance.currency
);
+ const [ isRefundModalOpen, setIsRefundModalOpen ] = useState( false );
return (
@@ -464,6 +479,71 @@ const PaymentDetailsSummary: React.FC< PaymentDetailsSummaryProps > = ( {
+
+ { ! charge?.refunded && charge?.captured && (
+
+
+ { ( { onClose } ) => (
+
+ {
+ setIsRefundModalOpen( true );
+ wcpayTracks.recordEvent(
+ 'payments_transactions_details_refund_modal_open',
+ {
+ payment_intent_id:
+ charge.payment_intent,
+ }
+ );
+ onClose();
+ } }
+ >
+ { __(
+ 'Refund in full',
+ 'woocommerce-payments'
+ ) }
+
+ { charge.order && (
+ {
+ wcpayTracks.recordEvent(
+ 'payments_transactions_details_partial_refund',
+ {
+ payment_intent_id:
+ charge.payment_intent,
+ order_id:
+ charge.order
+ ?.number,
+ }
+ );
+ window.location =
+ charge.order?.url;
+ } }
+ >
+ { __(
+ 'Partial refund',
+ 'woocommerce-payments'
+ ) }
+
+ ) }
+
+ ) }
+
+
+ ) }
+
@@ -491,14 +571,28 @@ const PaymentDetailsSummary: React.FC< PaymentDetailsSummaryProps > = ( {
) }
) }
- { isRefundControlsEnabled &&
- ! _.isEmpty( charge ) &&
- ! charge.order && (
-
- ) }
+ { isRefundModalOpen && (
+ {
+ setIsRefundModalOpen( false );
+ wcpayTracks.recordEvent(
+ 'payments_transactions_details_refund_modal_close',
+ {
+ payment_intent_id: charge.payment_intent,
+ }
+ );
+ } }
+ />
+ ) }
+ { ! _.isEmpty( charge ) && ! charge.order && ! isLoading && (
+ setIsRefundModalOpen( true ) }
+ />
+ ) }
{ isAuthAndCaptureEnabled &&
authorization &&
! authorization.captured && (
diff --git a/client/payment-details/summary/missing-order-notice/index.tsx b/client/payment-details/summary/missing-order-notice/index.tsx
index 69d7f008760..7b05331ee4c 100644
--- a/client/payment-details/summary/missing-order-notice/index.tsx
+++ b/client/payment-details/summary/missing-order-notice/index.tsx
@@ -5,10 +5,8 @@
*/
import React from 'react';
-import { Button, RadioControl } from '@wordpress/components';
-import { __, sprintf } from '@wordpress/i18n';
-import { useState } from '@wordpress/element';
-import interpolateComponents from '@automattic/interpolate-components';
+import { Button } from '@wordpress/components';
+import { __ } from '@wordpress/i18n';
/**
* Internal dependencies.
@@ -16,131 +14,53 @@ import interpolateComponents from '@automattic/interpolate-components';
import './style.scss';
import CardNotice from 'wcpay/components/card-notice';
-import ConfirmationModal from 'wcpay/components/confirmation-modal';
import Loadable from 'wcpay/components/loadable';
+import { Charge } from 'wcpay/types/charges';
interface MissingOrderNoticeProps {
+ charge: Charge;
isLoading: boolean;
- formattedAmount: string;
+ onButtonClick: () => void;
}
const MissingOrderNotice: React.FC< MissingOrderNoticeProps > = ( {
+ charge,
isLoading,
- formattedAmount,
+ onButtonClick,
} ) => {
- const [ isModalOpen, setIsModalOpen ] = useState( false );
-
- const [ reason, setReason ] = useState< string | null >( null );
-
- const handleOnButtonClick = () => {
- setIsModalOpen( true );
- };
-
- const handleModalCancel = () => {
- setIsModalOpen( false );
- };
-
- const handleModalConfirmation = () => {
- // TODO: Handle the refund.
- };
-
return (
<>
- { __( 'Refund', 'woocommerce-payments' ) }
-
+ ! charge.refunded ? (
+
+ { __( 'Refund', 'woocommerce-payments' ) }
+
+ ) : (
+ <>>
+ )
}
>
{ __(
- 'This transaction is not connected to order. Investigate this purchase and refund the transaction as needed.',
+ 'This transaction is not connected to order. ',
'woocommerce-payments'
) }
+ { charge.refunded
+ ? __(
+ 'It has been refunded and is not a subject for disputes.',
+ 'woocommerce-payments'
+ )
+ : __(
+ 'Investigate this purchase and refund the transaction as needed.',
+ 'woocommerce-payments'
+ ) }
- { isModalOpen && (
-
-
- { __( 'Cancel', 'woocommerce-payments' ) }
-
-
- { __(
- 'Refund transaction',
- 'woocommerce-payments'
- ) }
-
- >
- }
- onRequestClose={ handleModalCancel }
- >
-
- { interpolateComponents( {
- mixedString: sprintf(
- __(
- 'This will issue a full refund of {{strong}}%s{{/strong}} to the customer.',
- 'woocommerce-payments'
- ),
- formattedAmount
- ),
- components: {
- strong: ,
- },
- } ) }
-
- setReason( value ) }
- />
-
- ) }
>
);
};
diff --git a/client/payment-details/summary/missing-order-notice/test/__snapshots__/index.test.tsx.snap b/client/payment-details/summary/missing-order-notice/test/__snapshots__/index.test.tsx.snap
new file mode 100644
index 00000000000..64cd813ebc2
--- /dev/null
+++ b/client/payment-details/summary/missing-order-notice/test/__snapshots__/index.test.tsx.snap
@@ -0,0 +1,34 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`MissingOrderNotice it renders correctly 1`] = `
+
+
+
+`;
+
+exports[`MissingOrderNotice renders loading state 1`] = `
+
+
+
+`;
diff --git a/client/payment-details/summary/missing-order-notice/test/index.test.tsx b/client/payment-details/summary/missing-order-notice/test/index.test.tsx
new file mode 100644
index 00000000000..97758906fdc
--- /dev/null
+++ b/client/payment-details/summary/missing-order-notice/test/index.test.tsx
@@ -0,0 +1,39 @@
+/** @format */
+
+/**
+ * External dependencies
+ */
+import React from 'react';
+import { render } from '@testing-library/react';
+import { chargeMock } from 'wcpay/data/payment-intents/test/hooks';
+
+/**
+ * Internal dependencies
+ */
+import MissingOrderNotice from '..';
+import { Charge } from 'wcpay/types/charges';
+
+describe( 'MissingOrderNotice', () => {
+ test( 'it renders correctly', () => {
+ const { container: notice } = render(
+
+ );
+
+ expect( notice ).toMatchSnapshot();
+ } );
+
+ test( 'renders loading state', () => {
+ const { container: notice } = render(
+
+ );
+ expect( notice ).toMatchSnapshot();
+ } );
+} );
diff --git a/client/payment-details/summary/refund-modal/index.tsx b/client/payment-details/summary/refund-modal/index.tsx
new file mode 100644
index 00000000000..0127e379210
--- /dev/null
+++ b/client/payment-details/summary/refund-modal/index.tsx
@@ -0,0 +1,127 @@
+/** @format **/
+
+/**
+ * External dependencies
+ */
+
+import React from 'react';
+import { Button, RadioControl } from '@wordpress/components';
+import { __, sprintf } from '@wordpress/i18n';
+import { useState } from '@wordpress/element';
+import interpolateComponents from '@automattic/interpolate-components';
+
+/**
+ * Internal dependencies.
+ */
+
+import ConfirmationModal from 'wcpay/components/confirmation-modal';
+import { Charge } from 'wcpay/types/charges';
+import { usePaymentIntentWithChargeFallback } from 'wcpay/data';
+import { PaymentChargeDetailsResponse } from 'wcpay/payment-details/types';
+import wcpayTracks from 'tracks';
+
+interface RefundModalProps {
+ charge: Charge;
+ formattedAmount: string;
+ onModalClose: () => void;
+}
+
+const RefundModal: React.FC< RefundModalProps > = ( {
+ charge,
+ formattedAmount,
+ onModalClose,
+} ) => {
+ const [ reason, setReason ] = useState< string | null >( null );
+
+ const [ isRefundInProgress, setIsRefundInProgress ] = useState< boolean >(
+ false
+ );
+
+ const { doRefund } = usePaymentIntentWithChargeFallback(
+ charge.payment_intent as string
+ ) as PaymentChargeDetailsResponse;
+
+ const handleModalCancel = () => {
+ onModalClose();
+ };
+
+ const handleRefund = async () => {
+ wcpayTracks.recordEvent( 'payments_transactions_details_refund_full', {
+ payment_intent_id: charge.payment_intent,
+ } );
+ setIsRefundInProgress( true );
+ await doRefund( charge, reason === 'other' ? null : reason );
+ setIsRefundInProgress( false );
+ handleModalCancel();
+ };
+
+ return (
+
+
+ { __( 'Cancel', 'woocommerce-payments' ) }
+
+
+ { __( 'Refund transaction', 'woocommerce-payments' ) }
+
+ >
+ }
+ onRequestClose={ handleModalCancel }
+ >
+
+ { interpolateComponents( {
+ mixedString: sprintf(
+ __(
+ 'This will issue a full refund of {{strong}}%s{{/strong}} to the customer.',
+ 'woocommerce-payments'
+ ),
+ formattedAmount
+ ),
+ components: {
+ strong: ,
+ },
+ } ) }
+
+ setReason( value ) }
+ />
+
+ );
+};
+
+export default RefundModal;
diff --git a/client/payment-details/summary/refund-modal/test/__snapshots__/index.test.tsx.snap b/client/payment-details/summary/refund-modal/test/__snapshots__/index.test.tsx.snap
new file mode 100644
index 00000000000..251b5f8438f
--- /dev/null
+++ b/client/payment-details/summary/refund-modal/test/__snapshots__/index.test.tsx.snap
@@ -0,0 +1,7 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`RefundModal it renders correctly 1`] = `
+
+`;
diff --git a/client/payment-details/summary/refund-modal/test/index.test.tsx b/client/payment-details/summary/refund-modal/test/index.test.tsx
new file mode 100644
index 00000000000..fdd41eb1adb
--- /dev/null
+++ b/client/payment-details/summary/refund-modal/test/index.test.tsx
@@ -0,0 +1,92 @@
+/** @format */
+
+/**
+ * External dependencies
+ */
+import React from 'react';
+import { render } from '@testing-library/react';
+
+/**
+ * Internal dependencies
+ */
+import { Charge } from 'wcpay/types/charges';
+import RefundModal from '..';
+import { usePaymentIntentWithChargeFallback } from 'wcpay/data';
+import { ApiError } from 'wcpay/types/errors';
+
+jest.mock( 'wcpay/data', () => ( {
+ usePaymentIntentWithChargeFallback: jest.fn(),
+} ) );
+
+const mockUsePaymentIntentWithChargeFallback = usePaymentIntentWithChargeFallback as jest.MockedFunction<
+ typeof usePaymentIntentWithChargeFallback
+>;
+
+describe( 'RefundModal', () => {
+ test( 'it renders correctly', () => {
+ const charge: any = {
+ id: '776',
+ amount: 1500,
+ amount_captured: 0,
+ amount_refunded: 0,
+ application_fee_amount: 0,
+ balance_transaction: { currency: 'USD', amount: 1500, fee: 0 },
+ billing_details: {
+ address: {
+ city: 'San Francisco',
+ country: 'US',
+ line1: '60 29th street',
+ line2: '',
+ postal_code: '91140',
+ state: 'CA',
+ },
+ email: 'admin_test_example@email.com',
+ name: 'First Last',
+ phone: '20000000000',
+ formatted_address: '60 29th street San Francisco, CA 91140',
+ },
+ created: 1679922581,
+ currency: 'USD',
+ disputed: false,
+ outcome: null,
+ order: {
+ number: 776,
+ url: 'http://wcpay.test/wp-admin/post.php?post=776&action=edit',
+ customer_url:
+ 'admin.php?page=wc-admin&path=/customers&filter=single_customer&customers=55',
+ customer_name: '',
+ customer_email: '',
+ subscriptions: [],
+ fraud_meta_box_type: 'succeeded',
+ },
+ paid: false,
+ paydown: null,
+ payment_method: '',
+ payment_intent: null,
+ payment_method_details: {
+ card: { country: 'US', checks: [], network: '' },
+ type: 'card' as any,
+ },
+ refunded: false,
+ refunds: null,
+ status: 'pending',
+ };
+
+ mockUsePaymentIntentWithChargeFallback.mockReturnValue( {
+ doRefund: jest.fn(),
+ data: charge,
+ error: {} as ApiError,
+ isLoading: false,
+ } );
+
+ const { container: modal } = render(
+
+ );
+
+ expect( modal ).toMatchSnapshot();
+ } );
+} );
diff --git a/client/payment-details/summary/style.scss b/client/payment-details/summary/style.scss
index 42e5c91e368..95df0d33edd 100755
--- a/client/payment-details/summary/style.scss
+++ b/client/payment-details/summary/style.scss
@@ -8,8 +8,14 @@
margin-bottom: 24px;
}
+.components-card__body:first-of-type {
+ display: flex;
+ flex-direction: row;
+}
+
.payment-details-summary {
display: flex;
+ flex: 1;
@include breakpoint( '<660px' ) {
flex-direction: column;
}
@@ -93,3 +99,7 @@
.woocommerce-list--horizontal {
margin-top: 0 !important;
}
+
+.payment-details__refund-controls {
+ flex: 0 0 auto;
+}
diff --git a/client/payment-details/summary/test/__snapshots__/index.test.tsx.snap b/client/payment-details/summary/test/__snapshots__/index.test.tsx.snap
index e9a596d35d5..b719e25c342 100644
--- a/client/payment-details/summary/test/__snapshots__/index.test.tsx.snap
+++ b/client/payment-details/summary/test/__snapshots__/index.test.tsx.snap
@@ -62,6 +62,9 @@ exports[`PaymentDetailsSummary capture notification and fraud buttons renders ca
+
+
+
+
+
+
+
+
+
+
+
- This transaction is not connected to order. Investigate this purchase and refund the transaction as needed.
+ This transaction is not connected to order.
+ Investigate this purchase and refund the transaction as needed.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
void;
}
export interface PaymentDetailsProps {
diff --git a/client/settings/wcpay-settings-context.js b/client/settings/wcpay-settings-context.js
index 60508988dc9..531e806ff27 100644
--- a/client/settings/wcpay-settings-context.js
+++ b/client/settings/wcpay-settings-context.js
@@ -11,7 +11,6 @@ const WCPaySettingsContext = createContext( {
isAuthAndCaptureEnabled: false,
isDisputeIssuerEvidenceEnabled: false,
woopay: false,
- isRefundControlsEnabled: false,
},
} );
diff --git a/includes/admin/class-wc-rest-payments-refunds-controller.php b/includes/admin/class-wc-rest-payments-refunds-controller.php
new file mode 100644
index 00000000000..26d3c14c670
--- /dev/null
+++ b/includes/admin/class-wc-rest-payments-refunds-controller.php
@@ -0,0 +1,80 @@
+namespace,
+ '/' . $this->rest_base,
+ [
+ 'methods' => WP_REST_Server::CREATABLE,
+ 'callback' => [ $this, 'process_refund' ],
+ 'permission_callback' => [ $this, 'check_permission' ],
+ ]
+ );
+ }
+
+ /**
+ * Makes direct refund bypassing any order checks.
+ *
+ * @internal Not intended for usage in integrations or outside of WooCommerce Payments.
+ * @param WP_REST_Request $request Full data about the request.
+ */
+ public function process_refund( $request ) {
+ $order_id = $request->get_param( 'order_id' );
+ $charge_id = $request->get_param( 'charge_id' );
+ $amount = $request->get_param( 'amount' );
+ $reason = $request->get_param( 'reason' );
+
+ if ( $order_id ) {
+ $order = wc_get_order( $order_id );
+ if ( $order ) {
+ $result = wc_create_refund(
+ [
+ 'amount' => WC_Payments_Utils::interpret_stripe_amount( $amount, $order->get_currency() ),
+ 'reason' => $reason,
+ 'order_id' => $order_id,
+ 'refund_payment' => true,
+ ]
+ );
+
+ return rest_ensure_response( $result );
+ }
+ }
+
+ try {
+ $refund_request = Refund_Charge::create( $charge_id );
+ $refund_request->set_charge( $charge_id );
+ $refund_request->set_amount( $amount );
+ $refund_request->set_reason( $reason );
+ $refund_request->set_source( 'transaction_details_no_order' );
+ $response = $refund_request->send();
+
+ return rest_ensure_response( $response );
+ } catch ( API_Exception $e ) {
+ return rest_ensure_response( new WP_Error( 'wcpay_refund_payment', $e->getMessage() ) );
+ }
+ }
+}
diff --git a/includes/class-wc-payment-gateway-wcpay.php b/includes/class-wc-payment-gateway-wcpay.php
index b07ee398a92..03b8c9ebf12 100644
--- a/includes/class-wc-payment-gateway-wcpay.php
+++ b/includes/class-wc-payment-gateway-wcpay.php
@@ -1817,6 +1817,10 @@ static function ( $refund ) use ( $refund_amount ) {
if ( null !== $amount ) {
$refund_request->set_amount( WC_Payments_Utils::prepare_amount( $amount, $order->get_currency() ) );
}
+ // These are reasons supported by Stripe https://stripe.com/docs/api/refunds/create#create_refund-reason.
+ if ( in_array( $reason, [ 'duplicate', 'fraudulent', 'requested_by_customer' ], true ) ) {
+ $refund_request->set_reason( $reason );
+ }
$refund = $refund_request->send();
}
$currency = strtoupper( $refund['currency'] );
diff --git a/includes/class-wc-payments.php b/includes/class-wc-payments.php
index 26e51088d9f..c1cbfb64f7c 100644
--- a/includes/class-wc-payments.php
+++ b/includes/class-wc-payments.php
@@ -1052,6 +1052,10 @@ public static function init_rest_api() {
$customer_controller = new WC_REST_Payments_Customer_Controller( self::$api_client, self::$customer_service );
$customer_controller->register_routes();
+ include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-refunds-controller.php';
+ $refunds_controller = new WC_REST_Payments_Refunds_Controller( self::$api_client );
+ $refunds_controller->register_routes();
+
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-survey-controller.php';
$survey_controller = new WC_REST_Payments_Survey_Controller( self::get_wc_payments_http() );
$survey_controller->register_routes();
diff --git a/includes/core/server/request/class-refund-charge.php b/includes/core/server/request/class-refund-charge.php
index d792c942e53..93be681fb5e 100644
--- a/includes/core/server/request/class-refund-charge.php
+++ b/includes/core/server/request/class-refund-charge.php
@@ -19,6 +19,7 @@ class Refund_Charge extends Request {
const DEFAULT_PARAMS = [
'amount' => null,
+ 'reason' => null,
];
const IMMUTABLE_PARAMS = [ 'charge' ];
@@ -59,6 +60,32 @@ public function set_amount( int $amount ) {
$this->set_param( 'amount', $amount );
}
+ /**
+ * Sets the reason for the refund.
+ *
+ * @param string|null $reason The reason for the refund.
+ * @throws Invalid_Request_Parameter_Exception
+ */
+ public function set_reason( ?string $reason ) {
+ $this->set_param( 'reason', $reason );
+ }
+
+ /**
+ * Sets the refund source describing where it was initiated from.
+ *
+ * @param string $source The reason for the refund.
+ * @throws Invalid_Request_Parameter_Exception
+ */
+ public function set_source( string $source ) {
+ $this->set_param(
+ 'metadata',
+ array_merge(
+ $this->get_params()['metadata'] ?? [],
+ [ 'refund_source' => $source ]
+ )
+ );
+ }
+
/**
* Returns the request's API.
*
diff --git a/tests/unit/admin/test-class-wc-rest-payments-refunds-controller.php b/tests/unit/admin/test-class-wc-rest-payments-refunds-controller.php
new file mode 100644
index 00000000000..3f5b912e56f
--- /dev/null
+++ b/tests/unit/admin/test-class-wc-rest-payments-refunds-controller.php
@@ -0,0 +1,73 @@
+mock_api_client = $this->createMock( WC_Payments_API_Client::class );
+
+ $this->controller = new WC_REST_Payments_Refunds_Controller(
+ $this->mock_api_client
+ );
+ }
+
+ public function test_process_refund_without_order_id(): void {
+
+ $request = new WP_REST_Request( 'POST' );
+ $request->set_body_params(
+ [
+ 'order_id' => null,
+ 'charge_id' => 'ch_test',
+ 'amount' => 5000,
+ 'reason' => 'duplicate',
+ ]
+ );
+
+ $refund_request = $this->mock_wcpay_request( Refund_Charge::class );
+
+ $refund_request->expects( $this->once() )
+ ->method( 'set_charge' )
+ ->with( 'ch_test' );
+ $refund_request->expects( $this->once() )
+ ->method( 'set_amount' )
+ ->with( 5000 );
+ $refund_request->expects( $this->once() )
+ ->method( 'set_reason' )
+ ->with( 'duplicate' );
+ $refund_response = [
+ 'id' => 're_test',
+ ];
+ $refund_request->expects( $this->once() )
+ ->method( 'format_response' )
+ ->with()
+ ->willReturn( $refund_response );
+
+ $response = $this->controller->process_refund( $request );
+ $this->assertSame( 200, $response->get_status() );
+ $this->assertSame( $refund_response, $response->get_data() );
+ }
+}
diff --git a/tests/unit/bootstrap.php b/tests/unit/bootstrap.php
index 0188cfb4f93..0ff3d5a9ed1 100755
--- a/tests/unit/bootstrap.php
+++ b/tests/unit/bootstrap.php
@@ -96,6 +96,7 @@ function() {
require_once $_plugin_dir . 'includes/admin/class-wc-rest-payments-payment-intents-controller.php';
require_once $_plugin_dir . 'includes/class-woopay-tracker.php';
require_once $_plugin_dir . 'includes/admin/class-wc-rest-payments-customer-controller.php';
+ require_once $_plugin_dir . 'includes/admin/class-wc-rest-payments-refunds-controller.php';
// Load currency helper class early to ensure its implementation is used over the one resolved during further test initialization.
require_once __DIR__ . '/helpers/class-wc-helper-site-currency.php';
From 9a3237e32ad8e138b96e1b55486db9c260c236fd Mon Sep 17 00:00:00 2001
From: Dat Hoang
Date: Thu, 21 Dec 2023 15:18:21 +0700
Subject: [PATCH 43/56] Add test mode notice in page order detail. (#7898)
---
.../add-334-test-mode-notice-order-details | 4 ++
client/order/index.js | 22 ++++++----
client/order/test-mode-notice/index.tsx | 40 +++++++++++++++++++
includes/admin/class-wc-payments-admin.php | 1 +
includes/class-wc-payment-gateway-wcpay.php | 3 +-
...s-wc-payments-action-scheduler-service.php | 6 ++-
includes/class-wc-payments-order-service.php | 9 +++++
includes/class-wc-payments.php | 1 +
includes/constants/class-order-mode.php | 22 ++++++++++
src/Internal/Service/OrderService.php | 4 +-
.../Service/PaymentProcessingService.php | 3 +-
11 files changed, 102 insertions(+), 13 deletions(-)
create mode 100644 changelog/add-334-test-mode-notice-order-details
create mode 100644 client/order/test-mode-notice/index.tsx
create mode 100644 includes/constants/class-order-mode.php
diff --git a/changelog/add-334-test-mode-notice-order-details b/changelog/add-334-test-mode-notice-order-details
new file mode 100644
index 00000000000..de22a34c323
--- /dev/null
+++ b/changelog/add-334-test-mode-notice-order-details
@@ -0,0 +1,4 @@
+Significance: minor
+Type: add
+
+Add test mode notice in page order detail.
diff --git a/client/order/index.js b/client/order/index.js
index 4b2606caff0..1bfdfeee7ad 100644
--- a/client/order/index.js
+++ b/client/order/index.js
@@ -13,6 +13,7 @@ import { isAwaitingResponse, isUnderReview } from 'wcpay/disputes/utils';
import RefundConfirmationModal from './refund-confirm-modal';
import CancelConfirmationModal from './cancel-confirm-modal';
import CancelAuthorizationConfirmationModal from './cancel-authorization-confirm-modal';
+import TestModeNotice from './test-mode-notice';
import DisputedOrderNoticeHandler from 'wcpay/components/disputed-order-notice';
function disableWooOrderRefundButton( disputeStatus ) {
@@ -59,8 +60,9 @@ jQuery( function ( $ ) {
const disableManualRefunds = getConfig( 'disableManualRefunds' ) ?? false;
const manualRefundsTip = getConfig( 'manualRefundsTip' ) ?? '';
const chargeId = getConfig( 'chargeId' );
+ const testMode = getConfig( 'testMode' );
- maybeShowDisputeNotice();
+ maybeShowOrderNotices();
$( '#woocommerce-order-items' ).on(
'click',
@@ -168,21 +170,27 @@ jQuery( function ( $ ) {
ReactDOM.render( modalToRender, container );
}
- function maybeShowDisputeNotice() {
+ function maybeShowOrderNotices() {
const container = document.querySelector(
'#wcpay-order-payment-details-container'
);
// If the container doesn't exist (WC < 7.9), or the charge ID isn't present, don't render the notice.
- if ( ! container || ! chargeId ) {
+ if ( ! container ) {
return;
}
ReactDOM.render(
- ,
+ <>
+ { testMode && }
+
+ { chargeId && (
+
+ ) }
+ >,
container
);
}
diff --git a/client/order/test-mode-notice/index.tsx b/client/order/test-mode-notice/index.tsx
new file mode 100644
index 00000000000..7778f38a65a
--- /dev/null
+++ b/client/order/test-mode-notice/index.tsx
@@ -0,0 +1,40 @@
+/**
+ * External dependencies
+ */
+import React from 'react';
+import { __ } from '@wordpress/i18n';
+import interpolateComponents from '@automattic/interpolate-components';
+
+/**
+ * Internal dependencies
+ */
+import InlineNotice from 'wcpay/components/inline-notice';
+
+const TestModeNotice = (): JSX.Element => {
+ return (
+
+ { interpolateComponents( {
+ mixedString: __(
+ 'WooPayments was in test mode when this order was placed. {{learnMoreLink/}}',
+ 'woocommerce-payments'
+ ),
+ components: {
+ learnMoreLink: (
+
+ { __(
+ 'Learn more about test mode',
+ 'woocommerce-payments'
+ ) }
+
+ ),
+ },
+ } ) }
+
+ );
+};
+
+export default TestModeNotice;
diff --git a/includes/admin/class-wc-payments-admin.php b/includes/admin/class-wc-payments-admin.php
index 31934da5ebe..0aa9f9dd03c 100644
--- a/includes/admin/class-wc-payments-admin.php
+++ b/includes/admin/class-wc-payments-admin.php
@@ -735,6 +735,7 @@ public function enqueue_payments_scripts() {
'canRefund' => $this->wcpay_gateway->can_refund_order( $order ),
'chargeId' => $this->order_service->get_charge_id_for_order( $order ),
'hasOpenAuthorization' => $this->order_service->has_open_authorization( $order ),
+ 'testMode' => \WCPay\Constants\Order_Mode::TEST === $order->get_meta( WC_Payments_Order_Service::WCPAY_MODE_META_KEY ),
]
);
wp_localize_script(
diff --git a/includes/class-wc-payment-gateway-wcpay.php b/includes/class-wc-payment-gateway-wcpay.php
index 03b8c9ebf12..8d21920ac8f 100644
--- a/includes/class-wc-payment-gateway-wcpay.php
+++ b/includes/class-wc-payment-gateway-wcpay.php
@@ -10,6 +10,7 @@
}
use WCPay\Constants\Fraud_Meta_Box_Type;
+use WCPay\Constants\Order_Mode;
use WCPay\Constants\Order_Status;
use WCPay\Constants\Payment_Capture_Type;
use WCPay\Constants\Payment_Initiated_By;
@@ -1204,7 +1205,7 @@ public function process_payment_for_order( $cart, $payment_information, $schedul
$payment_method = $payment_information->get_payment_method();
$this->order_service->set_payment_method_id_for_order( $order, $payment_method );
$this->order_service->set_customer_id_for_order( $order, $customer_id );
- $order->update_meta_data( '_wcpay_mode', WC_Payments::mode()->is_test() ? 'test' : 'prod' );
+ $order->update_meta_data( WC_Payments_Order_Service::WCPAY_MODE_META_KEY, WC_Payments::mode()->is_test() ? Order_Mode::TEST : Order_Mode::PRODUCTION );
// In case amount is 0 and we're not saving the payment method, we won't be using intents and can confirm the order payment.
if ( apply_filters( 'wcpay_confirm_without_payment_intent', ! $payment_needed && ! $save_payment_method_to_store ) ) {
diff --git a/includes/class-wc-payments-action-scheduler-service.php b/includes/class-wc-payments-action-scheduler-service.php
index 4f19611ac0e..1952d427a31 100644
--- a/includes/class-wc-payments-action-scheduler-service.php
+++ b/includes/class-wc-payments-action-scheduler-service.php
@@ -5,6 +5,8 @@
* @package WooCommerce\Payments
*/
+use WCPay\Constants\Order_Mode;
+
defined( 'ABSPATH' ) || exit;
/**
@@ -99,10 +101,10 @@ private function track_order( $order_id, $is_update = false ) {
if ( empty( $payment_method ) ) {
return false;
}
- $order_mode = $order->get_meta( '_wcpay_mode' );
+ $order_mode = $order->get_meta( WC_Payments_Order_Service::WCPAY_MODE_META_KEY );
if ( $order_mode ) {
- $current_mode = WC_Payments::mode()->is_test() ? 'test' : 'prod';
+ $current_mode = WC_Payments::mode()->is_test() ? Order_Mode::TEST : Order_Mode::PRODUCTION;
if ( $current_mode !== $order_mode ) {
// If mode doesn't match make sure to stop order tracking to prevent order tracking issues.
// False will be returned so maybe future crons will have correct mode.
diff --git a/includes/class-wc-payments-order-service.php b/includes/class-wc-payments-order-service.php
index 44c5f22302f..eab529f6d92 100644
--- a/includes/class-wc-payments-order-service.php
+++ b/includes/class-wc-payments-order-service.php
@@ -97,6 +97,15 @@ class WC_Payments_Order_Service {
*/
const WCPAY_TRANSACTION_FEE_META_KEY = '_wcpay_transaction_fee';
+ /**
+ * Meta key used to store the mode, either 'test', or 'prod' of order.
+ *
+ * @see Order_Mode
+ *
+ * @const string
+ */
+ const WCPAY_MODE_META_KEY = '_wcpay_mode';
+
/**
* Client for making requests to the WooCommerce Payments API
*
diff --git a/includes/class-wc-payments.php b/includes/class-wc-payments.php
index c1cbfb64f7c..006f2deef2a 100644
--- a/includes/class-wc-payments.php
+++ b/includes/class-wc-payments.php
@@ -436,6 +436,7 @@ public static function init() {
include_once __DIR__ . '/exceptions/class-order-not-found-exception.php';
include_once __DIR__ . '/constants/class-base-constant.php';
include_once __DIR__ . '/constants/class-fraud-meta-box-type.php';
+ include_once __DIR__ . '/constants/class-order-mode.php';
include_once __DIR__ . '/constants/class-order-status.php';
include_once __DIR__ . '/constants/class-payment-type.php';
include_once __DIR__ . '/constants/class-payment-initiated-by.php';
diff --git a/includes/constants/class-order-mode.php b/includes/constants/class-order-mode.php
new file mode 100644
index 00000000000..689baca331d
--- /dev/null
+++ b/includes/constants/class-order-mode.php
@@ -0,0 +1,22 @@
+get_order( $order_id );
- $order->update_meta_data( '_wcpay_mode', $mode );
+ $order->update_meta_data( WC_Payments_Order_Service::WCPAY_MODE_META_KEY, $mode );
$order->save_meta_data();
}
@@ -235,7 +235,7 @@ public function set_mode( string $order_id, string $mode ) : void {
*/
public function get_mode( string $order_id ) : string {
$order = $this->get_order( $order_id );
- return $order->get_meta( '_wcpay_mode', true );
+ return $order->get_meta( WC_Payments_Order_Service::WCPAY_MODE_META_KEY, true );
}
/**
diff --git a/src/Internal/Service/PaymentProcessingService.php b/src/Internal/Service/PaymentProcessingService.php
index ca3647fcfc7..c68be314128 100644
--- a/src/Internal/Service/PaymentProcessingService.php
+++ b/src/Internal/Service/PaymentProcessingService.php
@@ -10,6 +10,7 @@
use Exception;
use WC_Payments_API_Abstract_Intention;
use WC_Payments_API_Setup_Intention;
+use WCPay\Constants\Order_Mode;
use WCPay\Exceptions\API_Exception;
use WCPay\Exceptions\Order_Not_Found_Exception;
use WCPay\Vendor\League\Container\Exception\ContainerException;
@@ -147,7 +148,7 @@ public function get_authentication_redirect_url( $intent, int $order_id ) {
protected function create_payment_context( int $order_id, bool $automatic_capture = false ): PaymentContext {
$context = new PaymentContext( $order_id );
try {
- $context->set_mode( $this->mode->is_test() ? 'test' : 'prod' );
+ $context->set_mode( $this->mode->is_test() ? Order_Mode::TEST : Order_Mode::PRODUCTION );
} catch ( Exception $e ) {
$context->set_mode( 'unknown' );
}
From f62ff7e5f70091b9da7fe06bce25509cf3e7f99c Mon Sep 17 00:00:00 2001
From: Daniel Mallory
Date: Thu, 21 Dec 2023 10:15:38 +0000
Subject: [PATCH 44/56] Reset Account Management (#7914)
Co-authored-by: Oleksandr Aratovskyi <79862886+oaratovskyi@users.noreply.github.com>
---
.../dev-3468-allow-reset-account-management | 4 +
.../account-status/account-fees/index.js | 9 +-
.../account-status/account-fees/styles.scss | 3 +
.../test/__snapshots__/index.js.snap | 187 ++++++++++++++----
.../account-status/account-tools/index.tsx | 67 +++++++
.../account-status/account-tools/strings.tsx | 15 ++
.../account-status/account-tools/styles.scss | 11 ++
.../test/__snapshots__/index.test.tsx.snap | 40 ++++
.../account-tools/test/index.test.tsx | 49 +++++
client/components/account-status/index.js | 4 +
.../test/__snapshots__/index.js.snap | 50 ++++-
client/onboarding/tracking.ts | 3 +
client/overview/modal/reset-account/index.tsx | 64 ++++++
.../overview/modal/reset-account/strings.tsx | 36 ++++
.../overview/modal/reset-account/style.scss | 25 +++
.../modal/reset-account/test/index.test.tsx | 35 ++++
client/tracks/index.js | 1 +
client/utils/index.js | 14 ++
includes/class-wc-payments-account.php | 9 +
19 files changed, 589 insertions(+), 37 deletions(-)
create mode 100644 changelog/dev-3468-allow-reset-account-management
create mode 100644 client/components/account-status/account-fees/styles.scss
create mode 100644 client/components/account-status/account-tools/index.tsx
create mode 100644 client/components/account-status/account-tools/strings.tsx
create mode 100644 client/components/account-status/account-tools/styles.scss
create mode 100644 client/components/account-status/account-tools/test/__snapshots__/index.test.tsx.snap
create mode 100644 client/components/account-status/account-tools/test/index.test.tsx
create mode 100644 client/overview/modal/reset-account/index.tsx
create mode 100644 client/overview/modal/reset-account/strings.tsx
create mode 100644 client/overview/modal/reset-account/style.scss
create mode 100644 client/overview/modal/reset-account/test/index.test.tsx
diff --git a/changelog/dev-3468-allow-reset-account-management b/changelog/dev-3468-allow-reset-account-management
new file mode 100644
index 00000000000..ed030674f95
--- /dev/null
+++ b/changelog/dev-3468-allow-reset-account-management
@@ -0,0 +1,4 @@
+Significance: minor
+Type: add
+
+Add Account Management tools with reset account functionality for partially onboarded accounts.
diff --git a/client/components/account-status/account-fees/index.js b/client/components/account-status/account-fees/index.js
index 066a4faf1b3..93a93293c11 100644
--- a/client/components/account-status/account-fees/index.js
+++ b/client/components/account-status/account-fees/index.js
@@ -16,6 +16,8 @@ import {
getCurrentBaseFee,
getTransactionsPaymentMethodName,
} from 'utils/account-fees';
+import { CardDivider } from '@wordpress/components';
+import './styles.scss';
const AccountFee = ( props ) => {
const { accountFee, paymentMethod } = props;
@@ -59,7 +61,12 @@ const AccountFees = ( props ) => {
return (
<>
{ haveDiscounts && (
- { __( 'Active discounts', 'woocommerce-payments' ) }
+
+
+
+ { __( 'Active discounts', 'woocommerce-payments' ) }
+
+
) }
{ activeDiscounts }
>
diff --git a/client/components/account-status/account-fees/styles.scss b/client/components/account-status/account-fees/styles.scss
new file mode 100644
index 00000000000..9938ef462b1
--- /dev/null
+++ b/client/components/account-status/account-fees/styles.scss
@@ -0,0 +1,3 @@
+.account-fees {
+ padding-top: 16px;
+}
diff --git a/client/components/account-status/account-fees/test/__snapshots__/index.js.snap b/client/components/account-status/account-fees/test/__snapshots__/index.js.snap
index 6a2576c6862..653e680afac 100644
--- a/client/components/account-status/account-fees/test/__snapshots__/index.js.snap
+++ b/client/components/account-status/account-fees/test/__snapshots__/index.js.snap
@@ -2,9 +2,20 @@
exports[`AccountFees renders discounted base fee 1`] = `
-
- Active discounts
-
+
+
+
+ Active discounts
+
+
Card transactions
:
@@ -47,9 +58,20 @@ exports[`AccountFees renders discounted base fee 1`] = `
exports[`AccountFees renders discounted fee with USD volume currency and non-USD base fee 1`] = `
-
- Active discounts
-
+
+
+
+ Active discounts
+
+
Card transactions
:
@@ -92,9 +114,20 @@ exports[`AccountFees renders discounted fee with USD volume currency and non-USD
exports[`AccountFees renders discounted fee with end date 1`] = `
-
- Active discounts
-
+
+
+
+ Active discounts
+
+
Card transactions
:
@@ -115,9 +148,20 @@ exports[`AccountFees renders discounted fee with end date 1`] = `
exports[`AccountFees renders discounted fee with volume limit 1`] = `
-
- Active discounts
-
+
+
+
+ Active discounts
+
+
Card transactions
:
@@ -160,9 +204,20 @@ exports[`AccountFees renders discounted fee with volume limit 1`] = `
exports[`AccountFees renders discounted fee with volume limit and end date 1`] = `
-
- Active discounts
-
+
+
+
+ Active discounts
+
+
Card transactions
:
@@ -205,9 +260,20 @@ exports[`AccountFees renders discounted fee with volume limit and end date 1`] =
exports[`AccountFees renders discounted fee without volume limit 1`] = `
-
- Active discounts
-
+
+
+
+ Active discounts
+
+
Card transactions
:
@@ -223,9 +289,20 @@ exports[`AccountFees renders discounted fee without volume limit 1`] = `
exports[`AccountFees renders discounted non-USD base fee 1`] = `
-
- Active discounts
-
+
+
+
+ Active discounts
+
+
Card transactions
:
@@ -268,9 +345,20 @@ exports[`AccountFees renders discounted non-USD base fee 1`] = `
exports[`AccountFees renders discounts multiple payment methods 1`] = `
-
- Active discounts
-
+
+
+
+ Active discounts
+
+
Card transactions
:
@@ -306,9 +394,20 @@ exports[`AccountFees renders discounts multiple payment methods 1`] = `
exports[`AccountFees renders first discounted fee ignoring the rest 1`] = `
-
- Active discounts
-
+
+
+
+ Active discounts
+
+
Card transactions
:
@@ -324,9 +423,20 @@ exports[`AccountFees renders first discounted fee ignoring the rest 1`] = `
exports[`AccountFees renders non-USD base fee 1`] = `
-
- Active discounts
-
+
+
+
+ Active discounts
+
+
Card transactions
:
@@ -342,9 +452,20 @@ exports[`AccountFees renders non-USD base fee 1`] = `
exports[`AccountFees renders normal base fee 1`] = `
-
- Active discounts
-
+
+
+
+ Active discounts
+
+
Card transactions
:
diff --git a/client/components/account-status/account-tools/index.tsx b/client/components/account-status/account-tools/index.tsx
new file mode 100644
index 00000000000..1a7d8039829
--- /dev/null
+++ b/client/components/account-status/account-tools/index.tsx
@@ -0,0 +1,67 @@
+/**
+ * External dependencies
+ */
+import React, { useState } from 'react';
+import { Button, CardDivider } from '@wordpress/components';
+import { addQueryArgs } from '@wordpress/url';
+
+/**
+ * Internal dependencies
+ */
+import strings from './strings';
+import { isInDevMode } from 'utils';
+import './styles.scss';
+import ResetAccountModal from 'wcpay/overview/modal/reset-account';
+import { trackAccountReset } from 'wcpay/onboarding/tracking';
+
+interface Props {
+ accountLink: string;
+ openModal: () => void;
+}
+
+const handleReset = () => {
+ trackAccountReset();
+
+ window.location.href = addQueryArgs( wcpaySettings.connectUrl, {
+ 'wcpay-reset-account': true,
+ } );
+};
+
+export const AccountTools: React.FC< Props > = ( props: Props ) => {
+ const accountLink = props.accountLink;
+ const [ modalVisible, setModalVisible ] = useState( false );
+
+ if ( isInDevMode() ) return null;
+
+ return (
+ <>
+
+
+
{ strings.title }
+
{ strings.description }
+ { /* Use wrapping div to keep buttons grouped together. */ }
+
+
+ { strings.finish }
+
+ setModalVisible( true ) }
+ >
+ { strings.reset }
+
+
+
+
+
setModalVisible( false ) }
+ onSubmit={ handleReset }
+ />
+ >
+ );
+};
diff --git a/client/components/account-status/account-tools/strings.tsx b/client/components/account-status/account-tools/strings.tsx
new file mode 100644
index 00000000000..47c668d0a88
--- /dev/null
+++ b/client/components/account-status/account-tools/strings.tsx
@@ -0,0 +1,15 @@
+/* eslint-disable max-len */
+/**
+ * External dependencies
+ */
+import { __ } from '@wordpress/i18n';
+
+export default {
+ title: __( 'Account Tools', 'woocommerce-payments' ),
+ description: __(
+ 'Payments and deposits are disabled until account setup is completed. If you are experiencing problems completing account setup, or need to change the email/country associated with your account, you can reset your account and start from the beginning.',
+ 'woocommerce-payments'
+ ),
+ finish: __( 'Finish setup', 'woocommerce-payments' ),
+ reset: __( 'Reset account', 'woocommerce-payments' ),
+};
diff --git a/client/components/account-status/account-tools/styles.scss b/client/components/account-status/account-tools/styles.scss
new file mode 100644
index 00000000000..aa2a29348cd
--- /dev/null
+++ b/client/components/account-status/account-tools/styles.scss
@@ -0,0 +1,11 @@
+.account-tools {
+ padding-top: $gap;
+
+ &__actions {
+ display: grid;
+ grid-auto-flow: column;
+ grid-auto-columns: max-content;
+ column-gap: $gap-small;
+ margin-top: $gap-small;
+ }
+}
diff --git a/client/components/account-status/account-tools/test/__snapshots__/index.test.tsx.snap b/client/components/account-status/account-tools/test/__snapshots__/index.test.tsx.snap
new file mode 100644
index 00000000000..cfeba86037a
--- /dev/null
+++ b/client/components/account-status/account-tools/test/__snapshots__/index.test.tsx.snap
@@ -0,0 +1,40 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AccountTools should render in live mode 1`] = `
+
+`;
diff --git a/client/components/account-status/account-tools/test/index.test.tsx b/client/components/account-status/account-tools/test/index.test.tsx
new file mode 100644
index 00000000000..7c5827b115a
--- /dev/null
+++ b/client/components/account-status/account-tools/test/index.test.tsx
@@ -0,0 +1,49 @@
+/** @format */
+/**
+ * External dependencies
+ */
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+
+/**
+ * Internal dependencies
+ */
+import { AccountTools } from '..';
+
+const accountLink = '/onboarding';
+const openModal = jest.fn();
+
+declare const global: {
+ wcpaySettings: {
+ devMode: boolean;
+ };
+};
+
+describe( 'AccountTools', () => {
+ it( 'should render in live mode', () => {
+ global.wcpaySettings = {
+ devMode: false,
+ };
+
+ const { container } = render(
+
+ );
+ expect( container ).toMatchSnapshot();
+ } );
+
+ it( 'should not render in dev mode', () => {
+ global.wcpaySettings = {
+ devMode: true,
+ };
+
+ render(
+
+ );
+
+ expect(
+ screen.queryByText(
+ 'If you are experiencing problems completing account setup, or need to change the email/country associated with your account, you can reset your account and start from the beginning.'
+ )
+ ).not.toBeInTheDocument();
+ } );
+} );
diff --git a/client/components/account-status/index.js b/client/components/account-status/index.js
index 6a35084ad18..19fc715b1ff 100755
--- a/client/components/account-status/index.js
+++ b/client/components/account-status/index.js
@@ -23,6 +23,7 @@ import PaymentsStatus from 'components/payments-status';
import StatusChip from './status-chip';
import './style.scss';
import './shared.scss';
+import { AccountTools } from './account-tools';
const AccountStatusCard = ( props ) => {
const { title, children, value } = props;
@@ -102,6 +103,9 @@ const AccountStatusDetails = ( props ) => {
}
/>
+ { ! accountStatus.detailsSubmitted && (
+
+ ) }
{ accountFees.length > 0 && (
) }
diff --git a/client/components/account-status/test/__snapshots__/index.js.snap b/client/components/account-status/test/__snapshots__/index.js.snap
index edead6f2fbd..712f139c0ca 100644
--- a/client/components/account-status/test/__snapshots__/index.js.snap
+++ b/client/components/account-status/test/__snapshots__/index.js.snap
@@ -166,9 +166,53 @@ exports[`AccountStatus renders normal status 1`] = `
-
- Active discounts
-
+
+
+
+
+ Active discounts
+
+
Card transactions
:
diff --git a/client/onboarding/tracking.ts b/client/onboarding/tracking.ts
index 3a083eeb64b..66ea41ebf60 100644
--- a/client/onboarding/tracking.ts
+++ b/client/onboarding/tracking.ts
@@ -57,6 +57,9 @@ export const trackRedirected = ( isEligible: boolean ): void => {
} );
};
+export const trackAccountReset = (): void =>
+ wcpayTracks.recordEvent( wcpayTracks.events.ONBOARDING_FLOW_RESET, {} );
+
export const trackEligibilityModalClosed = (
action: 'dismiss' | 'setup_deposits' | 'enable_payments_only'
): void =>
diff --git a/client/overview/modal/reset-account/index.tsx b/client/overview/modal/reset-account/index.tsx
new file mode 100644
index 00000000000..1146645566c
--- /dev/null
+++ b/client/overview/modal/reset-account/index.tsx
@@ -0,0 +1,64 @@
+/**
+ * External dependencies
+ */
+import React from 'react';
+import { Button, CardDivider, Modal } from '@wordpress/components';
+
+/**
+ * Internal dependencies
+ */
+import './style.scss';
+import strings from './strings';
+
+interface Props {
+ isVisible: boolean;
+ onSubmit: () => void;
+ onDismiss: () => void;
+}
+
+const ResetAccountModal: React.FC< Props > = ( props: Props ) => {
+ const { isVisible, onDismiss, onSubmit } = props;
+ if ( ! isVisible ) return null;
+
+ return (
+
+
+
{ strings.description }
+
+ { strings.beforeContinue }
+
+
+ { strings.step1 }
+
+
+
+ { strings.step2 }
+
+
+
+ { strings.step3 }
+
+
+
{ strings.confirmation }
+
+
+
+ { strings.cancel }
+
+
+ { strings.reset }
+
+
+
+ );
+};
+
+export default ResetAccountModal;
diff --git a/client/overview/modal/reset-account/strings.tsx b/client/overview/modal/reset-account/strings.tsx
new file mode 100644
index 00000000000..1a1c7616ff0
--- /dev/null
+++ b/client/overview/modal/reset-account/strings.tsx
@@ -0,0 +1,36 @@
+/* eslint-disable max-len */
+/**
+ * External dependencies
+ */
+import { __, sprintf } from '@wordpress/i18n';
+
+export default {
+ title: __( 'Reset account', 'woocommerce-payments' ),
+ description: __(
+ 'If you are experiencing problems completing account setup, or need to change the email/country associated with your account, you can reset your account and start from the beginning.',
+ 'woocommerce-payments'
+ ),
+ beforeContinue: __( 'Before you continue', 'woocommerce-payments' ),
+ step1: sprintf(
+ /* translators: %s: WooPayments. */
+ __(
+ 'Your %s account will be reset, and all data will be lost.',
+ 'woocommerce-payments'
+ ),
+ 'WooPayments'
+ ),
+ step2: __(
+ 'You will have to re-confirm your business and banking details.',
+ 'woocommerce-payments'
+ ),
+ step3: __(
+ 'Once confirmed, this cannot be undone.',
+ 'woocommerce-payments'
+ ),
+ confirmation: __(
+ 'Are you sure you want to continue?',
+ 'woocommerce-payments'
+ ),
+ cancel: __( 'Cancel', 'woocommerce-payments' ),
+ reset: __( 'Yes, reset account', 'woocommerce-payments' ),
+};
diff --git a/client/overview/modal/reset-account/style.scss b/client/overview/modal/reset-account/style.scss
new file mode 100644
index 00000000000..1c0f9fc0f36
--- /dev/null
+++ b/client/overview/modal/reset-account/style.scss
@@ -0,0 +1,25 @@
+.wcpay-reset-account-modal {
+ // fix for the modal being too short on smaller screens
+ @media ( max-height: 880px ) {
+ max-height: 100% !important;
+ }
+
+ .components-modal__content {
+ box-sizing: border-box;
+ max-width: 700px;
+ }
+
+ &__footer {
+ text-align: right;
+ margin-top: $gap-large;
+
+ & :first-child {
+ margin-right: $gap-smaller;
+ }
+
+ button {
+ margin-top: $gap;
+ padding: $gap-smaller $gap;
+ }
+ }
+}
diff --git a/client/overview/modal/reset-account/test/index.test.tsx b/client/overview/modal/reset-account/test/index.test.tsx
new file mode 100644
index 00000000000..50f55e78bbe
--- /dev/null
+++ b/client/overview/modal/reset-account/test/index.test.tsx
@@ -0,0 +1,35 @@
+/**
+ * External dependencies
+ */
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+
+/**
+ * Internal dependencies
+ */
+import ResetAccountModal from '..';
+
+jest.mock( '@wordpress/data', () => ( {
+ useDispatch: jest.fn().mockReturnValue( { updateOptions: jest.fn() } ),
+} ) );
+
+const onSubmit = jest.fn();
+const onDismiss = jest.fn();
+
+describe( 'Reset Account Modal', () => {
+ it( 'modal is open when is visible is true', () => {
+ render(
+
+ );
+
+ expect(
+ screen.queryByText(
+ 'If you are experiencing problems completing account setup, or need to change the email/country associated with your account, you can reset your account and start from the beginning.'
+ )
+ ).toBeInTheDocument();
+ } );
+} );
diff --git a/client/tracks/index.js b/client/tracks/index.js
index c02615f781d..c862f189954 100644
--- a/client/tracks/index.js
+++ b/client/tracks/index.js
@@ -124,6 +124,7 @@ const events = {
ONBOARDING_FLOW_HIDDEN: 'wcpay_onboarding_flow_hidden',
ONBOARDING_FLOW_EXITED: 'wcpay_onboarding_flow_exited',
ONBOARDING_FLOW_REDIRECTED: 'wcpay_onboarding_flow_redirected',
+ ONBOARDING_FLOW_RESET: 'wcpay_onboarding_flow_reset',
ONBOARDING_FLOW_ELIGIBILITY_MODAL_CLOSED:
'wcpay_onboarding_flow_eligibility_modal_closed',
};
diff --git a/client/utils/index.js b/client/utils/index.js
index 88756614649..d6e7a1c971d 100644
--- a/client/utils/index.js
+++ b/client/utils/index.js
@@ -22,6 +22,20 @@ export const isInTestMode = ( fallback = false ) => {
return wcpaySettings.testMode === '1' || fallback;
};
+/**
+ * Returns true if WooPayments is in dev mode, false otherwise.
+ *
+ * @param {boolean} fallback Fallback in case dev mode value can't be found (for example if the wcpaySettings are undefined).
+ *
+ * @return {boolean} True if in dev mode, false otherwise. Fallback value if test/dev mode value can't be found.
+ */
+export const isInDevMode = ( fallback = false ) => {
+ if ( typeof wcpaySettings === 'undefined' ) {
+ return fallback;
+ }
+ return wcpaySettings.devMode === '1' || fallback;
+};
+
export const getAdminUrl = ( args ) => addQueryArgs( 'admin.php', args );
/**
diff --git a/includes/class-wc-payments-account.php b/includes/class-wc-payments-account.php
index 18567fe25b6..fa4d3b45e45 100644
--- a/includes/class-wc-payments-account.php
+++ b/includes/class-wc-payments-account.php
@@ -1048,6 +1048,15 @@ public function maybe_handle_onboarding() {
return;
}
+ if ( isset( $_GET['wcpay-reset-account'] ) ) {
+ $test_mode = WC_Payments_Onboarding_Service::is_test_mode_enabled();
+
+ // Delete the account.
+ $this->payments_api_client->delete_account( $test_mode );
+ $this->redirect_to_onboarding_flow_page();
+ return;
+ }
+
// Hide menu notification badge upon starting setup.
update_option( 'wcpay_menu_badge_hidden', 'yes' );
From 84d033c9f2d9ba57cf8cdd5685b29eb5c9986004 Mon Sep 17 00:00:00 2001
From: jessy <32092402+jessy-p@users.noreply.github.com>
Date: Fri, 22 Dec 2023 12:09:55 +0530
Subject: [PATCH 45/56] Modify the test support phone numbers (#7939)
Co-authored-by: Jessy
---
changelog/fix-test-support-phone | 5 +++++
client/settings/support-phone-input/index.js | 6 ++----
2 files changed, 7 insertions(+), 4 deletions(-)
create mode 100644 changelog/fix-test-support-phone
diff --git a/changelog/fix-test-support-phone b/changelog/fix-test-support-phone
new file mode 100644
index 00000000000..97abae072f7
--- /dev/null
+++ b/changelog/fix-test-support-phone
@@ -0,0 +1,5 @@
+Significance: patch
+Type: fix
+Comment: Modified the test phone numbers supported by Stripe.
+
+
diff --git a/client/settings/support-phone-input/index.js b/client/settings/support-phone-input/index.js
index 28a3015e747..4a9259b62d4 100644
--- a/client/settings/support-phone-input/index.js
+++ b/client/settings/support-phone-input/index.js
@@ -25,9 +25,7 @@ const SupportPhoneInput = ( { setInputVallid } ) => {
const isEmptyPhoneValid = supportPhone === '' && currentPhone === '';
const isDevModeEnabled = useDevMode();
const isTestPhoneValid =
- isDevModeEnabled &&
- ( supportPhone === '+1000-000-0000' ||
- supportPhone === '+10000000000' );
+ isDevModeEnabled && supportPhone === '+10000000000';
const [ isPhoneValid, setPhoneValidity ] = useState( true );
if ( ! isTestPhoneValid && ! isPhoneValid && ! isEmptyPhoneValid ) {
@@ -53,7 +51,7 @@ const SupportPhoneInput = ( { setInputVallid } ) => {
let labelText = __( 'Support phone number', 'woocommerce-payments' );
if ( isDevModeEnabled ) {
labelText += __(
- ' (+1 000-000-0000 can be used in dev mode)',
+ ' (+1 0000000000 can be used in dev mode)',
'woocommerce-payments'
);
}
From 2e8e90afc05a3cc7657cbb3cbcbc83593cd54a37 Mon Sep 17 00:00:00 2001
From: jessy <32092402+jessy-p@users.noreply.github.com>
Date: Fri, 22 Dec 2023 12:37:38 +0530
Subject: [PATCH 46/56] Display a Confirmation Modal before enabling Test Mode
(#7931)
Co-authored-by: Jessy
---
changelog/add-7846-test-mode-confirm-modal | 4 ++
client/settings/general-settings/index.js | 23 ++++++-
.../test-mode-confirm-modal.tsx | 63 +++++++++++++++++++
.../test/general-settings.test.js | 39 ++++++++++++
.../test/test-mode-confirm-modal.test.js | 50 +++++++++++++++
5 files changed, 178 insertions(+), 1 deletion(-)
create mode 100644 changelog/add-7846-test-mode-confirm-modal
create mode 100644 client/settings/general-settings/test-mode-confirm-modal.tsx
create mode 100644 client/settings/general-settings/test/test-mode-confirm-modal.test.js
diff --git a/changelog/add-7846-test-mode-confirm-modal b/changelog/add-7846-test-mode-confirm-modal
new file mode 100644
index 00000000000..0725c55b1aa
--- /dev/null
+++ b/changelog/add-7846-test-mode-confirm-modal
@@ -0,0 +1,4 @@
+Significance: minor
+Type: add
+
+Display a Confirmaton Modal on enabling Test Mode
diff --git a/client/settings/general-settings/index.js b/client/settings/general-settings/index.js
index 23512d7a66c..b85e9e07632 100644
--- a/client/settings/general-settings/index.js
+++ b/client/settings/general-settings/index.js
@@ -13,12 +13,14 @@ import { useDevMode, useIsWCPayEnabled, useTestMode } from 'wcpay/data';
import CardBody from '../card-body';
import InlineNotice from 'wcpay/components/inline-notice';
import SetupLivePaymentsModal from 'wcpay/overview/modal/setup-live-payments';
+import TestModeConfirmationModal from './test-mode-confirm-modal';
const GeneralSettings = () => {
const [ isWCPayEnabled, setIsWCPayEnabled ] = useIsWCPayEnabled();
const [ isEnabled, updateIsTestModeEnabled ] = useTestMode();
const [ modalVisible, setModalVisible ] = useState( false );
const isDevModeEnabled = useDevMode();
+ const [ testModeModalVisible, setTestModeModalVisible ] = useState( false );
return (
<>
@@ -48,7 +50,15 @@ const GeneralSettings = () => {
{
+ if ( enableTestMode ) {
+ setTestModeModalVisible( true );
+ } else {
+ updateIsTestModeEnabled(
+ enableTestMode
+ );
+ }
+ } }
label={ __(
'Enable test mode',
'woocommerce-payments'
@@ -133,6 +143,17 @@ const GeneralSettings = () => {
closeModal={ () => setModalVisible( false ) }
/>
) }
+ { testModeModalVisible && (
+ {
+ setTestModeModalVisible( false );
+ } }
+ onConfirm={ () => {
+ updateIsTestModeEnabled( true );
+ setTestModeModalVisible( false );
+ } }
+ />
+ ) }
>
);
};
diff --git a/client/settings/general-settings/test-mode-confirm-modal.tsx b/client/settings/general-settings/test-mode-confirm-modal.tsx
new file mode 100644
index 00000000000..21e62af1ac8
--- /dev/null
+++ b/client/settings/general-settings/test-mode-confirm-modal.tsx
@@ -0,0 +1,63 @@
+/** @format **/
+
+/**
+ * External dependencies
+ */
+import React from 'react';
+import { Button, ExternalLink } from '@wordpress/components';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies
+ */
+import ConfirmationModal from '../../components/confirmation-modal';
+
+interface TestModeConfirmationModalProps {
+ onClose: () => void;
+ onConfirm: () => void;
+}
+
+const TestModeConfirmationModal: React.FC< TestModeConfirmationModalProps > = ( {
+ onClose,
+ onConfirm,
+} ) => {
+ return (
+
+
+ { __( 'Cancel', 'woocommerce-payments' ) }
+
+
+ { __( 'Enable', 'woocommerce-payments' ) }
+
+ >
+ }
+ >
+
+ { __(
+ 'Are you sure you want to enable test mode?',
+ 'woocommerce-payments'
+ ) }
+
+
+ { __(
+ "Test mode lets you try out payments, refunds, disputes and other such processes as you're working on your store " +
+ 'without handling live payment information. ' +
+ 'All incoming orders will be simulated, and test mode will have to be disabled before you can accept real orders.',
+ 'woocommerce-payments'
+ ) }
+
+
+ { __( 'Learn more about test mode', 'woocommerce-payments' ) }
+
+
+ );
+};
+
+export default TestModeConfirmationModal;
diff --git a/client/settings/general-settings/test/general-settings.test.js b/client/settings/general-settings/test/general-settings.test.js
index 93f27d56b2a..2e9ae53fcf6 100644
--- a/client/settings/general-settings/test/general-settings.test.js
+++ b/client/settings/general-settings/test/general-settings.test.js
@@ -71,4 +71,43 @@ describe( 'GeneralSettings', () => {
);
}
);
+
+ it.each( [ [ true ], [ false ] ] )(
+ 'display of CheckBox when initial Test Mode = %s',
+ ( isEnabled ) => {
+ useTestMode.mockReturnValue( [ isEnabled, jest.fn() ] );
+ render( );
+ const enableTestModeCheckbox = screen.getByLabelText(
+ 'Enable test mode'
+ );
+
+ let expectation = expect( enableTestModeCheckbox );
+ if ( ! isEnabled ) {
+ expectation = expectation.not;
+ }
+ expectation.toBeChecked();
+ }
+ );
+
+ it.each( [ [ true ], [ false ] ] )(
+ 'Checks Confirmation Modal display when initial Test Mode = %s',
+ ( isEnabled ) => {
+ useTestMode.mockReturnValue( [ isEnabled, jest.fn() ] );
+ render( );
+ const enableTestModeCheckbox = screen.getByLabelText(
+ 'Enable test mode'
+ );
+ fireEvent.click( enableTestModeCheckbox );
+
+ let expectation = expect(
+ screen.queryByText(
+ 'Are you sure you want to enable test mode?'
+ )
+ );
+ if ( isEnabled ) {
+ expectation = expectation.not;
+ }
+ expectation.toBeInTheDocument();
+ }
+ );
} );
diff --git a/client/settings/general-settings/test/test-mode-confirm-modal.test.js b/client/settings/general-settings/test/test-mode-confirm-modal.test.js
new file mode 100644
index 00000000000..df247142d81
--- /dev/null
+++ b/client/settings/general-settings/test/test-mode-confirm-modal.test.js
@@ -0,0 +1,50 @@
+/** @format */
+
+/**
+ * External dependencies
+ */
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import user from '@testing-library/user-event';
+
+/**
+ * Internal dependencies
+ */
+import TestModeConfirmationModal from '../test-mode-confirm-modal';
+
+const mockOnClose = jest.fn();
+const mockOnConfirm = jest.fn();
+
+describe( 'Dev Mode Confirmation Modal', () => {
+ const renderTestModeConfirmationModal = () => {
+ return render(
+
+ );
+ };
+
+ it( 'Dev mode confirmation modal asks confirmation', () => {
+ renderTestModeConfirmationModal();
+ expect(
+ screen.queryByText( 'Are you sure you want to enable test mode?' )
+ ).toBeInTheDocument();
+ } );
+
+ it( 'triggers the onClose function on close button click', () => {
+ renderTestModeConfirmationModal();
+ const closeButton = screen.queryByRole( 'button', { name: 'Cancel' } );
+ expect( mockOnClose ).not.toBeCalled();
+ user.click( closeButton );
+ expect( mockOnClose ).toBeCalled();
+ } );
+
+ it( 'triggers the onConfirm function on Enable button click', () => {
+ renderTestModeConfirmationModal();
+ const enableButton = screen.queryByRole( 'button', { name: 'Enable' } );
+ expect( mockOnConfirm ).not.toBeCalled();
+ user.click( enableButton );
+ expect( mockOnConfirm ).toBeCalled();
+ } );
+} );
From 693bb752414f17aab03525be945d0f42f1ff1df5 Mon Sep 17 00:00:00 2001
From: Timur Karimov
Date: Fri, 22 Dec 2023 15:30:52 +0100
Subject: [PATCH 47/56] Streamline checkout classes (#7869)
Co-authored-by: Timur Karimov
---
changelog/cleanup-upe-checkout-class | 4 +
includes/class-wc-payment-gateway-wcpay.php | 9 -
includes/class-wc-payments-checkout.php | 262 ++++++--
includes/class-wc-payments-upe-checkout.php | 399 ------------
includes/class-wc-payments.php | 8 +-
.../class-upe-payment-gateway.php | 4 +-
.../test-class-upe-payment-gateway.php | 154 +----
.../test-class-upe-split-payment-gateway.php | 466 +-------------
.../test-class-wc-payment-gateway-wcpay.php | 343 +++--------
.../unit/test-class-wc-payments-checkout.php | 569 ++++++++++++++++++
10 files changed, 909 insertions(+), 1309 deletions(-)
create mode 100644 changelog/cleanup-upe-checkout-class
delete mode 100644 includes/class-wc-payments-upe-checkout.php
create mode 100644 tests/unit/test-class-wc-payments-checkout.php
diff --git a/changelog/cleanup-upe-checkout-class b/changelog/cleanup-upe-checkout-class
new file mode 100644
index 00000000000..95cfa040bf5
--- /dev/null
+++ b/changelog/cleanup-upe-checkout-class
@@ -0,0 +1,4 @@
+Significance: minor
+Type: dev
+
+Cleanup the deprecated payment gateway processing - part IV
diff --git a/includes/class-wc-payment-gateway-wcpay.php b/includes/class-wc-payment-gateway-wcpay.php
index 8d21920ac8f..415d9e0a411 100644
--- a/includes/class-wc-payment-gateway-wcpay.php
+++ b/includes/class-wc-payment-gateway-wcpay.php
@@ -725,15 +725,6 @@ public function should_use_stripe_platform_on_checkout_page() {
return false;
}
- /**
- * Renders the credit card input fields needed to get the user's payment information on the checkout page.
- *
- * We also add the JavaScript which drives the UI.
- */
- public function payment_fields() {
- do_action( 'wc_payments_add_payment_fields' );
- }
-
/**
* Checks whether the new payment process should be used to pay for a given order.
*
diff --git a/includes/class-wc-payments-checkout.php b/includes/class-wc-payments-checkout.php
index 18198308323..9851a2ea0c2 100644
--- a/includes/class-wc-payments-checkout.php
+++ b/includes/class-wc-payments-checkout.php
@@ -7,18 +7,21 @@
namespace WCPay;
+use Exception;
use Jetpack_Options;
use WC_AJAX;
use WC_Checkout;
-use WC_Payment_Gateway_WCPay;
use WC_Payments;
use WC_Payments_Account;
use WC_Payments_Customer_Service;
-use WC_Payments_Features;
use WC_Payments_Fraud_Service;
use WC_Payments_Utils;
+use WC_Payments_Features;
+use WCPay\Constants\Payment_Method;
use WCPay\Fraud_Prevention\Fraud_Prevention_Service;
+use WCPay\Payment_Methods\UPE_Payment_Gateway;
use WCPay\WooPay\WooPay_Utilities;
+use WCPay\Payment_Methods\UPE_Payment_Method;
/**
@@ -29,7 +32,7 @@ class WC_Payments_Checkout {
/**
* WC Payments Gateway.
*
- * @var WC_Payment_Gateway_WCPay
+ * @var UPE_Payment_Gateway
*/
protected $gateway;
@@ -64,14 +67,14 @@ class WC_Payments_Checkout {
/**
* Construct.
*
- * @param WC_Payment_Gateway_WCPay $gateway WC Payment Gateway.
- * @param WooPay_Utilities $woopay_util WooPay Utilities.
- * @param WC_Payments_Account $account WC Payments Account.
- * @param WC_Payments_Customer_Service $customer_service WC Payments Customer Service.
- * @param WC_Payments_Fraud_Service $fraud_service Fraud service instance.
+ * @param UPE_Payment_Gateway $gateway WC Payment Gateway.
+ * @param WooPay_Utilities $woopay_util WooPay Utilities.
+ * @param WC_Payments_Account $account WC Payments Account.
+ * @param WC_Payments_Customer_Service $customer_service WC Payments Customer Service.
+ * @param WC_Payments_Fraud_Service $fraud_service Fraud service instance.
*/
public function __construct(
- WC_Payment_Gateway_WCPay $gateway,
+ UPE_Payment_Gateway $gateway,
WooPay_Utilities $woopay_util,
WC_Payments_Account $account,
WC_Payments_Customer_Service $customer_service,
@@ -90,16 +93,51 @@ public function __construct(
* @return void
*/
public function init_hooks() {
- add_action( 'wc_payments_add_payment_fields', [ $this, 'payment_fields' ] );
+ add_action( 'wc_payments_set_gateway', [ $this, 'set_gateway' ] );
+ add_action( 'wc_payments_add_upe_payment_fields', [ $this, 'payment_fields' ] );
+ add_action( 'woocommerce_after_account_payment_methods', [ $this->gateway, 'remove_upe_setup_intent_from_session' ], 10, 0 );
+ add_action( 'woocommerce_subscription_payment_method_updated', [ $this->gateway, 'remove_upe_setup_intent_from_session' ], 10, 0 );
+ add_action( 'woocommerce_order_payment_status_changed', [ get_class( $this->gateway ), 'remove_upe_payment_intent_from_session' ], 10, 0 );
+ add_action( 'wp', [ $this->gateway, 'maybe_process_upe_redirect' ] );
+ add_action( 'wc_ajax_wcpay_log_payment_error', [ $this->gateway, 'log_payment_error_ajax' ] );
+ add_action( 'wp_ajax_save_upe_appearance', [ $this->gateway, 'save_upe_appearance_ajax' ] );
+ add_action( 'wp_ajax_nopriv_save_upe_appearance', [ $this->gateway, 'save_upe_appearance_ajax' ] );
+ add_action( 'switch_theme', [ $this->gateway, 'clear_upe_appearance_transient' ] );
+ add_action( 'woocommerce_woocommerce_payments_updated', [ $this->gateway, 'clear_upe_appearance_transient' ] );
+ add_action( 'wc_ajax_wcpay_init_setup_intent', [ $this->gateway, 'init_setup_intent_ajax' ] );
+ add_action( 'wc_ajax_wcpay_log_payment_error', [ $this->gateway, 'log_payment_error_ajax' ] );
+
+ add_action( 'wp_enqueue_scripts', [ $this, 'register_scripts' ] );
add_action( 'wp_enqueue_scripts', [ $this, 'register_scripts_for_zero_order_total' ], 11 );
}
/**
- * Enqueues and localizes WCPay's checkout scripts.
+ * Registers all scripts, necessary for the gateway.
*/
- public function enqueue_payment_scripts() {
- wp_localize_script( 'WCPAY_CHECKOUT', 'wcpayConfig', WC_Payments::get_wc_payments_checkout()->get_payment_fields_js_config() );
- wp_enqueue_script( 'WCPAY_CHECKOUT' );
+ public function register_scripts() {
+ // Register Stripe's JavaScript using the same ID as the Stripe Gateway plugin. This prevents this JS being
+ // loaded twice in the event a site has both plugins enabled. We still run the risk of different plugins
+ // loading different versions however. If Stripe release a v4 of their JavaScript, we could consider
+ // changing the ID to stripe_v4. This would allow older plugins to keep using v3 while we used any new
+ // feature in v4. Stripe have allowed loading of 2 different versions of stripe.js in the past (
+ // https://stripe.com/docs/stripe-js/elements/migrating).
+ wp_register_script(
+ 'stripe',
+ 'https://js.stripe.com/v3/',
+ [],
+ '3.0',
+ true
+ );
+
+ $script_dependencies = [ 'stripe', 'wc-checkout', 'wp-i18n' ];
+
+ if ( $this->gateway->supports( 'tokenization' ) ) {
+ $script_dependencies[] = 'woocommerce-tokenization-form';
+ }
+
+ $script = 'dist/checkout';
+
+ WC_Payments::register_script_with_dependencies( 'wcpay-upe-checkout', $script, $script_dependencies );
}
/**
@@ -132,7 +170,6 @@ public function register_scripts_for_zero_order_total() {
* @return array
*/
public function get_payment_fields_js_config() {
-
// Needed to init the hooks.
WC_Checkout::instance();
@@ -179,11 +216,140 @@ public function get_payment_fields_js_config() {
*
* @param array $js_config The JS config for the payment fields.
*/
- return apply_filters( 'wcpay_payment_fields_js_config', $js_config );
+ $payment_fields = apply_filters( 'wcpay_payment_fields_js_config', $js_config );
+
+ $payment_fields['accountDescriptor'] = $this->gateway->get_account_statement_descriptor();
+ $payment_fields['addPaymentReturnURL'] = wc_get_account_endpoint_url( 'payment-methods' );
+ $payment_fields['gatewayId'] = UPE_Payment_Gateway::GATEWAY_ID;
+ $payment_fields['isCheckout'] = is_checkout();
+ $payment_fields['paymentMethodsConfig'] = $this->get_enabled_payment_method_config();
+ $payment_fields['testMode'] = WC_Payments::mode()->is_test();
+ $payment_fields['upeAppearance'] = get_transient( UPE_Payment_Gateway::UPE_APPEARANCE_TRANSIENT );
+ $payment_fields['wcBlocksUPEAppearance'] = get_transient( UPE_Payment_Gateway::WC_BLOCKS_UPE_APPEARANCE_TRANSIENT );
+ $payment_fields['cartContainsSubscription'] = $this->gateway->is_subscription_item_in_cart();
+ $payment_fields['currency'] = get_woocommerce_currency();
+ $cart_total = ( WC()->cart ? WC()->cart->get_total( '' ) : 0 );
+ $payment_fields['cartTotal'] = WC_Payments_Utils::prepare_amount( $cart_total, get_woocommerce_currency() );
+
+ $enabled_billing_fields = [];
+ foreach ( WC()->checkout()->get_checkout_fields( 'billing' ) as $billing_field => $billing_field_options ) {
+ if ( ! isset( $billing_field_options['enabled'] ) || $billing_field_options['enabled'] ) {
+ $enabled_billing_fields[] = $billing_field;
+ }
+ }
+ $payment_fields['enabledBillingFields'] = $enabled_billing_fields;
+
+ if ( is_wc_endpoint_url( 'order-pay' ) ) {
+ if ( $this->gateway->is_subscriptions_enabled() && $this->gateway->is_changing_payment_method_for_subscription() ) {
+ $payment_fields['isChangingPayment'] = true;
+ $payment_fields['addPaymentReturnURL'] = esc_url_raw( home_url( add_query_arg( [] ) ) );
+
+ if ( $this->gateway->is_setup_intent_success_creation_redirection() && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( wc_clean( wp_unslash( $_GET['_wpnonce'] ) ) ) ) {
+ $setup_intent_id = isset( $_GET['setup_intent'] ) ? wc_clean( wp_unslash( $_GET['setup_intent'] ) ) : '';
+ $token = $this->gateway->create_token_from_setup_intent( $setup_intent_id, wp_get_current_user() );
+ if ( null !== $token ) {
+ $payment_fields['newTokenFormId'] = '#wc-' . $token->get_gateway_id() . '-payment-token-' . $token->get_id();
+ }
+ }
+ return $payment_fields; // nosemgrep: audit.php.wp.security.xss.query-arg -- server generated url is passed in.
+ }
+
+ $payment_fields['isOrderPay'] = true;
+ $order_id = absint( get_query_var( 'order-pay' ) );
+ $payment_fields['orderId'] = $order_id;
+ $order = wc_get_order( $order_id );
+
+ if ( is_a( $order, 'WC_Order' ) ) {
+ $order_currency = $order->get_currency();
+ $payment_fields['currency'] = $order_currency;
+ $payment_fields['cartTotal'] = WC_Payments_Utils::prepare_amount( $order->get_total(), $order_currency );
+ $payment_fields['orderReturnURL'] = esc_url_raw(
+ add_query_arg(
+ [
+ 'wc_payment_method' => UPE_Payment_Gateway::GATEWAY_ID,
+ '_wpnonce' => wp_create_nonce( 'wcpay_process_redirect_order_nonce' ),
+ ],
+ $this->gateway->get_return_url( $order )
+ )
+ );
+ }
+ }
+
+ /**
+ * Allows filtering for the payment fields.
+ *
+ * @param array $payment_fields The payment fields.
+ */
+ return apply_filters( 'wcpay_payment_fields_js_config', $payment_fields ); // nosemgrep: audit.php.wp.security.xss.query-arg -- server generated url is passed in.
}
/**
- * Renders the credit card input fields needed to get the user's payment information on the checkout page.
+ * Checks if WooPay is enabled.
+ *
+ * @return bool - True if WooPay enabled, false otherwise.
+ */
+ private function is_woopay_enabled() {
+ return WC_Payments_Features::is_woopay_eligible() && 'yes' === $this->gateway->get_option( 'platform_checkout', 'no' ) && WC_Payments_Features::is_woopay_express_checkout_enabled();
+ }
+
+ /**
+ * Gets payment method settings to pass to client scripts
+ *
+ * @return array
+ */
+ public function get_enabled_payment_method_config() {
+ $settings = [];
+ $enabled_payment_methods = $this->gateway->get_payment_method_ids_enabled_at_checkout();
+
+ foreach ( $enabled_payment_methods as $payment_method_id ) {
+ // Link by Stripe should be validated with available fees.
+ if ( Payment_Method::LINK === $payment_method_id ) {
+ if ( ! in_array( Payment_Method::LINK, array_keys( $this->account->get_fees() ), true ) ) {
+ continue;
+ }
+ }
+
+ $payment_method = $this->gateway->wc_payments_get_payment_method_by_id( $payment_method_id );
+ $settings[ $payment_method_id ] = [
+ 'isReusable' => $payment_method->is_reusable(),
+ 'title' => $payment_method->get_title(),
+ 'icon' => $payment_method->get_icon(),
+ 'showSaveOption' => $this->should_upe_payment_method_show_save_option( $payment_method ),
+ 'countries' => $payment_method->get_countries(),
+ ];
+
+ $gateway_for_payment_method = $this->gateway->wc_payments_get_payment_gateway_by_id( $payment_method_id );
+ $settings[ $payment_method_id ]['upePaymentIntentData'] = $this->gateway->get_payment_intent_data_from_session( $payment_method_id );
+ $settings[ $payment_method_id ]['upeSetupIntentData'] = $this->gateway->get_setup_intent_data_from_session( $payment_method_id );
+ $settings[ $payment_method_id ]['testingInstructions'] = WC_Payments_Utils::esc_interpolated_html(
+ /* translators: link to Stripe testing page */
+ $payment_method->get_testing_instructions(),
+ [
+ 'strong' => '',
+ 'a' => '',
+ ]
+ );
+ $settings[ $payment_method_id ]['forceNetworkSavedCards'] = $gateway_for_payment_method->should_use_stripe_platform_on_checkout_page();
+ }
+
+ return $settings;
+ }
+
+ /**
+ * Checks if the save option for a payment method should be displayed or not.
+ *
+ * @param UPE_Payment_Method $payment_method UPE Payment Method instance.
+ * @return bool - True if the payment method is reusable and the saved cards feature is enabled for the gateway and there is no subscription item in the cart, false otherwise.
+ */
+ private function should_upe_payment_method_show_save_option( $payment_method ) {
+ if ( $payment_method->is_reusable() ) {
+ return $this->gateway->is_saved_cards_enabled() && ! $this->gateway->is_subscription_item_in_cart();
+ }
+ return false;
+ }
+
+ /**
+ * Renders the UPE input fields needed to get the user's payment information on the checkout page.
*
* We also add the JavaScript which drives the UI.
*/
@@ -191,15 +357,28 @@ public function payment_fields() {
try {
$display_tokenization = $this->gateway->supports( 'tokenization' ) && ( is_checkout() || is_add_payment_method_page() );
- add_action( 'wp_footer', [ $this, 'enqueue_payment_scripts' ] );
+ /**
+ * Localizing scripts within shortcodes does not work in WP 5.9,
+ * but we need `$this->get_payment_fields_js_config` to be called
+ * before `$this->saved_payment_methods()`.
+ */
+ $payment_fields = $this->get_payment_fields_js_config();
+ $upe_object_name = 'wcpay_upe_config';
+ wp_enqueue_script( 'wcpay-upe-checkout' );
+ add_action(
+ 'wp_footer',
+ function() use ( $payment_fields, $upe_object_name ) {
+ wp_localize_script( 'wcpay-upe-checkout', $upe_object_name, $payment_fields );
+ }
+ );
$prepared_customer_data = $this->customer_service->get_prepared_customer_data();
if ( ! empty( $prepared_customer_data ) ) {
- wp_localize_script( 'WCPAY_CHECKOUT', 'wcpayCustomerData', $prepared_customer_data );
+ wp_localize_script( 'wcpay-upe-checkout', 'wcpayCustomerData', $prepared_customer_data );
}
WC_Payments_Utils::enqueue_style(
- 'WCPAY_CHECKOUT',
+ 'wcpay-upe-checkout',
plugins_url( 'dist/checkout.css', WCPAY_PLUGIN_FILE ),
[],
WC_Payments::get_file_version( 'dist/checkout.css' ),
@@ -215,14 +394,17 @@ public function payment_fields() {
is_test() ) : ?>
Test mode:
use the test VISA card 4242424242424242 with any expiry date and CVC, or any test card numbers listed here .', 'woocommerce-payments' ),
- [
- 'strong' => '',
- 'a' => '',
- ]
- );
+ $testing_instructions = $this->gateway->get_payment_method()->get_testing_instructions();
+ if ( false !== $testing_instructions ) {
+ echo WC_Payments_Utils::esc_interpolated_html(
+ /* translators: link to Stripe testing page */
+ $testing_instructions,
+ [
+ 'strong' => '',
+ 'a' => '',
+ ]
+ );
+ }
?>
@@ -238,13 +420,10 @@ public function payment_fields() {
}
?>
-
-
-
-
-
+
gateway->is_saved_cards_enabled() ) {
+ $this->gateway->display_gateway_html();
+ if ( $this->gateway->is_saved_cards_enabled() && $this->gateway->should_support_saved_payments() ) {
$force_save_payment = ( $display_tokenization && ! apply_filters( 'wc_payments_display_save_payment_method_checkbox', $display_tokenization ) ) || is_add_payment_method_page();
if ( is_user_logged_in() || $force_save_payment ) {
$this->gateway->save_payment_method_checkbox( $force_save_payment );
@@ -260,10 +439,11 @@ public function payment_fields() {
gateway->id );
+ do_action( 'wcpay_payment_fields_upe', $this->gateway->id );
} catch ( \Exception $e ) {
// Output the error message.
+ Logger::log( 'Error: ' . $e->getMessage() );
?>
gateway = $this->gateway->wc_payments_get_payment_gateway_by_id( $payment_method_id );
+ }
+ }
+
}
diff --git a/includes/class-wc-payments-upe-checkout.php b/includes/class-wc-payments-upe-checkout.php
deleted file mode 100644
index 4096b0d068d..00000000000
--- a/includes/class-wc-payments-upe-checkout.php
+++ /dev/null
@@ -1,399 +0,0 @@
-gateway = $gateway;
- $this->woopay_util = $woopay_util;
- $this->account = $account;
- $this->customer_service = $customer_service;
- $this->fraud_service = $fraud_service;
- }
-
- /**
- * Initializes this class's WP hooks.
- *
- * @return void
- */
- public function init_hooks() {
- add_action( 'wc_payments_set_gateway', [ $this, 'set_gateway' ] );
- add_action( 'wc_payments_add_upe_payment_fields', [ $this, 'payment_fields' ] );
- add_action( 'woocommerce_after_account_payment_methods', [ $this->gateway, 'remove_upe_setup_intent_from_session' ], 10, 0 );
- add_action( 'woocommerce_subscription_payment_method_updated', [ $this->gateway, 'remove_upe_setup_intent_from_session' ], 10, 0 );
- add_action( 'woocommerce_order_payment_status_changed', [ get_class( $this->gateway ), 'remove_upe_payment_intent_from_session' ], 10, 0 );
- add_action( 'wp', [ $this->gateway, 'maybe_process_upe_redirect' ] );
- add_action( 'wc_ajax_wcpay_log_payment_error', [ $this->gateway, 'log_payment_error_ajax' ] );
- add_action( 'wp_ajax_save_upe_appearance', [ $this->gateway, 'save_upe_appearance_ajax' ] );
- add_action( 'wp_ajax_nopriv_save_upe_appearance', [ $this->gateway, 'save_upe_appearance_ajax' ] );
- add_action( 'switch_theme', [ $this->gateway, 'clear_upe_appearance_transient' ] );
- add_action( 'woocommerce_woocommerce_payments_updated', [ $this->gateway, 'clear_upe_appearance_transient' ] );
- add_action( 'wc_ajax_wcpay_init_setup_intent', [ $this->gateway, 'init_setup_intent_ajax' ] );
- add_action( 'wc_ajax_wcpay_log_payment_error', [ $this->gateway, 'log_payment_error_ajax' ] );
-
- add_action( 'wp_enqueue_scripts', [ $this, 'register_scripts' ] );
- add_action( 'wp_enqueue_scripts', [ $this, 'register_scripts_for_zero_order_total' ], 11 );
- }
-
- /**
- * Registers all scripts, necessary for the gateway.
- */
- public function register_scripts() {
- // Register Stripe's JavaScript using the same ID as the Stripe Gateway plugin. This prevents this JS being
- // loaded twice in the event a site has both plugins enabled. We still run the risk of different plugins
- // loading different versions however. If Stripe release a v4 of their JavaScript, we could consider
- // changing the ID to stripe_v4. This would allow older plugins to keep using v3 while we used any new
- // feature in v4. Stripe have allowed loading of 2 different versions of stripe.js in the past (
- // https://stripe.com/docs/stripe-js/elements/migrating).
- wp_register_script(
- 'stripe',
- 'https://js.stripe.com/v3/',
- [],
- '3.0',
- true
- );
-
- $script_dependencies = [ 'stripe', 'wc-checkout', 'wp-i18n' ];
-
- if ( $this->gateway->supports( 'tokenization' ) ) {
- $script_dependencies[] = 'woocommerce-tokenization-form';
- }
-
- $script = 'dist/checkout';
-
- WC_Payments::register_script_with_dependencies( 'wcpay-upe-checkout', $script, $script_dependencies );
- }
-
- /**
- * Generates the configuration values, needed for payment fields.
- *
- * Isolated as a separate method in order to be available both
- * during the classic checkout, as well as the checkout block.
- *
- * @return array
- */
- public function get_payment_fields_js_config() {
-
- $payment_fields = parent::get_payment_fields_js_config();
- $payment_fields['accountDescriptor'] = $this->gateway->get_account_statement_descriptor();
- $payment_fields['addPaymentReturnURL'] = wc_get_account_endpoint_url( 'payment-methods' );
- $payment_fields['gatewayId'] = UPE_Payment_Gateway::GATEWAY_ID;
- $payment_fields['isCheckout'] = is_checkout();
- $payment_fields['paymentMethodsConfig'] = $this->get_enabled_payment_method_config();
- $payment_fields['testMode'] = WC_Payments::mode()->is_test();
- $payment_fields['upeAppearance'] = get_transient( UPE_Payment_Gateway::UPE_APPEARANCE_TRANSIENT );
- $payment_fields['wcBlocksUPEAppearance'] = get_transient( UPE_Payment_Gateway::WC_BLOCKS_UPE_APPEARANCE_TRANSIENT );
- $payment_fields['cartContainsSubscription'] = $this->gateway->is_subscription_item_in_cart();
- $payment_fields['currency'] = get_woocommerce_currency();
- $cart_total = ( WC()->cart ? WC()->cart->get_total( '' ) : 0 );
- $payment_fields['cartTotal'] = WC_Payments_Utils::prepare_amount( $cart_total, get_woocommerce_currency() );
-
- $enabled_billing_fields = [];
- foreach ( WC()->checkout()->get_checkout_fields( 'billing' ) as $billing_field => $billing_field_options ) {
- if ( ! isset( $billing_field_options['enabled'] ) || $billing_field_options['enabled'] ) {
- $enabled_billing_fields[] = $billing_field;
- }
- }
- $payment_fields['enabledBillingFields'] = $enabled_billing_fields;
-
- if ( is_wc_endpoint_url( 'order-pay' ) ) {
- if ( $this->gateway->is_subscriptions_enabled() && $this->gateway->is_changing_payment_method_for_subscription() ) {
- $payment_fields['isChangingPayment'] = true;
- $payment_fields['addPaymentReturnURL'] = esc_url_raw( home_url( add_query_arg( [] ) ) );
-
- if ( $this->gateway->is_setup_intent_success_creation_redirection() && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( wc_clean( wp_unslash( $_GET['_wpnonce'] ) ) ) ) {
- $setup_intent_id = isset( $_GET['setup_intent'] ) ? wc_clean( wp_unslash( $_GET['setup_intent'] ) ) : '';
- $token = $this->gateway->create_token_from_setup_intent( $setup_intent_id, wp_get_current_user() );
- if ( null !== $token ) {
- $payment_fields['newTokenFormId'] = '#wc-' . $token->get_gateway_id() . '-payment-token-' . $token->get_id();
- }
- }
- return $payment_fields; // nosemgrep: audit.php.wp.security.xss.query-arg -- server generated url is passed in.
- }
-
- $payment_fields['isOrderPay'] = true;
- $order_id = absint( get_query_var( 'order-pay' ) );
- $payment_fields['orderId'] = $order_id;
- $order = wc_get_order( $order_id );
-
- if ( is_a( $order, 'WC_Order' ) ) {
- $order_currency = $order->get_currency();
- $payment_fields['currency'] = $order_currency;
- $payment_fields['cartTotal'] = WC_Payments_Utils::prepare_amount( $order->get_total(), $order_currency );
- $payment_fields['orderReturnURL'] = esc_url_raw(
- add_query_arg(
- [
- 'wc_payment_method' => UPE_Payment_Gateway::GATEWAY_ID,
- '_wpnonce' => wp_create_nonce( 'wcpay_process_redirect_order_nonce' ),
- ],
- $this->gateway->get_return_url( $order )
- )
- );
- }
- }
-
- /**
- * Allows filtering for the payment fields.
- *
- * @param array $payment_fields The payment fields.
- */
- return apply_filters( 'wcpay_payment_fields_js_config', $payment_fields ); // nosemgrep: audit.php.wp.security.xss.query-arg -- server generated url is passed in.
- }
-
- /**
- * Checks if WooPay is enabled.
- *
- * @return bool - True if WooPay enabled, false otherwise.
- */
- private function is_woopay_enabled() {
- return WC_Payments_Features::is_woopay_eligible() && 'yes' === $this->gateway->get_option( 'platform_checkout', 'no' ) && WC_Payments_Features::is_woopay_express_checkout_enabled();
- }
-
- /**
- * Gets payment method settings to pass to client scripts
- *
- * @return array
- */
- public function get_enabled_payment_method_config() {
- $settings = [];
- $enabled_payment_methods = $this->gateway->get_payment_method_ids_enabled_at_checkout();
-
- foreach ( $enabled_payment_methods as $payment_method_id ) {
- // Link by Stripe should be validated with available fees.
- if ( Payment_Method::LINK === $payment_method_id ) {
- if ( ! in_array( Payment_Method::LINK, array_keys( $this->account->get_fees() ), true ) ) {
- continue;
- }
- }
-
- $payment_method = $this->gateway->wc_payments_get_payment_method_by_id( $payment_method_id );
- $settings[ $payment_method_id ] = [
- 'isReusable' => $payment_method->is_reusable(),
- 'title' => $payment_method->get_title(),
- 'icon' => $payment_method->get_icon(),
- 'showSaveOption' => $this->should_upe_payment_method_show_save_option( $payment_method ),
- 'countries' => $payment_method->get_countries(),
- ];
-
- $gateway_for_payment_method = $this->gateway->wc_payments_get_payment_gateway_by_id( $payment_method_id );
- $settings[ $payment_method_id ]['upePaymentIntentData'] = $this->gateway->get_payment_intent_data_from_session( $payment_method_id );
- $settings[ $payment_method_id ]['upeSetupIntentData'] = $this->gateway->get_setup_intent_data_from_session( $payment_method_id );
- $settings[ $payment_method_id ]['testingInstructions'] = WC_Payments_Utils::esc_interpolated_html(
- /* translators: link to Stripe testing page */
- $payment_method->get_testing_instructions(),
- [
- 'strong' => '
',
- 'a' => '',
- ]
- );
- $settings[ $payment_method_id ]['forceNetworkSavedCards'] = $gateway_for_payment_method->should_use_stripe_platform_on_checkout_page();
- }
-
- return $settings;
- }
-
- /**
- * Checks if the save option for a payment method should be displayed or not.
- *
- * @param UPE_Payment_Method $payment_method UPE Payment Method instance.
- * @return bool - True if the payment method is reusable and the saved cards feature is enabled for the gateway and there is no subscription item in the cart, false otherwise.
- */
- private function should_upe_payment_method_show_save_option( $payment_method ) {
- if ( $payment_method->is_reusable() ) {
- return $this->gateway->is_saved_cards_enabled() && ! $this->gateway->is_subscription_item_in_cart();
- }
- return false;
- }
-
- /**
- * Renders the UPE input fields needed to get the user's payment information on the checkout page.
- *
- * We also add the JavaScript which drives the UI.
- */
- public function payment_fields() {
- try {
- $display_tokenization = $this->gateway->supports( 'tokenization' ) && ( is_checkout() || is_add_payment_method_page() );
-
- /**
- * Localizing scripts within shortcodes does not work in WP 5.9,
- * but we need `$this->get_payment_fields_js_config` to be called
- * before `$this->saved_payment_methods()`.
- */
- $payment_fields = $this->get_payment_fields_js_config();
- $upe_object_name = 'wcpay_upe_config';
- wp_enqueue_script( 'wcpay-upe-checkout' );
- add_action(
- 'wp_footer',
- function() use ( $payment_fields, $upe_object_name ) {
- wp_localize_script( 'wcpay-upe-checkout', $upe_object_name, $payment_fields );
- }
- );
-
- $prepared_customer_data = $this->customer_service->get_prepared_customer_data();
- if ( ! empty( $prepared_customer_data ) ) {
- wp_localize_script( 'wcpay-upe-checkout', 'wcpayCustomerData', $prepared_customer_data );
- }
-
- WC_Payments_Utils::enqueue_style(
- 'wcpay-upe-checkout',
- plugins_url( 'dist/checkout.css', WCPAY_PLUGIN_FILE ),
- [],
- WC_Payments::get_file_version( 'dist/checkout.css' ),
- 'all'
- );
-
- // Output the form HTML.
- ?>
- gateway->get_description() ) ) : ?>
- gateway->get_description() ); ?>
-
-
- is_test() ) : ?>
-
- gateway->get_payment_method()->get_testing_instructions();
- if ( false !== $testing_instructions ) {
- echo WC_Payments_Utils::esc_interpolated_html(
- /* translators: link to Stripe testing page */
- $testing_instructions,
- [
- 'strong' => '',
- 'a' => '',
- ]
- );
- }
- ?>
-
-
-
- gateway->tokenization_script();
- // avoid showing saved payment methods on my-accounts add payment method page.
- if ( ! is_add_payment_method_page() ) {
- $this->gateway->saved_payment_methods();
- }
- }
- ?>
-
-
- gateway->display_gateway_html();
- if ( $this->gateway->is_saved_cards_enabled() && $this->gateway->should_support_saved_payments() ) {
- $force_save_payment = ( $display_tokenization && ! apply_filters( 'wc_payments_display_save_payment_method_checkbox', $display_tokenization ) ) || is_add_payment_method_page();
- if ( is_user_logged_in() || $force_save_payment ) {
- $this->gateway->save_payment_method_checkbox( $force_save_payment );
- }
- }
- ?>
-
-
-
- session && Fraud_Prevention_Service::get_instance()->is_enabled() ) : ?>
-
-
-
- gateway->id );
-
- } catch ( \Exception $e ) {
- // Output the error message.
- Logger::log( 'Error: ' . $e->getMessage() );
- ?>
-
-
-
- gateway = $this->gateway->wc_payments_get_payment_gateway_by_id( $payment_method_id );
- }
- }
-
-}
diff --git a/includes/class-wc-payments.php b/includes/class-wc-payments.php
index 006f2deef2a..baf1ea9a8ca 100644
--- a/includes/class-wc-payments.php
+++ b/includes/class-wc-payments.php
@@ -35,7 +35,6 @@
use WCPay\Session_Rate_Limiter;
use WCPay\Database_Cache;
use WCPay\WC_Payments_Checkout;
-use WCPay\WC_Payments_UPE_Checkout;
use WCPay\WooPay\Service\Checkout_Service;
use WCPay\Core\WC_Payments_Customer_Service_API;
use WCPay\Constants\Payment_Method;
@@ -264,7 +263,7 @@ class WC_Payments {
/**
* WC Payments Checkout
*
- * @var WC_Payments_Checkout|WC_Payments_UPE_Checkout
+ * @var WC_Payments_Checkout
*/
private static $wc_payments_checkout;
@@ -399,7 +398,6 @@ public static function init() {
include_once __DIR__ . '/class-session-rate-limiter.php';
include_once __DIR__ . '/class-wc-payment-gateway-wcpay.php';
include_once __DIR__ . '/class-wc-payments-checkout.php';
- include_once __DIR__ . '/class-wc-payments-upe-checkout.php';
include_once __DIR__ . '/payment-methods/class-cc-payment-gateway.php';
include_once __DIR__ . '/payment-methods/class-upe-payment-gateway.php';
include_once __DIR__ . '/payment-methods/class-upe-split-payment-gateway.php';
@@ -555,7 +553,7 @@ public static function init() {
}
self::$card_gateway = self::get_payment_gateway_by_id( 'card' );
- self::$wc_payments_checkout = new WC_Payments_UPE_Checkout( self::get_gateway(), self::$woopay_util, self::$account, self::$customer_service, self::$fraud_service );
+ self::$wc_payments_checkout = new WC_Payments_Checkout( self::get_gateway(), self::$woopay_util, self::$account, self::$customer_service, self::$fraud_service );
self::$card_gateway->init_hooks();
self::$wc_payments_checkout->init_hooks();
@@ -1191,7 +1189,7 @@ public static function get_gateway() {
/**
* Returns the WC_Payments_Checkout instance
*
- * @return WC_Payments_Checkout|WC_Payments_UPE_Checkout gateway instance
+ * @return WC_Payments_Checkout gateway instance
*/
public static function get_wc_payments_checkout() {
return self::$wc_payments_checkout;
diff --git a/includes/payment-methods/class-upe-payment-gateway.php b/includes/payment-methods/class-upe-payment-gateway.php
index a8cfbbfced1..b1ba28589b6 100644
--- a/includes/payment-methods/class-upe-payment-gateway.php
+++ b/includes/payment-methods/class-upe-payment-gateway.php
@@ -854,7 +854,7 @@ public function is_proper_intent_used_with_order( $order, $intent_id_from_reques
* @return array
*/
public function get_payment_fields_js_config() {
- wc_deprecated_function( __FUNCTION__, '5.0.0', 'WC_Payments_UPE_Checkout::get_payment_fields_js_config' );
+ wc_deprecated_function( __FUNCTION__, '5.0.0', 'WC_Payments_Checkout::get_payment_fields_js_config' );
return WC_Payments::get_wc_payments_checkout()->get_payment_fields_js_config();
}
@@ -1111,7 +1111,7 @@ private function validate_order_id_received_vs_intent_meta_order_id( WC_Order $o
* @return array
*/
private function get_enabled_payment_method_config() {
- wc_deprecated_function( __FUNCTION__, '5.0.0', 'WC_Payments_UPE_Checkout::get_enabled_payment_method_config' );
+ wc_deprecated_function( __FUNCTION__, '5.0.0', 'WC_Payments_Checkout::get_enabled_payment_method_config' );
return WC_Payments::get_wc_payments_checkout()->get_enabled_payment_method_config();
}
diff --git a/tests/unit/payment-methods/test-class-upe-payment-gateway.php b/tests/unit/payment-methods/test-class-upe-payment-gateway.php
index 7ca31052a47..fded27349c0 100644
--- a/tests/unit/payment-methods/test-class-upe-payment-gateway.php
+++ b/tests/unit/payment-methods/test-class-upe-payment-gateway.php
@@ -21,7 +21,6 @@
use WCPay\Exceptions\Process_Payment_Exception;
use WCPay\WooPay\WooPay_Utilities;
use WCPay\Session_Rate_Limiter;
-use WCPay\WC_Payments_UPE_Checkout;
use WCPAY_UnitTestCase;
use WC_Helper_Order;
use WC_Helper_Intention;
@@ -345,23 +344,9 @@ public function tear_down() {
wcpay_get_test_container()->reset_all_replacements();
}
- public function test_payment_fields_outputs_fields() {
- $this->set_cart_contains_subscription_items( false );
- $this->set_get_upe_enabled_payment_method_statuses_return_value();
-
- // Add the UPE Checkout action.
- $checkout = new WC_Payments_UPE_Checkout(
- $this->mock_upe_gateway,
- $this->mock_woopay_utilities,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_fraud_service
- );
- $checkout->init_hooks();
-
- $this->mock_upe_gateway->payment_fields();
-
+ public function test_display_gateway_html() {
$this->expectOutputRegex( '/<\/div>/' );
+ $this->mock_upe_gateway->display_gateway_html();
}
public function test_update_payment_intent_adds_customer_save_payment_and_level3_data() {
@@ -1799,145 +1784,16 @@ function( $argument ) {
}
public function test_remove_link_payment_method_if_card_disabled() {
+ $this->mock_upe_gateway->settings['upe_enabled_payment_method_ids'] = [ 'link' ];
- $mock_upe_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class )
- ->setConstructorArgs(
- [
- $this->mock_api_client,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_token_service,
- $this->mock_action_scheduler_service,
- $this->mock_payment_methods,
- $this->mock_rate_limiter,
- $this->mock_order_service,
- $this->mock_dpps,
- $this->mock_localization_service,
- $this->mock_fraud_service,
- ]
- )
- ->setMethods(
- [
- 'get_upe_enabled_payment_method_statuses',
- 'get_upe_enabled_payment_method_ids',
- ]
- )
- ->getMock();
-
- $mock_upe_gateway
- ->expects( $this->once() )
- ->method( 'get_upe_enabled_payment_method_ids' )
- ->will(
- $this->returnValue( [ 'link' ] )
- );
- $mock_upe_gateway
+ $this->mock_upe_gateway
->expects( $this->once() )
->method( 'get_upe_enabled_payment_method_statuses' )
->will(
$this->returnValue( [ 'link_payments' => [ 'status' => 'active' ] ] )
);
- $upe_checkout = new WC_Payments_UPE_Checkout(
- $mock_upe_gateway,
- $this->mock_woopay_utilities,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_fraud_service
- );
-
- $this->assertSame( $upe_checkout->get_payment_fields_js_config()['paymentMethodsConfig'], [] );
- }
-
- public function test_link_payment_method_if_card_enabled() {
- WC_Helper_Site_Currency::$mock_site_currency = 'USD';
-
- $mock_upe_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class )
- ->setConstructorArgs(
- [
- $this->mock_api_client,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_token_service,
- $this->mock_action_scheduler_service,
- $this->mock_payment_methods,
- $this->mock_rate_limiter,
- $this->mock_order_service,
- $this->mock_dpps,
- $this->mock_localization_service,
- $this->mock_fraud_service,
- ]
- )
- ->setMethods(
- [
- 'get_upe_enabled_payment_method_statuses',
- 'get_upe_enabled_payment_method_ids',
- ]
- )
- ->getMock();
- $mock_upe_gateway
- ->expects( $this->once() )
- ->method( 'get_upe_enabled_payment_method_ids' )
- ->will(
- $this->returnValue( [ 'card', 'link' ] )
- );
- $mock_upe_gateway
- ->expects( $this->once() )
- ->method( 'get_upe_enabled_payment_method_statuses' )
- ->will(
- $this->returnValue(
- [
- 'link_payments' => [ 'status' => 'active' ],
- 'card_payments' => [ 'status' => 'active' ],
- ]
- )
- );
-
- $this->mock_payment_methods[ Payment_Method::LINK ]->expects( $this->any() )
- ->method( 'get_icon' )
- ->will(
- $this->returnValue( $this->icon_url )
- );
- $this->mock_payment_methods[ Payment_Method::CARD ]->expects( $this->any() )
- ->method( 'get_icon' )
- ->will(
- $this->returnValue( $this->icon_url )
- );
-
- $upe_checkout = new WC_Payments_UPE_Checkout(
- $mock_upe_gateway,
- $this->mock_woopay_utilities,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_fraud_service
- );
-
- $this->assertSame(
- $upe_checkout->get_payment_fields_js_config()['paymentMethodsConfig'],
- [
- 'card' => [
- 'isReusable' => true,
- 'title' => 'Credit card / debit card',
- 'icon' => $this->icon_url,
- 'showSaveOption' => true,
- 'countries' => [],
- 'upePaymentIntentData' => null,
- 'upeSetupIntentData' => null,
- 'testingInstructions' => '
Test mode: use the test VISA card 4242424242424242 with any expiry date and CVC. Other payment methods may redirect to a Stripe test page to authorize payment. More test card numbers are listed
here .',
- 'forceNetworkSavedCards' => false,
- ],
- 'link' => [
- 'isReusable' => true,
- 'title' => 'Link',
- 'icon' => $this->icon_url,
- 'showSaveOption' => true,
- 'countries' => [],
- 'upePaymentIntentData' => null,
- 'upeSetupIntentData' => null,
- 'testingInstructions' => '',
- 'forceNetworkSavedCards' => false,
- ],
- ]
- );
+ $this->assertSame( $this->mock_upe_gateway->get_payment_method_ids_enabled_at_checkout(), [] );
}
/**
diff --git a/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php b/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php
index 2d6e888229e..40cc78eda7d 100644
--- a/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php
+++ b/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php
@@ -16,7 +16,6 @@
use WCPay\Exceptions\Amount_Too_Small_Exception;
use WCPay\WooPay\WooPay_Utilities;
use WCPay\Session_Rate_Limiter;
-use WCPay\WC_Payments_UPE_Checkout;
use WCPAY_UnitTestCase;
use WC_Helper_Order;
use WC_Helper_Intention;
@@ -34,7 +33,6 @@
use WCPay\Core\Server\Request\Get_Intention;
use WCPay\Core\Server\Request\Update_Intention;
use WCPay\Duplicate_Payment_Prevention_Service;
-use WCPay\WC_Payments_Checkout;
use WCPay\Payment_Information;
use WC_Payments;
use WC_Payments_Localization_Service;
@@ -102,13 +100,6 @@ class UPE_Split_Payment_Gateway_Test extends WCPAY_UnitTestCase {
*/
private $mock_payment_gateways;
- /**
- * WC_Payments_Checkout
- *
- * @var WC_Payments_Checkout|MockObject
- */
- private $mock_legacy_checkout;
-
/**
* WC_Payments_Account instance.
*
@@ -253,10 +244,6 @@ public function set_up() {
->disableOriginalConstructor()
->getMock();
- $this->mock_legacy_checkout = $this->getMockBuilder( WC_Payments_Checkout::class )
- ->disableOriginalConstructor()
- ->getMock();
-
$this->mock_rate_limiter = $this->createMock( Session_Rate_Limiter::class );
$this->order_service = new WC_Payments_Order_Service( $this->mock_api_client );
@@ -373,36 +360,19 @@ public function tear_down() {
*
* @return void
*/
- public function test_payment_fields_outputs_fields() {
- $checkout = new WC_Payments_UPE_Checkout(
- $this->mock_payment_gateways[ Payment_Method::CARD ],
- $this->mock_woopay_utilities,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_fraud_service
- );
- $checkout->init_hooks();
-
- $registered_card_gateway = WC_Payments::get_registered_card_gateway();
- WC_Payments::set_registered_card_gateway( $this->mock_payment_gateways[ Payment_Method::CARD ] );
-
+ public function test_display_gateway_html_for_multiple_gateways() {
foreach ( $this->mock_payment_gateways as $payment_method_id => $mock_payment_gateway ) {
- $mock_payment_gateway
- ->method( 'get_payment_method_ids_enabled_at_checkout' )
- ->willReturn( [] );
/**
* This tests each payment method output separately without concatenating the output
* into 1 single buffer. Each iteration has 1 assertion.
*/
ob_start();
- $mock_payment_gateway->payment_fields();
+ $mock_payment_gateway->display_gateway_html();
$actual_output = ob_get_contents();
ob_end_clean();
$this->assertStringContainsString( '
', $actual_output );
}
-
- WC_Payments::set_registered_card_gateway( $registered_card_gateway );
}
public function test_should_not_use_stripe_platform_on_checkout_page_for_upe() {
@@ -1727,438 +1697,6 @@ public function test_process_payment_caches_mimimum_amount_and_displays_error_up
}
}
- public function test_no_save_option_for_non_sepa_upe() {
- $payment_methods_with_no_save_option = [
- Payment_Method::BANCONTACT,
- Payment_Method::EPS,
- Payment_Method::GIROPAY,
- Payment_Method::IDEAL,
- Payment_Method::P24,
- Payment_Method::SOFORT,
- ];
-
- foreach ( $payment_methods_with_no_save_option as $payment_method ) {
- $mock_upe_gateway = $this->getMockBuilder( UPE_Split_Payment_Gateway::class )
- ->setConstructorArgs(
- [
- $this->mock_api_client,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_token_service,
- $this->mock_action_scheduler_service,
- $this->mock_payment_methods[ $payment_method ],
- $this->mock_payment_methods,
- $this->mock_rate_limiter,
- $this->order_service,
- $this->mock_dpps,
- $this->mock_localization_service,
- $this->mock_fraud_service,
- ]
- )
- ->setMethods(
- [
- 'get_payment_method_ids_enabled_at_checkout',
- 'wc_payments_get_payment_method_by_id',
- 'wc_payments_get_payment_gateway_by_id',
- 'is_saved_cards_enabled',
- 'is_subscription_item_in_cart',
- ]
- )
- ->getMock();
-
- $mock_upe_gateway->method( 'get_payment_method_ids_enabled_at_checkout' )
- ->willReturn( [ $payment_method ] );
-
- $mock_upe_gateway
- ->method( 'wc_payments_get_payment_method_by_id' )
- ->with( $payment_method )
- ->willReturn( $this->mock_payment_methods[ $payment_method ] );
-
- $mock_upe_gateway
- ->method( 'wc_payments_get_payment_gateway_by_id' )
- ->with( $payment_method )
- ->willReturn( $this->mock_payment_gateways[ $payment_method ] );
-
- $upe_checkout = new WC_Payments_UPE_Checkout(
- $mock_upe_gateway,
- $this->mock_woopay_utilities,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_fraud_service
- );
-
- $this->assertSame( $upe_checkout->get_payment_fields_js_config()['paymentMethodsConfig'][ $payment_method ]['showSaveOption'], false );
- }
- }
-
- public function test_no_save_option_for_sepa_due_to_subscription_cart() {
- $mock_upe_gateway = $this->getMockBuilder( UPE_Split_Payment_Gateway::class )
- ->setConstructorArgs(
- [
- $this->mock_api_client,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_token_service,
- $this->mock_action_scheduler_service,
- $this->mock_payment_methods[ Payment_Method::SEPA ],
- $this->mock_payment_methods,
- $this->mock_rate_limiter,
- $this->order_service,
- $this->mock_dpps,
- $this->mock_localization_service,
- $this->mock_fraud_service,
- ]
- )
- ->setMethods(
- [
- 'get_payment_method_ids_enabled_at_checkout',
- 'wc_payments_get_payment_method_by_id',
- 'wc_payments_get_payment_gateway_by_id',
- 'is_saved_cards_enabled',
- 'is_subscription_item_in_cart',
- ]
- )
- ->getMock();
-
- // saved cards enabled.
- $mock_upe_gateway
- ->method( 'is_saved_cards_enabled' )
- ->will(
- $this->returnValue( true )
- );
-
- // there is a subscription item in cart, which should disable the save option checkbox for a payment method.
- $mock_upe_gateway
- ->method( 'is_subscription_item_in_cart' )
- ->will(
- $this->returnValue( true )
- );
-
- $mock_upe_gateway->method( 'get_payment_method_ids_enabled_at_checkout' )
- ->willReturn( [ Payment_Method::SEPA ] );
-
- $mock_upe_gateway
- ->method( 'wc_payments_get_payment_method_by_id' )
- ->with( Payment_Method::SEPA )
- ->willReturn( $this->mock_payment_methods[ Payment_Method::SEPA ] );
-
- $mock_upe_gateway
- ->method( 'wc_payments_get_payment_gateway_by_id' )
- ->with( Payment_Method::SEPA )
- ->willReturn( $this->mock_payment_gateways[ Payment_Method::SEPA ] );
-
- $upe_checkout = new WC_Payments_UPE_Checkout(
- $mock_upe_gateway,
- $this->mock_woopay_utilities,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_fraud_service
- );
-
- $this->assertSame( $upe_checkout->get_payment_fields_js_config()['paymentMethodsConfig'][ Payment_Method::SEPA ]['showSaveOption'], false );
- }
-
- public function test_no_save_option_for_sepa_due_to_saved_cards_disabled() {
- $mock_upe_gateway = $this->getMockBuilder( UPE_Split_Payment_Gateway::class )
- ->setConstructorArgs(
- [
- $this->mock_api_client,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_token_service,
- $this->mock_action_scheduler_service,
- $this->mock_payment_methods[ Payment_Method::SEPA ],
- $this->mock_payment_methods,
- $this->mock_rate_limiter,
- $this->order_service,
- $this->mock_dpps,
- $this->mock_localization_service,
- $this->mock_fraud_service,
- ]
- )
- ->setMethods(
- [
- 'get_payment_method_ids_enabled_at_checkout',
- 'wc_payments_get_payment_method_by_id',
- 'wc_payments_get_payment_gateway_by_id',
- 'is_saved_cards_enabled',
- 'is_subscription_item_in_cart',
- ]
- )
- ->getMock();
-
- // saved cards disabled.
- $mock_upe_gateway
- ->method( 'is_saved_cards_enabled' )
- ->will(
- $this->returnValue( false )
- );
-
- // no subscription item in cart.
- $mock_upe_gateway
- ->method( 'is_subscription_item_in_cart' )
- ->will(
- $this->returnValue( false )
- );
-
- $mock_upe_gateway->method( 'get_payment_method_ids_enabled_at_checkout' )
- ->willReturn( [ Payment_Method::SEPA ] );
-
- $mock_upe_gateway
- ->method( 'wc_payments_get_payment_method_by_id' )
- ->with( Payment_Method::SEPA )
- ->willReturn( $this->mock_payment_methods[ Payment_Method::SEPA ] );
-
- $mock_upe_gateway
- ->method( 'wc_payments_get_payment_gateway_by_id' )
- ->with( Payment_Method::SEPA )
- ->willReturn( $this->mock_payment_gateways[ Payment_Method::SEPA ] );
-
- $upe_checkout = new WC_Payments_UPE_Checkout(
- $mock_upe_gateway,
- $this->mock_woopay_utilities,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_fraud_service
- );
-
- $this->assertSame( $upe_checkout->get_payment_fields_js_config()['paymentMethodsConfig'][ Payment_Method::SEPA ]['showSaveOption'], false );
- }
-
- public function test_save_option_for_sepa_debit() {
- $mock_upe_gateway = $this->getMockBuilder( UPE_Split_Payment_Gateway::class )
- ->setConstructorArgs(
- [
- $this->mock_api_client,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_token_service,
- $this->mock_action_scheduler_service,
- $this->mock_payment_methods[ Payment_Method::SEPA ],
- $this->mock_payment_methods,
- $this->mock_rate_limiter,
- $this->order_service,
- $this->mock_dpps,
- $this->mock_localization_service,
- $this->mock_fraud_service,
- ]
- )
- ->setMethods(
- [
- 'get_payment_method_ids_enabled_at_checkout',
- 'wc_payments_get_payment_method_by_id',
- 'wc_payments_get_payment_gateway_by_id',
- 'is_saved_cards_enabled',
- 'is_subscription_item_in_cart',
- ]
- )
- ->getMock();
-
- $mock_upe_gateway->method( 'get_payment_method_ids_enabled_at_checkout' )
- ->willReturn( [ Payment_Method::SEPA ] );
-
- $mock_upe_gateway
- ->method( 'wc_payments_get_payment_method_by_id' )
- ->with( Payment_Method::SEPA )
- ->willReturn( $this->mock_payment_methods[ Payment_Method::SEPA ] );
-
- $mock_upe_gateway
- ->method( 'wc_payments_get_payment_gateway_by_id' )
- ->with( Payment_Method::SEPA )
- ->willReturn( $this->mock_payment_gateways[ Payment_Method::SEPA ] );
-
- // saved cards enabled.
- $mock_upe_gateway
- ->method( 'is_saved_cards_enabled' )
- ->will(
- $this->returnValue( true )
- );
-
- // no subscription items in cart.
- $mock_upe_gateway
- ->method( 'is_subscription_item_in_cart' )
- ->will(
- $this->returnValue( false )
- );
-
- $upe_checkout = new WC_Payments_UPE_Checkout(
- $mock_upe_gateway,
- $this->mock_woopay_utilities,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_fraud_service
- );
-
- $this->assertSame( $upe_checkout->get_payment_fields_js_config()['paymentMethodsConfig'][ Payment_Method::SEPA ]['showSaveOption'], false );
- }
-
- public function test_remove_link_payment_method_if_card_disabled() {
- $mock_upe_gateway = $this->getMockBuilder( UPE_Split_Payment_Gateway::class )
- ->setConstructorArgs(
- [
- $this->mock_api_client,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_token_service,
- $this->mock_action_scheduler_service,
- $this->mock_payment_methods[ Payment_Method::LINK ],
- $this->mock_payment_methods,
- $this->mock_rate_limiter,
- $this->order_service,
- $this->mock_dpps,
- $this->mock_localization_service,
- $this->mock_fraud_service,
- ]
- )
- ->setMethods(
- [
- 'get_upe_enabled_payment_method_statuses',
- 'get_upe_enabled_payment_method_ids',
- 'wc_payments_get_payment_method_by_id',
- ]
- )
- ->getMock();
-
- $mock_upe_gateway
- ->expects( $this->once() )
- ->method( 'get_upe_enabled_payment_method_ids' )
- ->will(
- $this->returnValue( [ 'link' ] )
- );
- $mock_upe_gateway
- ->expects( $this->once() )
- ->method( 'get_upe_enabled_payment_method_statuses' )
- ->will(
- $this->returnValue( [ 'link_payments' => [ 'status' => 'active' ] ] )
- );
- $mock_upe_gateway
- ->method( 'wc_payments_get_payment_method_by_id' )
- ->with( Payment_Method::LINK )
- ->willReturn( $this->mock_payment_methods[ Payment_Method::LINK ] );
-
- $upe_checkout = new WC_Payments_UPE_Checkout(
- $mock_upe_gateway,
- $this->mock_woopay_utilities,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_fraud_service
- );
-
- $this->assertSame( $upe_checkout->get_payment_fields_js_config()['paymentMethodsConfig'], [] );
- }
-
- public function test_link_payment_method_if_card_enabled() {
- $this->mock_cache->method( 'get' )->willReturn( [ 'is_deferred_intent_creation_upe_enabled' => true ] );
- WC_Helper_Site_Currency::$mock_site_currency = 'USD';
-
- $mock_upe_gateway = $this->getMockBuilder( UPE_Split_Payment_Gateway::class )
- ->setConstructorArgs(
- [
- $this->mock_api_client,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_token_service,
- $this->mock_action_scheduler_service,
- $this->mock_payment_methods[ Payment_Method::CARD ],
- $this->mock_payment_methods,
- $this->mock_rate_limiter,
- $this->order_service,
- $this->mock_dpps,
- $this->mock_localization_service,
- $this->mock_fraud_service,
- ]
- )
- ->setMethods(
- [
- 'get_upe_enabled_payment_method_statuses',
- 'get_upe_enabled_payment_method_ids',
- 'wc_payments_get_payment_method_by_id',
- 'wc_payments_get_payment_gateway_by_id',
- ]
- )
- ->getMock();
- $mock_upe_gateway
- ->expects( $this->once() )
- ->method( 'get_upe_enabled_payment_method_ids' )
- ->will(
- $this->returnValue( [ 'card', 'link' ] )
- );
- $mock_upe_gateway
- ->expects( $this->once() )
- ->method( 'get_upe_enabled_payment_method_statuses' )
- ->will(
- $this->returnValue(
- [
- 'link_payments' => [ 'status' => 'active' ],
- 'card_payments' => [ 'status' => 'active' ],
- ]
- )
- );
-
- $this->mock_payment_methods[ Payment_Method::LINK ]->expects( $this->any() )
- ->method( 'get_icon' )
- ->will(
- $this->returnValue( $this->icon_url )
- );
-
- $mock_upe_gateway
- ->method( 'wc_payments_get_payment_method_by_id' )
- ->willReturnMap(
- [
- [ Payment_Method::CARD, $this->mock_payment_methods[ Payment_Method::CARD ] ],
- [ Payment_Method::LINK, $this->mock_payment_methods[ Payment_Method::LINK ] ],
- ]
- );
-
- $mock_upe_gateway
- ->method( 'wc_payments_get_payment_gateway_by_id' )
- ->willReturnCallback(
- function ( $payment_method ) {
- if ( Payment_Method::CARD === $payment_method ) {
- return $this->mock_payment_gateways[ Payment_Method::CARD ];
- } elseif ( Payment_Method::LINK === $payment_method ) {
- return $this->mock_payment_gateways[ Payment_Method::LINK ];
- }
- }
- );
-
- $upe_checkout = new WC_Payments_UPE_Checkout(
- $mock_upe_gateway,
- $this->mock_woopay_utilities,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_fraud_service
- );
-
- $this->assertSame(
- $upe_checkout->get_payment_fields_js_config()['paymentMethodsConfig'],
- [
- 'card' => [
- 'isReusable' => true,
- 'title' => 'Credit card / debit card',
- 'icon' => null,
- 'showSaveOption' => true,
- 'countries' => [],
- 'upePaymentIntentData' => null,
- 'upeSetupIntentData' => null,
- 'testingInstructions' => '
Test mode: use the test VISA card 4242424242424242 with any expiry date and CVC. Other payment methods may redirect to a Stripe test page to authorize payment. More test card numbers are listed
here .',
- 'forceNetworkSavedCards' => false,
- ],
- 'link' => [
- 'isReusable' => true,
- 'title' => 'Link',
- 'icon' => $this->icon_url,
- 'showSaveOption' => true,
- 'countries' => [],
- 'upePaymentIntentData' => null,
- 'upeSetupIntentData' => null,
- 'testingInstructions' => '',
- 'forceNetworkSavedCards' => false,
- ],
- ]
- );
- }
-
public function test_remove_upe_setup_intent_from_session() {
// Two payment methods (SEPA and giropay) are enabled.
$sepa_setup_intent_key = UPE_Split_Payment_Gateway::KEY_UPE_SETUP_INTENT . '_sepa_debit';
diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay.php b/tests/unit/test-class-wc-payment-gateway-wcpay.php
index c1bb486f296..8efcc4ccb0e 100644
--- a/tests/unit/test-class-wc-payment-gateway-wcpay.php
+++ b/tests/unit/test-class-wc-payment-gateway-wcpay.php
@@ -33,7 +33,6 @@
use WCPay\Payment_Methods\UPE_Split_Payment_Gateway;
use WCPay\WooPay\WooPay_Utilities;
use WCPay\Session_Rate_Limiter;
-use WCPay\WC_Payments_Checkout;
// Need to use WC_Mock_Data_Store.
require_once dirname( __FILE__ ) . '/helpers/class-wc-mock-wc-data-store.php';
@@ -49,7 +48,7 @@ class WC_Payment_Gateway_WCPay_Test extends WCPAY_UnitTestCase {
/**
* System under test.
*
- * @var WC_Payment_Gateway_WCPay
+ * @var UPE_Split_Payment_Gateway
*/
private $wcpay_gateway;
@@ -95,6 +94,13 @@ class WC_Payment_Gateway_WCPay_Test extends WCPAY_UnitTestCase {
*/
private $mock_rate_limiter;
+ /**
+ * UPE_Payment_Method instance.
+ *
+ * @var UPE_Payment_Method|MockObject
+ */
+ private $mock_payment_method;
+
/**
* WC_Payments_Order_Service instance.
*
@@ -109,12 +115,6 @@ class WC_Payment_Gateway_WCPay_Test extends WCPAY_UnitTestCase {
*/
private $woopay_utilities;
- /**
- * WC_Payments_Checkout instance.
- * @var WC_Payments_Checkout
- */
- private $payments_checkout;
-
/**
* Duplicate_Payment_Prevention_Service instance.
* @var Duplicate_Payment_Prevention_Service|MockObject
@@ -171,6 +171,16 @@ public function set_up() {
$this->mock_api_client->expects( $this->any() )->method( 'get_blog_id' )->willReturn( 1234567 );
$this->mock_wcpay_account = $this->createMock( WC_Payments_Account::class );
+ $this->mock_wcpay_account
+ ->expects( $this->any() )
+ ->method( 'get_fees' )
+ ->willReturn(
+ [
+ 'card' => [
+ 'base' => 0.1,
+ ],
+ ]
+ );
// Mock the main class's cache service.
$this->_cache = WC_Payments::get_database_cache();
@@ -190,32 +200,39 @@ public function set_up() {
$this->mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class );
$this->mock_localization_service = $this->createMock( WC_Payments_Localization_Service::class );
- $this->mock_fraud_service = $this->createMock( WC_Payments_Fraud_Service::class );
+ $this->mock_localization_service->expects( $this->any() )
+ ->method( 'get_country_locale_data' )
+ ->willReturn(
+ [
+ 'currency_code' => 'usd',
+ ]
+ );
+ $this->mock_fraud_service = $this->createMock( WC_Payments_Fraud_Service::class );
- $this->wcpay_gateway = new WC_Payment_Gateway_WCPay(
+ $this->mock_payment_method = $this->getMockBuilder( CC_Payment_Method::class )
+ ->setConstructorArgs( [ $this->mock_token_service ] )
+ ->setMethods( [ 'is_subscription_item_in_cart' ] )
+ ->getMock();
+
+ $this->wcpay_gateway = new UPE_Split_Payment_Gateway(
$this->mock_api_client,
$this->mock_wcpay_account,
$this->mock_customer_service,
$this->mock_token_service,
$this->mock_action_scheduler_service,
+ $this->mock_payment_method,
+ [ 'card' => $this->mock_payment_method ],
$this->mock_rate_limiter,
$this->order_service,
$this->mock_dpps,
$this->mock_localization_service,
$this->mock_fraud_service
);
+
WC_Payments::set_gateway( $this->wcpay_gateway );
$this->woopay_utilities = new WooPay_Utilities();
- $this->payments_checkout = new WC_Payments_Checkout(
- $this->wcpay_gateway,
- $this->woopay_utilities,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_fraud_service
- );
-
// Mock the level3 service to always return an empty array.
$mock_level3_service = $this->createMock( Level3Service::class );
$mock_level3_service->expects( $this->any() )
@@ -368,83 +385,58 @@ public function test_attach_exchange_info_to_order_with_different_order_currency
$this->assertEquals( 0.853, $order->get_meta( '_wcpay_multi_currency_stripe_exchange_rate' ) );
}
- public function test_save_card_checkbox_not_displayed_when_saved_cards_disabled() {
- $this->wcpay_gateway->update_option( 'saved_cards', 'no' );
-
- $this->refresh_payments_checkout();
-
+ public function test_save_payment_method_checkbox_displayed() {
// Use a callback to get and test the output (also suppresses the output buffering being printed to the CLI).
$this->setOutputCallback(
function ( $output ) {
- $result = preg_match_all( '/.*
.*/', $output );
+ $input_element = preg_match_all( '/.*
.*/', $output );
+ $parent_div = preg_match_all( '/
.*<\/div>/s', $output );
- $this->assertSame( 0, $result );
+ $this->assertSame( 1, $input_element );
+ $this->assertSame( 1, $parent_div );
}
);
- $this->wcpay_gateway->payment_fields();
+ $this->wcpay_gateway->save_payment_method_checkbox();
}
- public function test_save_card_checkbox_not_displayed_for_non_logged_in_users() {
- $this->wcpay_gateway->update_option( 'saved_cards', 'yes' );
- wp_set_current_user( 0 );
-
- $this->refresh_payments_checkout();
-
- // Use a callback to get and test the output (also suppresses the output buffering being printed to the CLI).
+ public function test_save_payment_method_checkbox_not_displayed_when_force_checked() {
$this->setOutputCallback(
function ( $output ) {
- $result = preg_match_all( '/.*
.*/', $output );
+ $input_element = preg_match_all( '/.*
.*/', $output );
+ $parent_div = preg_match_all( '/
.*<\/div>/s', $output );
- $this->assertSame( 0, $result );
+ $this->assertSame( 1, $input_element );
+ $this->assertSame( 1, $parent_div );
}
);
- $this->wcpay_gateway->payment_fields();
+ $this->wcpay_gateway->save_payment_method_checkbox( true );
}
- public function test_save_card_checkbox_displayed_for_logged_in_users() {
- $this->wcpay_gateway->update_option( 'saved_cards', 'yes' );
- wp_set_current_user( 1 );
-
- $this->refresh_payments_checkout();
+ public function test_save_payment_method_checkbox_not_displayed_when_stripe_platform_account_used() {
+ // Setup the test so that should_use_stripe_platform_on_checkout_page returns true.
+ $this->mock_cache->method( 'get' )->willReturn( [ 'platform_checkout_eligible' => true ] );
+ $this->wcpay_gateway->update_option( 'platform_checkout', 'yes' );
+ add_filter( 'woocommerce_is_checkout', '__return_true' );
+ WC()->session->init();
+ WC()->cart->add_to_cart( WC_Helper_Product::create_simple_product()->get_id(), 1 );
+ WC()->cart->calculate_totals();
- // Use a callback to get and test the output (also suppresses the output buffering being printed to the CLI).
$this->setOutputCallback(
function ( $output ) {
- $result = preg_match_all( '/.*
.*/', $output );
+ $input_element = preg_match_all( '/.*
.*/', $output );
+ $parent_div = preg_match_all( '/
.*<\/div>/s', $output );
- $this->assertSame( 1, $result );
+ $this->assertSame( 1, $input_element );
+ $this->assertSame( 1, $parent_div );
}
);
- $this->wcpay_gateway->payment_fields();
- }
+ $this->wcpay_gateway->save_payment_method_checkbox( false );
- public function test_fraud_prevention_token_added_when_enabled() {
- $token_value = 'test-token';
- $fraud_prevention_service_mock = $this->get_fraud_prevention_service_mock();
- $fraud_prevention_service_mock
- ->expects( $this->once() )
- ->method( 'is_enabled' )
- ->willReturn( true );
- $fraud_prevention_service_mock
- ->expects( $this->once() )
- ->method( 'get_token' )
- ->willReturn( $token_value );
-
- $this->refresh_payments_checkout();
-
- // Use a callback to get and test the output (also suppresses the output buffering being printed to the CLI).
- $this->setOutputCallback(
- function ( $output ) use ( $token_value ) {
- $result = preg_match_all( '/.*
.*/', $output );
-
- $this->assertSame( 0, $result );
- }
- );
-
- $this->wcpay_gateway->payment_fields();
+ remove_filter( 'woocommerce_is_checkout', '__return_true' );
+ WC()->cart->empty_cart();
}
public function test_capture_charge_success() {
@@ -466,7 +458,7 @@ public function test_capture_charge_success() {
->with( $mock_intent->get_amount() );
$capture_intent_request->expects( $this->once() )
->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'legacy_card' ] );
+ ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
$capture_intent_request->expects( $this->once() )
->method( 'format_response' )
->willReturn( WC_Helper_Intention::create_intention() );
@@ -521,7 +513,7 @@ public function test_capture_charge_success_non_usd() {
->with( $mock_intent->get_amount() );
$capture_intent_request->expects( $this->once() )
->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'legacy_card' ] );
+ ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
$capture_intent_request->expects( $this->once() )
->method( 'format_response' )
->willReturn( WC_Helper_Intention::create_intention( [ 'currency' => 'eur' ] ) );
@@ -573,7 +565,7 @@ public function test_capture_charge_failure() {
->with( $mock_intent->get_amount() );
$capture_intent_request->expects( $this->once() )
->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'legacy_card' ] );
+ ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
$capture_intent_request->expects( $this->once() )
->method( 'format_response' )
->willReturn( $mock_intent );
@@ -628,7 +620,7 @@ public function test_capture_charge_failure_non_usd() {
->with( $mock_intent->get_amount() );
$capture_intent_request->expects( $this->once() )
->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'legacy_card' ] );
+ ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
$capture_intent_request->expects( $this->once() )
->method( 'format_response' )
->willReturn( $mock_intent );
@@ -685,7 +677,7 @@ public function test_capture_charge_api_failure() {
->with( $mock_intent->get_amount() );
$capture_intent_request->expects( $this->once() )
->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'legacy_card' ] );
+ ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
$capture_intent_request->expects( $this->once() )
->method( 'format_response' )
->will( $this->throwException( new API_Exception( 'test exception', 'server_error', 500 ) ) );
@@ -747,7 +739,7 @@ public function test_capture_charge_api_failure_non_usd() {
->with( $mock_intent->get_amount() );
$capture_intent_request->expects( $this->once() )
->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'legacy_card' ] );
+ ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
$capture_intent_request->expects( $this->once() )
->method( 'format_response' )
->will( $this->throwException( new API_Exception( 'test exception', 'server_error', 500 ) ) );
@@ -805,7 +797,7 @@ public function test_capture_charge_expired() {
->with( $mock_intent->get_amount() );
$capture_intent_request->expects( $this->once() )
->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'legacy_card' ] );
+ ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
$capture_intent_request->expects( $this->once() )
->method( 'format_response' )
->will( $this->throwException( new API_Exception( 'test exception', 'server_error', 500 ) ) );
@@ -863,7 +855,7 @@ public function test_capture_charge_metadata() {
->with( $mock_intent->get_amount() );
$capture_intent_request->expects( $this->once() )
->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'legacy_card' ] );
+ ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
$capture_intent_request->expects( $this->once() )
->method( 'format_response' )
->willReturn( WC_Helper_Intention::create_intention() );
@@ -912,7 +904,7 @@ public function test_capture_charge_without_level3() {
->with( $mock_intent->get_amount() );
$capture_intent_request->expects( $this->once() )
->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'legacy_card' ] );
+ ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
$capture_intent_request->expects( $this->once() )
->method( 'format_response' )
->willReturn( WC_Helper_Intention::create_intention() );
@@ -1284,7 +1276,7 @@ public function test_add_payment_method_no_customer() {
$this->assertEquals( 'error', $result['result'] );
}
- public function test_add_payment_method_canceled_intent() {
+ public function test_add_payment_method_cancelled_intent() {
$_POST = [ 'wcpay-setup-intent' => 'sti_mock' ];
$this->mock_customer_service
@@ -1576,22 +1568,6 @@ public function test_process_payment_for_order_rejects_with_cached_minimum_amoun
}
public function test_mandate_data_not_added_to_payment_intent_if_not_required() {
- // Mandate data is required for SEPA and Stripe Link only, hence initializing the gateway with a CC payment method should not add mandate data.
- $gateway = new UPE_Split_Payment_Gateway(
- $this->mock_api_client,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_token_service,
- $this->mock_action_scheduler_service,
- new CC_Payment_Method( $this->mock_token_service ),
- [],
- $this->mock_rate_limiter,
- $this->order_service,
- $this->mock_dpps,
- $this->mock_localization_service,
- $this->mock_fraud_service
- );
- WC_Payments::set_gateway( $gateway );
$payment_method = 'woocommerce_payments_sepa_debit';
$order = WC_Helper_Order::create_order();
$order->set_currency( 'USD' );
@@ -1609,27 +1585,13 @@ public function test_mandate_data_not_added_to_payment_intent_if_not_required()
$request->expects( $this->never() )
->method( 'set_mandate_data' );
- $gateway->process_payment_for_order( WC()->cart, $pi );
- WC_Payments::set_gateway( $this->wcpay_gateway );
+ // Mandate data is required for SEPA and Stripe Link only, $this->wcpay_gateway is created with card hence mandate data should not be added.
+ $this->wcpay_gateway->process_payment_for_order( WC()->cart, $pi );
}
public function test_mandate_data_added_to_payment_intent_if_required() {
- // Mandate data is required for SEPA and Stripe Link, hence initializing the gateway with a SEPA payment method should add mandate data.
- $gateway = new UPE_Split_Payment_Gateway(
- $this->mock_api_client,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_token_service,
- $this->mock_action_scheduler_service,
- new Sepa_Payment_Method( $this->mock_token_service ),
- [],
- $this->mock_rate_limiter,
- $this->order_service,
- $this->mock_dpps,
- $this->mock_localization_service,
- $this->mock_fraud_service
- );
- WC_Payments::set_gateway( $gateway );
+ // Mandate data is required for SEPA and Stripe Link, hence creating the gateway with a SEPA payment method should add mandate data.
+ $gateway = $this->create_gateway_with( new Sepa_Payment_Method( $this->mock_token_service ) );
$payment_method = 'woocommerce_payments_sepa_debit';
$order = WC_Helper_Order::create_order();
$order->set_currency( 'USD' );
@@ -1659,26 +1621,11 @@ function ( $data ) {
);
$gateway->process_payment_for_order( WC()->cart, $pi );
- WC_Payments::set_gateway( $this->wcpay_gateway );
}
public function test_mandate_data_not_added_to_setup_intent_request_when_link_is_disabled() {
- $gateway = new UPE_Split_Payment_Gateway(
- $this->mock_api_client,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_token_service,
- $this->mock_action_scheduler_service,
- new CC_Payment_Method( $this->mock_token_service ),
- [],
- $this->mock_rate_limiter,
- $this->order_service,
- $this->mock_dpps,
- $this->mock_localization_service,
- $this->mock_fraud_service
- );
- WC_Payments::set_gateway( $gateway );
- $gateway->settings['upe_enabled_payment_method_ids'] = [ 'card' ];
+ // Disabled link is reflected in upe_enabled_payment_method_ids: when link is disabled, the array contains only card.
+ $this->wcpay_gateway->settings['upe_enabled_payment_method_ids'] = [ 'card' ];
$payment_method = 'woocommerce_payments';
$order = WC_Helper_Order::create_order();
@@ -1714,27 +1661,11 @@ public function test_mandate_data_not_added_to_setup_intent_request_when_link_is
$request->expects( $this->never() )
->method( 'set_mandate_data' );
- $gateway->process_payment_for_order( WC()->cart, $pi );
- WC_Payments::set_gateway( $this->wcpay_gateway );
+ $this->wcpay_gateway->process_payment_for_order( WC()->cart, $pi );
}
public function test_mandate_data_added_to_setup_intent_request_when_link_is_enabled() {
- $gateway = new UPE_Split_Payment_Gateway(
- $this->mock_api_client,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_token_service,
- $this->mock_action_scheduler_service,
- new CC_Payment_Method( $this->mock_token_service ),
- [],
- $this->mock_rate_limiter,
- $this->order_service,
- $this->mock_dpps,
- $this->mock_localization_service,
- $this->mock_fraud_service
- );
- WC_Payments::set_gateway( $gateway );
- $gateway->settings['upe_enabled_payment_method_ids'] = [ 'card', 'link' ];
+ $this->wcpay_gateway->settings['upe_enabled_payment_method_ids'] = [ 'card', 'link' ];
$payment_method = 'woocommerce_payments';
$order = WC_Helper_Order::create_order();
@@ -1780,8 +1711,8 @@ function ( $data ) {
)
);
- $gateway->process_payment_for_order( WC()->cart, $pi );
- WC_Payments::set_gateway( $this->wcpay_gateway );
+ $this->wcpay_gateway->process_payment_for_order( WC()->cart, $pi );
+ $this->wcpay_gateway->settings['upe_enabled_payment_method_ids'] = [ 'card' ];
}
public function test_process_payment_for_order_cc_payment_method() {
@@ -1872,7 +1803,7 @@ public function test_process_payment_caches_mimimum_amount_and_displays_error_up
$request->expects( $this->once() )
->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'legacy_card' ] );
+ ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
$request->expects( $this->once() )
->method( 'format_response' )
@@ -2039,7 +1970,6 @@ public function test_is_woopay_enabled_returns_true() {
add_filter( 'woocommerce_is_checkout', '__return_true' );
$this->assertTrue( $this->woopay_utilities->should_enable_woopay( $this->wcpay_gateway ) );
- $this->assertTrue( $this->payments_checkout->get_payment_fields_js_config()['isWooPayEnabled'] );
remove_filter( 'woocommerce_is_checkout', '__return_true' );
}
@@ -2056,90 +1986,6 @@ public function test_should_use_stripe_platform_on_checkout_page_not_woopay() {
$this->assertFalse( $this->wcpay_gateway->should_use_stripe_platform_on_checkout_page() );
}
- public function test_force_network_saved_cards_is_returned_as_true_if_should_use_stripe_platform() {
- $mock_wcpay_gateway = $this->get_partial_mock_for_gateway( [ 'should_use_stripe_platform_on_checkout_page' ] );
-
- $mock_wcpay_gateway
- ->expects( $this->once() )
- ->method( 'should_use_stripe_platform_on_checkout_page' )
- ->willReturn( true );
-
- $registered_card_gateway = WC_Payments::get_registered_card_gateway();
- WC_Payments::set_registered_card_gateway( $mock_wcpay_gateway );
-
- $payments_checkout = new WC_Payments_Checkout(
- $mock_wcpay_gateway,
- $this->woopay_utilities,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_fraud_service
- );
-
- $this->assertTrue( $payments_checkout->get_payment_fields_js_config()['forceNetworkSavedCards'] );
- WC_Payments::set_registered_card_gateway( $registered_card_gateway );
- }
-
- public function test_registered_gateway_replaced_by_gateway_if_not_initialized() {
- // Set the registered gateway to null to simulate the case where the gateway is not initialized and thus should be replaced by $mock_wcpay_gateway.
- WC_Payments::set_registered_card_gateway( null );
-
- $mock_wcpay_gateway = $this->get_partial_mock_for_gateway( [ 'should_use_stripe_platform_on_checkout_page' ] );
-
- $mock_wcpay_gateway
- ->expects( $this->once() )
- ->method( 'should_use_stripe_platform_on_checkout_page' )
- ->willReturn( true );
-
- $payments_checkout = new WC_Payments_Checkout(
- $mock_wcpay_gateway,
- $this->woopay_utilities,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_fraud_service
- );
-
- $this->assertTrue( $payments_checkout->get_payment_fields_js_config()['forceNetworkSavedCards'] );
- }
-
- public function test_force_network_saved_cards_is_returned_as_false_if_should_not_use_stripe_platform() {
- $mock_wcpay_gateway = $this->get_partial_mock_for_gateway( [ 'should_use_stripe_platform_on_checkout_page' ] );
-
- $mock_wcpay_gateway
- ->expects( $this->once() )
- ->method( 'should_use_stripe_platform_on_checkout_page' )
- ->willReturn( false );
-
- $registered_card_gateway = WC_Payments::get_registered_card_gateway();
- WC_Payments::set_registered_card_gateway( $mock_wcpay_gateway );
-
- $payments_checkout = new WC_Payments_Checkout(
- $mock_wcpay_gateway,
- $this->woopay_utilities,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_fraud_service
- );
-
- $this->assertFalse( $payments_checkout->get_payment_fields_js_config()['forceNetworkSavedCards'] );
- WC_Payments::set_registered_card_gateway( $registered_card_gateway );
- }
-
- public function test_is_woopay_enabled_returns_false_if_ineligible() {
- $this->mock_cache->method( 'get' )->willReturn( [ 'platform_checkout_eligible' => false ] );
- $this->assertFalse( $this->payments_checkout->get_payment_fields_js_config()['isWooPayEnabled'] );
- }
-
- public function test_is_woopay_enabled_returns_false_if_ineligible_and_enabled() {
- $this->wcpay_gateway->update_option( 'platform_checkout', 'yes' );
- $this->assertFalse( $this->payments_checkout->get_payment_fields_js_config()['isWooPayEnabled'] );
- }
-
- public function test_return_icon_url() {
- $returned_icon = $this->payments_checkout->get_payment_fields_js_config()['icon'];
- $this->assertNotNull( $returned_icon );
- $this->assertStringContainsString( 'assets/images/payment-methods/cc.svg', $returned_icon );
- }
-
public function is_woopay_falsy_value_provider() {
return [
[ '0' ],
@@ -2191,7 +2037,7 @@ public function test_is_in_test_mode() {
* @return MockObject|WC_Payment_Gateway_WCPay
*/
private function get_partial_mock_for_gateway( array $methods = [] ) {
- return $this->getMockBuilder( WC_Payment_Gateway_WCPay::class )
+ return $this->getMockBuilder( UPE_Split_Payment_Gateway::class )
->setConstructorArgs(
[
$this->mock_api_client,
@@ -2199,6 +2045,8 @@ private function get_partial_mock_for_gateway( array $methods = [] ) {
$this->mock_customer_service,
$this->mock_token_service,
$this->mock_action_scheduler_service,
+ $this->mock_payment_method,
+ [ $this->mock_payment_method ],
$this->mock_rate_limiter,
$this->order_service,
$this->mock_dpps,
@@ -2545,17 +2393,20 @@ private function create_charge_object() {
return new WC_Payments_API_Charge( $this->mock_charge_id, 1500, $created );
}
- private function refresh_payments_checkout() {
- remove_all_actions( 'wc_payments_add_payment_fields' );
-
- $this->payments_checkout = new WC_Payments_Checkout(
- $this->wcpay_gateway,
- $this->woopay_utilities,
+ private function create_gateway_with( $payment_method ) {
+ return new UPE_Split_Payment_Gateway(
+ $this->mock_api_client,
$this->mock_wcpay_account,
$this->mock_customer_service,
+ $this->mock_token_service,
+ $this->mock_action_scheduler_service,
+ $payment_method,
+ [ $payment_method ],
+ $this->mock_rate_limiter,
+ $this->order_service,
+ $this->mock_dpps,
+ $this->mock_localization_service,
$this->mock_fraud_service
);
-
- $this->payments_checkout->init_hooks();
}
}
diff --git a/tests/unit/test-class-wc-payments-checkout.php b/tests/unit/test-class-wc-payments-checkout.php
new file mode 100644
index 00000000000..49906d2edea
--- /dev/null
+++ b/tests/unit/test-class-wc-payments-checkout.php
@@ -0,0 +1,569 @@
+mock_wcpay_gateway = $this->getMockBuilder( UPE_Split_Payment_Gateway::class )
+ ->onlyMethods( [ 'get_account_domestic_currency', 'get_payment_method_ids_enabled_at_checkout', 'should_use_stripe_platform_on_checkout_page', 'should_support_saved_payments', 'is_saved_cards_enabled', 'save_payment_method_checkbox', 'get_account_statement_descriptor', 'get_icon_url', 'get_payment_method_ids_enabled_at_checkout_filtered_by_fees', 'is_subscription_item_in_cart', 'wc_payments_get_payment_method_by_id', 'display_gateway_html' ] )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->mock_wcpay_gateway->id = 'woocommerce_payments';
+ $this->mock_wcpay_gateway
+ ->method( 'get_account_domestic_currency' )
+ ->willReturn( 'USD' );
+
+ $this->mock_woopay_utilities = $this->createMock( WooPay_Utilities::class );
+ $this->mock_woopay_utilities = $this->getMockBuilder( WooPay_Utilities::class )
+ ->onlyMethods( [ 'should_enable_woopay', 'should_enable_woopay_on_cart_or_checkout' ] )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->mock_wcpay_account = $this->createMock( WC_Payments_Account::class );
+ $this->mock_customer_service = $this->createMock( WC_Payments_Customer_Service::class );
+ $this->mock_fraud_service = $this->createMock( WC_Payments_Fraud_Service::class );
+
+ $this->mock_wcpay_gateway
+ ->method( 'get_account_statement_descriptor' )
+ ->willReturn( 'localhost' );
+
+ $this->mock_wcpay_gateway
+ ->expects( $this->any() )
+ ->method( 'get_payment_method_ids_enabled_at_checkout_filtered_by_fees' )
+ ->willReturn( [] );
+
+ $this->mock_token_service = $this->createMock( WC_Payments_Token_Service::class );
+
+ // This is needed to ensure that only the mocked gateway is always used by the checkout class.
+ $this->default_gateway = WC_Payments::get_registered_card_gateway();
+ WC_Payments::set_registered_card_gateway( $this->mock_wcpay_gateway );
+ WC_Payments::set_gateway( $this->mock_wcpay_gateway );
+
+ // Use a callback to suppresses the output buffering being printed to the CLI.
+ $this->setOutputCallback(
+ function ( $output ) {
+ preg_match_all( '/.*
.*/s', $output );
+ }
+ );
+
+ $this->system_under_test = new WC_Payments_Checkout( $this->mock_wcpay_gateway, $this->mock_woopay_utilities, $this->mock_wcpay_account, $this->mock_customer_service, $this->mock_fraud_service );
+ }
+
+ public function tear_down() {
+ parent::tear_down();
+ WC_Payments::set_registered_card_gateway( $this->default_gateway );
+ WC_Payments::set_gateway( $this->default_gateway );
+ }
+
+ public function test_fraud_prevention_token_added_when_prevention_service_enabled() {
+ $token_value = 'test-token';
+ $fraud_prevention_service_mock = $this->getMockBuilder( Fraud_Prevention_Service::class )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $fraud_prevention_service_mock
+ ->expects( $this->once() )
+ ->method( 'is_enabled' )
+ ->willReturn( true );
+
+ $fraud_prevention_service_mock
+ ->expects( $this->once() )
+ ->method( 'get_token' )
+ ->willReturn( $token_value );
+
+ Fraud_Prevention_Service::set_instance( $fraud_prevention_service_mock );
+
+ $this->mock_wcpay_gateway
+ ->expects( $this->any() )
+ ->method( 'get_payment_method_ids_enabled_at_checkout' )
+ ->willReturn( [] );
+
+ // Use a callback to get and test the output (also suppresses the output buffering being printed to the CLI).
+ $this->setOutputCallback(
+ function ( $output ) use ( $token_value ) {
+ $result = preg_match_all( '/ ]*type="hidden"[^>]*name="wcpay-fraud-prevention-token"[^>]*value="' . preg_quote( $token_value, '/' ) . '"[^>]*>/', $output );
+
+ $this->assertSame( 1, $result );
+ }
+ );
+
+ $this->system_under_test->payment_fields();
+ }
+
+ public function test_fraud_prevention_token_not_added_when_prevention_service_disabled() {
+ $token_value = 'test-token';
+ $fraud_prevention_service_mock = $this->getMockBuilder( Fraud_Prevention_Service::class )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $fraud_prevention_service_mock
+ ->expects( $this->once() )
+ ->method( 'is_enabled' )
+ ->willReturn( true );
+
+ Fraud_Prevention_Service::set_instance( $fraud_prevention_service_mock );
+
+ $this->mock_wcpay_gateway
+ ->expects( $this->any() )
+ ->method( 'get_payment_method_ids_enabled_at_checkout' )
+ ->willReturn( [] );
+
+ // Use a callback to get and test the output (also suppresses the output buffering being printed to the CLI).
+ $this->setOutputCallback(
+ function ( $output ) use ( $token_value ) {
+ $result = preg_match_all( '/ ]*type="hidden"[^>]*name="wcpay-fraud-prevention-token"[^>]*value="' . preg_quote( $token_value, '/' ) . '"[^>]*>/', $output );
+
+ $this->assertSame( 0, $result );
+ }
+ );
+
+ $this->system_under_test->payment_fields();
+ }
+
+ public function test_save_payment_method_checkbox_not_called_when_saved_cards_disabled() {
+ // given: prepare the dependencies.
+ wp_set_current_user( 1 );
+
+ $this->mock_wcpay_gateway
+ ->expects( $this->any() )
+ ->method( 'get_payment_method_ids_enabled_at_checkout' )
+ ->willReturn( [] );
+
+ $this->mock_wcpay_gateway
+ ->method( 'is_saved_cards_enabled' )
+ ->willReturn( false );
+
+ // then: check that the save_payment_method_checkbox method was called.
+ $this->mock_wcpay_gateway
+ ->expects( $this->never() )
+ ->method( 'save_payment_method_checkbox' );
+
+ $this->system_under_test->payment_fields();
+ }
+
+ public function test_save_payment_method_checkbox_not_called_for_non_logged_in_user() {
+ // given: prepare the dependencies.
+ wp_set_current_user( 0 );
+
+ $this->mock_wcpay_gateway
+ ->expects( $this->any() )
+ ->method( 'get_payment_method_ids_enabled_at_checkout' )
+ ->willReturn( [] );
+
+ $this->mock_wcpay_gateway
+ ->method( 'is_saved_cards_enabled' )
+ ->willReturn( true );
+
+ $this->mock_wcpay_gateway
+ ->expects( $this->once() )
+ ->method( 'should_support_saved_payments' )
+ ->willReturn( true );
+
+ // then: check that the save_payment_method_checkbox method was called.
+ $this->mock_wcpay_gateway
+ ->expects( $this->never() )
+ ->method( 'save_payment_method_checkbox' );
+
+ $this->system_under_test->payment_fields();
+ }
+
+ public function test_save_payment_method_checkbox_called() {
+ // given: prepare the dependencies.
+ wp_set_current_user( 1 );
+
+ $this->mock_wcpay_gateway
+ ->expects( $this->any() )
+ ->method( 'get_payment_method_ids_enabled_at_checkout' )
+ ->willReturn( [] );
+
+ $this->mock_wcpay_gateway
+ ->method( 'is_saved_cards_enabled' )
+ ->willReturn( true );
+
+ $this->mock_wcpay_gateway
+ ->expects( $this->once() )
+ ->method( 'should_support_saved_payments' )
+ ->willReturn( true );
+
+ // then: check that the save_payment_method_checkbox method was called.
+ $this->mock_wcpay_gateway
+ ->expects( $this->once() )
+ ->method( 'save_payment_method_checkbox' );
+
+ $this->system_under_test->payment_fields();
+ }
+
+ public function test_display_gateway_html_called() {
+ $this->mock_wcpay_gateway
+ ->expects( $this->any() )
+ ->method( 'get_payment_method_ids_enabled_at_checkout' )
+ ->willReturn( [] );
+
+ $this->mock_wcpay_gateway
+ ->expects( $this->once() )
+ ->method( 'display_gateway_html' );
+
+ $this->system_under_test->payment_fields();
+ }
+
+ public function test_is_woopay_enabled_when_should_enable_woopay_and_enable_it_on_cart_or_checkout() {
+ $this->mock_wcpay_gateway
+ ->expects( $this->any() )
+ ->method( 'get_payment_method_ids_enabled_at_checkout' )
+ ->willReturn( [] );
+
+ $this->mock_woopay_utilities->method( 'should_enable_woopay' )->willReturn( true );
+ $this->mock_woopay_utilities->method( 'should_enable_woopay_on_cart_or_checkout' )->willReturn( true );
+
+ $is_woopay_enabled = $this->system_under_test->get_payment_fields_js_config()['isWooPayEnabled'];
+ $this->assertTrue( $is_woopay_enabled );
+ }
+
+ public function test_is_woopay_enabled_false_when_should_not_enable_woopay() {
+ $this->mock_wcpay_gateway
+ ->expects( $this->any() )
+ ->method( 'get_payment_method_ids_enabled_at_checkout' )
+ ->willReturn( [] );
+
+ $this->mock_woopay_utilities->method( 'should_enable_woopay' )->willReturn( false );
+ $this->mock_woopay_utilities->method( 'should_enable_woopay_on_cart_or_checkout' )->willReturn( true );
+
+ $is_woopay_enabled = $this->system_under_test->get_payment_fields_js_config()['isWooPayEnabled'];
+ $this->assertFalse( $is_woopay_enabled );
+ }
+
+ public function test_is_woopay_enabled_false_when_should_enable_woopay_but_not_enable_it_on_cart_or_checkout() {
+ $this->mock_wcpay_gateway
+ ->expects( $this->any() )
+ ->method( 'get_payment_method_ids_enabled_at_checkout' )
+ ->willReturn( [] );
+
+ $this->mock_woopay_utilities->method( 'should_enable_woopay' )->willReturn( true );
+ $this->mock_woopay_utilities->method( 'should_enable_woopay_on_cart_or_checkout' )->willReturn( false );
+
+ $is_woopay_enabled = $this->system_under_test->get_payment_fields_js_config()['isWooPayEnabled'];
+ $this->assertFalse( $is_woopay_enabled );
+ }
+
+ public function test_return_icon_url() {
+ $this->mock_wcpay_gateway
+ ->expects( $this->any() )
+ ->method( 'get_payment_method_ids_enabled_at_checkout' )
+ ->willReturn( [] );
+
+ $this->mock_wcpay_gateway
+ ->method( 'get_icon_url' )
+ ->willReturn( 'assets/images/payment-methods/cc.svg' );
+
+ $returned_icon = $this->system_under_test->get_payment_fields_js_config()['icon'];
+
+ $this->assertNotNull( $returned_icon );
+ $this->assertStringContainsString( 'assets/images/payment-methods/cc.svg', $returned_icon );
+ }
+
+ public function test_force_network_saved_cards_enabled_when_should_use_stripe_platform() {
+ $this->mock_wcpay_gateway
+ ->expects( $this->any() )
+ ->method( 'get_payment_method_ids_enabled_at_checkout' )
+ ->willReturn( [] );
+
+ $this->mock_wcpay_gateway
+ ->method( 'should_use_stripe_platform_on_checkout_page' )
+ ->willReturn( true );
+
+ $force_network_saved_cards = $this->system_under_test->get_payment_fields_js_config()['forceNetworkSavedCards'];
+ $this->assertTrue( $force_network_saved_cards );
+ }
+
+ public function test_force_network_saved_cards_disabled_when_should_not_use_stripe_platform() {
+ $this->mock_wcpay_gateway
+ ->expects( $this->any() )
+ ->method( 'get_payment_method_ids_enabled_at_checkout' )
+ ->willReturn( [] );
+
+ $this->mock_wcpay_gateway
+ ->method( 'should_use_stripe_platform_on_checkout_page' )
+ ->willReturn( false );
+
+ $force_network_saved_cards = $this->system_under_test->get_payment_fields_js_config()['forceNetworkSavedCards'];
+ $this->assertFalse( $force_network_saved_cards );
+ }
+
+ public function test_link_payment_method_provided_when_card_enabled() {
+ $icon_url = 'test-icon-url';
+ $this->mock_wcpay_gateway
+ ->expects( $this->any() )
+ ->method( 'get_payment_method_ids_enabled_at_checkout' )
+ ->willReturn( [ 'card', 'link' ] );
+
+ $this->mock_wcpay_gateway
+ ->method( 'is_saved_cards_enabled' )
+ ->willReturn( true );
+
+ $this->mock_wcpay_gateway
+ ->method( 'is_subscription_item_in_cart' )
+ ->willReturn( false );
+
+ $payment_methods = [
+ 'card' => [ 'base' => 0.1 ],
+ 'link' => [
+ 'base' => 0.1,
+ ],
+ ];
+
+ $card_pm = $this->getMockBuilder( CC_Payment_Method::class )
+ ->setConstructorArgs( [ $this->mock_token_service ] )
+ ->onlyMethods( [ 'get_icon' ] )
+ ->getMock();
+
+ $link_pm = $this->getMockBuilder( Link_Payment_Method::class )
+ ->setConstructorArgs( [ $this->mock_token_service ] )
+ ->onlyMethods( [ 'get_icon' ] )
+ ->getMock();
+
+ $card_pm->expects( $this->any() )
+ ->method( 'get_icon' )
+ ->will(
+ $this->returnValue( $icon_url )
+ );
+
+ $link_pm->expects( $this->any() )
+ ->method( 'get_icon' )
+ ->will(
+ $this->returnValue( $icon_url )
+ );
+
+ $this->mock_wcpay_gateway
+ ->method( 'wc_payments_get_payment_method_by_id' )
+ ->withConsecutive( [ 'card' ], [ 'link' ] )
+ ->willReturnOnConsecutiveCalls( $card_pm, $link_pm );
+
+ $this->mock_wcpay_account
+ ->expects( $this->any() )
+ ->method( 'get_fees' )
+ ->willReturn( $payment_methods );
+
+ $this->assertSame(
+ $this->system_under_test->get_payment_fields_js_config()['paymentMethodsConfig'],
+ [
+ 'card' => [
+ 'isReusable' => true,
+ 'title' => 'Credit card / debit card',
+ 'icon' => $icon_url,
+ 'showSaveOption' => true,
+ 'countries' => [],
+ 'upePaymentIntentData' => null,
+ 'upeSetupIntentData' => null,
+ 'testingInstructions' => 'Test mode: use the test VISA card 4242424242424242 with any expiry date and CVC. Other payment methods may redirect to a Stripe test page to authorize payment. More test card numbers are listed here .',
+ 'forceNetworkSavedCards' => false,
+ ],
+ 'link' => [
+ 'isReusable' => true,
+ 'title' => 'Link',
+ 'icon' => $icon_url,
+ 'showSaveOption' => true,
+ 'countries' => [],
+ 'upePaymentIntentData' => null,
+ 'upeSetupIntentData' => null,
+ 'testingInstructions' => '',
+ 'forceNetworkSavedCards' => false,
+ ],
+ ]
+ );
+ }
+
+ /**
+ * @dataProvider non_reusable_payment_method_provider
+ */
+ public function test_no_save_option_for_non_reusable_payment_method( $payment_method_id, $payment_method_class ) {
+ $this->mock_wcpay_gateway
+ ->expects( $this->any() )
+ ->method( 'get_payment_method_ids_enabled_at_checkout' )
+ ->willReturn(
+ [
+ $payment_method_id,
+ ]
+ );
+
+ $this->mock_wcpay_gateway
+ ->method( 'wc_payments_get_payment_method_by_id' )
+ ->willReturn(
+ new $payment_method_class( $this->mock_token_service )
+ );
+
+ $this->assertSame( false, $this->system_under_test->get_payment_fields_js_config()['paymentMethodsConfig'][ $payment_method_id ]['showSaveOption'] );
+ }
+
+ public function non_reusable_payment_method_provider() {
+ return [
+ [ Payment_Method::BANCONTACT, Bancontact_Payment_Method::class ],
+ [ Payment_Method::EPS, Eps_Payment_Method::class ],
+ [ Payment_Method::GIROPAY, Giropay_Payment_Method::class ],
+ [ Payment_Method::IDEAL, Ideal_Payment_Method::class ],
+ [ Payment_Method::P24, P24_Payment_Method::class ],
+ [ Payment_Method::SOFORT, Sofort_Payment_Method::class ],
+ ];
+ }
+
+ public function test_no_save_option_for_reusable_payment_payment_with_subscription_in_cart() {
+ $this->mock_wcpay_gateway
+ ->method( 'is_subscription_item_in_cart' )
+ ->willReturn( true );
+
+ $this->mock_wcpay_gateway
+ ->method( 'is_saved_cards_enabled' )
+ ->willReturn( true );
+
+ $this->mock_wcpay_gateway
+ ->expects( $this->any() )
+ ->method( 'get_payment_method_ids_enabled_at_checkout' )
+ ->willReturn(
+ [
+ Payment_Method::CARD,
+ ]
+ );
+
+ $this->mock_wcpay_gateway
+ ->method( 'wc_payments_get_payment_method_by_id' )
+ ->willReturn(
+ new CC_Payment_Method( $this->mock_token_service )
+ );
+ $this->assertSame( false, $this->system_under_test->get_payment_fields_js_config()['paymentMethodsConfig'][ Payment_Method::CARD ]['showSaveOption'] );
+ }
+
+ public function test_no_save_option_for_reusable_payment_payment_but_with_saved_cards_disabled() {
+ $this->mock_wcpay_gateway
+ ->method( 'is_subscription_item_in_cart' )
+ ->willReturn( false );
+
+ $this->mock_wcpay_gateway
+ ->method( 'is_saved_cards_enabled' )
+ ->willReturn( false );
+
+ $this->mock_wcpay_gateway
+ ->expects( $this->any() )
+ ->method( 'get_payment_method_ids_enabled_at_checkout' )
+ ->willReturn(
+ [
+ Payment_Method::CARD,
+ ]
+ );
+
+ $this->mock_wcpay_gateway
+ ->method( 'wc_payments_get_payment_method_by_id' )
+ ->willReturn(
+ new CC_Payment_Method( $this->mock_token_service )
+ );
+ $this->assertSame( false, $this->system_under_test->get_payment_fields_js_config()['paymentMethodsConfig'][ Payment_Method::CARD ]['showSaveOption'] );
+ }
+
+ public function test_save_option_for_reusable_payment_payment() {
+ $this->mock_wcpay_gateway
+ ->method( 'is_subscription_item_in_cart' )
+ ->willReturn( false );
+
+ $this->mock_wcpay_gateway
+ ->method( 'is_saved_cards_enabled' )
+ ->willReturn( true );
+
+ $this->mock_wcpay_gateway
+ ->expects( $this->any() )
+ ->method( 'get_payment_method_ids_enabled_at_checkout' )
+ ->willReturn(
+ [
+ Payment_Method::CARD,
+ ]
+ );
+
+ $this->mock_wcpay_gateway
+ ->method( 'wc_payments_get_payment_method_by_id' )
+ ->willReturn(
+ new CC_Payment_Method( $this->mock_token_service )
+ );
+ $this->assertSame( true, $this->system_under_test->get_payment_fields_js_config()['paymentMethodsConfig'][ Payment_Method::CARD ]['showSaveOption'] );
+ }
+}
From ce4dc97e3090db266a813d76a2443d475f4dfdd7 Mon Sep 17 00:00:00 2001
From: Mike Moore
Date: Fri, 22 Dec 2023 18:20:02 -0500
Subject: [PATCH 48/56] Introduce express checkout utilities class (#7926)
---
changelog/7588-express-checkout-utilities | 4 +
...xpress-checkout-button-display-handler.php | 13 +-
...ayments-payment-request-button-handler.php | 216 ++--------------
...lass-wc-payments-woopay-button-handler.php | 191 --------------
includes/class-wc-payments.php | 13 +-
...ayments-express-checkout-button-helper.php | 235 ++++++++++++++++++
...xpress-checkout-button-display-handler.php | 12 +-
...ayments-payment-request-button-handler.php | 19 +-
8 files changed, 312 insertions(+), 391 deletions(-)
create mode 100644 changelog/7588-express-checkout-utilities
create mode 100644 includes/express-checkout/class-wc-payments-express-checkout-button-helper.php
diff --git a/changelog/7588-express-checkout-utilities b/changelog/7588-express-checkout-utilities
new file mode 100644
index 00000000000..143b670d60c
--- /dev/null
+++ b/changelog/7588-express-checkout-utilities
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Introduce WC_Payments_Express_Checkout_Button_Utils class.
diff --git a/includes/class-wc-payments-express-checkout-button-display-handler.php b/includes/class-wc-payments-express-checkout-button-display-handler.php
index ad8db375684..5a9cf2ec12c 100644
--- a/includes/class-wc-payments-express-checkout-button-display-handler.php
+++ b/includes/class-wc-payments-express-checkout-button-display-handler.php
@@ -35,17 +35,26 @@ class WC_Payments_Express_Checkout_Button_Display_Handler {
*/
private $platform_checkout_button_handler;
+ /**
+ * Express Checkout Helper instance.
+ *
+ * @var WC_Payments_Express_Checkout_Button_Helper
+ */
+ private $express_checkout_helper;
+
/**
* Initialize class actions.
*
* @param WC_Payment_Gateway_WCPay $gateway WCPay gateway.
* @param WC_Payments_Payment_Request_Button_Handler $payment_request_button_handler Payment request button handler.
* @param WC_Payments_WooPay_Button_Handler $platform_checkout_button_handler Platform checkout button handler.
+ * @param WC_Payments_Express_Checkout_Button_Helper $express_checkout_helper Express checkout helper.
*/
- public function __construct( WC_Payment_Gateway_WCPay $gateway, WC_Payments_Payment_Request_Button_Handler $payment_request_button_handler, WC_Payments_WooPay_Button_Handler $platform_checkout_button_handler ) {
+ public function __construct( WC_Payment_Gateway_WCPay $gateway, WC_Payments_Payment_Request_Button_Handler $payment_request_button_handler, WC_Payments_WooPay_Button_Handler $platform_checkout_button_handler, WC_Payments_Express_Checkout_Button_Helper $express_checkout_helper ) {
$this->gateway = $gateway;
$this->payment_request_button_handler = $payment_request_button_handler;
$this->platform_checkout_button_handler = $platform_checkout_button_handler;
+ $this->express_checkout_helper = $express_checkout_helper;
$this->platform_checkout_button_handler->init();
$this->payment_request_button_handler->init();
@@ -54,6 +63,8 @@ public function __construct( WC_Payment_Gateway_WCPay $gateway, WC_Payments_Paym
$is_payment_request_enabled = 'yes' === $this->gateway->get_option( 'payment_request' );
if ( $is_woopay_enabled || $is_payment_request_enabled ) {
+ add_action( 'wc_ajax_wcpay_add_to_cart', [ $this->express_checkout_helper, 'ajax_add_to_cart' ] );
+
add_action( 'woocommerce_after_add_to_cart_form', [ $this, 'display_express_checkout_buttons' ], 1 );
add_action( 'woocommerce_proceed_to_checkout', [ $this, 'display_express_checkout_buttons' ], 21 );
add_action( 'woocommerce_checkout_before_customer_details', [ $this, 'display_express_checkout_buttons' ], 1 );
diff --git a/includes/class-wc-payments-payment-request-button-handler.php b/includes/class-wc-payments-payment-request-button-handler.php
index ff030924969..7a30adad550 100644
--- a/includes/class-wc-payments-payment-request-button-handler.php
+++ b/includes/class-wc-payments-payment-request-button-handler.php
@@ -36,15 +36,24 @@ class WC_Payments_Payment_Request_Button_Handler {
*/
private $gateway;
+ /**
+ * Express Checkout Helper instance.
+ *
+ * @var WC_Payments_Express_Checkout_Button_Helper
+ */
+ private $express_checkout_helper;
+
/**
* Initialize class actions.
*
- * @param WC_Payments_Account $account Account information.
- * @param WC_Payment_Gateway_WCPay $gateway WCPay gateway.
+ * @param WC_Payments_Account $account Account information.
+ * @param WC_Payment_Gateway_WCPay $gateway WCPay gateway.
+ * @param WC_Payments_Express_Checkout_Button_Helper $express_checkout_helper Express checkout helper.
*/
- public function __construct( WC_Payments_Account $account, WC_Payment_Gateway_WCPay $gateway ) {
- $this->account = $account;
- $this->gateway = $gateway;
+ public function __construct( WC_Payments_Account $account, WC_Payment_Gateway_WCPay $gateway, WC_Payments_Express_Checkout_Button_Helper $express_checkout_helper ) {
+ $this->account = $account;
+ $this->gateway = $gateway;
+ $this->express_checkout_helper = $express_checkout_helper;
}
/**
@@ -78,7 +87,6 @@ public function init() {
add_action( 'wc_ajax_wcpay_get_shipping_options', [ $this, 'ajax_get_shipping_options' ] );
add_action( 'wc_ajax_wcpay_update_shipping_method', [ $this, 'ajax_update_shipping_method' ] );
add_action( 'wc_ajax_wcpay_create_order', [ $this, 'ajax_create_order' ] );
- add_action( 'wc_ajax_wcpay_add_to_cart', [ $this, 'ajax_add_to_cart' ] );
add_action( 'wc_ajax_wcpay_get_selected_product_data', [ $this, 'ajax_get_selected_product_data' ] );
add_action( 'wc_ajax_wcpay_pay_for_order', [ $this, 'ajax_pay_for_order' ] );
@@ -134,17 +142,6 @@ public function is_account_creation_possible() {
);
}
- /**
- * Gets total label.
- *
- * @return string
- */
- public function get_total_label() {
- // Get statement descriptor from API/cached account data.
- $statement_descriptor = $this->account->get_statement_descriptor();
- return str_replace( "'", '', $statement_descriptor ) . apply_filters( 'wcpay_payment_request_total_label_suffix', ' (via WooCommerce)' );
- }
-
/**
* Sets the WC customer session if one is not set.
* This is needed so nonces can be verified by AJAX Request.
@@ -211,7 +208,7 @@ public function get_button_height() {
*/
public function get_product_price( $product ) {
// If prices should include tax, using tax inclusive price.
- if ( $this->cart_prices_include_tax() ) {
+ if ( $this->express_checkout_helper->cart_prices_include_tax() ) {
$base_price = wc_get_price_including_tax( $product );
} else {
$base_price = wc_get_price_excluding_tax( $product );
@@ -319,7 +316,7 @@ public function get_product_data() {
$data['displayItems'] = $items;
$data['total'] = [
- 'label' => apply_filters( 'wcpay_payment_request_total_label', $this->get_total_label() ),
+ 'label' => apply_filters( 'wcpay_payment_request_total_label', $this->express_checkout_helper->get_total_label() ),
'amount' => WC_Payments_Utils::prepare_amount( $price + $total_tax, $currency ),
'pending' => true,
];
@@ -382,7 +379,7 @@ public function display_pay_for_order_page_html( $order ) {
$data['displayItems'] = $items;
$data['needs_shipping'] = false; // This should be already entered/prepared.
$data['total'] = [
- 'label' => apply_filters( 'wcpay_payment_request_total_label', $this->get_total_label() ),
+ 'label' => apply_filters( 'wcpay_payment_request_total_label', $this->express_checkout_helper->get_total_label() ),
'amount' => WC_Payments_Utils::prepare_amount( $order->get_total(), $currency ),
'pending' => true,
];
@@ -400,7 +397,7 @@ public function get_cart_data() {
return false;
}
- return $this->build_display_items();
+ return $this->express_checkout_helper->build_display_items();
}
/**
@@ -802,7 +799,7 @@ public function scripts() {
'is_pay_for_order' => $this->is_pay_for_order_page(),
'has_block' => has_block( 'woocommerce/cart' ) || has_block( 'woocommerce/checkout' ),
'product' => $this->get_product_data(),
- 'total_label' => $this->get_total_label(),
+ 'total_label' => $this->express_checkout_helper->get_total_label(),
];
WC_Payments::register_script_with_dependencies( 'WCPAY_PAYMENT_REQUEST', 'dist/payment-request', [ 'jquery', 'stripe' ] );
@@ -890,7 +887,7 @@ public function ajax_get_cart_details() {
WC()->cart->calculate_totals();
- wp_send_json( array_merge( $this->build_display_items(), [ 'needs_shipping' => WC()->cart->needs_shipping() ] ) );
+ wp_send_json( array_merge( $this->express_checkout_helper->build_display_items(), [ 'needs_shipping' => WC()->cart->needs_shipping() ] ) );
}
/**
@@ -986,10 +983,10 @@ public function get_shipping_options( $shipping_address, $itemized_display_items
WC()->cart->calculate_totals();
- $data += $this->build_display_items( $itemized_display_items );
+ $data += $this->express_checkout_helper->build_display_items( $itemized_display_items );
$data['result'] = 'success';
} catch ( Exception $e ) {
- $data += $this->build_display_items( $itemized_display_items );
+ $data += $this->express_checkout_helper->build_display_items( $itemized_display_items );
$data['result'] = 'invalid_shipping_address';
}
@@ -1015,7 +1012,7 @@ public function ajax_update_shipping_method() {
$should_show_itemized_view = ! isset( $product_view_options['is_product_page'] ) ? true : filter_var( $product_view_options['is_product_page'], FILTER_VALIDATE_BOOLEAN );
$data = [];
- $data += $this->build_display_items( $should_show_itemized_view );
+ $data += $this->express_checkout_helper->build_display_items( $should_show_itemized_view );
$data['result'] = 'success';
wp_send_json( $data );
@@ -1121,7 +1118,7 @@ public function ajax_get_selected_product_data() {
$data['displayItems'] = $items;
$data['total'] = [
- 'label' => $this->get_total_label(),
+ 'label' => $this->express_checkout_helper->get_total_label(),
'amount' => WC_Payments_Utils::prepare_amount( $total + $total_tax, $currency ),
'pending' => true,
];
@@ -1139,62 +1136,6 @@ public function ajax_get_selected_product_data() {
}
}
- /**
- * Adds the current product to the cart. Used on product detail page.
- */
- public function ajax_add_to_cart() {
- check_ajax_referer( 'wcpay-add-to-cart', 'security' );
-
- if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
- define( 'WOOCOMMERCE_CART', true );
- }
-
- WC()->shipping->reset_shipping();
-
- $product_id = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : false;
- $product = wc_get_product( $product_id );
-
- if ( ! $product ) {
- wp_send_json(
- [
- 'error' => [
- 'code' => 'invalid_product_id',
- 'message' => __( 'Invalid product id', 'woocommerce-payments' ),
- ],
- ],
- 404
- );
- return;
- }
-
- $qty = ! isset( $_POST['qty'] ) ? 1 : absint( $_POST['qty'] );
- $product_type = $product->get_type();
-
- // First empty the cart to prevent wrong calculation.
- WC()->cart->empty_cart();
-
- if ( ( 'variable' === $product_type || 'variable-subscription' === $product_type ) && isset( $_POST['attributes'] ) ) {
- $attributes = wc_clean( wp_unslash( $_POST['attributes'] ) );
-
- $data_store = WC_Data_Store::load( 'product' );
- $variation_id = $data_store->find_matching_product_variation( $product, $attributes );
-
- WC()->cart->add_to_cart( $product->get_id(), $qty, $variation_id, $attributes );
- }
-
- if ( in_array( $product_type, [ 'simple', 'variation', 'subscription', 'subscription_variation' ], true ) ) {
- WC()->cart->add_to_cart( $product->get_id(), $qty );
- }
-
- WC()->cart->calculate_totals();
-
- $data = [];
- $data += $this->build_display_items();
- $data['result'] = 'success';
-
- wp_send_json( $data );
- }
-
/**
* Handles payment requests on the Pay for Order page.
*
@@ -1510,16 +1451,6 @@ protected function calculate_shipping( $address = [] ) {
WC()->shipping->calculate_shipping( $packages );
}
- /**
- * Whether tax should be displayed on separate line in cart.
- * returns true if tax is disabled or display of tax in checkout is set to inclusive.
- *
- * @return boolean
- */
- private function cart_prices_include_tax() {
- return ! wc_tax_enabled() || 'incl' === get_option( 'woocommerce_tax_display_cart' );
- }
-
/**
* Builds the shipping methods to pass to Payment Request
*
@@ -1544,103 +1475,6 @@ protected function build_shipping_methods( $shipping_methods ) {
return $shipping;
}
- /**
- * Builds the line items to pass to Payment Request
- *
- * @param boolean $itemized_display_items Indicates whether to show subtotals or itemized views.
- */
- public function build_display_items( $itemized_display_items = false ) {
- if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
- define( 'WOOCOMMERCE_CART', true );
- }
-
- $items = [];
- $subtotal = 0;
- $discounts = 0;
- $currency = get_woocommerce_currency();
-
- // Default show only subtotal instead of itemization.
- if ( ! apply_filters( 'wcpay_payment_request_hide_itemization', true ) || $itemized_display_items ) {
- foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
- $amount = $cart_item['line_subtotal'];
- $subtotal += $cart_item['line_subtotal'];
- $quantity_label = 1 < $cart_item['quantity'] ? ' (x' . $cart_item['quantity'] . ')' : '';
-
- $product_name = $cart_item['data']->get_name();
-
- $item_tax = $this->cart_prices_include_tax() ? ( $cart_item['line_subtotal_tax'] ?? 0 ) : 0;
-
- $item = [
- 'label' => $product_name . $quantity_label,
- 'amount' => WC_Payments_Utils::prepare_amount( $amount + $item_tax, $currency ),
- ];
-
- $items[] = $item;
- }
- }
-
- if ( version_compare( WC_VERSION, '3.2', '<' ) ) {
- $discounts = wc_format_decimal( WC()->cart->get_cart_discount_total(), WC()->cart->dp );
- } else {
- $applied_coupons = array_values( WC()->cart->get_coupon_discount_totals() );
-
- foreach ( $applied_coupons as $amount ) {
- $discounts += (float) $amount;
- }
- }
-
- $discounts = wc_format_decimal( $discounts, WC()->cart->dp );
- $tax = wc_format_decimal( WC()->cart->tax_total + WC()->cart->shipping_tax_total, WC()->cart->dp );
- $shipping = wc_format_decimal( WC()->cart->shipping_total, WC()->cart->dp );
- $items_total = wc_format_decimal( WC()->cart->cart_contents_total, WC()->cart->dp ) + $discounts;
- $order_total = version_compare( WC_VERSION, '3.2', '<' ) ? wc_format_decimal( $items_total + $tax + $shipping - $discounts, WC()->cart->dp ) : WC()->cart->get_total( '' );
-
- if ( ! $this->cart_prices_include_tax() ) {
- $items[] = [
- 'label' => esc_html( __( 'Tax', 'woocommerce-payments' ) ),
- 'amount' => WC_Payments_Utils::prepare_amount( $tax, $currency ),
- ];
- }
-
- if ( WC()->cart->needs_shipping() ) {
- $shipping_tax = $this->cart_prices_include_tax() ? WC()->cart->shipping_tax_total : 0;
- $items[] = [
- 'label' => esc_html( __( 'Shipping', 'woocommerce-payments' ) ),
- 'amount' => WC_Payments_Utils::prepare_amount( $shipping + $shipping_tax, $currency ),
- ];
- }
-
- if ( WC()->cart->has_discount() ) {
- $items[] = [
- 'label' => esc_html( __( 'Discount', 'woocommerce-payments' ) ),
- 'amount' => WC_Payments_Utils::prepare_amount( $discounts, $currency ),
- ];
- }
-
- if ( version_compare( WC_VERSION, '3.2', '<' ) ) {
- $cart_fees = WC()->cart->fees;
- } else {
- $cart_fees = WC()->cart->get_fees();
- }
-
- // Include fees and taxes as display items.
- foreach ( $cart_fees as $key => $fee ) {
- $items[] = [
- 'label' => $fee->name,
- 'amount' => WC_Payments_Utils::prepare_amount( $fee->amount, $currency ),
- ];
- }
-
- return [
- 'displayItems' => $items,
- 'total' => [
- 'label' => $this->get_total_label(),
- 'amount' => max( 0, apply_filters( 'wcpay_calculated_total', WC_Payments_Utils::prepare_amount( $order_total, $currency ), $order_total, WC()->cart ) ),
- 'pending' => false,
- ],
- ];
- }
-
/**
* Calculates whether Apple Pay is enabled for this store.
* The option value is not stored in the database, and is calculated
@@ -1715,7 +1549,7 @@ public function get_login_confirmation_settings() {
* @return array An array of final taxes.
*/
private function get_taxes_like_cart( $product, $price ) {
- if ( ! wc_tax_enabled() || $this->cart_prices_include_tax() ) {
+ if ( ! wc_tax_enabled() || $this->express_checkout_helper->cart_prices_include_tax() ) {
// Only proceed when taxes are enabled, but not included.
return [];
}
diff --git a/includes/class-wc-payments-woopay-button-handler.php b/includes/class-wc-payments-woopay-button-handler.php
index 44154c29ee7..5045174a7b3 100644
--- a/includes/class-wc-payments-woopay-button-handler.php
+++ b/includes/class-wc-payments-woopay-button-handler.php
@@ -125,8 +125,6 @@ public function init() {
add_filter( 'wcpay_payment_fields_js_config', [ $this, 'add_woopay_config' ] );
- add_action( 'wc_ajax_wcpay_add_to_cart', [ $this, 'ajax_add_to_cart' ] );
-
add_action( 'wp_ajax_woopay_express_checkout_button_show_error_notice', [ $this, 'show_error_notice' ] );
add_action( 'wp_ajax_nopriv_woopay_express_checkout_button_show_error_notice', [ $this, 'show_error_notice' ] );
}
@@ -214,195 +212,6 @@ public function show_error_notice() {
wp_die();
}
- /**
- * Adds the current product to the cart. Used on product detail page.
- */
- public function ajax_add_to_cart() {
- check_ajax_referer( 'wcpay-add-to-cart', 'security' );
-
- if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
- define( 'WOOCOMMERCE_CART', true );
- }
-
- WC()->shipping->reset_shipping();
-
- $product_id = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : false;
- $quantity = ! isset( $_POST['quantity'] ) ? 1 : absint( $_POST['quantity'] );
- $product = wc_get_product( $product_id );
-
- if ( ! $product ) {
- wp_send_json(
- [
- 'error' => [
- 'code' => 'invalid_product_id',
- 'message' => __( 'Invalid product id', 'woocommerce-payments' ),
- ],
- ],
- 404
- );
- return;
- }
-
- $product_type = $product->get_type();
-
- // First empty the cart to prevent wrong calculation.
- WC()->cart->empty_cart();
-
- $is_add_to_cart_valid = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
-
- if ( ! $is_add_to_cart_valid ) {
- // Some extensions error messages needs to be
- // submitted to show error messages.
- wp_send_json(
- [
- 'error' => true,
- 'submit' => true,
- ],
- 400
- );
- return;
- }
-
- if ( ( 'variable' === $product_type || 'variable-subscription' === $product_type ) && isset( $_POST['attributes'] ) ) {
- $attributes = wc_clean( wp_unslash( $_POST['attributes'] ) );
-
- $data_store = WC_Data_Store::load( 'product' );
- $variation_id = $data_store->find_matching_product_variation( $product, $attributes );
-
- WC()->cart->add_to_cart( $product->get_id(), $quantity, $variation_id, $attributes );
- }
-
- if ( in_array( $product_type, [ 'simple', 'subscription', 'subscription_variation', 'bundle', 'mix-and-match' ], true ) ) {
- WC()->cart->add_to_cart( $product->get_id(), $quantity );
- }
-
- WC()->cart->calculate_totals();
-
- $data = [];
- $data += $this->build_display_items();
- $data['result'] = 'success';
-
- wp_send_json( $data );
- }
-
- /**
- * Builds the line items to pass to Payment Request
- *
- * @param boolean $itemized_display_items Indicates whether to show subtotals or itemized views.
- */
- protected function build_display_items( $itemized_display_items = false ) {
- if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
- define( 'WOOCOMMERCE_CART', true );
- }
-
- $items = [];
- $subtotal = 0;
- $discounts = 0;
- $currency = get_woocommerce_currency();
-
- // Default show only subtotal instead of itemization.
- if ( ! apply_filters( 'wcpay_payment_request_hide_itemization', true ) || $itemized_display_items ) {
- foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
- $amount = $cart_item['line_subtotal'];
- $subtotal += $cart_item['line_subtotal'];
- $quantity_label = 1 < $cart_item['quantity'] ? ' (x' . $cart_item['quantity'] . ')' : '';
-
- $product_name = $cart_item['data']->get_name();
-
- $item_tax = $this->cart_prices_include_tax() ? ( $cart_item['line_subtotal_tax'] ?? 0 ) : 0;
-
- $item = [
- 'label' => $product_name . $quantity_label,
- 'amount' => WC_Payments_Utils::prepare_amount( $amount + $item_tax, $currency ),
- ];
-
- $items[] = $item;
- }
- }
-
- if ( version_compare( WC_VERSION, '3.2', '<' ) ) {
- $discounts = wc_format_decimal( WC()->cart->get_cart_discount_total(), WC()->cart->dp );
- } else {
- $applied_coupons = array_values( WC()->cart->get_coupon_discount_totals() );
-
- foreach ( $applied_coupons as $amount ) {
- $discounts += (float) $amount;
- }
- }
-
- $discounts = wc_format_decimal( $discounts, WC()->cart->dp );
- $tax = wc_format_decimal( WC()->cart->tax_total + WC()->cart->shipping_tax_total, WC()->cart->dp );
- $shipping = wc_format_decimal( WC()->cart->shipping_total, WC()->cart->dp );
- $items_total = wc_format_decimal( WC()->cart->cart_contents_total, WC()->cart->dp ) + $discounts;
- $order_total = version_compare( WC_VERSION, '3.2', '<' ) ? wc_format_decimal( $items_total + $tax + $shipping - $discounts, WC()->cart->dp ) : WC()->cart->get_total( '' );
-
- if ( ! $this->cart_prices_include_tax() ) {
- $items[] = [
- 'label' => esc_html( __( 'Tax', 'woocommerce-payments' ) ),
- 'amount' => WC_Payments_Utils::prepare_amount( $tax, $currency ),
- ];
- }
-
- if ( WC()->cart->needs_shipping() ) {
- $shipping_tax = $this->cart_prices_include_tax() ? WC()->cart->shipping_tax_total : 0;
- $items[] = [
- 'label' => esc_html( __( 'Shipping', 'woocommerce-payments' ) ),
- 'amount' => WC_Payments_Utils::prepare_amount( $shipping + $shipping_tax, $currency ),
- ];
- }
-
- if ( WC()->cart->has_discount() ) {
- $items[] = [
- 'label' => esc_html( __( 'Discount', 'woocommerce-payments' ) ),
- 'amount' => WC_Payments_Utils::prepare_amount( $discounts, $currency ),
- ];
- }
-
- if ( version_compare( WC_VERSION, '3.2', '<' ) ) {
- $cart_fees = WC()->cart->fees;
- } else {
- $cart_fees = WC()->cart->get_fees();
- }
-
- // Include fees and taxes as display items.
- foreach ( $cart_fees as $key => $fee ) {
- $items[] = [
- 'label' => $fee->name,
- 'amount' => WC_Payments_Utils::prepare_amount( $fee->amount, $currency ),
- ];
- }
-
- return [
- 'displayItems' => $items,
- 'total' => [
- 'label' => $this->get_total_label(),
- 'amount' => max( 0, apply_filters( 'wcpay_calculated_total', WC_Payments_Utils::prepare_amount( $order_total, $currency ), $order_total, WC()->cart ) ),
- 'pending' => false,
- ],
- ];
- }
-
- /**
- * Whether tax should be displayed on separate line in cart.
- * returns true if tax is disabled or display of tax in checkout is set to inclusive.
- *
- * @return boolean
- */
- private function cart_prices_include_tax() {
- return ! wc_tax_enabled() || 'incl' === get_option( 'woocommerce_tax_display_cart' );
- }
-
- /**
- * Gets total label.
- *
- * @return string
- */
- public function get_total_label() {
- // Get statement descriptor from API/cached account data.
- $statement_descriptor = $this->account->get_statement_descriptor();
- return str_replace( "'", '', $statement_descriptor ) . apply_filters( 'wcpay_payment_request_total_label_suffix', ' (via WooCommerce)' );
- }
-
/**
* Checks if this is a product page or content contains a product_page shortcode.
*
diff --git a/includes/class-wc-payments.php b/includes/class-wc-payments.php
index baf1ea9a8ca..bd0cb8dc97f 100644
--- a/includes/class-wc-payments.php
+++ b/includes/class-wc-payments.php
@@ -295,6 +295,13 @@ class WC_Payments {
*/
private static $incentives_service;
+ /**
+ * Instance of WC_Payments_Express_Checkout_Button_Helper, created in init function.
+ *
+ * @var WC_Payments_Express_Checkout_Button_Helper
+ */
+ private static $express_checkout_helper;
+
/**
* Instance of Compatibility_Service, created in init function
*
@@ -415,6 +422,7 @@ public static function init() {
include_once __DIR__ . '/payment-methods/class-affirm-payment-method.php';
include_once __DIR__ . '/payment-methods/class-afterpay-payment-method.php';
include_once __DIR__ . '/payment-methods/class-klarna-payment-method.php';
+ include_once __DIR__ . '/express-checkout/class-wc-payments-express-checkout-button-helper.php';
include_once __DIR__ . '/class-wc-payment-token-wcpay-sepa.php';
include_once __DIR__ . '/class-wc-payments-status.php';
include_once __DIR__ . '/class-wc-payments-token-service.php';
@@ -501,6 +509,7 @@ public static function init() {
self::$failed_transaction_rate_limiter = new Session_Rate_Limiter( Session_Rate_Limiter::SESSION_KEY_DECLINED_CARD_REGISTRY, 5, 10 * MINUTE_IN_SECONDS );
self::$order_success_page = new WC_Payments_Order_Success_Page();
self::$onboarding_service = new WC_Payments_Onboarding_Service( self::$api_client, self::$database_cache );
+ self::$express_checkout_helper = new WC_Payments_Express_Checkout_Button_Helper( self::$account );
self::$woopay_util = new WooPay_Utilities();
self::$woopay_tracker = new WooPay_Tracker( self::get_wc_payments_http() );
self::$incentives_service = new WC_Payments_Incentives_Service( self::$database_cache );
@@ -1504,9 +1513,9 @@ function ( $container ) {
*/
public static function maybe_display_express_checkout_buttons() {
if ( WC_Payments_Features::are_payments_enabled() ) {
- $payment_request_button_handler = new WC_Payments_Payment_Request_Button_Handler( self::$account, self::get_gateway() );
+ $payment_request_button_handler = new WC_Payments_Payment_Request_Button_Handler( self::$account, self::get_gateway(), self::$express_checkout_helper );
$woopay_button_handler = new WC_Payments_WooPay_Button_Handler( self::$account, self::get_gateway(), self::$woopay_util );
- $express_checkout_button_display_handler = new WC_Payments_Express_Checkout_Button_Display_Handler( self::get_gateway(), $payment_request_button_handler, $woopay_button_handler );
+ $express_checkout_button_display_handler = new WC_Payments_Express_Checkout_Button_Display_Handler( self::get_gateway(), $payment_request_button_handler, $woopay_button_handler, self::$express_checkout_helper );
}
}
diff --git a/includes/express-checkout/class-wc-payments-express-checkout-button-helper.php b/includes/express-checkout/class-wc-payments-express-checkout-button-helper.php
new file mode 100644
index 00000000000..1eb77586ebb
--- /dev/null
+++ b/includes/express-checkout/class-wc-payments-express-checkout-button-helper.php
@@ -0,0 +1,235 @@
+account = $account;
+ }
+
+ /**
+ * Adds the current product to the cart. Used on product detail page.
+ */
+ public function ajax_add_to_cart() {
+ check_ajax_referer( 'wcpay-add-to-cart', 'security' );
+
+ if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
+ define( 'WOOCOMMERCE_CART', true );
+ }
+
+ WC()->shipping->reset_shipping();
+
+ $product_id = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : false;
+ $product = wc_get_product( $product_id );
+
+ if ( ! $product ) {
+ wp_send_json(
+ [
+ 'error' => [
+ 'code' => 'invalid_product_id',
+ 'message' => __( 'Invalid product id', 'woocommerce-payments' ),
+ ],
+ ],
+ 404
+ );
+ return;
+ }
+
+ $quantity = $this->get_quantity();
+
+ $product_type = $product->get_type();
+
+ $is_add_to_cart_valid = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
+
+ if ( ! $is_add_to_cart_valid ) {
+ // Some extensions error messages needs to be
+ // submitted to show error messages.
+ wp_send_json(
+ [
+ 'error' => true,
+ 'submit' => true,
+ ],
+ 400
+ );
+ return;
+ }
+
+ // First empty the cart to prevent wrong calculation.
+ WC()->cart->empty_cart();
+
+ if ( ( 'variable' === $product_type || 'variable-subscription' === $product_type ) && isset( $_POST['attributes'] ) ) {
+ $attributes = wc_clean( wp_unslash( $_POST['attributes'] ) );
+
+ $data_store = WC_Data_Store::load( 'product' );
+ $variation_id = $data_store->find_matching_product_variation( $product, $attributes );
+
+ WC()->cart->add_to_cart( $product->get_id(), $quantity, $variation_id, $attributes );
+ }
+
+ if ( in_array( $product_type, [ 'simple', 'subscription', 'subscription_variation', 'bundle', 'mix-and-match' ], true ) ) {
+ WC()->cart->add_to_cart( $product->get_id(), $quantity );
+ }
+
+ WC()->cart->calculate_totals();
+
+ $data = [];
+ $data += $this->build_display_items();
+ $data['result'] = 'success';
+
+ wp_send_json( $data );
+ }
+
+ /**
+ * Builds the line items to pass to Payment Request
+ *
+ * @param boolean $itemized_display_items Indicates whether to show subtotals or itemized views.
+ */
+ public function build_display_items( $itemized_display_items = false ) {
+ if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
+ define( 'WOOCOMMERCE_CART', true );
+ }
+
+ $items = [];
+ $subtotal = 0;
+ $discounts = 0;
+ $currency = get_woocommerce_currency();
+
+ // Default show only subtotal instead of itemization.
+ if ( ! apply_filters( 'wcpay_payment_request_hide_itemization', true ) || $itemized_display_items ) {
+ foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
+ $amount = $cart_item['line_subtotal'];
+ $subtotal += $cart_item['line_subtotal'];
+ $quantity_label = 1 < $cart_item['quantity'] ? ' (x' . $cart_item['quantity'] . ')' : '';
+
+ $product_name = $cart_item['data']->get_name();
+
+ $item_tax = $this->cart_prices_include_tax() ? ( $cart_item['line_subtotal_tax'] ?? 0 ) : 0;
+
+ $item = [
+ 'label' => $product_name . $quantity_label,
+ 'amount' => WC_Payments_Utils::prepare_amount( $amount + $item_tax, $currency ),
+ ];
+
+ $items[] = $item;
+ }
+ }
+
+ if ( version_compare( WC_VERSION, '3.2', '<' ) ) {
+ $discounts = wc_format_decimal( WC()->cart->get_cart_discount_total(), WC()->cart->dp );
+ } else {
+ $applied_coupons = array_values( WC()->cart->get_coupon_discount_totals() );
+
+ foreach ( $applied_coupons as $amount ) {
+ $discounts += (float) $amount;
+ }
+ }
+
+ $discounts = wc_format_decimal( $discounts, WC()->cart->dp );
+ $tax = wc_format_decimal( WC()->cart->tax_total + WC()->cart->shipping_tax_total, WC()->cart->dp );
+ $shipping = wc_format_decimal( WC()->cart->shipping_total, WC()->cart->dp );
+ $items_total = wc_format_decimal( WC()->cart->cart_contents_total, WC()->cart->dp ) + $discounts;
+ $order_total = version_compare( WC_VERSION, '3.2', '<' ) ? wc_format_decimal( $items_total + $tax + $shipping - $discounts, WC()->cart->dp ) : WC()->cart->get_total( '' );
+
+ if ( ! $this->cart_prices_include_tax() ) {
+ $items[] = [
+ 'label' => esc_html( __( 'Tax', 'woocommerce-payments' ) ),
+ 'amount' => WC_Payments_Utils::prepare_amount( $tax, $currency ),
+ ];
+ }
+
+ if ( WC()->cart->needs_shipping() ) {
+ $shipping_tax = $this->cart_prices_include_tax() ? WC()->cart->shipping_tax_total : 0;
+ $items[] = [
+ 'label' => esc_html( __( 'Shipping', 'woocommerce-payments' ) ),
+ 'amount' => WC_Payments_Utils::prepare_amount( $shipping + $shipping_tax, $currency ),
+ ];
+ }
+
+ if ( WC()->cart->has_discount() ) {
+ $items[] = [
+ 'label' => esc_html( __( 'Discount', 'woocommerce-payments' ) ),
+ 'amount' => WC_Payments_Utils::prepare_amount( $discounts, $currency ),
+ ];
+ }
+
+ if ( version_compare( WC_VERSION, '3.2', '<' ) ) {
+ $cart_fees = WC()->cart->fees;
+ } else {
+ $cart_fees = WC()->cart->get_fees();
+ }
+
+ // Include fees and taxes as display items.
+ foreach ( $cart_fees as $key => $fee ) {
+ $items[] = [
+ 'label' => $fee->name,
+ 'amount' => WC_Payments_Utils::prepare_amount( $fee->amount, $currency ),
+ ];
+ }
+
+ return [
+ 'displayItems' => $items,
+ 'total' => [
+ 'label' => $this->get_total_label(),
+ 'amount' => max( 0, apply_filters( 'wcpay_calculated_total', WC_Payments_Utils::prepare_amount( $order_total, $currency ), $order_total, WC()->cart ) ),
+ 'pending' => false,
+ ],
+ ];
+ }
+
+ /**
+ * Whether tax should be displayed on separate line in cart.
+ * returns true if tax is disabled or display of tax in checkout is set to inclusive.
+ *
+ * @return boolean
+ */
+ public function cart_prices_include_tax() {
+ return ! wc_tax_enabled() || 'incl' === get_option( 'woocommerce_tax_display_cart' );
+ }
+
+ /**
+ * Gets total label.
+ *
+ * @return string
+ */
+ public function get_total_label() {
+ // Get statement descriptor from API/cached account data.
+ $statement_descriptor = $this->account->get_statement_descriptor();
+ return str_replace( "'", '', $statement_descriptor ) . apply_filters( 'wcpay_payment_request_total_label_suffix', ' (via WooCommerce)' );
+ }
+
+ /**
+ * Gets quantity from request.
+ *
+ * @return int
+ */
+ private function get_quantity() {
+ // Payment Request Button sends the quantity as qty. WooPay sends it as quantity.
+ if ( isset( $_POST['quantity'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ return absint( $_POST['quantity'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ } elseif ( isset( $_POST['qty'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ return absint( $_POST['qty'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ } else {
+ return 1;
+ }
+ }
+}
diff --git a/tests/unit/test-class-wc-payments-express-checkout-button-display-handler.php b/tests/unit/test-class-wc-payments-express-checkout-button-display-handler.php
index 220f3d2ff03..dfb059ba7b4 100644
--- a/tests/unit/test-class-wc-payments-express-checkout-button-display-handler.php
+++ b/tests/unit/test-class-wc-payments-express-checkout-button-display-handler.php
@@ -63,6 +63,13 @@ class WC_Payments_Express_Checkout_Button_Display_Handler_Test extends WCPAY_Uni
*/
private $mock_woopay_utilities;
+ /**
+ * Express Checkout Helper instance.
+ *
+ * @var WC_Payments_Express_Checkout_Button_Helper
+ */
+ private $express_checkout_helper;
+
/**
* Sets up things all tests need.
*/
@@ -103,11 +110,14 @@ public function set_up() {
)
->getMock();
+ $this->express_checkout_helper = new WC_Payments_Express_Checkout_Button_Helper( $this->mock_wcpay_account );
+
$this->mock_payment_request_button_handler = $this->getMockBuilder( WC_Payments_Payment_Request_Button_Handler::class )
->setConstructorArgs(
[
$this->mock_wcpay_account,
$this->mock_wcpay_gateway,
+ $this->express_checkout_helper,
]
)
->setMethods(
@@ -118,7 +128,7 @@ public function set_up() {
)
->getMock();
- $this->express_checkout_button_display_handler = new WC_Payments_Express_Checkout_Button_Display_Handler( $this->mock_wcpay_gateway, $this->mock_payment_request_button_handler, $this->mock_woopay_button_handler );
+ $this->express_checkout_button_display_handler = new WC_Payments_Express_Checkout_Button_Display_Handler( $this->mock_wcpay_gateway, $this->mock_payment_request_button_handler, $this->mock_woopay_button_handler, $this->express_checkout_helper );
add_filter(
'woocommerce_available_payment_gateways',
diff --git a/tests/unit/test-class-wc-payments-payment-request-button-handler.php b/tests/unit/test-class-wc-payments-payment-request-button-handler.php
index 7940d7b20f0..ce1283265b4 100644
--- a/tests/unit/test-class-wc-payments-payment-request-button-handler.php
+++ b/tests/unit/test-class-wc-payments-payment-request-button-handler.php
@@ -76,6 +76,13 @@ class WC_Payments_Payment_Request_Button_Handler_Test extends WCPAY_UnitTestCase
*/
private $mock_wcpay_gateway;
+ /**
+ * Express Checkout Helper instance.
+ *
+ * @var WC_Payments_Express_Checkout_Button_Helper
+ */
+ private $express_checkout_helper;
+
/**
* Sets up things all tests need.
*/
@@ -100,7 +107,9 @@ public function set_up() {
$this->mock_wcpay_gateway = $this->make_wcpay_gateway();
- $this->pr = new WC_Payments_Payment_Request_Button_Handler( $this->mock_wcpay_account, $this->mock_wcpay_gateway );
+ $this->express_checkout_helper = new WC_Payments_Express_Checkout_Button_Helper( $this->mock_wcpay_account );
+
+ $this->pr = new WC_Payments_Payment_Request_Button_Handler( $this->mock_wcpay_account, $this->mock_wcpay_gateway, $this->express_checkout_helper );
$this->simple_product = WC_Helper_Product::create_simple_product();
@@ -294,7 +303,7 @@ public function test_get_shipping_options_keeps_chosen_option() {
public function test_get_button_settings() {
$this->mock_wcpay_gateway = $this->make_wcpay_gateway();
- $this->pr = new WC_Payments_Payment_Request_Button_Handler( $this->mock_wcpay_account, $this->mock_wcpay_gateway );
+ $this->pr = new WC_Payments_Payment_Request_Button_Handler( $this->mock_wcpay_account, $this->mock_wcpay_gateway, $this->express_checkout_helper );
$this->assertEquals(
[
@@ -320,7 +329,7 @@ function() {
}
);
$this->mock_wcpay_gateway = $this->make_wcpay_gateway();
- $this->pr = new WC_Payments_Payment_Request_Button_Handler( $this->mock_wcpay_account, $this->mock_wcpay_gateway );
+ $this->pr = new WC_Payments_Payment_Request_Button_Handler( $this->mock_wcpay_account, $this->mock_wcpay_gateway, $this->express_checkout_helper );
$this->assertFalse( $this->pr->has_allowed_items_in_cart() );
}
@@ -505,10 +514,10 @@ public function test_get_product_data_returns_the_same_as_build_display_items_wi
add_filter( 'pre_option_woocommerce_tax_display_cart', [ $this, "__return_$tax_display_cart" ] ); // reset in tear_down.
add_filter( 'wc_shipping_enabled', '__return_false' ); // reset in tear_down.
WC()->cart->calculate_totals();
- $build_display_items_result = $this->pr->build_display_items( true );
+ $build_display_items_result = $this->express_checkout_helper->build_display_items( true );
$mock_pr = $this->getMockBuilder( WC_Payments_Payment_Request_Button_Handler::class )
- ->setConstructorArgs( [ $this->mock_wcpay_account, $this->mock_wcpay_gateway ] )
+ ->setConstructorArgs( [ $this->mock_wcpay_account, $this->mock_wcpay_gateway, $this->express_checkout_helper ] )
->setMethods( [ 'is_product', 'get_product' ] )
->getMock();
From 401d67f9384e13a95130d38d04ebda90ce3b6202 Mon Sep 17 00:00:00 2001
From: Alefe Souza
Date: Tue, 26 Dec 2023 14:48:11 -0300
Subject: [PATCH 49/56] Fix account status error messages with JSX (#7941)
---
changelog/fix-jsx-account-status-error-messages | 4 ++++
.../task-list/tasks/update-business-details-task.tsx | 10 ++++++----
client/overview/task-list/types.d.ts | 2 ++
3 files changed, 12 insertions(+), 4 deletions(-)
create mode 100644 changelog/fix-jsx-account-status-error-messages
diff --git a/changelog/fix-jsx-account-status-error-messages b/changelog/fix-jsx-account-status-error-messages
new file mode 100644
index 00000000000..a45adc8b5ab
--- /dev/null
+++ b/changelog/fix-jsx-account-status-error-messages
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Fix account status error messages with links.
diff --git a/client/overview/task-list/tasks/update-business-details-task.tsx b/client/overview/task-list/tasks/update-business-details-task.tsx
index 5f6542c67ff..adb8e5b430f 100644
--- a/client/overview/task-list/tasks/update-business-details-task.tsx
+++ b/client/overview/task-list/tasks/update-business-details-task.tsx
@@ -26,7 +26,7 @@ export const getUpdateBusinessDetailsTask = (
const hasMultipleErrors = 1 < errorMessages.length;
const hasSingleError = 1 === errorMessages.length;
- let accountDetailsTaskDescription = '',
+ let accountDetailsTaskDescription: React.ReactElement | string = '',
errorMessageDescription,
accountDetailsUpdateByDescription;
@@ -45,9 +45,11 @@ export const getUpdateBusinessDetailsTask = (
if ( hasSingleError ) {
errorMessageDescription = errorMessages[ 0 ];
- accountDetailsTaskDescription = errorMessageDescription.concat(
- ' ',
- accountDetailsUpdateByDescription
+ accountDetailsTaskDescription = (
+ <>
+ { errorMessageDescription }{ ' ' }
+ { accountDetailsUpdateByDescription }
+ >
);
} else {
accountDetailsTaskDescription = accountDetailsUpdateByDescription;
diff --git a/client/overview/task-list/types.d.ts b/client/overview/task-list/types.d.ts
index 2556617dcd7..d572fc0cbb3 100644
--- a/client/overview/task-list/types.d.ts
+++ b/client/overview/task-list/types.d.ts
@@ -17,4 +17,6 @@ export interface TaskItemProps extends React.ComponentProps< typeof TaskItem > {
* Whether the task is dismissable.
*/
isDismissable?: boolean;
+
+ content: string | React.ReactElement;
}
From b24197fdf6af1218e9f554a02b3b0f57e0178907 Mon Sep 17 00:00:00 2001
From: Alefe Souza
Date: Tue, 26 Dec 2023 14:49:58 -0300
Subject: [PATCH 50/56] Fix WooPay integration with AutomateWoo - Refer a
Friend extension (#7916)
---
.../fix-7913-woopay-automatewoo-referrals-integration | 4 ++++
includes/woopay/class-woopay-adapted-extensions.php | 4 +---
includes/woopay/class-woopay-session.php | 10 +++++++++-
3 files changed, 14 insertions(+), 4 deletions(-)
create mode 100644 changelog/fix-7913-woopay-automatewoo-referrals-integration
diff --git a/changelog/fix-7913-woopay-automatewoo-referrals-integration b/changelog/fix-7913-woopay-automatewoo-referrals-integration
new file mode 100644
index 00000000000..bace9a2cc9b
--- /dev/null
+++ b/changelog/fix-7913-woopay-automatewoo-referrals-integration
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Fix WooPay integration with AutomateWoo - Refer a Friend extension.
diff --git a/includes/woopay/class-woopay-adapted-extensions.php b/includes/woopay/class-woopay-adapted-extensions.php
index cd6ed56f2d0..bc5a4b37c96 100644
--- a/includes/woopay/class-woopay-adapted-extensions.php
+++ b/includes/woopay/class-woopay-adapted-extensions.php
@@ -259,9 +259,7 @@ private function is_automate_woo_referrals_enabled() {
method_exists( AW_Referrals(), 'options' ) &&
AW_Referrals()->options()->type === 'link' &&
class_exists( '\AutomateWoo\Referrals\Referral_Manager' ) &&
- method_exists( \AutomateWoo\Referrals\Referral_Manager::class, 'get_advocate_key_from_cookie' ) && class_exists( 'AFWC_API' ) &&
- method_exists( 'AFWC_API', 'get_instance' ) &&
- method_exists( 'AFWC_API', 'track_conversion' );
+ method_exists( \AutomateWoo\Referrals\Referral_Manager::class, 'get_advocate_key_from_cookie' );
}
/**
diff --git a/includes/woopay/class-woopay-session.php b/includes/woopay/class-woopay-session.php
index 5fb2af81ef5..398219468be 100644
--- a/includes/woopay/class-woopay-session.php
+++ b/includes/woopay/class-woopay-session.php
@@ -262,7 +262,15 @@ public static function run_and_remove_woopay_restore_order_customer_id_schedules
* Fix for AutomateWoo - Refer A Friend Add-on
* plugin when using link referrals.
*/
- public static function automatewoo_refer_a_friend_referral_from_parameter() {
+ public static function automatewoo_refer_a_friend_referral_from_parameter( $advocate_id ) {
+ if ( ! self::is_request_from_woopay() || ! self::is_store_api_request() ) {
+ return $advocate_id;
+ }
+
+ if ( ! self::is_woopay_enabled() ) {
+ return $advocate_id;
+ }
+
if ( empty( $_GET['automatewoo_referral_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
return false;
}
From b6a3669713c124c00f31c21036ccc5dcd41b563b Mon Sep 17 00:00:00 2001
From: Timur Karimov
Date: Wed, 27 Dec 2023 08:00:26 +0100
Subject: [PATCH 51/56] Consolidate gateways implementation - step I (#7937)
Co-authored-by: Timur Karimov
---
changelog/cleanup-upe-gateways-part-1 | 4 +
client/checkout/api/index.js | 104 ---
client/checkout/utils/test/upe.test.js | 66 --
client/checkout/utils/upe.js | 28 -
includes/class-wc-payment-gateway-wcpay.php | 18 +-
includes/class-wc-payments-checkout.php | 12 +-
...ments-payment-method-messaging-element.php | 7 +-
includes/class-wc-payments.php | 12 +-
.../class-upe-payment-gateway.php | 530 +++++---------
.../class-upe-split-payment-gateway.php | 544 --------------
src/Internal/Payment/State/ProcessedState.php | 12 -
...s-wc-rest-payments-settings-controller.php | 6 +-
.../test-class-upe-payment-gateway.php | 668 +-----------------
.../test-class-upe-split-payment-gateway.php | 457 +-----------
.../Payment/State/ProcessedStateTest.php | 7 -
...wc-payment-gateway-wcpay-subscriptions.php | 7 -
.../test-class-wc-payment-gateway-wcpay.php | 41 +-
.../unit/test-class-wc-payments-checkout.php | 14 +-
tests/unit/test-class-wc-payments.php | 6 +-
19 files changed, 231 insertions(+), 2312 deletions(-)
create mode 100644 changelog/cleanup-upe-gateways-part-1
delete mode 100644 includes/payment-methods/class-upe-split-payment-gateway.php
diff --git a/changelog/cleanup-upe-gateways-part-1 b/changelog/cleanup-upe-gateways-part-1
new file mode 100644
index 00000000000..d449f2047df
--- /dev/null
+++ b/changelog/cleanup-upe-gateways-part-1
@@ -0,0 +1,4 @@
+Significance: minor
+Type: dev
+
+Cleanup the deprecated payment gateway processing - part V
diff --git a/client/checkout/api/index.js b/client/checkout/api/index.js
index 3e2dcf1f7af..9ecdf245b62 100644
--- a/client/checkout/api/index.js
+++ b/client/checkout/api/index.js
@@ -335,24 +335,6 @@ export default class WCPayAPI {
};
}
- /**
- * Creates a setup intent without confirming it.
- *
- * @return {Promise} The final promise for the request to the server.
- */
- initSetupIntent() {
- const path = 'init_setup_intent';
-
- return this.request( buildAjaxURL( getConfig( 'wcAjaxUrl' ), path ), {
- _ajax_nonce: getConfig( 'createSetupIntentNonce' ),
- } ).then( ( response ) => {
- if ( ! response.success ) {
- throw response.data.error;
- }
- return response.data;
- } );
- }
-
/**
* Sets up an intent based on a payment method.
*
@@ -389,92 +371,6 @@ export default class WCPayAPI {
} );
}
- /**
- * Creates an intent based on a payment method.
- *
- * @param {Object} options Object containing intent optional parameters (fingerprint, paymentMethodType, orderId)
- *
- * @return {Promise} The final promise for the request to the server.
- */
- createIntent( options ) {
- const { fingerprint, orderId } = options;
- const path = 'create_payment_intent';
- const params = {
- _ajax_nonce: getConfig( 'createPaymentIntentNonce' ),
- 'wcpay-fingerprint': fingerprint,
- };
-
- if ( orderId ) {
- params.wcpay_order_id = orderId;
- }
-
- return this.request(
- buildAjaxURL( getConfig( 'wcAjaxUrl' ), path ),
- params
- )
- .then( ( response ) => {
- if ( ! response.success ) {
- throw response.data.error;
- }
- return response.data;
- } )
- .catch( ( error ) => {
- if ( error.message ) {
- throw error;
- } else {
- // Covers the case of error on the Ajax request.
- throw new Error( error.statusText );
- }
- } );
- }
-
- /**
- * Updates a payment intent with data from order: customer, level3 data and maybe sets the payment for future use.
- *
- * @param {string} paymentIntentId The id of the payment intent.
- * @param {int} orderId The id of the order.
- * @param {string} savePaymentMethod 'yes' if saving.
- * @param {string} selectedUPEPaymentType The name of the selected UPE payment type or empty string.
- * @param {string?} paymentCountry The payment two-letter iso country code or null.
- * @param {string?} fingerprint User fingerprint.
- *
- * @return {Promise} The final promise for the request to the server.
- */
- updateIntent(
- paymentIntentId,
- orderId,
- savePaymentMethod,
- selectedUPEPaymentType,
- paymentCountry,
- fingerprint
- ) {
- const path = 'update_payment_intent';
-
- return this.request( buildAjaxURL( getConfig( 'wcAjaxUrl' ), path ), {
- wcpay_order_id: orderId,
- wc_payment_intent_id: paymentIntentId,
- save_payment_method: savePaymentMethod,
- wcpay_selected_upe_payment_type: selectedUPEPaymentType,
- wcpay_payment_country: paymentCountry,
- _ajax_nonce: getConfig( 'updatePaymentIntentNonce' ),
- 'wcpay-fingerprint': fingerprint,
- } )
- .then( ( response ) => {
- if ( response.result === 'failure' ) {
- throw new Error( response.messages );
- }
- return response;
- } )
- .catch( ( error ) => {
- if ( error.message ) {
- throw error;
- } else {
- // Covers the case of error on the Ajaxrequest.
- throw new Error( error.statusText );
- }
- } );
- }
-
/**
* Confirm Stripe payment with fallback for rate limit error.
*
diff --git a/client/checkout/utils/test/upe.test.js b/client/checkout/utils/test/upe.test.js
index c6bbd8e726e..c785baa427b 100644
--- a/client/checkout/utils/test/upe.test.js
+++ b/client/checkout/utils/test/upe.test.js
@@ -5,7 +5,6 @@ import {
getTerms,
getCookieValue,
isWCPayChosen,
- getPaymentIntentFromSession,
generateCheckoutEventNames,
getUpeSettings,
getStripeElementOptions,
@@ -168,71 +167,6 @@ describe( 'UPE checkout utils', () => {
} );
} );
- describe( 'getPaymentIntentFromSession', () => {
- const paymentMethodsConfig = {
- card: {
- upePaymentIntentData:
- 'abcd1234-pi_abc123-pi_abc123_secret_5678xyz',
- },
- eps: {
- upePaymentIntentData: null,
- },
- };
-
- const cardData = {
- clientSecret: 'pi_abc123_secret_5678xyz',
- intentId: 'pi_abc123',
- };
-
- it( 'should return the correct client secret and intent ID', () => {
- Object.defineProperty( document, 'cookie', {
- get: () => {
- return 'woocommerce_cart_hash=abcd1234;';
- },
- configurable: true,
- } );
- expect(
- getPaymentIntentFromSession( paymentMethodsConfig, 'card' )
- ).toEqual( cardData );
- } );
-
- it( 'should return an empty object if no payment intent exists', () => {
- Object.defineProperty( document, 'cookie', {
- get: () => {
- return 'woocommerce_cart_hash=abcd1234;';
- },
- configurable: true,
- } );
- expect(
- getPaymentIntentFromSession( paymentMethodsConfig, 'eps' )
- ).toEqual( {} );
- } );
-
- it( 'should return an empty object if no cart hash exists', () => {
- Object.defineProperty( document, 'cookie', {
- get: () => {
- return 'woocommerce_cart_items=1;';
- },
- configurable: true,
- } );
- expect(
- getPaymentIntentFromSession( paymentMethodsConfig, 'card' )
- ).toEqual( {} );
- } );
-
- it( 'should return an empty object if the payment intent data does not start with the cart hash', () => {
- Object.defineProperty( document, 'cookie', {
- get: () => {
- return 'woocommerce_cart_hash=xyz9876;';
- },
- configurable: true,
- } );
- expect(
- getPaymentIntentFromSession( paymentMethodsConfig, 'card' )
- ).toEqual( {} );
- } );
- } );
-
describe( 'getUPESettings', () => {
afterEach( () => {
const checkboxElement = document.getElementById(
diff --git a/client/checkout/utils/upe.js b/client/checkout/utils/upe.js
index 71a673d3a2a..f7b49138690 100644
--- a/client/checkout/utils/upe.js
+++ b/client/checkout/utils/upe.js
@@ -44,34 +44,6 @@ export const isWCPayChosen = function () {
.checked;
};
-/**
- * Returns the cached payment intent for the current cart state.
- *
- * @param {Object} paymentMethodsConfig Array of configs for payment methods.
- * @param {string} paymentMethodType Type of the payment method.
- * @return {Object} The intent id and client secret required for mounting the UPE element.
- */
-export const getPaymentIntentFromSession = (
- paymentMethodsConfig,
- paymentMethodType
-) => {
- const cartHash = getCookieValue( 'woocommerce_cart_hash' );
- const upePaymentIntentData =
- paymentMethodsConfig[ paymentMethodType ].upePaymentIntentData;
-
- if (
- cartHash &&
- upePaymentIntentData &&
- upePaymentIntentData.startsWith( cartHash )
- ) {
- const intentId = upePaymentIntentData.split( '-' )[ 1 ];
- const clientSecret = upePaymentIntentData.split( '-' )[ 2 ];
- return { intentId, clientSecret };
- }
-
- return {};
-};
-
/**
* Finds selected payment gateway and returns matching Stripe payment method for gateway.
*
diff --git a/includes/class-wc-payment-gateway-wcpay.php b/includes/class-wc-payment-gateway-wcpay.php
index 415d9e0a411..0348466cf19 100644
--- a/includes/class-wc-payment-gateway-wcpay.php
+++ b/includes/class-wc-payment-gateway-wcpay.php
@@ -37,7 +37,6 @@
use WCPay\Logger;
use WCPay\Payment_Information;
use WCPay\Payment_Methods\UPE_Payment_Gateway;
-use WCPay\Payment_Methods\UPE_Split_Payment_Gateway;
use WCPay\Payment_Methods\Link_Payment_Method;
use WCPay\WooPay\WooPay_Order_Status_Sync;
use WCPay\WooPay\WooPay_Utilities;
@@ -1644,19 +1643,8 @@ public function set_payment_method_title_for_order( $order, $payment_method_type
* @return array Array of keyed metadata values.
*/
protected function get_metadata_from_order( $order, $payment_type ) {
- $service = wcpay_get_container()->get( OrderService::class );
- $metadata = $service->get_payment_metadata( $order->get_id(), $payment_type );
-
- if ( $this instanceof UPE_Split_Payment_Gateway ) {
- $gateway_type = 'split_upe_with_deferred_intent_creation';
- } elseif ( $this instanceof UPE_Payment_Gateway ) {
- $gateway_type = 'legacy_upe';
- } else {
- $gateway_type = 'legacy_card';
- }
- $metadata['gateway_type'] = $gateway_type;
-
- return $metadata;
+ $service = wcpay_get_container()->get( OrderService::class );
+ return $service->get_payment_metadata( $order->get_id(), $payment_type );
}
/**
@@ -3729,7 +3717,7 @@ private function upe_needs_redirection( $payment_methods ) {
/**
* Modifies the create intent parameters when processing a payment.
*
- * Currently used by child UPE_Split_Payment_Gateway to add required shipping information for Afterpay.
+ * Currently used by child UPE_Payment_Gateway to add required shipping information for Afterpay.
*
* @param Create_And_Confirm_Intention $request The request object for creating and confirming intention.
* @param Payment_Information $payment_information The payment information object.
diff --git a/includes/class-wc-payments-checkout.php b/includes/class-wc-payments-checkout.php
index 9851a2ea0c2..89f8654f716 100644
--- a/includes/class-wc-payments-checkout.php
+++ b/includes/class-wc-payments-checkout.php
@@ -95,16 +95,12 @@ public function __construct(
public function init_hooks() {
add_action( 'wc_payments_set_gateway', [ $this, 'set_gateway' ] );
add_action( 'wc_payments_add_upe_payment_fields', [ $this, 'payment_fields' ] );
- add_action( 'woocommerce_after_account_payment_methods', [ $this->gateway, 'remove_upe_setup_intent_from_session' ], 10, 0 );
- add_action( 'woocommerce_subscription_payment_method_updated', [ $this->gateway, 'remove_upe_setup_intent_from_session' ], 10, 0 );
- add_action( 'woocommerce_order_payment_status_changed', [ get_class( $this->gateway ), 'remove_upe_payment_intent_from_session' ], 10, 0 );
add_action( 'wp', [ $this->gateway, 'maybe_process_upe_redirect' ] );
add_action( 'wc_ajax_wcpay_log_payment_error', [ $this->gateway, 'log_payment_error_ajax' ] );
add_action( 'wp_ajax_save_upe_appearance', [ $this->gateway, 'save_upe_appearance_ajax' ] );
add_action( 'wp_ajax_nopriv_save_upe_appearance', [ $this->gateway, 'save_upe_appearance_ajax' ] );
add_action( 'switch_theme', [ $this->gateway, 'clear_upe_appearance_transient' ] );
add_action( 'woocommerce_woocommerce_payments_updated', [ $this->gateway, 'clear_upe_appearance_transient' ] );
- add_action( 'wc_ajax_wcpay_init_setup_intent', [ $this->gateway, 'init_setup_intent_ajax' ] );
add_action( 'wc_ajax_wcpay_log_payment_error', [ $this->gateway, 'log_payment_error_ajax' ] );
add_action( 'wp_enqueue_scripts', [ $this, 'register_scripts' ] );
@@ -183,8 +179,6 @@ public function get_payment_fields_js_config() {
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
'wcAjaxUrl' => WC_AJAX::get_endpoint( '%%endpoint%%' ),
'createSetupIntentNonce' => wp_create_nonce( 'wcpay_create_setup_intent_nonce' ),
- 'createPaymentIntentNonce' => wp_create_nonce( 'wcpay_create_payment_intent_nonce' ),
- 'updatePaymentIntentNonce' => wp_create_nonce( 'wcpay_update_payment_intent_nonce' ),
'logPaymentErrorNonce' => wp_create_nonce( 'wcpay_log_payment_error_nonce' ),
'initWooPayNonce' => wp_create_nonce( 'wcpay_init_woopay_nonce' ),
'saveUPEAppearanceNonce' => wp_create_nonce( 'wcpay_save_upe_appearance_nonce' ),
@@ -318,10 +312,8 @@ public function get_enabled_payment_method_config() {
'countries' => $payment_method->get_countries(),
];
- $gateway_for_payment_method = $this->gateway->wc_payments_get_payment_gateway_by_id( $payment_method_id );
- $settings[ $payment_method_id ]['upePaymentIntentData'] = $this->gateway->get_payment_intent_data_from_session( $payment_method_id );
- $settings[ $payment_method_id ]['upeSetupIntentData'] = $this->gateway->get_setup_intent_data_from_session( $payment_method_id );
- $settings[ $payment_method_id ]['testingInstructions'] = WC_Payments_Utils::esc_interpolated_html(
+ $gateway_for_payment_method = $this->gateway->wc_payments_get_payment_gateway_by_id( $payment_method_id );
+ $settings[ $payment_method_id ]['testingInstructions'] = WC_Payments_Utils::esc_interpolated_html(
/* translators: link to Stripe testing page */
$payment_method->get_testing_instructions(),
[
diff --git a/includes/class-wc-payments-payment-method-messaging-element.php b/includes/class-wc-payments-payment-method-messaging-element.php
index 27ca330245b..6fe6006188f 100644
--- a/includes/class-wc-payments-payment-method-messaging-element.php
+++ b/includes/class-wc-payments-payment-method-messaging-element.php
@@ -11,7 +11,6 @@
exit;
}
use WCPay\Payment_Methods\UPE_Payment_Gateway;
-use WCPay\Payment_Methods\UPE_Split_Payment_Gateway;
/**
* WC_Payments_Payment_Method_Messaging_Element class.
*/
@@ -25,15 +24,15 @@ class WC_Payments_Payment_Method_Messaging_Element {
/**
* WC_Payments_Gateway instance to get information about the enabled payment methods.
*
- * @var UPE_Payment_Gateway|UPE_Split_Payment_Gateway
+ * @var UPE_Payment_Gateway
*/
private $gateway;
/**
* WC_Payments_Payment_Method_Messaging_Element constructor
*
- * @param WC_Payments_Account $account Account instance.
- * @param UPE_Payment_Gateway|UPE_Split_Payment_Gateway $gateway Gateway instance.
+ * @param WC_Payments_Account $account Account instance.
+ * @param UPE_Payment_Gateway $gateway Gateway instance.
* @return void
*/
public function __construct( WC_Payments_Account $account, $gateway ) {
diff --git a/includes/class-wc-payments.php b/includes/class-wc-payments.php
index bd0cb8dc97f..f171f9b07d6 100644
--- a/includes/class-wc-payments.php
+++ b/includes/class-wc-payments.php
@@ -22,7 +22,6 @@
use WCPay\Payment_Methods\Sepa_Payment_Method;
use WCPay\Payment_Methods\Sofort_Payment_Method;
use WCPay\Payment_Methods\UPE_Payment_Gateway;
-use WCPay\Payment_Methods\UPE_Split_Payment_Gateway;
use WCPay\Payment_Methods\Ideal_Payment_Method;
use WCPay\Payment_Methods\Eps_Payment_Method;
use WCPay\Payment_Methods\UPE_Payment_Method;
@@ -52,7 +51,7 @@ class WC_Payments {
/**
* Main payment gateway controller instance, created in init function.
*
- * @var WC_Payment_Gateway_WCPay|UPE_Payment_Gateway|UPE_Split_Payment_Gateway
+ * @var WC_Payment_Gateway_WCPay|UPE_Payment_Gateway
*/
private static $card_gateway;
@@ -67,7 +66,7 @@ class WC_Payments {
* Copy of either $card_gateway or $legacy_card_gateway,
* depending on which gateway is registered as main CC gateway.
*
- * @var WC_Payment_Gateway_WCPay|UPE_Payment_Gateway|UPE_Split_Payment_Gateway
+ * @var WC_Payment_Gateway_WCPay|UPE_Payment_Gateway
*/
private static $registered_card_gateway;
@@ -407,7 +406,6 @@ public static function init() {
include_once __DIR__ . '/class-wc-payments-checkout.php';
include_once __DIR__ . '/payment-methods/class-cc-payment-gateway.php';
include_once __DIR__ . '/payment-methods/class-upe-payment-gateway.php';
- include_once __DIR__ . '/payment-methods/class-upe-split-payment-gateway.php';
include_once __DIR__ . '/payment-methods/class-upe-payment-method.php';
include_once __DIR__ . '/payment-methods/class-cc-payment-method.php';
include_once __DIR__ . '/payment-methods/class-bancontact-payment-method.php';
@@ -551,7 +549,7 @@ public static function init() {
foreach ( $payment_methods as $payment_method ) {
self::$upe_payment_method_map[ $payment_method->get_id() ] = $payment_method;
- $split_gateway = new UPE_Split_Payment_Gateway( self::$api_client, self::$account, self::$customer_service, self::$token_service, self::$action_scheduler_service, $payment_method, $payment_methods, self::$failed_transaction_rate_limiter, self::$order_service, self::$duplicate_payment_prevention_service, self::$localization_service, self::$fraud_service );
+ $split_gateway = new UPE_Payment_Gateway( self::$api_client, self::$account, self::$customer_service, self::$token_service, self::$action_scheduler_service, $payment_method, $payment_methods, self::$failed_transaction_rate_limiter, self::$order_service, self::$duplicate_payment_prevention_service, self::$localization_service, self::$fraud_service );
// Card gateway hooks are registered once below.
if ( 'card' !== $payment_method->get_id() ) {
@@ -797,7 +795,7 @@ public static function register_gateway( $gateways ) {
/**
* Returns main CC gateway registered for WCPay.
*
- * @return WC_Payment_Gateway_WCPay|UPE_Payment_Gateway|UPE_Split_Payment_Gateway
+ * @return WC_Payment_Gateway_WCPay|UPE_Payment_Gateway
*/
public static function get_registered_card_gateway() {
return self::$registered_card_gateway;
@@ -806,7 +804,7 @@ public static function get_registered_card_gateway() {
/**
* Sets registered card gateway instance.
*
- * @param WC_Payment_Gateway_WCPay|UPE_Payment_Gateway|UPE_Split_Payment_Gateway $gateway Gateway instance.
+ * @param WC_Payment_Gateway_WCPay|UPE_Payment_Gateway $gateway Gateway instance.
*/
public static function set_registered_card_gateway( $gateway ) {
self::$registered_card_gateway = $gateway;
diff --git a/includes/payment-methods/class-upe-payment-gateway.php b/includes/payment-methods/class-upe-payment-gateway.php
index b1ba28589b6..eff6d3ad1d8 100644
--- a/includes/payment-methods/class-upe-payment-gateway.php
+++ b/includes/payment-methods/class-upe-payment-gateway.php
@@ -14,14 +14,10 @@
use WCPay\Constants\Intent_Status;
use WCPay\Constants\Payment_Method;
use WCPay\Constants\Payment_Type;
-use WCPay\Core\Server\Request\Create_Intention;
-use WCPay\Core\Server\Request\Create_Setup_Intention;
use WCPay\Core\Server\Request\Get_Charge;
use WCPay\Core\Server\Request\Get_Intention;
-use WCPay\Core\Server\Request;
use WCPay\Core\Server\Request\Get_Setup_Intention;
use WCPay\Core\Server\Request\Update_Intention;
-use WCPay\Exceptions\Add_Payment_Method_Exception;
use WCPay\Exceptions\Amount_Too_Small_Exception;
use WCPay\Exceptions\API_Exception;
use WCPay\Exceptions\Order_Not_Found_Exception;
@@ -42,12 +38,12 @@
use WC_Payments_Token_Service;
use WC_Payment_Token_WCPay_SEPA;
use WC_Payments_Utils;
-use WC_Payments_Features;
use WCPay\Duplicate_Payment_Prevention_Service;
use WP_User;
use WC_Payments_Localization_Service;
use WCPay\Payment_Information;
use WCPay\Core\Server\Request\Create_And_Confirm_Intention;
+use WCPay\Exceptions\Invalid_Address_Exception;
/**
* UPE Payment method extended from WCPay generic Gateway.
@@ -66,10 +62,6 @@ class UPE_Payment_Gateway extends WC_Payment_Gateway_WCPay {
const WC_BLOCKS_UPE_APPEARANCE_TRANSIENT = 'wcpay_wc_blocks_upe_appearance';
- const KEY_UPE_PAYMENT_INTENT = 'wcpay_upe_payment_intent';
-
- const KEY_UPE_SETUP_INTENT = 'wcpay_upe_setup_intent';
-
const PROCESS_REDIRECT_ORDER_MISMATCH_ERROR_CODE = 'upe_process_redirect_order_id_mismatched';
/**
@@ -86,6 +78,20 @@ class UPE_Payment_Gateway extends WC_Payment_Gateway_WCPay {
*/
protected $checkout_title;
+ /**
+ * UPE Payment Method for gateway.
+ *
+ * @var UPE_Payment_Method
+ */
+ protected $payment_method;
+
+ /**
+ * Stripe payment method type ID.
+ *
+ * @var string
+ */
+ protected $stripe_id;
+
/**
* UPE Constructor same parameters as WC_Payment_Gateway_WCPay constructor.
*
@@ -94,6 +100,7 @@ class UPE_Payment_Gateway extends WC_Payment_Gateway_WCPay {
* @param WC_Payments_Customer_Service $customer_service - Customer class instance.
* @param WC_Payments_Token_Service $token_service - Token class instance.
* @param WC_Payments_Action_Scheduler_Service $action_scheduler_service - Action Scheduler service instance.
+ * @param UPE_Payment_Method $payment_method - Specific UPE_Payment_Method instance for gateway.
* @param array $payment_methods - Array of UPE payment methods.
* @param Session_Rate_Limiter $failed_transaction_rate_limiter - Session Rate Limiter instance.
* @param WC_Payments_Order_Service $order_service - Order class instance.
@@ -107,6 +114,7 @@ public function __construct(
WC_Payments_Customer_Service $customer_service,
WC_Payments_Token_Service $token_service,
WC_Payments_Action_Scheduler_Service $action_scheduler_service,
+ UPE_Payment_Method $payment_method,
array $payment_methods,
Session_Rate_Limiter $failed_transaction_rate_limiter,
WC_Payments_Order_Service $order_service,
@@ -115,22 +123,28 @@ public function __construct(
WC_Payments_Fraud_Service $fraud_service
) {
parent::__construct( $payments_api_client, $account, $customer_service, $token_service, $action_scheduler_service, $failed_transaction_rate_limiter, $order_service, $duplicate_payment_prevention_service, $localization_service, $fraud_service );
- $this->title = 'WooPayments';
- $this->description = '';
- $this->checkout_title = __( 'Popular payment methods', 'woocommerce-payments' );
- $this->payment_methods = $payment_methods;
+ $this->title = $payment_method->get_title();
+ $this->method_description = __( 'Payments made simple, with no monthly fees - designed exclusively for WooCommerce stores. Accept credit cards, debit cards, and other popular payment methods.', 'woocommerce-payments' );
+ $this->description = '';
+ $this->checkout_title = __( 'Popular payment methods', 'woocommerce-payments' );
+ $this->payment_methods = $payment_methods;
+
+ $this->stripe_id = $payment_method->get_id();
+ $this->payment_method = $payment_method;
+ $this->icon = $payment_method->get_icon();
+
+ if ( 'card' !== $this->stripe_id ) {
+ $this->id = self::GATEWAY_ID . '_' . $this->stripe_id;
+ $this->method_title = "WooPayments ($this->title)";
+ }
}
/**
- * Displays HTML tags for WC payment gateway radio button.
+ * Displays HTML tags for WC payment gateway radio button content.
*/
public function display_gateway_html() {
?>
-
-
-
-
-
+
payment_methods[ $payment_method_type ] ) ) {
- return false;
- }
- return $this->payment_methods[ $payment_method_type ];
- }
-
- /**
- * Handle AJAX request for updating a payment intent for Stripe UPE.
- *
- * @throws Process_Payment_Exception - If nonce or setup intent is invalid.
- */
- public function update_payment_intent_ajax() {
- try {
- $is_nonce_valid = check_ajax_referer( 'wcpay_update_payment_intent_nonce', false, false );
- if ( ! $is_nonce_valid ) {
- throw new Process_Payment_Exception(
- __( "We're not able to process this payment. Please refresh the page and try again.", 'woocommerce-payments' ),
- 'wcpay_upe_intent_error'
- );
- }
-
- $order_id = isset( $_POST['wcpay_order_id'] ) ? absint( $_POST['wcpay_order_id'] ) : null;
- $payment_intent_id = isset( $_POST['wc_payment_intent_id'] ) ? wc_clean( wp_unslash( $_POST['wc_payment_intent_id'] ) ) : '';
- $fingerprint = isset( $_POST['wcpay-fingerprint'] ) ? wc_clean( wp_unslash( $_POST['wcpay-fingerprint'] ) ) : '';
- $save_payment_method = isset( $_POST['save_payment_method'] ) ? 'yes' === wc_clean( wp_unslash( $_POST['save_payment_method'] ) ) : false;
- $selected_upe_payment_type = ! empty( $_POST['wcpay_selected_upe_payment_type'] ) ? wc_clean( wp_unslash( $_POST['wcpay_selected_upe_payment_type'] ) ) : '';
- $payment_country = ! empty( $_POST['wcpay_payment_country'] ) ? wc_clean( wp_unslash( $_POST['wcpay_payment_country'] ) ) : null;
-
- wp_send_json_success( $this->update_payment_intent( $payment_intent_id, $order_id, $save_payment_method, $selected_upe_payment_type, $payment_country, $fingerprint ), 200 );
- } catch ( Exception $e ) {
- // Send back error so it can be displayed to the customer.
- wp_send_json_error(
- [
- 'error' => [
- 'message' => WC_Payments_Utils::get_filtered_error_message( $e ),
- ],
- ],
- WC_Payments_Utils::get_filtered_error_status_code( $e ),
- );
- }
- }
-
- /**
- * Updates payment intent to be able to save payment method.
- *
- * @param string $payment_intent_id The id of the payment intent to update.
- * @param int $order_id The id of the order if intent created from Order.
- * @param boolean $save_payment_method True if saving the payment method.
- * @param string $selected_upe_payment_type The name of the selected UPE payment type or empty string.
- * @param ?string $payment_country The payment two-letter iso country code or null.
- * @param ?string $fingerprint Fingerprint data.
- *
- * @return array|null An array with result of the update, or nothing
- */
- public function update_payment_intent( $payment_intent_id = '', $order_id = null, $save_payment_method = false, $selected_upe_payment_type = '', $payment_country = null, $fingerprint = '' ) {
- $order = wc_get_order( $order_id );
- if ( ! is_a( $order, 'WC_Order' ) ) {
- return;
- }
-
- $check_session_order = $this->duplicate_payment_prevention_service->check_against_session_processing_order( $order );
- if ( is_array( $check_session_order ) ) {
- return $check_session_order;
- }
- $this->duplicate_payment_prevention_service->maybe_update_session_processing_order( $order_id );
-
- $check_existing_intention = $this->duplicate_payment_prevention_service->check_payment_intent_attached_to_order_succeeded( $order );
- if ( is_array( $check_existing_intention ) ) {
- return $check_existing_intention;
- }
-
- $amount = $order->get_total();
- $currency = $order->get_currency();
-
- if ( $payment_intent_id ) {
- list( $user, $customer_id ) = $this->manage_customer_details_for_order( $order );
- $payment_type = $this->is_payment_recurring( $order_id ) ? Payment_Type::RECURRING() : Payment_Type::SINGLE();
- $payment_methods = $this->get_selected_upe_payment_methods( (string) $selected_upe_payment_type, $this->get_payment_method_ids_enabled_at_checkout( null, true ) ?? [] );
- $request = Update_Intention::create( $payment_intent_id );
- $request->set_currency_code( strtolower( $currency ) );
- $request->set_amount( WC_Payments_Utils::prepare_amount( $amount, $currency ) );
- $request->set_metadata( $this->get_metadata_from_order( $order, $payment_type ) );
- $request->set_level3( $this->get_level3_data_from_order( $order ) );
- $request->set_payment_method_types( $payment_methods );
- $request->set_fingerprint( $fingerprint );
- $request->set_hook_args( $order, $payment_intent_id );
- if ( $payment_country ) {
- $request->set_payment_country( $payment_country );
- }
- if ( true === $save_payment_method ) {
- $request->setup_future_usage();
- }
- if ( $customer_id ) {
- $request->set_customer( $customer_id );
- }
-
- $updated_payment_intent = $request->send();
-
- // Attach the intent and exchange info to the order before doing the redirect,
- // so that when processing redirect, the up-to-date intent information is available.
- $intent_id = $updated_payment_intent->get_id();
- $intent_status = $updated_payment_intent->get_status();
- $payment_method = $updated_payment_intent->get_payment_method_id();
- $charge = $updated_payment_intent->get_charge();
- $charge_id = $charge ? $charge->get_id() : null;
-
- $this->order_service->attach_intent_info_to_order( $order, $intent_id, $intent_status, $payment_method, $customer_id, $charge_id, $currency );
- $this->attach_exchange_info_to_order( $order, $charge_id );
- }
-
- return [
- 'success' => true,
- ];
- }
-
- /**
- * Creates payment intent using current cart or order and store details.
- *
- * @param array $displayed_payment_methods Array of enabled payment methods to display in payment element.
- * @param int|null $order_id The id of the order if intent created from Order.
- * @param string $fingerprint User fingerprint.
- *
- * @return array
- */
- public function create_payment_intent( $displayed_payment_methods, $order_id = null, $fingerprint = '' ) {
- $request = null;
- $amount = WC()->cart->get_total( '' );
- $currency = get_woocommerce_currency();
- $number = 0;
- $order = wc_get_order( $order_id );
- $metadata = [];
- if ( is_a( $order, 'WC_Order' ) ) {
- $amount = $order->get_total();
- $currency = $order->get_currency();
- $metadata['order_number'] = $order->get_order_number();
- }
-
- $converted_amount = WC_Payments_Utils::prepare_amount( $amount, $currency );
- if ( 1 > $converted_amount ) {
- return $this->create_setup_intent( $displayed_payment_methods );
- }
-
- $minimum_amount = WC_Payments_Utils::get_cached_minimum_amount( $currency );
- if ( ! is_null( $minimum_amount ) && $converted_amount < $minimum_amount ) {
- // Use the minimum amount in order to create an intent and display fields.
- $converted_amount = $minimum_amount;
- }
-
- $manual_capture = ! empty( $this->settings['manual_capture'] ) && 'yes' === $this->settings['manual_capture'];
-
- try {
- $request = Create_Intention::create();
- $request->set_amount( $converted_amount );
- $request->set_currency_code( strtolower( $currency ) );
- $request->set_payment_method_types( array_values( $displayed_payment_methods ) );
- $request->set_metadata( $metadata );
- $request->set_capture_method( $manual_capture );
- $request->set_fingerprint( $fingerprint );
- $request->set_hook_args( $order );
- $payment_intent = $request->send();
- } catch ( Amount_Too_Small_Exception $e ) {
- $minimum_amount = $e->get_minimum_amount();
-
- WC_Payments_Utils::cache_minimum_amount( $e->get_currency(), $minimum_amount );
-
- /**
- * Try to create a new payment intent with the minimum amount
- * in order to display fields on the checkout page and allow
- * customers to select a shipping method, which might make
- * the total amount of the order higher than the minimum
- * amount for the API.
- */
- $request->set_amount( $minimum_amount );
- $payment_intent = $request->send();
- }
-
- return [
- 'id' => $payment_intent->get_id(),
- 'client_secret' => $payment_intent->get_client_secret(),
- ];
- }
-
- /**
- * Handle AJAX request for creating a setup intent without confirmation for Stripe UPE.
- *
- * @throws Add_Payment_Method_Exception - If nonce or setup intent is invalid.
- */
- public function init_setup_intent_ajax() {
- try {
- $is_nonce_valid = check_ajax_referer( 'wcpay_create_setup_intent_nonce', false, false );
- if ( ! $is_nonce_valid ) {
- throw new Add_Payment_Method_Exception(
- __( "We're not able to add this payment method. Please refresh the page and try again.", 'woocommerce-payments' ),
- 'invalid_referrer'
- );
- }
-
- $enabled_payment_methods = array_filter( $this->get_upe_enabled_payment_method_ids(), [ $this, 'is_enabled_for_saved_payments' ] );
- $response = $this->create_setup_intent( $enabled_payment_methods );
-
- // Encrypt client secret before exposing it to the browser.
- if ( $response['client_secret'] ) {
- $response['client_secret'] = WC_Payments_Utils::encrypt_client_secret( $this->account->get_stripe_account_id(), $response['client_secret'] );
- }
-
- $this->add_upe_setup_intent_to_session( $response['id'], $response['client_secret'] );
-
- wp_send_json_success( $response, 200 );
- } catch ( Exception $e ) {
- // Send back error so it can be displayed to the customer.
- wp_send_json_error(
- [
- 'error' => [
- 'message' => WC_Payments_Utils::get_filtered_error_message( $e ),
- ],
- ],
- WC_Payments_Utils::get_filtered_error_status_code( $e ),
- );
- }
- }
-
- /**
- * Creates setup intent without confirmation.
- *
- * @param array $displayed_payment_methods Array of enabled payment methods to display on element.
- * @return array
- */
- public function create_setup_intent( $displayed_payment_methods ) {
- // Determine the customer managing the payment methods, create one if we don't have one already.
- $user = wp_get_current_user();
- $customer_id = $this->customer_service->get_customer_id_by_user_id( $user->ID );
- if ( null === $customer_id ) {
- $customer_data = WC_Payments_Customer_Service::map_customer_data( null, new \WC_Customer( $user->ID ) );
- $customer_id = $this->customer_service->create_customer_for_user( $user, $customer_data );
- }
-
- $request = Create_Setup_Intention::create();
- $request->set_customer( $customer_id );
- $request->set_payment_method_types( array_values( $displayed_payment_methods ) );
- /** @var WC_Payments_API_Setup_Intention $setup_intent */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort
- $setup_intent = $request->send();
-
- return [
- 'id' => $setup_intent->get_id(),
- 'client_secret' => $setup_intent->get_client_secret(),
- ];
+ return WC_Payments::get_payment_method_by_id( $payment_method_type );
}
/**
@@ -410,6 +175,7 @@ public function parent_process_payment( $order_id ) {
* We also add the JavaScript which drives the UI.
*/
public function payment_fields() {
+ do_action( 'wc_payments_set_gateway', $this->get_selected_stripe_payment_type_id() );
do_action( 'wc_payments_add_upe_payment_fields' );
}
@@ -431,15 +197,14 @@ public function process_payment( $order_id ) {
'invalid_phone_number'
);
}
- $payment_intent_id = isset( $_POST['wc_payment_intent_id'] ) ? wc_clean( wp_unslash( $_POST['wc_payment_intent_id'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
- $amount = $order->get_total();
- $currency = $order->get_currency();
- $converted_amount = WC_Payments_Utils::prepare_amount( $amount, $currency );
- $payment_needed = 0 < $converted_amount;
- $selected_upe_payment_type = ! empty( $_POST['wcpay_selected_upe_payment_type'] ) ? wc_clean( wp_unslash( $_POST['wcpay_selected_upe_payment_type'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
- $payment_type = $this->is_payment_recurring( $order_id ) ? Payment_Type::RECURRING() : Payment_Type::SINGLE();
- $save_payment_method = $payment_type->equals( Payment_Type::RECURRING() ) || ! empty( $_POST[ 'wc-' . $this->id . '-new-payment-method' ] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
- $payment_country = ! empty( $_POST['wcpay_payment_country'] ) ? wc_clean( wp_unslash( $_POST['wcpay_payment_country'] ) ) : null; // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ $payment_intent_id = isset( $_POST['wc_payment_intent_id'] ) ? wc_clean( wp_unslash( $_POST['wc_payment_intent_id'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ $amount = $order->get_total();
+ $currency = $order->get_currency();
+ $converted_amount = WC_Payments_Utils::prepare_amount( $amount, $currency );
+ $payment_needed = 0 < $converted_amount;
+ $payment_type = $this->is_payment_recurring( $order_id ) ? Payment_Type::RECURRING() : Payment_Type::SINGLE();
+ $save_payment_method = $payment_type->equals( Payment_Type::RECURRING() ) || ! empty( $_POST[ 'wc-' . $this->id . '-new-payment-method' ] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ $payment_country = ! empty( $_POST['wcpay_payment_country'] ) ? wc_clean( wp_unslash( $_POST['wcpay_payment_country'] ) ) : null; // phpcs:ignore WordPress.Security.NonceVerification.Missing
if ( $payment_intent_id ) {
list( $user, $customer_id ) = $this->manage_customer_details_for_order( $order );
@@ -485,7 +250,7 @@ public function process_payment( $order_id ) {
$additional_api_parameters = $this->get_mandate_params_for_order( $order );
try {
- $payment_methods = $this->get_selected_upe_payment_methods( (string) $selected_upe_payment_type, $this->get_payment_method_ids_enabled_at_checkout( null, true ) ?? [] );
+ $payment_methods = $this->get_selected_upe_payment_methods( $this->stripe_id, $this->get_payment_method_ids_enabled_at_checkout( null, true ) ?? [] );
$request = Update_Intention::create( $payment_intent_id );
$request->set_currency_code( strtolower( $currency ) );
@@ -769,8 +534,6 @@ public function process_redirect_payment( $order, $intent_id, $save_payment_meth
$this->set_payment_method_title_for_order( $order, $payment_method_type, $payment_method_details );
$this->order_service->attach_transaction_fee_to_order( $order, $charge );
- static::remove_upe_payment_intent_from_session();
-
if ( Intent_Status::REQUIRES_ACTION === $status ) {
// I don't think this case should be possible, but just in case...
$next_action = $intent->get_next_action();
@@ -809,8 +572,6 @@ public function process_redirect_payment( $order, $intent_id, $save_payment_meth
$this->order_service->mark_payment_failed( $order, $intent_id, $status, $charge_id, $message );
}
- static::remove_upe_payment_intent_from_session();
-
wc_add_notice( WC_Payments_Utils::get_filtered_error_message( $e ), 'error' );
$redirect_url = wc_get_checkout_url();
@@ -887,7 +648,8 @@ public function create_token_from_setup_intent( $setup_intent_id, $user ) {
$payment_method_id = $setup_intent->get_payment_method_id();
// TODO: When adding SEPA and Sofort, we will need a new API call to get the payment method and from there get the type.
// Leaving 'card' as a hardcoded value for now to avoid the extra API call.
- $payment_method = $this->payment_methods['card'];
+ // $payment_method = $this->payment_methods['card'];// Maybe this should be enforced.
+ $payment_method = $this->payment_method;
return $payment_method->get_payment_token_for_user( $user, $payment_method_id );
} catch ( Exception $e ) {
@@ -896,11 +658,34 @@ public function create_token_from_setup_intent( $setup_intent_id, $user ) {
}
}
+ /**
+ * Mandate must be shown and acknowledged by customer before deferred intent UPE payment can be processed.
+ * This applies to SEPA and Link payment methods.
+ * https://stripe.com/docs/payments/finalize-payments-on-the-server
+ *
+ * @return boolean True if mandate must be shown and acknowledged by customer before deferred intent UPE payment can be processed, false otherwise.
+ */
+ public function is_mandate_data_required() {
+ $is_stripe_link_enabled = Payment_Method::CARD === $this->get_selected_stripe_payment_type_id() && in_array( Payment_Method::LINK, $this->get_upe_enabled_payment_method_ids(), true );
+ $is_sepa_debit_payment = Payment_Method::SEPA === $this->get_selected_stripe_payment_type_id();
+
+ return $is_stripe_link_enabled || $is_sepa_debit_payment;
+ }
+
+ /**
+ * Returns the Stripe payment type of the selected payment method.
+ *
+ * @return string
+ */
+ public function get_selected_stripe_payment_type_id() {
+ return $this->stripe_id;
+ }
+
/**
* Set formatted readable payment method title for order,
* using payment method details from accompanying charge.
*
- * @param WC_Order $order WC Order being processed.
+ * @param \WC_Order $order WC Order being processed.
* @param string $payment_method_type Stripe payment method key.
* @param array|bool $payment_method_details Array of payment method details from charge or false.
*/
@@ -912,7 +697,9 @@ public function set_payment_method_title_for_order( $order, $payment_method_type
$payment_method_title = $payment_method->get_title( $payment_method_details );
- $order->set_payment_method( self::GATEWAY_ID );
+ $payment_gateway = in_array( $payment_method->get_id(), [ Payment_Method::CARD, Payment_Method::LINK ], true ) ? self::GATEWAY_ID : self::GATEWAY_ID . '_' . $payment_method_type;
+
+ $order->set_payment_method( $payment_gateway );
$order->set_payment_method_title( $payment_method_title );
$order->save();
}
@@ -1138,8 +925,36 @@ public function is_enabled_for_saved_payments( $payment_method_id ) {
* @return bool True, if gateway supports saved payments. False, otherwise.
*/
public function should_support_saved_payments() {
- $methods_enabled_for_saved_payments = array_filter( $this->get_upe_enabled_payment_method_ids(), [ $this, 'is_enabled_for_saved_payments' ] );
- return ! empty( $methods_enabled_for_saved_payments );
+ return $this->is_enabled_for_saved_payments( $this->stripe_id );
+ }
+
+ /**
+ * Whether we should use the platform account to initialize Stripe on the checkout page.
+ *
+ * @return bool Result of the WCPay gateway checks if the card payment method is used, false otherwise.
+ */
+ public function should_use_stripe_platform_on_checkout_page() {
+ if ( 'card' === $this->stripe_id ) {
+ return parent::should_use_stripe_platform_on_checkout_page();
+ }
+ return false;
+ }
+
+ /**
+ * This method is used by WooCommerce Core's WC_Payment_Gateways::get_available_payment_gateways() to filter out gateways.
+ *
+ * The availability decision includes an additional business rule that checks if the payment method is enabled at checkout
+ * via the is_enabled_at_checkout method. This method provides crucial information, among others, to determine if the gateway
+ * is reusable in case there's a subcription in the cart.
+ *
+ * @return bool Whether the gateway is enabled and ready to accept payments.
+ */
+ public function is_available() {
+ $processing_payment_method = $this->payment_methods[ $this->payment_method->get_id() ];
+ if ( ! $processing_payment_method->is_enabled_at_checkout( $this->get_account_country() ) ) {
+ return false;
+ }
+ return parent::is_available();
}
/**
@@ -1182,12 +997,8 @@ public function log_payment_error_ajax() {
$this->order_service->mark_payment_failed( $order, $intent_id, $intent_status, $charge_id, $error_message );
- static::remove_upe_payment_intent_from_session();
-
wp_send_json_success();
} catch ( Exception $e ) {
- static::remove_upe_payment_intent_from_session();
-
wp_send_json_error(
[
'error' => [
@@ -1200,71 +1011,12 @@ public function log_payment_error_ajax() {
}
/**
- * Returns payment intent session data.
+ * This function wraps WC_Payments::get_payment_method_map, useful for unit testing.
*
- * @param false|string $payment_method Stripe payment method.
- * @return array|string value of session variable
+ * @return array Array of UPE_Payment_Method instances.
*/
- public function get_payment_intent_data_from_session( $payment_method = false ) {
- return WC()->session->get( self::KEY_UPE_PAYMENT_INTENT );
- }
-
- /**
- * Returns setup intent session data.
- *
- * @param false|string $payment_method Stripe payment method.
- * @return array|string value of session variable
- */
- public function get_setup_intent_data_from_session( $payment_method = false ) {
- return WC()->session->get( self::KEY_UPE_SETUP_INTENT );
- }
-
- /**
- * Adds the id and client secret of payment intent needed to mount the UPE element in frontend to WC session.
- *
- * @param string $intent_id The payment intent id.
- * @param string $client_secret The payment intent client secret.
- */
- private function add_upe_payment_intent_to_session( string $intent_id = '', string $client_secret = '' ) {
- $cart_hash = 'undefined';
-
- if ( isset( $_COOKIE['woocommerce_cart_hash'] ) ) {
- $cart_hash = sanitize_text_field( wp_unslash( $_COOKIE['woocommerce_cart_hash'] ) );
- }
-
- $value = $cart_hash . '-' . $intent_id . '-' . $client_secret;
-
- WC()->session->set( self::KEY_UPE_PAYMENT_INTENT, $value );
- }
-
- /**
- * Removes the payment intent created for UPE from WC session.
- */
- public static function remove_upe_payment_intent_from_session() {
- if ( isset( WC()->session ) ) {
- WC()->session->__unset( self::KEY_UPE_PAYMENT_INTENT );
- }
- }
-
- /**
- * Adds the id and client secret of setup intent needed to mount the UPE element in frontend to WC session.
- *
- * @param string $intent_id The setup intent id.
- * @param string $client_secret The setup intent client secret.
- */
- private function add_upe_setup_intent_to_session( string $intent_id = '', string $client_secret = '' ) {
- $value = $intent_id . '-' . $client_secret;
-
- WC()->session->set( self::KEY_UPE_SETUP_INTENT, $value );
- }
-
- /**
- * Removes the setup intent created for UPE from WC session.
- */
- public function remove_upe_setup_intent_from_session() {
- if ( isset( WC()->session ) ) {
- WC()->session->__unset( self::KEY_UPE_SETUP_INTENT );
- }
+ public function wc_payments_get_payment_method_map() {
+ return WC_Payments::get_payment_method_map();
}
/**
@@ -1286,12 +1038,21 @@ public function get_payment_methods() {
}
/**
- * Returns the UPE payment method for the gateway (default card gateway).
+ * Returns the UPE payment method for the gateway.
*
* @return UPE_Payment_Method
*/
public function get_payment_method() {
- return $this->payment_methods['card'];
+ return $this->payment_method;
+ }
+
+ /**
+ * Returns Stripe payment method type ID.
+ *
+ * @return string
+ */
+ public function get_stripe_id() {
+ return $this->stripe_id;
}
/**
@@ -1311,7 +1072,7 @@ private function get_payment_method_type_from_payment_details( $payment_method_d
* @return false|UPE_Payment_Gateway Matching UPE Payment Gateway instance.
*/
public function wc_payments_get_payment_gateway_by_id( $payment_method_id ) {
- return $this;
+ return WC_Payments::get_payment_gateway_by_id( $payment_method_id );
}
/**
@@ -1321,6 +1082,57 @@ public function wc_payments_get_payment_gateway_by_id( $payment_method_id ) {
* @return false|UPE_Payment_Method Matching UPE Payment Method instance.
*/
public function wc_payments_get_payment_method_by_id( $payment_method_id ) {
- return $this->payment_methods[ $payment_method_id ];
+ return WC_Payments::get_payment_method_by_id( $payment_method_id );
+ }
+
+ /**
+ * Handles the shipping requirement for Afterpay payments.
+ *
+ * This method extracts the shipping and billing data from the order and sets the appropriate
+ * shipping data for the Afterpay payment request. If neither shipping nor billing data is valid
+ * for shipping, an exception is thrown.
+ *
+ * @param WC_Order $order The order object containing shipping and billing information.
+ * @param Create_And_Confirm_Intention $request The Afterpay payment request object to set shipping data on.
+ *
+ * @throws Invalid_Address_Exception If neither shipping nor billing address is valid for Afterpay payments.
+ * @return void
+ */
+ private function handle_afterpay_shipping_requirement( WC_Order $order, Create_And_Confirm_Intention $request ): void {
+ $check_if_usable = function( array $address ): bool {
+ return $address['country'] && $address['state'] && $address['city'] && $address['postal_code'] && $address['line1'];
+ };
+
+ $shipping_data = $this->order_service->get_shipping_data_from_order( $order );
+ if ( $check_if_usable( $shipping_data['address'] ) ) {
+ $request->set_shipping( $shipping_data );
+ return;
+ }
+
+ $billing_data = $this->order_service->get_billing_data_from_order( $order );
+ if ( $check_if_usable( $billing_data['address'] ) ) {
+ $request->set_shipping( $billing_data );
+ return;
+ }
+
+ throw new Invalid_Address_Exception( __( 'A valid shipping address is required for Afterpay payments.', 'woocommerce-payments' ) );
+ }
+
+
+ /**
+ * Modifies the create intent parameters when processing a payment.
+ *
+ * If the selected Stripe payment type is AFTERPAY, it updates the shipping data in the request.
+ *
+ * @param Create_And_Confirm_Intention $request The request object for creating and confirming intention.
+ * @param Payment_Information $payment_information The payment information object.
+ * @param WC_Order $order The order object.
+ *
+ * @return void
+ */
+ protected function modify_create_intent_parameters_when_processing_payment( Create_And_Confirm_Intention $request, Payment_Information $payment_information, WC_Order $order ): void {
+ if ( Payment_Method::AFTERPAY === $this->get_selected_stripe_payment_type_id() ) {
+ $this->handle_afterpay_shipping_requirement( $order, $request );
+ }
}
}
diff --git a/includes/payment-methods/class-upe-split-payment-gateway.php b/includes/payment-methods/class-upe-split-payment-gateway.php
deleted file mode 100644
index e1fe2be2cff..00000000000
--- a/includes/payment-methods/class-upe-split-payment-gateway.php
+++ /dev/null
@@ -1,544 +0,0 @@
-method_description = __( 'Payments made simple, with no monthly fees - designed exclusively for WooCommerce stores. Accept credit cards, debit cards, and other popular payment methods.', 'woocommerce-payments' );
- $this->description = '';
- $this->stripe_id = $payment_method->get_id();
- $this->payment_method = $payment_method;
- $this->title = $payment_method->get_title();
- $this->icon = $payment_method->get_icon();
-
- if ( 'card' !== $this->stripe_id ) {
- $this->id = self::GATEWAY_ID . '_' . $this->stripe_id;
- $this->method_title = "WooPayments ($this->title)";
- }
- }
-
- /**
- * Initializes this class's WP hooks.
- *
- * @return void
- */
- public function init_hooks() {
- add_action( "wc_ajax_wcpay_init_setup_intent_$this->stripe_id", [ $this, 'init_setup_intent_ajax' ] );
-
- parent::init_hooks();
- }
-
- /**
- * Displays HTML tags for WC payment gateway radio button content.
- */
- public function display_gateway_html() {
- ?>
-
- is_enabled_for_saved_payments( $this->stripe_id );
- }
-
- /**
- * Whether we should use the platform account to initialize Stripe on the checkout page.
- *
- * @return bool Result of the WCPay gateway checks if the card payment method is used, false otherwise.
- */
- public function should_use_stripe_platform_on_checkout_page() {
- if ( 'card' === $this->stripe_id ) {
- return parent::should_use_stripe_platform_on_checkout_page();
- }
- return false;
- }
-
- /**
- * This method is used by WooCommerce Core's WC_Payment_Gateways::get_available_payment_gateways() to filter out gateways.
- *
- * The availability decision includes an additional business rule that checks if the payment method is enabled at checkout
- * via the is_enabled_at_checkout method. This method provides crucial information, among others, to determine if the gateway
- * is reusable in case there's a subcription in the cart.
- *
- * @return bool Whether the gateway is enabled and ready to accept payments.
- */
- public function is_available() {
- $processing_payment_method = $this->payment_methods[ $this->payment_method->get_id() ];
- if ( ! $processing_payment_method->is_enabled_at_checkout( $this->get_account_country() ) ) {
- return false;
- }
- return parent::is_available();
- }
-
- /**
- * Gets UPE_Payment_Method instance from ID.
- *
- * @param string $payment_method_type Stripe payment method type ID.
- * @return UPE_Payment_Method|false UPE payment method instance.
- */
- public function get_selected_payment_method( $payment_method_type ) {
- return WC_Payments::get_payment_method_by_id( $payment_method_type );
- }
-
- /**
- * Set formatted readable payment method title for order,
- * using payment method details from accompanying charge.
- *
- * @param \WC_Order $order WC Order being processed.
- * @param string $payment_method_type Stripe payment method key.
- * @param array|bool $payment_method_details Array of payment method details from charge or false.
- */
- public function set_payment_method_title_for_order( $order, $payment_method_type, $payment_method_details ) {
- $payment_method = $this->get_selected_payment_method( $payment_method_type );
- if ( ! $payment_method ) {
- return;
- }
-
- $payment_method_title = $payment_method->get_title( $payment_method_details );
-
- $payment_gateway = in_array( $payment_method->get_id(), [ Payment_Method::CARD, Payment_Method::LINK ], true ) ? self::GATEWAY_ID : self::GATEWAY_ID . '_' . $payment_method_type;
-
- $order->set_payment_method( $payment_gateway );
- $order->set_payment_method_title( $payment_method_title );
- $order->save();
- }
-
- /**
- * Handle AJAX request for updating a payment intent for Stripe UPE.
- *
- * @throws Process_Payment_Exception - If nonce or setup intent is invalid.
- */
- public function update_payment_intent_ajax() {
- try {
- $is_nonce_valid = check_ajax_referer( 'wcpay_update_payment_intent_nonce', false, false );
- if ( ! $is_nonce_valid ) {
- throw new Process_Payment_Exception(
- __( "We're not able to process this payment. Please refresh the page and try again.", 'woocommerce-payments' ),
- 'wcpay_upe_intent_error'
- );
- }
-
- $order_id = isset( $_POST['wcpay_order_id'] ) ? absint( $_POST['wcpay_order_id'] ) : null;
- $payment_intent_id = isset( $_POST['wc_payment_intent_id'] ) ? wc_clean( wp_unslash( $_POST['wc_payment_intent_id'] ) ) : '';
- $fingerprint = isset( $_POST['wcpay-fingerprint'] ) ? wc_clean( wp_unslash( $_POST['wcpay-fingerprint'] ) ) : '';
- $save_payment_method = isset( $_POST['save_payment_method'] ) ? 'yes' === wc_clean( wp_unslash( $_POST['save_payment_method'] ) ) : false;
- $selected_upe_payment_type = $this->stripe_id;
- $payment_country = ! empty( $_POST['wcpay_payment_country'] ) ? wc_clean( wp_unslash( $_POST['wcpay_payment_country'] ) ) : null;
-
- wp_send_json_success( $this->update_payment_intent( $payment_intent_id, $order_id, $save_payment_method, $selected_upe_payment_type, $payment_country, $fingerprint ), 200 );
- } catch ( Exception $e ) {
- // Send back error so it can be displayed to the customer.
- wp_send_json_error(
- [
- 'error' => [
- 'message' => WC_Payments_Utils::get_filtered_error_message( $e ),
- ],
- ],
- WC_Payments_Utils::get_filtered_error_status_code( $e ),
- );
- }
- }
-
- /**
- * Handle AJAX request for creating a setup intent without confirmation for Stripe UPE.
- *
- * @throws Add_Payment_Method_Exception - If nonce or setup intent is invalid.
- */
- public function init_setup_intent_ajax() {
- try {
- $is_nonce_valid = check_ajax_referer( 'wcpay_create_setup_intent_nonce', false, false );
- if ( ! $is_nonce_valid ) {
- throw new Add_Payment_Method_Exception(
- __( "We're not able to add this payment method. Please refresh the page and try again.", 'woocommerce-payments' ),
- 'invalid_referrer'
- );
- }
-
- $enabled_payment_methods = array_filter( $this->get_upe_enabled_payment_method_ids(), [ $this, 'is_enabled_for_saved_payments' ] );
- if ( ! in_array( $this->payment_method->get_id(), $enabled_payment_methods, true ) ) {
- throw new Process_Payment_Exception(
- __( "We're not able to process this payment. Please refresh the page and try again.", 'woocommerce-payments' ),
- 'wcpay_upe_intent_error'
- );
- }
- $displayed_payment_methods = [ $this->payment_method->get_id() ];
-
- $response = $this->create_setup_intent( $displayed_payment_methods );
-
- // Encrypt client secret before exposing it to the browser.
- if ( $response['client_secret'] ) {
- $response['client_secret'] = WC_Payments_Utils::encrypt_client_secret( $this->account->get_stripe_account_id(), $response['client_secret'] );
- }
-
- $this->add_upe_setup_intent_to_session( $response['id'], $response['client_secret'] );
-
- wp_send_json_success( $response, 200 );
- } catch ( Exception $e ) {
- // Send back error so it can be displayed to the customer.
- wp_send_json_error(
- [
- 'error' => [
- 'message' => WC_Payments_Utils::get_filtered_error_message( $e ),
- ],
- ],
- WC_Payments_Utils::get_filtered_error_status_code( $e ),
- );
- }
- }
-
-
- /**
- * Renders the credit card input fields needed to get the user's payment information on the checkout page.
- *
- * We also add the JavaScript which drives the UI.
- */
- public function payment_fields() {
- do_action( 'wc_payments_set_gateway', $this->get_selected_stripe_payment_type_id() );
- do_action( 'wc_payments_add_upe_payment_fields' );
- }
-
- /**
- * Update payment intent for completed checkout and return redirect URL for Stripe to confirm payment.
- *
- * @param int $order_id Order ID to process the payment for.
- *
- * @return array|null An array with result of payment and redirect URL, or nothing.
- * @throws Exception Error processing the payment.
- */
- public function process_payment( $order_id ) {
- $_POST['wcpay_selected_upe_payment_type'] = $this->stripe_id;
- return parent::process_payment( $order_id );
- }
-
- /**
- * Adds a token to current user from a setup intent id.
- *
- * @param string $setup_intent_id ID of the setup intent.
- * @param WP_User $user User to add token to.
- *
- * @return WC_Payment_Token_CC|WC_Payment_Token_WCPay_SEPA|null The added token.
- */
- public function create_token_from_setup_intent( $setup_intent_id, $user ) {
- try {
- $setup_intent_request = Get_Setup_Intention::create( $setup_intent_id );
- /** @var WC_Payments_API_Setup_Intention $setup_intent */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort
- $setup_intent = $setup_intent_request->send();
-
- $payment_method_id = $setup_intent->get_payment_method_id();
- // TODO: When adding SEPA and Sofort, we will need a new API call to get the payment method and from there get the type.
- // Leaving 'card' as a hardcoded value for now to avoid the extra API call.
- // $payment_method = $this->payment_methods['card'];// Maybe this should be enforced.
- $payment_method = $this->payment_method;
-
- return $payment_method->get_payment_token_for_user( $user, $payment_method_id );
- } catch ( Exception $e ) {
- wc_add_notice( WC_Payments_Utils::get_filtered_error_message( $e ), 'error', [ 'icon' => 'error' ] );
- Logger::log( 'Error when adding payment method: ' . $e->getMessage() );
- }
- }
-
- /**
- * Mandate must be shown and acknowledged by customer before deferred intent UPE payment can be processed.
- * This applies to SEPA and Link payment methods.
- * https://stripe.com/docs/payments/finalize-payments-on-the-server
- *
- * @return boolean True if mandate must be shown and acknowledged by customer before deferred intent UPE payment can be processed, false otherwise.
- */
- public function is_mandate_data_required() {
- $is_stripe_link_enabled = Payment_Method::CARD === $this->get_selected_stripe_payment_type_id() && in_array( Payment_Method::LINK, $this->get_upe_enabled_payment_method_ids(), true );
- $is_sepa_debit_payment = Payment_Method::SEPA === $this->get_selected_stripe_payment_type_id();
-
- return $is_stripe_link_enabled || $is_sepa_debit_payment;
- }
-
- /**
- * Returns the Stripe payment type of the selected payment method.
- *
- * @return string
- */
- public function get_selected_stripe_payment_type_id() {
- return $this->stripe_id;
- }
-
- /**
- * Adds the id and client secret of payment intent needed to mount the UPE element in frontend to WC session.
- *
- * @param string $intent_id The payment intent id.
- * @param string $client_secret The payment intent client secret.
- */
- private function add_upe_payment_intent_to_session( string $intent_id = '', string $client_secret = '' ) {
- $cart_hash = 'undefined';
-
- if ( isset( $_COOKIE['woocommerce_cart_hash'] ) ) {
- $cart_hash = sanitize_text_field( wp_unslash( $_COOKIE['woocommerce_cart_hash'] ) );
- }
-
- $value = $cart_hash . '-' . $intent_id . '-' . $client_secret;
-
- WC()->session->set( $this->get_payment_intent_session_key(), $value );
- }
-
- /**
- * Removes all UPE payment intents from WC session.
- */
- public static function remove_upe_payment_intent_from_session() {
- if ( isset( WC()->session ) ) {
- foreach ( WC_Payments::get_payment_method_map() as $id => $payment_method ) {
- WC()->session->__unset( self::KEY_UPE_PAYMENT_INTENT . '_' . $payment_method->get_id() );
- }
- }
- }
-
- /**
- * Adds the id and client secret of setup intent needed to mount the UPE element in frontend to WC session.
- *
- * @param string $intent_id The setup intent id.
- * @param string $client_secret The setup intent client secret.
- */
- private function add_upe_setup_intent_to_session( string $intent_id = '', string $client_secret = '' ) {
- $value = $intent_id . '-' . $client_secret;
-
- WC()->session->set( $this->get_setup_intent_session_key(), $value );
- }
-
- /**
- * Removes all UPE setup intents from WC session.
- */
- public function remove_upe_setup_intent_from_session() {
- if ( isset( WC()->session ) ) {
- foreach ( $this->wc_payments_get_payment_method_map() as $id => $payment_method ) {
- WC()->session->__unset( $this->get_setup_intent_session_key( $payment_method->get_id() ) );
- }
- }
- }
-
- /**
- * Returns session key for UPE SEPA payment intents.
- *
- * @param false|string $payment_method Stripe payment method.
- * @return string
- */
- public function get_payment_intent_session_key( $payment_method = false ) {
- if ( false === $payment_method ) {
- $payment_method = $this->stripe_id;
- }
- return self::KEY_UPE_PAYMENT_INTENT . '_' . $payment_method;
- }
-
- /**
- * Returns session key for UPE SEPA setup intents.
- *
- * @param false|string $payment_method Stripe payment method.
- * @return string
- */
- public function get_setup_intent_session_key( $payment_method = false ) {
- if ( false === $payment_method ) {
- $payment_method = $this->stripe_id;
- }
- return self::KEY_UPE_SETUP_INTENT . '_' . $payment_method;
- }
-
- /**
- * Returns payment intent session data.
- *
- * @param false|string $payment_method Stripe payment method.
- * @return array|string value of session variable
- */
- public function get_payment_intent_data_from_session( $payment_method = false ) {
- return WC()->session->get( $this->get_payment_intent_session_key( $payment_method ) );
- }
-
- /**
- * Returns setup intent session data.
- *
- * @param false|string $payment_method Stripe payment method.
- * @return array|string value of session variable
- */
- public function get_setup_intent_data_from_session( $payment_method = false ) {
- return WC()->session->get( $this->get_setup_intent_session_key( $payment_method ) );
- }
-
- /**
- * This function wraps WC_Payments::get_payment_method_by_id, useful for unit testing.
- *
- * @param string $payment_method_id Stripe payment method type ID.
- * @return false|UPE_Payment_Method Matching UPE Payment Method instance.
- */
- public function wc_payments_get_payment_method_by_id( $payment_method_id ) {
- return WC_Payments::get_payment_method_by_id( $payment_method_id );
- }
-
- /**
- * This function wraps WC_Payments::get_payment_gateway_by_id, useful for unit testing.
- *
- * @param string $payment_method_id Stripe payment method type ID.
- * @return false|UPE_Payment_Gateway Matching UPE Payment Gateway instance.
- */
- public function wc_payments_get_payment_gateway_by_id( $payment_method_id ) {
- return WC_Payments::get_payment_gateway_by_id( $payment_method_id );
- }
-
- /**
- * This function wraps WC_Payments::get_payment_method_map, useful for unit testing.
- *
- * @return array Array of UPE_Payment_Method instances.
- */
- public function wc_payments_get_payment_method_map() {
- return WC_Payments::get_payment_method_map();
- }
-
- /**
- * Returns the UPE payment method for the gateway.
- *
- * @return UPE_Payment_Method
- */
- public function get_payment_method() {
- return $this->payment_method;
- }
-
- /**
- * Returns Stripe payment method type ID.
- *
- * @return string
- */
- public function get_stripe_id() {
- return $this->stripe_id;
- }
-
- /**
- * Handles the shipping requirement for Afterpay payments.
- *
- * This method extracts the shipping and billing data from the order and sets the appropriate
- * shipping data for the Afterpay payment request. If neither shipping nor billing data is valid
- * for shipping, an exception is thrown.
- *
- * @param WC_Order $order The order object containing shipping and billing information.
- * @param Create_And_Confirm_Intention $request The Afterpay payment request object to set shipping data on.
- *
- * @throws Invalid_Address_Exception If neither shipping nor billing address is valid for Afterpay payments.
- * @return void
- */
- private function handle_afterpay_shipping_requirement( WC_Order $order, Create_And_Confirm_Intention $request ): void {
- $check_if_usable = function( array $address ): bool {
- return $address['country'] && $address['state'] && $address['city'] && $address['postal_code'] && $address['line1'];
- };
-
- $shipping_data = $this->order_service->get_shipping_data_from_order( $order );
- if ( $check_if_usable( $shipping_data['address'] ) ) {
- $request->set_shipping( $shipping_data );
- return;
- }
-
- $billing_data = $this->order_service->get_billing_data_from_order( $order );
- if ( $check_if_usable( $billing_data['address'] ) ) {
- $request->set_shipping( $billing_data );
- return;
- }
-
- throw new Invalid_Address_Exception( __( 'A valid shipping address is required for Afterpay payments.', 'woocommerce-payments' ) );
- }
-
-
- /**
- * Modifies the create intent parameters when processing a payment.
- *
- * If the selected Stripe payment type is AFTERPAY, it updates the shipping data in the request.
- *
- * @param Create_And_Confirm_Intention $request The request object for creating and confirming intention.
- * @param Payment_Information $payment_information The payment information object.
- * @param WC_Order $order The order object.
- *
- * @return void
- */
- protected function modify_create_intent_parameters_when_processing_payment( Create_And_Confirm_Intention $request, Payment_Information $payment_information, WC_Order $order ): void {
- if ( Payment_Method::AFTERPAY === $this->get_selected_stripe_payment_type_id() ) {
- $this->handle_afterpay_shipping_requirement( $order, $request );
- }
- }
-}
diff --git a/src/Internal/Payment/State/ProcessedState.php b/src/Internal/Payment/State/ProcessedState.php
index a7f222a0caf..7e8629121eb 100644
--- a/src/Internal/Payment/State/ProcessedState.php
+++ b/src/Internal/Payment/State/ProcessedState.php
@@ -14,7 +14,6 @@
use WCPay\Vendor\League\Container\Exception\ContainerException;
use WCPay\Internal\Proxy\LegacyProxy;
use WCPay\Payment_Methods\UPE_Payment_Gateway;
-use WCPay\Payment_Methods\UPE_Split_Payment_Gateway;
/**
* This state is used when payment is completed on the server, and we need to update date on the plugin side.
@@ -81,7 +80,6 @@ public function complete_processing() {
// cleaning up.
$this->legacy_proxy->call_function( 'wc_reduce_stock_levels', $order_id );
$this->clear_cart();
- $this->clear_upe_payment_intent_from_session();
// If everything went well, transition to the completed state.
return $this->create_state( CompletedState::class );
@@ -98,14 +96,4 @@ private function clear_cart() {
$cart->empty_cart();
}
}
-
- /**
- * Remove UPE payment intents from session.
- * Using Legacy_Proxy temporarily to provide functionality until replaced by deferred intents.
- */
- private function clear_upe_payment_intent_from_session() : void {
- $this->legacy_proxy->call_static( UPE_Payment_Gateway::class, 'remove_upe_payment_intent_from_session' );
- $this->legacy_proxy->call_static( UPE_Split_Payment_Gateway::class, 'remove_upe_payment_intent_from_session' );
- }
-
}
diff --git a/tests/unit/admin/test-class-wc-rest-payments-settings-controller.php b/tests/unit/admin/test-class-wc-rest-payments-settings-controller.php
index 3f109547442..72d9c1854e3 100644
--- a/tests/unit/admin/test-class-wc-rest-payments-settings-controller.php
+++ b/tests/unit/admin/test-class-wc-rest-payments-settings-controller.php
@@ -13,7 +13,6 @@
use WCPay\Duplicate_Payment_Prevention_Service;
use WCPay\Payment_Methods\Eps_Payment_Method;
use WCPay\Payment_Methods\UPE_Payment_Gateway;
-use WCPay\Payment_Methods\UPE_Split_Payment_Gateway;
use WCPay\Payment_Methods\CC_Payment_Method;
use WCPay\Payment_Methods\Bancontact_Payment_Method;
use WCPay\Payment_Methods\Becs_Payment_Method;
@@ -76,7 +75,7 @@ class WC_REST_Payments_Settings_Controller_Test extends WCPAY_UnitTestCase {
/**
* An array of mocked split UPE payment gateways mapped to payment method ID.
*
- * @var UPE_Split_Payment_Gateway
+ * @var UPE_Payment_Gateway
*/
private $mock_split_upe_payment_gateway;
@@ -191,6 +190,7 @@ public function set_up() {
$customer_service,
$token_service,
$action_scheduler_service,
+ $mock_payment_method,
$mock_payment_methods,
$mock_rate_limiter,
$order_service,
@@ -201,7 +201,7 @@ public function set_up() {
$this->upe_controller = new WC_REST_Payments_Settings_Controller( $this->mock_api_client, $this->mock_upe_payment_gateway, $this->mock_wcpay_account );
- $this->mock_split_upe_payment_gateway = new UPE_Split_Payment_Gateway(
+ $this->mock_split_upe_payment_gateway = new UPE_Payment_Gateway(
$this->mock_api_client,
$this->mock_wcpay_account,
$customer_service,
diff --git a/tests/unit/payment-methods/test-class-upe-payment-gateway.php b/tests/unit/payment-methods/test-class-upe-payment-gateway.php
index fded27349c0..cd41a804268 100644
--- a/tests/unit/payment-methods/test-class-upe-payment-gateway.php
+++ b/tests/unit/payment-methods/test-class-upe-payment-gateway.php
@@ -108,6 +108,13 @@ class UPE_Payment_Gateway_Test extends WCPAY_UnitTestCase {
*/
private $mock_payment_methods;
+ /**
+ * Mock UPE payment method.
+ *
+ * @var UPE_Payment_Method|MockObject
+ */
+ private $mock_payment_method;
+
/**
* WC_Payments_Account instance.
*
@@ -268,6 +275,12 @@ public function set_up() {
)
->getMock();
+ $this->mock_payment_method = $this->getMockBuilder( $payment_method_class )
+ ->setConstructorArgs( [ $this->mock_token_service ] )
+ ->onlyMethods( [ 'is_subscription_item_in_cart', 'get_icon' ] )
+ ->getMock();
+ $this->mock_payment_methods[ $this->mock_payment_method->get_id() ] = $this->mock_payment_method;
+
// Arrange: Mock UPE_Payment_Gateway so that some of its methods can be
// mocked, and their return values can be used for testing.
$this->mock_upe_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class )
@@ -278,6 +291,7 @@ public function set_up() {
$this->mock_customer_service,
$this->mock_token_service,
$this->mock_action_scheduler_service,
+ $this->mock_payment_method,
$this->mock_payment_methods,
$this->mock_rate_limiter,
$this->mock_order_service,
@@ -344,428 +358,6 @@ public function tear_down() {
wcpay_get_test_container()->reset_all_replacements();
}
- public function test_display_gateway_html() {
- $this->expectOutputRegex( '/<\/div>/' );
- $this->mock_upe_gateway->display_gateway_html();
- }
-
- public function test_update_payment_intent_adds_customer_save_payment_and_level3_data() {
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $order_number = $order->get_order_number();
- $product_item = current( $order->get_items( 'line_item' ) );
- $intent_id = 'pi_mock';
- $user = '';
- $customer_id = 'cus_mock';
- $save_payment_method = true;
-
- $this->set_cart_contains_subscription_items( false );
-
- $this->mock_upe_gateway->expects( $this->once() )
- ->method( 'manage_customer_details_for_order' )
- ->will(
- $this->returnValue( [ $user, $customer_id ] )
- );
-
- $this->mock_customer_service
- ->expects( $this->never() )
- ->method( 'create_customer_for_user' );
-
- $intent = WC_Helper_Intention::create_intention(
- [
- 'id' => $intent_id,
- 'amount' => 5000,
- ]
- );
-
- $request = $this->mock_wcpay_request( Update_Intention::class, 1, 'pi_mock' );
-
- $request->expects( $this->once() )
- ->method( 'set_amount' )
- ->with( 5000 );
-
- $request->expects( $this->once() )
- ->method( 'set_currency_code' )
- ->with( 'usd' );
-
- $request->expects( $this->once() )
- ->method( 'set_customer' )
- ->with( 'cus_mock' );
-
- $request->expects( $this->once() )
- ->method( 'setup_future_usage' );
-
- $request->expects( $this->once() )
- ->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'legacy_upe' ] );
-
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- $result = $this->mock_upe_gateway->update_payment_intent( $intent_id, $order_id, $save_payment_method );
- }
-
- public function test_update_payment_intent_with_selected_upe_payment_method() {
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $order_number = $order->get_order_number();
- $product_item = current( $order->get_items( 'line_item' ) );
- $intent_id = 'pi_mock';
- $user = '';
- $customer_id = 'cus_mock';
- $save_payment_method = true;
- $selected_upe_payment_type = 'giropay';
-
- $this->set_cart_contains_subscription_items( false );
-
- $this->mock_upe_gateway->expects( $this->once() )
- ->method( 'manage_customer_details_for_order' )
- ->will(
- $this->returnValue( [ $user, $customer_id ] )
- );
-
- $this->mock_customer_service
- ->expects( $this->never() )
- ->method( 'create_customer_for_user' );
-
- $intent = WC_Helper_Intention::create_intention(
- [
- 'id' => $intent_id,
- 'amount' => 5000,
- ]
- );
-
- $request = $this->mock_wcpay_request( Update_Intention::class, 1, 'pi_mock' );
-
- $request->expects( $this->once() )
- ->method( 'set_amount' )
- ->with( 5000 );
-
- $request->expects( $this->once() )
- ->method( 'set_currency_code' )
- ->with( 'usd' );
-
- $request->expects( $this->once() )
- ->method( 'set_customer' )
- ->with( 'cus_mock' );
-
- $request->expects( $this->once() )
- ->method( 'set_payment_method_types' )
- ->with( [ 'giropay' ] );
-
- $request->expects( $this->once() )
- ->method( 'setup_future_usage' );
-
- $request->expects( $this->once() )
- ->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'legacy_upe' ] );
-
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- $result = $this->mock_upe_gateway->update_payment_intent( $intent_id, $order_id, $save_payment_method, $selected_upe_payment_type );
- }
-
- public function test_update_payment_intent_with_payment_country() {
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $intent_id = 'pi_mock';
- $order_number = $order->get_order_number();
- $product_item = current( $order->get_items( 'line_item' ) );
-
- $this->set_cart_contains_subscription_items( false );
-
- $this->mock_upe_gateway->expects( $this->once() )
- ->method( 'manage_customer_details_for_order' )
- ->will(
- $this->returnValue( [ '', 'cus_mock' ] )
- );
-
- $this->mock_customer_service
- ->expects( $this->never() )
- ->method( 'create_customer_for_user' );
-
- $intent = WC_Helper_Intention::create_intention(
- [
- 'id' => $intent_id,
- 'amount' => 5000,
- ]
- );
-
- $request = $this->mock_wcpay_request( Update_Intention::class, 1, 'pi_mock' );
-
- $request->expects( $this->once() )
- ->method( 'set_amount' )
- ->with( 5000 );
-
- $request->expects( $this->once() )
- ->method( 'set_currency_code' )
- ->with( 'usd' );
-
- $request->expects( $this->once() )
- ->method( 'set_customer' )
- ->with( 'cus_mock' );
-
- $request->expects( $this->once() )
- ->method( 'set_payment_country' )
- ->with( 'US' );
-
- $request->expects( $this->never() )
- ->method( 'setup_future_usage' );
-
- $request->expects( $this->once() )
- ->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'legacy_upe' ] );
-
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- $this->mock_upe_gateway->update_payment_intent( 'pi_mock', $order_id, false, null, 'US' );
- }
-
- public function test_create_payment_intent_uses_order_amount_if_order() {
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::REQUIRES_PAYMENT_METHOD ] );
- $request = $this->mock_wcpay_request( Create_Intention::class );
- $request->expects( $this->once() )
- ->method( 'set_amount' )
- ->with( $intent->get_amount() );
-
- $request->expects( $this->once() )
- ->method( 'set_currency_code' )
- ->with( strtolower( $intent->get_currency() ) );
-
- $request->expects( $this->once() )
- ->method( 'set_capture_method' )
- ->with( false );
-
- $request->expects( $this->once() )
- ->method( 'set_metadata' )
- ->with( [ 'order_number' => $order->get_order_number() ] );
-
- $request->expects( $this->once() )
- ->method( 'set_payment_method_types' );
-
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- $this->set_cart_contains_subscription_items( false );
- $this->set_get_upe_enabled_payment_method_statuses_return_value();
-
- $result = $this->mock_upe_gateway->create_payment_intent( [ 'card' ], $order_id );
- }
-
- public function test_create_payment_intent_defaults_to_automatic_capture() {
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::REQUIRES_PAYMENT_METHOD ] );
- $request = $this->mock_wcpay_request( Create_Intention::class );
- $request->expects( $this->once() )
- ->method( 'set_amount' )
- ->with( $intent->get_amount() );
-
- $request->expects( $this->once() )
- ->method( 'set_currency_code' )
- ->with( strtolower( $intent->get_currency() ) );
-
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- $this->set_get_upe_enabled_payment_method_statuses_return_value();
-
- $this->mock_upe_gateway->create_payment_intent( [ 'card' ], $order_id );
- }
-
- public function test_create_payment_intent_with_automatic_capture() {
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::REQUIRES_PAYMENT_METHOD ] );
- $this->mock_upe_gateway->settings['manual_capture'] = 'no';
- $request = $this->mock_wcpay_request( Create_Intention::class );
- $request->expects( $this->once() )
- ->method( 'set_amount' )
- ->with( $intent->get_amount() );
-
- $request->expects( $this->once() )
- ->method( 'set_currency_code' )
- ->with( strtolower( $intent->get_currency() ) );
-
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- $this->set_get_upe_enabled_payment_method_statuses_return_value();
-
- $this->mock_upe_gateway->create_payment_intent( [ 'card' ], $order_id );
- }
-
- public function test_create_payment_intent_with_manual_capture() {
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::REQUIRES_PAYMENT_METHOD ] );
- $this->mock_upe_gateway->settings['manual_capture'] = 'yes';
- $request = $this->mock_wcpay_request( Create_Intention::class );
-
- $request->expects( $this->once() )
- ->method( 'set_amount' )
- ->with( $intent->get_amount() );
-
- $request->expects( $this->once() )
- ->method( 'set_currency_code' )
- ->with( strtolower( $intent->get_currency() ) );
-
- $request->expects( $this->once() )
- ->method( 'set_capture_method' )
- ->with( true );
-
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- $this->set_get_upe_enabled_payment_method_statuses_return_value();
-
- $this->mock_upe_gateway->create_payment_intent( [ 'card' ], $order_id );
- }
-
- public function test_create_payment_intent_with_fingerprint() {
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $fingerprint = 'abc123';
- $intent = WC_Helper_Intention::create_intention();
-
- $request = $this->mock_wcpay_request( Create_Intention::class, 1 );
- $request
- ->expects( $this->once() )
- ->method( 'set_amount' )
- ->with( 5000 );
- $request
- ->expects( $this->once() )
- ->method( 'set_currency_code' )
- ->with( 'usd' );
- $request
- ->expects( $this->once() )
- ->method( 'set_payment_method_types' )
- ->with( [ 'card' ] );
-
- $request->expects( $this->once() )
- ->method( 'set_metadata' )
- ->with( [ 'order_number' => $order->get_order_number() ] );
- $request
- ->expects( $this->once() )
- ->method( 'set_fingerprint' )
- ->with( $fingerprint );
- $request
- ->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
- $this->set_get_upe_enabled_payment_method_statuses_return_value();
-
- $this->mock_upe_gateway->create_payment_intent( [ 'card' ], $order_id, $fingerprint );
- }
-
- public function test_create_payment_intent_with_no_fingerprint() {
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $intent = WC_Helper_Intention::create_intention();
- $request = $this->mock_wcpay_request( Create_Intention::class );
- $request->expects( $this->once() )
- ->method( 'set_amount' )
- ->with( $intent->get_amount() );
-
- $request->expects( $this->once() )
- ->method( 'set_fingerprint' )
- ->with( '' );
-
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
- $this->set_get_upe_enabled_payment_method_statuses_return_value();
-
- $this->mock_upe_gateway->create_payment_intent( [ 'card' ], $order_id );
- }
-
- public function test_create_setup_intent_existing_customer() {
- $_POST = [ 'wcpay-payment-method' => 'pm_mock' ];
-
- $this->mock_customer_service
- ->expects( $this->once() )
- ->method( 'get_customer_id_by_user_id' )
- ->will( $this->returnValue( 'cus_mock' ) );
-
- $this->mock_customer_service
- ->expects( $this->never() )
- ->method( 'create_customer_for_user' );
-
- $request = $this->mock_wcpay_request( Create_Setup_Intention::class );
- $request->expects( $this->once() )
- ->method( 'set_customer' )
- ->with( 'cus_mock' );
-
- $request->expects( $this->once() )
- ->method( 'set_payment_method_types' );
-
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn(
- WC_Helper_Intention::create_setup_intention(
- [
- 'id' => 'seti_mock',
- 'client_secret' => 'client_secret_mock',
- ]
- )
- );
-
- $this->set_cart_contains_subscription_items( false );
-
- $result = $this->mock_upe_gateway->create_setup_intent( [ 'card' ] );
-
- $this->assertEquals( 'seti_mock', $result['id'] );
- $this->assertEquals( 'client_secret_mock', $result['client_secret'] );
- }
-
- public function test_create_setup_intent_no_customer() {
- $_POST = [ 'wcpay-payment-method' => 'pm_mock' ];
-
- $this->mock_customer_service
- ->expects( $this->once() )
- ->method( 'get_customer_id_by_user_id' )
- ->will( $this->returnValue( null ) );
-
- $this->mock_customer_service
- ->expects( $this->once() )
- ->method( 'create_customer_for_user' )
- ->will( $this->returnValue( 'cus_12346' ) );
-
- $request = $this->mock_wcpay_request( Create_Setup_Intention::class );
- $request->expects( $this->once() )
- ->method( 'set_customer' )
- ->with( 'cus_12346' );
-
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn(
- WC_Helper_Intention::create_setup_intention(
- [
- 'id' => 'seti_mock',
- 'client_secret' => 'client_secret_mock',
- ]
- )
- );
-
- $this->set_cart_contains_subscription_items( false );
-
- $result = $this->mock_upe_gateway->create_setup_intent( [ 'card' ] );
-
- $this->assertEquals( 'seti_mock', $result['id'] );
- $this->assertEquals( 'client_secret_mock', $result['client_secret'] );
- }
-
public function test_process_payment_returns_correct_redirect_url() {
$order = WC_Helper_Order::create_order();
$_POST['wc_payment_intent_id'] = 'pi_mock';
@@ -790,33 +382,6 @@ public function test_process_payment_returns_correct_redirect_url() {
$this->assertMatchesRegularExpression( '/save_payment_method=no/', $result['redirect_url'] );
}
- public function test_process_payment_passes_save_payment_method_to_store() {
- $order = WC_Helper_Order::create_order();
- $gateway_id = UPE_Payment_Gateway::GATEWAY_ID;
- $save_payment_param = "wc-$gateway_id-new-payment-method";
- $_POST[ $save_payment_param ] = 'yes';
- $_POST['wc_payment_intent_id'] = 'pi_mock';
-
- $payment_intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::PROCESSING ] );
-
- $request = $this->mock_wcpay_request( Update_Intention::class, 1, 'pi_mock' );
-
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $payment_intent );
-
- $this->set_cart_contains_subscription_items( false );
-
- $result = $this->mock_upe_gateway->process_payment( $order->get_id() );
-
- unset( $_POST[ $save_payment_param ] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
- unset( $_POST['wc_payment_intent_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
-
- $this->assertEquals( 'success', $result['result'] );
- $this->assertMatchesRegularExpression( '/wc_payment_method=woocommerce_payments/', $result['redirect_url'] );
- $this->assertMatchesRegularExpression( '/save_payment_method=yes/', $result['redirect_url'] );
- }
-
public function test_process_subscription_payment_passes_save_payment_method() {
$order = WC_Helper_Order::create_order();
$order_id = $order->get_id();
@@ -1127,138 +692,6 @@ public function test_validate_order_id_received_vs_intent_meta_order_id_returnin
$this->assertSame( null, $res );
}
- public function test_process_redirect_setup_intent_succeded() {
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $save_payment_method = true;
- $user = wp_get_current_user();
- $intent_status = Intent_Status::SUCCEEDED;
- $client_secret = 'cs_mock';
- $customer_id = 'cus_mock';
- $intent_id = 'si_mock';
- $payment_method_id = 'pm_mock';
- $token = WC_Helper_Token::create_token( $payment_method_id );
-
- // Supply the order with the intent id so that it can be retrieved during the redirect payment processing.
- $order->update_meta_data( '_intent_id', $intent_id );
- $order->save();
-
- $order->set_shipping_total( 0 );
- $order->set_shipping_tax( 0 );
- $order->set_cart_tax( 0 );
- $order->set_total( 0 );
- $order->save();
-
- $setup_intent = WC_Helper_Intention::create_setup_intention(
- [
- 'id' => $intent_id,
- 'client_secret' => $client_secret,
- 'status' => $intent_status,
- 'payment_method' => $payment_method_id,
- 'payment_method_options' => [
- 'card' => [
- 'request_three_d_secure' => 'automatic',
- ],
- ],
- 'last_setup_error' => [],
- ]
- );
-
- $this->mock_upe_gateway->expects( $this->once() )
- ->method( 'manage_customer_details_for_order' )
- ->will(
- $this->returnValue( [ $user, $customer_id ] )
- );
-
- $request = $this->mock_wcpay_request( Get_Setup_Intention::class, 1, $intent_id );
-
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $setup_intent );
-
- $this->mock_token_service->expects( $this->once() )
- ->method( 'add_payment_method_to_user' )
- ->will(
- $this->returnValue( $token )
- );
-
- $this->set_cart_contains_subscription_items( true );
-
- $this->mock_upe_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method );
-
- $result_order = wc_get_order( $order_id );
-
- $this->assertEquals( $intent_id, $result_order->get_meta( '_intent_id', true ) );
- $this->assertEquals( $intent_status, $result_order->get_meta( '_intention_status', true ) );
- $this->assertEquals( $payment_method_id, $result_order->get_meta( '_payment_method_id', true ) );
- $this->assertEquals( $customer_id, $result_order->get_meta( '_stripe_customer_id', true ) );
- $this->assertEquals( Order_Status::PROCESSING, $result_order->get_status() );
- $this->assertEquals( 1, count( $result_order->get_payment_tokens() ) );
- }
-
- public function test_process_redirect_payment_save_payment_token() {
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $save_payment_method = true;
- $user = wp_get_current_user();
- $intent_status = Intent_Status::PROCESSING;
- $intent_metadata = [ 'order_id' => (string) $order_id ];
- $charge_id = 'ch_mock';
- $customer_id = 'cus_mock';
- $intent_id = 'pi_mock';
- $payment_method_id = 'pm_mock';
- $token = WC_Helper_Token::create_token( $payment_method_id );
-
- // Supply the order with the intent id so that it can be retrieved during the redirect payment processing.
- $order->update_meta_data( '_intent_id', $intent_id );
- $order->save();
-
- $payment_intent = WC_Helper_Intention::create_intention(
- [
- 'status' => $intent_status,
- 'metadata' => $intent_metadata,
- ]
- );
-
- $this->mock_upe_gateway->expects( $this->once() )
- ->method( 'manage_customer_details_for_order' )
- ->will(
- $this->returnValue( [ $user, $customer_id ] )
- );
-
- $request = $this->mock_wcpay_request( Get_Intention::class, 1, $intent_id );
-
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->will( $this->returnValue( $payment_intent ) );
-
- $this->mock_token_service->expects( $this->once() )
- ->method( 'add_payment_method_to_user' )
- ->will(
- $this->returnValue( $token )
- );
-
- $this->set_cart_contains_subscription_items( false );
-
- $this->mock_upe_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method );
-
- $result_order = wc_get_order( $order_id );
- $note = wc_get_order_notes(
- [
- 'order_id' => $order_id,
- 'limit' => 1,
- ]
- )[0];
-
- $this->assertStringContainsString( 'authorized', $note->content );
- $this->assertEquals( $intent_id, $result_order->get_meta( '_intent_id', true ) );
- $this->assertEquals( $charge_id, $result_order->get_meta( '_charge_id', true ) );
- $this->assertEquals( $intent_status, $result_order->get_meta( '_intention_status', true ) );
- $this->assertEquals( $payment_method_id, $result_order->get_meta( '_payment_method_id', true ) );
- $this->assertEquals( $customer_id, $result_order->get_meta( '_stripe_customer_id', true ) );
- $this->assertEquals( Order_Status::ON_HOLD, $result_order->get_status() );
- $this->assertEquals( 1, count( $result_order->get_payment_tokens() ) );
- }
public function test_correct_payment_method_title_for_order() {
$order = WC_Helper_Order::create_order();
@@ -1639,74 +1072,6 @@ public function test_create_token_from_setup_intent_adds_token() {
$this->assertEquals( $mock_token, $this->mock_upe_gateway->create_token_from_setup_intent( $mock_setup_intent_id, $mock_user ) );
}
-
-
-
- public function test_create_payment_intent_uses_cached_minimum_amount() {
- $order = WC_Helper_Order::create_order();
- $order->set_total( 0.45 );
- $order->save();
-
- set_transient( 'wcpay_minimum_amount_usd', '50', DAY_IN_SECONDS );
-
- $intent = WC_Helper_Intention::create_intention(
- [
- 'status' => Intent_Status::REQUIRES_PAYMENT_METHOD,
- 'amount' => 50,
- ]
- );
-
- $request = $this->mock_wcpay_request( Create_Intention::class );
- $request->expects( $this->once() )
- ->method( 'set_amount' )
- ->with( $intent->get_amount() );
-
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- $this->set_get_upe_enabled_payment_method_statuses_return_value();
-
- $this->mock_upe_gateway->create_payment_intent( [ 'card' ], $order->get_id() );
- }
-
- public function test_create_payment_intent_creates_new_intent_with_minimum_amount() {
- $order = WC_Helper_Order::create_order();
- $order->set_currency( 'USD' );
- $order->set_total( 0.45 );
- $order->save();
-
- $intent = WC_Helper_Intention::create_intention(
- [
- 'status' => Intent_Status::REQUIRES_PAYMENT_METHOD,
- 'amount' => 50,
- ]
- );
-
- $request = $this->mock_wcpay_request( Create_Intention::class, 2 );
-
- $request->expects( $this->exactly( 2 ) )
- ->method( 'set_amount' )
- ->withConsecutive( [ 45 ], [ $intent->get_amount() ] );
-
- $request->expects( $this->once() )
- ->method( 'set_currency_code' )
- ->with( strtolower( $intent->get_currency() ) );
-
- $request->expects( $this->exactly( 2 ) )
- ->method( 'format_response' )
- ->will(
- $this->onConsecutiveCalls(
- $this->throwException( new Amount_Too_Small_Exception( 'Error: Amount must be at least $0.50 usd', 50, 'usd', 400 ) ),
- $this->returnValue( $intent )
- )
- );
- $this->set_get_upe_enabled_payment_method_statuses_return_value();
-
- $result = $this->mock_upe_gateway->create_payment_intent( [ 'card' ], $order->get_id() );
- $this->assertsame( 'cs_mock', $result['client_secret'] );
- }
-
public function test_process_payment_rejects_with_cached_minimum_acount() {
$order = WC_Helper_Order::create_order();
$order->set_currency( 'USD' );
@@ -1752,10 +1117,6 @@ public function test_process_payment_caches_mimimum_amount_and_displays_error_up
->method( 'set_amount' )
->with( (int) ( $amount * 100 ) );
- $request->expects( $this->once() )
- ->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'legacy_upe' ] );
-
$request->expects( $this->once() )
->method( 'set_level3' )
->with(
@@ -1812,6 +1173,7 @@ public function test_get_upe_available_payment_methods( $payment_methods, $expec
$this->mock_customer_service,
$this->mock_token_service,
$this->mock_action_scheduler_service,
+ $this->mock_payment_method,
$this->mock_payment_methods,
$this->mock_rate_limiter,
$this->mock_order_service,
diff --git a/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php b/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php
index 40cc78eda7d..54ffd9669f0 100644
--- a/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php
+++ b/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php
@@ -1,6 +1,6 @@
'pm_mock',
- 'payment_method' => UPE_Split_Payment_Gateway::GATEWAY_ID,
+ 'payment_method' => UPE_Payment_Gateway::GATEWAY_ID,
];
$get_payment_gateway_by_id_return_value_map = [];
@@ -268,7 +268,7 @@ public function set_up() {
->getMock();
$this->mock_payment_methods[ $mock_payment_method->get_id() ] = $mock_payment_method;
- $mock_gateway = $this->getMockBuilder( UPE_Split_Payment_Gateway::class )
+ $mock_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class )
->setConstructorArgs(
[
$this->mock_api_client,
@@ -412,324 +412,6 @@ public function test_non_reusable_payment_method_is_not_available_when_subscript
$this->assertFalse( $payment_gateway->is_available() );
}
- public function test_update_payment_intent_adds_customer_save_payment_and_level3_data() {
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $order_number = $order->get_order_number();
- $user = '';
- $customer_id = 'cus_mock';
- $save_payment_method = true;
- $intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::REQUIRES_PAYMENT_METHOD ] );
-
- $this->set_cart_contains_subscription_items( false );
-
- $this->mock_customer_service
- ->expects( $this->never() )
- ->method( 'create_customer_for_user' );
-
- // Test update_payment_intent on each payment gateway.
- foreach ( $this->mock_payment_gateways as $mock_payment_gateway ) {
- $request = $this->mock_wcpay_request( Update_Intention::class, 1, $intent->get_id() );
- $request->expects( $this->once() )->method( 'set_amount' )->with( 5000 );
- $request->expects( $this->once() )->method( 'set_currency_code' )->with( 'usd' );
- $request->expects( $this->once() )->method( 'setup_future_usage' );
- $request->expects( $this->once() )->method( 'set_customer' )->with( 'cus_mock' );
- $request->expects( $this->once() )->method( 'set_metadata' )->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- $mock_payment_gateway
- ->method( 'manage_customer_details_for_order' )
- ->will(
- $this->returnValue( [ $user, $customer_id ] )
- );
- $result = $mock_payment_gateway->update_payment_intent( $intent->get_id(), $order_id, $save_payment_method );
- $this->assertSame( [ 'success' => true ], $result );
- }
- }
-
- public function test_update_payment_intent_with_selected_upe_payment_method() {
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $order_number = $order->get_order_number();
- $product_item = current( $order->get_items( 'line_item' ) );
- $user = '';
- $customer_id = 'cus_mock';
- $save_payment_method = true;
- $intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::REQUIRES_PAYMENT_METHOD ] );
-
- $this->set_cart_contains_subscription_items( false );
-
- $this->mock_customer_service
- ->expects( $this->never() )
- ->method( 'create_customer_for_user' );
-
- /**
- * In order to test each gateway, we need to setup mock_api_client so that
- * its input are mocked in sequence, matching the gateways.
- */
- foreach ( $this->mock_payment_gateways as $payment_method_id => $mock_payment_gateway ) {
- $request = $this->mock_wcpay_request( Update_Intention::class, 1, $intent->get_id() );
- $request->expects( $this->once() )->method( 'set_amount' )->with( 5000 );
- $request->expects( $this->once() )->method( 'set_currency_code' )->with( 'usd' );
- $request->expects( $this->once() )->method( 'setup_future_usage' );
- $request->expects( $this->once() )->method( 'set_customer' )->with( 'cus_mock' );
- $request->expects( $this->once() )->method( 'set_metadata' )->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
- $request->expects( $this->once() )->method( 'set_payment_method_types' )->with( [ $payment_method_id ] );
-
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- // Test update_payment_intent on each payment gateway.
- $mock_payment_gateway
- ->method( 'manage_customer_details_for_order' )
- ->will(
- $this->returnValue( [ $user, $customer_id ] )
- );
- $result = $mock_payment_gateway->update_payment_intent( $intent->get_id(), $order_id, $save_payment_method, $payment_method_id );
- $this->assertSame( [ 'success' => true ], $result );
- }
- }
-
- public function test_update_payment_intent_with_payment_country() {
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $order_number = $order->get_order_number();
- $product_item = current( $order->get_items( 'line_item' ) );
- $intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::REQUIRES_PAYMENT_METHOD ] );
-
- $this->set_cart_contains_subscription_items( false );
-
- $this->mock_customer_service
- ->expects( $this->never() )
- ->method( 'create_customer_for_user' );
-
- // Test update_payment_intent on each payment gateway.
- foreach ( $this->mock_payment_gateways as $mock_payment_gateway ) {
- $request = $this->mock_wcpay_request( Update_Intention::class, 1, $intent->get_id() );
- $request->expects( $this->once() )->method( 'set_amount' )->with( 5000 );
- $request->expects( $this->once() )->method( 'set_currency_code' )->with( 'usd' );
- $request->expects( $this->once() )->method( 'set_customer' )->with( 'cus_mock' );
- $request->expects( $this->once() )->method( 'set_metadata' )->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
- $request->expects( $this->once() )->method( 'set_payment_country' )->with( 'US' );
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- $mock_payment_gateway
- ->method( 'manage_customer_details_for_order' )
- ->will(
- $this->returnValue( [ '', 'cus_mock' ] )
- );
- $result = $mock_payment_gateway->update_payment_intent( $intent->get_id(), $order_id, false, null, 'US' );
- $this->assertSame( [ 'success' => true ], $result );
- }
- }
-
- public function test_create_payment_intent_uses_order_amount_if_order() {
- $mock_payment_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ];
-
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::REQUIRES_PAYMENT_METHOD ] );
-
- $request = $this->mock_wcpay_request( Create_Intention::class );
- $request->expects( $this->once() )
- ->method( 'set_amount' )
- ->with( 5000 );
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- $this->set_cart_contains_subscription_items( false );
-
- $mock_payment_gateway->method( 'get_payment_method_ids_enabled_at_checkout' )
- ->willReturn( [ Payment_Method::CARD ] );
-
- $this->set_get_upe_enabled_payment_method_statuses_return_value( $mock_payment_gateway );
- $mock_payment_gateway->create_payment_intent( [ 'card' ], $order_id );
- }
-
- public function test_create_payment_intent_defaults_to_automatic_capture() {
- $mock_payment_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ];
-
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::REQUIRES_PAYMENT_METHOD ] );
-
- $request = $this->mock_wcpay_request( Create_Intention::class );
- $request->expects( $this->once() )->method( 'set_capture_method' )->with( false );
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- $mock_payment_gateway->method( 'get_payment_method_ids_enabled_at_checkout' )
- ->willReturn( [ Payment_Method::CARD ] );
-
- $this->set_get_upe_enabled_payment_method_statuses_return_value( $mock_payment_gateway );
-
- $mock_payment_gateway->create_payment_intent( [ 'card' ], $order_id );
- }
-
- public function test_create_payment_intent_with_automatic_capture() {
- $mock_payment_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ];
-
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::REQUIRES_PAYMENT_METHOD ] );
- $mock_payment_gateway->settings['manual_capture'] = 'no';
- $request = $this->mock_wcpay_request( Create_Intention::class );
- $request->expects( $this->once() )->method( 'set_capture_method' )->with( false );
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- $mock_payment_gateway->method( 'get_payment_method_ids_enabled_at_checkout' )
- ->willReturn( [ Payment_Method::CARD ] );
-
- $this->set_get_upe_enabled_payment_method_statuses_return_value( $mock_payment_gateway );
-
- $mock_payment_gateway->create_payment_intent( [ 'card' ], $order_id );
- }
-
- public function test_create_payment_intent_with_manual_capture() {
- $mock_payment_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ];
-
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::REQUIRES_PAYMENT_METHOD ] );
- $mock_payment_gateway->settings['manual_capture'] = 'yes';
-
- $request = $this->mock_wcpay_request( Create_Intention::class );
- $request->expects( $this->once() )->method( 'set_capture_method' )->with( true );
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- $mock_payment_gateway->method( 'get_payment_method_ids_enabled_at_checkout' )
- ->willReturn( [ Payment_Method::CARD ] );
-
- $this->set_get_upe_enabled_payment_method_statuses_return_value( $mock_payment_gateway );
-
- $mock_payment_gateway->create_payment_intent( [ 'card' ], $order_id );
- }
-
- public function test_create_payment_intent_with_fingerprint() {
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $fingerprint = 'abc123';
- $intent = WC_Helper_Intention::create_intention();
- $mock_card_payment_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ];
-
- $request = $this->mock_wcpay_request( Create_Intention::class );
- $request->expects( $this->once() )->method( 'set_fingerprint' )->with( $fingerprint );
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- $mock_card_payment_gateway->method( 'get_payment_method_ids_enabled_at_checkout' )
- ->willReturn( [ Payment_Method::CARD ] );
- $this->set_get_upe_enabled_payment_method_statuses_return_value( $mock_card_payment_gateway );
-
- $mock_card_payment_gateway->create_payment_intent( [ 'card' ], $order_id, $fingerprint );
- }
-
- public function test_create_payment_intent_with_no_fingerprint() {
- $mock_card_payment_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ];
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $intent = WC_Helper_Intention::create_intention();
-
- $request = $this->mock_wcpay_request( Create_Intention::class );
- $request->expects( $this->once() )->method( 'set_fingerprint' )->with( '' );
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- $mock_card_payment_gateway->method( 'get_payment_method_ids_enabled_at_checkout' )
- ->willReturn( [ Payment_Method::CARD ] );
- $this->set_get_upe_enabled_payment_method_statuses_return_value( $mock_card_payment_gateway );
-
- $mock_card_payment_gateway->create_payment_intent( [ 'card' ], $order_id );
- }
-
- public function test_create_setup_intent_existing_customer() {
- $mock_payment_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ];
-
- $_POST = [ 'wcpay-payment-method' => 'pm_mock' ];
-
- $this->mock_customer_service
- ->expects( $this->once() )
- ->method( 'get_customer_id_by_user_id' )
- ->will( $this->returnValue( 'cus_mock' ) );
-
- $this->mock_customer_service
- ->expects( $this->never() )
- ->method( 'create_customer_for_user' );
-
- $request = $this->mock_wcpay_request( Create_Setup_Intention::class );
- $request->expects( $this->once() )
- ->method( 'set_customer' )
- ->with( 'cus_mock' );
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn(
- WC_Helper_Intention::create_setup_intention(
- [
- 'id' => 'seti_mock',
- 'client_secret' => 'client_secret_mock',
- ]
- )
- );
-
- $this->set_cart_contains_subscription_items( false );
-
- $result = $mock_payment_gateway->create_setup_intent( [ 'card' ] );
-
- $this->assertEquals( 'seti_mock', $result['id'] );
- $this->assertEquals( 'client_secret_mock', $result['client_secret'] );
- }
-
- public function test_create_setup_intent_no_customer() {
- $mock_payment_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ];
-
- $_POST = [ 'wcpay-payment-method' => 'pm_mock' ];
-
- $this->mock_customer_service
- ->expects( $this->once() )
- ->method( 'get_customer_id_by_user_id' )
- ->will( $this->returnValue( null ) );
-
- $this->mock_customer_service
- ->expects( $this->once() )
- ->method( 'create_customer_for_user' )
- ->will( $this->returnValue( 'cus_12346' ) );
-
- $request = $this->mock_wcpay_request( Create_Setup_Intention::class );
- $request->expects( $this->once() )
- ->method( 'set_customer' )
- ->with( 'cus_12346' );
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn(
- WC_Helper_Intention::create_setup_intention(
- [
- 'id' => 'seti_mock',
- 'client_secret' => 'client_secret_mock',
- ]
- )
- );
-
- $this->set_cart_contains_subscription_items( false );
-
- $result = $mock_payment_gateway->create_setup_intent( [ 'card' ] );
-
- $this->assertEquals( 'seti_mock', $result['id'] );
- $this->assertEquals( 'client_secret_mock', $result['client_secret'] );
- }
-
public function test_process_payment_returns_correct_redirect_url() {
$order = WC_Helper_Order::create_order();
$order_id = $order->get_id();
@@ -759,7 +441,7 @@ public function test_process_payment_passes_save_payment_method_to_store() {
$mock_sepa_payment_gateway = $this->mock_payment_gateways[ Payment_Method::SEPA ];
$order = WC_Helper_Order::create_order();
- $gateway_id = UPE_Split_Payment_Gateway::GATEWAY_ID . '_' . Payment_Method::SEPA;
+ $gateway_id = UPE_Payment_Gateway::GATEWAY_ID . '_' . Payment_Method::SEPA;
$save_payment_param = "wc-$gateway_id-new-payment-method";
$_POST[ $save_payment_param ] = 'yes';
$_POST['wc_payment_intent_id'] = 'pi_mock';
@@ -1581,71 +1263,6 @@ public function test_create_token_from_setup_intent_adds_token() {
}
}
- public function test_create_payment_intent_uses_cached_minimum_amount() {
- $mock_payment_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ];
-
- $order = WC_Helper_Order::create_order();
- $order->set_total( 0.45 );
- $order->save();
-
- set_transient( 'wcpay_minimum_amount_usd', '50', DAY_IN_SECONDS );
-
- $intent = WC_Helper_Intention::create_intention(
- [
- 'status' => Intent_Status::REQUIRES_PAYMENT_METHOD,
- 'amount' => 50,
- ]
- );
-
- $request = $this->mock_wcpay_request( Create_Intention::class );
- $request->expects( $this->once() )->method( 'set_amount' )->with( 50 );
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- $mock_payment_gateway->method( 'get_payment_method_ids_enabled_at_checkout' )
- ->willReturn( [ Payment_Method::CARD ] );
-
- $this->set_get_upe_enabled_payment_method_statuses_return_value( $mock_payment_gateway );
-
- $mock_payment_gateway->create_payment_intent( [ 'card' ], $order->get_id() );
- }
-
- public function test_create_payment_intent_creates_new_intent_with_minimum_amount() {
- $mock_payment_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ];
-
- $order = WC_Helper_Order::create_order();
- $order->set_currency( 'USD' );
- $order->set_total( 0.45 );
- $order->save();
-
- $intent = WC_Helper_Intention::create_intention(
- [
- 'status' => Intent_Status::REQUIRES_PAYMENT_METHOD,
- 'amount' => 50,
- ]
- );
-
- $request = $this->mock_wcpay_request( Create_Intention::class, 2 );
- $request->expects( $this->exactly( 2 ) )->method( 'set_amount' )->withConsecutive( [ 45 ], [ 50 ] );
- $request->expects( $this->exactly( 2 ) )
- ->method( 'format_response' )
- ->will(
- $this->onConsecutiveCalls(
- $this->throwException( new Amount_Too_Small_Exception( 'Error: Amount must be at least $0.50 usd', 50, 'usd', 400 ) ),
- $this->returnValue( $intent )
- )
- );
-
- $mock_payment_gateway->method( 'get_payment_method_ids_enabled_at_checkout' )
- ->willReturn( [ Payment_Method::CARD ] );
-
- $this->set_get_upe_enabled_payment_method_statuses_return_value( $mock_payment_gateway );
-
- $result = $mock_payment_gateway->create_payment_intent( [ 'card' ], $order->get_id() );
- $this->assertsame( 'cs_mock', $result['client_secret'] );
- }
-
public function test_process_payment_rejects_with_cached_minimum_acount() {
$order = WC_Helper_Order::create_order();
@@ -1697,63 +1314,13 @@ public function test_process_payment_caches_mimimum_amount_and_displays_error_up
}
}
- public function test_remove_upe_setup_intent_from_session() {
- // Two payment methods (SEPA and giropay) are enabled.
- $sepa_setup_intent_key = UPE_Split_Payment_Gateway::KEY_UPE_SETUP_INTENT . '_sepa_debit';
- $giropay_setup_intent_key = UPE_Split_Payment_Gateway::KEY_UPE_SETUP_INTENT . '_giropay';
-
- $mock_upe_gateway = $this->getMockBuilder( UPE_Split_Payment_Gateway::class )
- ->setConstructorArgs(
- [
- $this->mock_api_client,
- $this->mock_wcpay_account,
- $this->mock_customer_service,
- $this->mock_token_service,
- $this->mock_action_scheduler_service,
- $this->mock_payment_methods['card'],
- $this->mock_payment_methods,
- $this->mock_rate_limiter,
- $this->order_service,
- $this->mock_dpps,
- $this->mock_localization_service,
- $this->mock_fraud_service,
- ]
- )
- ->setMethods( [ 'wc_payments_get_payment_method_map' ] )
- ->getMock();
-
- $mock_upe_gateway
- ->expects( $this->once() )
- ->method( 'wc_payments_get_payment_method_map' )
- ->will(
- $this->returnValue(
- [
- 'sepa_debit' => $this->mock_payment_methods[ Payment_Method::SEPA ],
- 'giropay' => $this->mock_payment_methods[ Payment_Method::GIROPAY ],
- ]
- )
- );
-
- // and both SEPA and giropay have a setup intent stored in WC session object.
- WC()->session->set( $sepa_setup_intent_key, 'pi_test_setup_intent_sepa_debit' );
- WC()->session->set( $giropay_setup_intent_key, 'pi_test_setup_intent_giropay' );
-
- $this->assertNotNull( WC()->session->get( $sepa_setup_intent_key ) );
- $this->assertNotNull( WC()->session->get( $giropay_setup_intent_key ) );
-
- $mock_upe_gateway->remove_upe_setup_intent_from_session();
-
- $this->assertNull( WC()->session->get( $sepa_setup_intent_key ) );
- $this->assertNull( WC()->session->get( $giropay_setup_intent_key ) );
- }
-
/**
* Test get_payment_method_types with regular checkout post request context.
*
* @return void
*/
public function test_get_payment_methods_with_request_context() {
- $mock_upe_gateway = $this->getMockBuilder( UPE_Split_Payment_Gateway::class )
+ $mock_upe_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class )
->setConstructorArgs(
[
$this->mock_api_client,
@@ -1798,7 +1365,7 @@ public function test_get_payment_methods_with_request_context() {
* @return void
*/
public function test_get_payment_methods_without_request_context() {
- $mock_upe_gateway = $this->getMockBuilder( UPE_Split_Payment_Gateway::class )
+ $mock_upe_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class )
->setConstructorArgs(
[
$this->mock_api_client,
@@ -1842,7 +1409,7 @@ public function test_get_payment_methods_without_request_context() {
* @return void
*/
public function test_get_payment_methods_without_request_context_or_token() {
- $mock_upe_gateway = $this->getMockBuilder( UPE_Split_Payment_Gateway::class )
+ $mock_upe_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class )
->setConstructorArgs(
[
$this->mock_api_client,
@@ -1895,7 +1462,7 @@ public function test_get_payment_methods_without_request_context_or_token() {
*/
public function test_get_payment_methods_from_gateway_id_upe() {
WC_Helper_Order::create_order();
- $mock_upe_gateway = $this->getMockBuilder( UPE_Split_Payment_Gateway::class )
+ $mock_upe_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class )
->setConstructorArgs(
[
$this->mock_api_client,
@@ -1929,7 +1496,7 @@ public function test_get_payment_methods_from_gateway_id_upe() {
$this->returnValue( [ Payment_Method::CARD, Payment_Method::LINK ] )
);
- $payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( UPE_Split_Payment_Gateway::GATEWAY_ID . '_' . Payment_Method::BANCONTACT );
+ $payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( UPE_Payment_Gateway::GATEWAY_ID . '_' . Payment_Method::BANCONTACT );
$this->assertSame( [ Payment_Method::BANCONTACT ], $payment_methods );
$mock_upe_gateway->expects( $this->any() )
@@ -1941,10 +1508,10 @@ public function test_get_payment_methods_from_gateway_id_upe() {
)
);
- $payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( UPE_Split_Payment_Gateway::GATEWAY_ID );
+ $payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( UPE_Payment_Gateway::GATEWAY_ID );
$this->assertSame( [ Payment_Method::CARD, Payment_Method::LINK ], $payment_methods );
- $payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( UPE_Split_Payment_Gateway::GATEWAY_ID );
+ $payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( UPE_Payment_Gateway::GATEWAY_ID );
$this->assertSame( [ Payment_Method::CARD ], $payment_methods );
WC_Payments::set_gateway( $gateway );
diff --git a/tests/unit/src/Internal/Payment/State/ProcessedStateTest.php b/tests/unit/src/Internal/Payment/State/ProcessedStateTest.php
index b7f2febece9..94273521a05 100644
--- a/tests/unit/src/Internal/Payment/State/ProcessedStateTest.php
+++ b/tests/unit/src/Internal/Payment/State/ProcessedStateTest.php
@@ -17,7 +17,6 @@
use WCPay\Internal\Service\OrderService;
use WCPay\Internal\Proxy\LegacyProxy;
use WCPay\Payment_Methods\UPE_Payment_Gateway;
-use WCPay\Payment_Methods\UPE_Split_Payment_Gateway;
use WCPAY_UnitTestCase;
/**
@@ -167,12 +166,6 @@ function ( $arg ) use ( $mock_cart ) {
$mock_cart->expects( $this->once() )
->method( 'empty_cart' );
- // Test methods to remove upe payment intent are called.
- $this->mock_legacy_proxy
- ->expects( $this->exactly( 2 ) )
- ->method( 'call_static' )
- ->withConsecutive( [ UPE_Payment_Gateway::class, 'remove_upe_payment_intent_from_session' ], [ UPE_Split_Payment_Gateway::class, 'remove_upe_payment_intent_from_session' ] );
-
$this->sut->complete_processing();
}
diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions.php b/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions.php
index 60d00031f8c..9c27fda1b2d 100644
--- a/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions.php
+++ b/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions.php
@@ -318,10 +318,6 @@ public function test_scheduled_subscription_payment() {
->method( 'set_capture_method' )
->with( false );
- $request->expects( $this->once() )
- ->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'legacy_card' ] );
-
$request->expects( $this->once() )
->method( 'format_response' )
->willReturn( WC_Helper_Intention::create_intention() );
@@ -479,9 +475,6 @@ public function test_scheduled_subscription_payment_adds_mandate() {
->method( 'set_capture_method' )
->with( false );
- $request->expects( $this->once() )
- ->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'legacy_card' ] );
$request->expects( $this->once() )
->method( 'format_response' )
->willReturn( WC_Helper_Intention::create_intention() );
diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay.php b/tests/unit/test-class-wc-payment-gateway-wcpay.php
index 8efcc4ccb0e..3eb69d5cfb5 100644
--- a/tests/unit/test-class-wc-payment-gateway-wcpay.php
+++ b/tests/unit/test-class-wc-payment-gateway-wcpay.php
@@ -30,7 +30,7 @@
use WCPay\Payment_Information;
use WCPay\Payment_Methods\CC_Payment_Method;
use WCPay\Payment_Methods\Sepa_Payment_Method;
-use WCPay\Payment_Methods\UPE_Split_Payment_Gateway;
+use WCPay\Payment_Methods\UPE_Payment_Gateway;
use WCPay\WooPay\WooPay_Utilities;
use WCPay\Session_Rate_Limiter;
@@ -48,7 +48,7 @@ class WC_Payment_Gateway_WCPay_Test extends WCPAY_UnitTestCase {
/**
* System under test.
*
- * @var UPE_Split_Payment_Gateway
+ * @var UPE_Payment_Gateway
*/
private $wcpay_gateway;
@@ -214,7 +214,7 @@ public function set_up() {
->setMethods( [ 'is_subscription_item_in_cart' ] )
->getMock();
- $this->wcpay_gateway = new UPE_Split_Payment_Gateway(
+ $this->wcpay_gateway = new UPE_Payment_Gateway(
$this->mock_api_client,
$this->mock_wcpay_account,
$this->mock_customer_service,
@@ -456,9 +456,6 @@ public function test_capture_charge_success() {
$capture_intent_request->expects( $this->once() )
->method( 'set_amount_to_capture' )
->with( $mock_intent->get_amount() );
- $capture_intent_request->expects( $this->once() )
- ->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
$capture_intent_request->expects( $this->once() )
->method( 'format_response' )
->willReturn( WC_Helper_Intention::create_intention() );
@@ -511,9 +508,6 @@ public function test_capture_charge_success_non_usd() {
$capture_intent_request->expects( $this->once() )
->method( 'set_amount_to_capture' )
->with( $mock_intent->get_amount() );
- $capture_intent_request->expects( $this->once() )
- ->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
$capture_intent_request->expects( $this->once() )
->method( 'format_response' )
->willReturn( WC_Helper_Intention::create_intention( [ 'currency' => 'eur' ] ) );
@@ -563,9 +557,6 @@ public function test_capture_charge_failure() {
$capture_intent_request->expects( $this->once() )
->method( 'set_amount_to_capture' )
->with( $mock_intent->get_amount() );
- $capture_intent_request->expects( $this->once() )
- ->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
$capture_intent_request->expects( $this->once() )
->method( 'format_response' )
->willReturn( $mock_intent );
@@ -618,9 +609,6 @@ public function test_capture_charge_failure_non_usd() {
$capture_intent_request->expects( $this->once() )
->method( 'set_amount_to_capture' )
->with( $mock_intent->get_amount() );
- $capture_intent_request->expects( $this->once() )
- ->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
$capture_intent_request->expects( $this->once() )
->method( 'format_response' )
->willReturn( $mock_intent );
@@ -675,9 +663,6 @@ public function test_capture_charge_api_failure() {
$capture_intent_request->expects( $this->once() )
->method( 'set_amount_to_capture' )
->with( $mock_intent->get_amount() );
- $capture_intent_request->expects( $this->once() )
- ->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
$capture_intent_request->expects( $this->once() )
->method( 'format_response' )
->will( $this->throwException( new API_Exception( 'test exception', 'server_error', 500 ) ) );
@@ -737,9 +722,6 @@ public function test_capture_charge_api_failure_non_usd() {
$capture_intent_request->expects( $this->once() )
->method( 'set_amount_to_capture' )
->with( $mock_intent->get_amount() );
- $capture_intent_request->expects( $this->once() )
- ->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
$capture_intent_request->expects( $this->once() )
->method( 'format_response' )
->will( $this->throwException( new API_Exception( 'test exception', 'server_error', 500 ) ) );
@@ -795,9 +777,6 @@ public function test_capture_charge_expired() {
$capture_intent_request->expects( $this->once() )
->method( 'set_amount_to_capture' )
->with( $mock_intent->get_amount() );
- $capture_intent_request->expects( $this->once() )
- ->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
$capture_intent_request->expects( $this->once() )
->method( 'format_response' )
->will( $this->throwException( new API_Exception( 'test exception', 'server_error', 500 ) ) );
@@ -853,9 +832,6 @@ public function test_capture_charge_metadata() {
$capture_intent_request->expects( $this->once() )
->method( 'set_amount_to_capture' )
->with( $mock_intent->get_amount() );
- $capture_intent_request->expects( $this->once() )
- ->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
$capture_intent_request->expects( $this->once() )
->method( 'format_response' )
->willReturn( WC_Helper_Intention::create_intention() );
@@ -902,9 +878,6 @@ public function test_capture_charge_without_level3() {
$capture_intent_request->expects( $this->once() )
->method( 'set_amount_to_capture' )
->with( $mock_intent->get_amount() );
- $capture_intent_request->expects( $this->once() )
- ->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
$capture_intent_request->expects( $this->once() )
->method( 'format_response' )
->willReturn( WC_Helper_Intention::create_intention() );
@@ -1801,10 +1774,6 @@ public function test_process_payment_caches_mimimum_amount_and_displays_error_up
->method( 'set_capture_method' )
->with( false );
- $request->expects( $this->once() )
- ->method( 'set_metadata' )
- ->with( [ 'gateway_type' => 'split_upe_with_deferred_intent_creation' ] );
-
$request->expects( $this->once() )
->method( 'format_response' )
->will( $this->throwException( new Amount_Too_Small_Exception( 'Error: Amount must be at least $60 usd', 6000, 'usd', 400 ) ) );
@@ -2037,7 +2006,7 @@ public function test_is_in_test_mode() {
* @return MockObject|WC_Payment_Gateway_WCPay
*/
private function get_partial_mock_for_gateway( array $methods = [] ) {
- return $this->getMockBuilder( UPE_Split_Payment_Gateway::class )
+ return $this->getMockBuilder( UPE_Payment_Gateway::class )
->setConstructorArgs(
[
$this->mock_api_client,
@@ -2394,7 +2363,7 @@ private function create_charge_object() {
}
private function create_gateway_with( $payment_method ) {
- return new UPE_Split_Payment_Gateway(
+ return new UPE_Payment_Gateway(
$this->mock_api_client,
$this->mock_wcpay_account,
$this->mock_customer_service,
diff --git a/tests/unit/test-class-wc-payments-checkout.php b/tests/unit/test-class-wc-payments-checkout.php
index 49906d2edea..b187c4f51ce 100644
--- a/tests/unit/test-class-wc-payments-checkout.php
+++ b/tests/unit/test-class-wc-payments-checkout.php
@@ -8,7 +8,7 @@
use WCPay\WC_Payments_Checkout;
use PHPUnit\Framework\MockObject\MockObject;
use WCPay\Constants\Payment_Method;
-use WCPay\Payment_Methods\UPE_Split_Payment_Gateway;
+use WCPay\Payment_Methods\UPE_Payment_Gateway;
use WCPay\WooPay\WooPay_Utilities;
use WCPay\Fraud_Prevention\Fraud_Prevention_Service;
use WCPay\Payment_Methods\Bancontact_Payment_Method;
@@ -36,9 +36,9 @@ class WC_Payments_Checkout_Test extends WP_UnitTestCase {
private $system_under_test;
/**
- * UPE_Split_Payment_Gateway instance.
+ * UPE_Payment_Gateway instance.
*
- * @var UPE_Split_Payment_Gateway|MockObject
+ * @var UPE_Payment_Gateway|MockObject
*/
private $mock_wcpay_gateway;
@@ -81,7 +81,7 @@ class WC_Payments_Checkout_Test extends WP_UnitTestCase {
/**
* Default gateway.
*
- * @var UPE_Split_Payment_Gateway
+ * @var UPE_Payment_Gateway
*/
private $default_gateway;
@@ -89,7 +89,7 @@ public function set_up() {
parent::set_up();
// Setup the gateway mock.
- $this->mock_wcpay_gateway = $this->getMockBuilder( UPE_Split_Payment_Gateway::class )
+ $this->mock_wcpay_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class )
->onlyMethods( [ 'get_account_domestic_currency', 'get_payment_method_ids_enabled_at_checkout', 'should_use_stripe_platform_on_checkout_page', 'should_support_saved_payments', 'is_saved_cards_enabled', 'save_payment_method_checkbox', 'get_account_statement_descriptor', 'get_icon_url', 'get_payment_method_ids_enabled_at_checkout_filtered_by_fees', 'is_subscription_item_in_cart', 'wc_payments_get_payment_method_by_id', 'display_gateway_html' ] )
->disableOriginalConstructor()
->getMock();
@@ -436,8 +436,6 @@ public function test_link_payment_method_provided_when_card_enabled() {
'icon' => $icon_url,
'showSaveOption' => true,
'countries' => [],
- 'upePaymentIntentData' => null,
- 'upeSetupIntentData' => null,
'testingInstructions' => '
Test mode: use the test VISA card 4242424242424242 with any expiry date and CVC. Other payment methods may redirect to a Stripe test page to authorize payment. More test card numbers are listed
here .',
'forceNetworkSavedCards' => false,
],
@@ -447,8 +445,6 @@ public function test_link_payment_method_provided_when_card_enabled() {
'icon' => $icon_url,
'showSaveOption' => true,
'countries' => [],
- 'upePaymentIntentData' => null,
- 'upeSetupIntentData' => null,
'testingInstructions' => '',
'forceNetworkSavedCards' => false,
],
diff --git a/tests/unit/test-class-wc-payments.php b/tests/unit/test-class-wc-payments.php
index 692a45b96df..ce6aa216a1d 100644
--- a/tests/unit/test-class-wc-payments.php
+++ b/tests/unit/test-class-wc-payments.php
@@ -5,7 +5,7 @@
* @package WooCommerce\Payments\Tests
*/
-use WCPay\Payment_Methods\UPE_Split_Payment_Gateway;
+use WCPay\Payment_Methods\UPE_Payment_Gateway;
use WCPay\WooPay\WooPay_Session;
/**
@@ -81,7 +81,7 @@ public function test_it_does_not_register_woopay_hooks_if_feature_flag_is_disabl
public function test_it_skips_stripe_link_gateway_registration() {
$this->mock_cache->method( 'get' )->willReturn( [ 'is_deferred_intent_creation_upe_enabled' => true ] );
- $card_gateway_mock = $this->createMock( UPE_Split_Payment_Gateway::class );
+ $card_gateway_mock = $this->createMock( UPE_Payment_Gateway::class );
$card_gateway_mock
->expects( $this->once() )
->method( 'get_payment_method_ids_enabled_at_checkout' )
@@ -100,7 +100,7 @@ public function test_it_skips_stripe_link_gateway_registration() {
$registered_gateways = WC_Payments::register_gateway( [] );
$this->assertCount( 1, $registered_gateways );
- $this->assertInstanceOf( UPE_Split_Payment_Gateway::class, $registered_gateways[0] );
+ $this->assertInstanceOf( UPE_Payment_Gateway::class, $registered_gateways[0] );
$this->assertEquals( $registered_gateways[0]->get_stripe_id(), 'card' );
}
From 60f7e868a0453fdfac55061476b01c837740405f Mon Sep 17 00:00:00 2001
From: Anurag Bhandari
Date: Thu, 28 Dec 2023 17:38:29 +0530
Subject: [PATCH 52/56] Bump WC tested up to version to 8.4.0 (#7943)
---
changelog/dev-bump-wc-version-8-4-0 | 4 ++++
woocommerce-payments.php | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
create mode 100644 changelog/dev-bump-wc-version-8-4-0
diff --git a/changelog/dev-bump-wc-version-8-4-0 b/changelog/dev-bump-wc-version-8-4-0
new file mode 100644
index 00000000000..5c00289cc5b
--- /dev/null
+++ b/changelog/dev-bump-wc-version-8-4-0
@@ -0,0 +1,4 @@
+Significance: minor
+Type: dev
+
+Bump WC tested up to version to 8.4.0.
\ No newline at end of file
diff --git a/woocommerce-payments.php b/woocommerce-payments.php
index df1a348ec90..df7afe47766 100644
--- a/woocommerce-payments.php
+++ b/woocommerce-payments.php
@@ -9,7 +9,7 @@
* Text Domain: woocommerce-payments
* Domain Path: /languages
* WC requires at least: 7.6
- * WC tested up to: 8.3.1
+ * WC tested up to: 8.4.0
* Requires at least: 6.0
* Requires PHP: 7.3
* Version: 6.9.2
From 62c69cbe63b6987394f88363b5b97efefc09e206 Mon Sep 17 00:00:00 2001
From: Timur Karimov
Date: Fri, 29 Dec 2023 11:06:30 +0100
Subject: [PATCH 53/56] Consolidate gateways implementation - step II (#7944)
Co-authored-by: Timur Karimov
Co-authored-by: Timur Karimov
---
changelog/cleanup-upe-gateways-II | 4 +
client/checkout/api/index.js | 33 -
includes/class-wc-payment-gateway-wcpay.php | 815 +++++++++++-
includes/class-wc-payments-checkout.php | 18 +-
...ments-payment-method-messaging-element.php | 8 +-
includes/class-wc-payments.php | 99 +-
.../class-upe-payment-gateway.php | 1138 -----------------
src/Internal/Payment/State/ProcessedState.php | 2 +-
...s-wc-rest-payments-settings-controller.php | 174 +--
...-class-wc-rest-payments-tos-controller.php | 4 +
.../test-class-upe-payment-gateway.php | 329 +----
.../test-class-upe-split-payment-gateway.php | 325 +----
.../Payment/State/ProcessedStateTest.php | 2 +-
...wc-payment-gateway-wcpay-payment-types.php | 7 +-
...-payment-gateway-wcpay-process-payment.php | 11 +-
...c-payment-gateway-wcpay-process-refund.php | 4 +
...ubscriptions-payment-method-order-note.php | 12 +-
...ay-wcpay-subscriptions-process-payment.php | 10 +-
...wc-payment-gateway-wcpay-subscriptions.php | 26 +
.../test-class-wc-payment-gateway-wcpay.php | 11 +-
.../unit/test-class-wc-payments-checkout.php | 13 +-
...xpress-checkout-button-display-handler.php | 4 +
...ayments-payment-request-button-handler.php | 4 +
...lass-wc-payments-woopay-button-handler.php | 4 +
tests/unit/test-class-wc-payments.php | 5 +-
25 files changed, 1016 insertions(+), 2046 deletions(-)
create mode 100644 changelog/cleanup-upe-gateways-II
delete mode 100644 includes/payment-methods/class-upe-payment-gateway.php
diff --git a/changelog/cleanup-upe-gateways-II b/changelog/cleanup-upe-gateways-II
new file mode 100644
index 00000000000..16f3e3cd17f
--- /dev/null
+++ b/changelog/cleanup-upe-gateways-II
@@ -0,0 +1,4 @@
+Significance: minor
+Type: dev
+
+Cleanup the deprecated payment gateway processing - part VI
diff --git a/client/checkout/api/index.js b/client/checkout/api/index.js
index 9ecdf245b62..9b05ea40a26 100644
--- a/client/checkout/api/index.js
+++ b/client/checkout/api/index.js
@@ -440,39 +440,6 @@ export default class WCPayAPI {
} );
}
- /**
- * Process checkout and update payment intent via AJAX.
- *
- * @param {string} paymentIntentId ID of payment intent to be updated.
- * @param {Object} fields Checkout fields.
- * @param {string} fingerprint User fingerprint.
- * @return {Promise} Promise containing redirect URL for UPE element.
- */
- processCheckout( paymentIntentId, fields, fingerprint ) {
- return this.request(
- buildAjaxURL( getConfig( 'wcAjaxUrl' ), 'checkout', '' ),
- {
- ...fields,
- wc_payment_intent_id: paymentIntentId,
- 'wcpay-fingerprint': fingerprint,
- }
- )
- .then( ( response ) => {
- if ( response.result === 'failure' ) {
- throw new Error( response.messages );
- }
- return response;
- } )
- .catch( ( error ) => {
- if ( error.message ) {
- throw error;
- } else {
- // Covers the case of error on the Ajaxrequest.
- throw new Error( error.statusText );
- }
- } );
- }
-
/**
* Submits shipping address to get available shipping options
* from Payment Request button.
diff --git a/includes/class-wc-payment-gateway-wcpay.php b/includes/class-wc-payment-gateway-wcpay.php
index 0348466cf19..32910b60cad 100644
--- a/includes/class-wc-payment-gateway-wcpay.php
+++ b/includes/class-wc-payment-gateway-wcpay.php
@@ -17,7 +17,7 @@
use WCPay\Constants\Intent_Status;
use WCPay\Constants\Payment_Type;
use WCPay\Constants\Payment_Method;
-use WCPay\Exceptions\{ Add_Payment_Method_Exception, Amount_Too_Small_Exception, Process_Payment_Exception, Intent_Authentication_Exception, API_Exception };
+use WCPay\Exceptions\{ Add_Payment_Method_Exception, Amount_Too_Small_Exception, Process_Payment_Exception, Intent_Authentication_Exception, API_Exception, Invalid_Address_Exception};
use WCPay\Core\Server\Request\Cancel_Intention;
use WCPay\Core\Server\Request\Capture_Intention;
use WCPay\Core\Server\Request\Create_And_Confirm_Intention;
@@ -36,7 +36,6 @@
use WCPay\Internal\Service\DuplicatePaymentPreventionService;
use WCPay\Logger;
use WCPay\Payment_Information;
-use WCPay\Payment_Methods\UPE_Payment_Gateway;
use WCPay\Payment_Methods\Link_Payment_Method;
use WCPay\WooPay\WooPay_Order_Status_Sync;
use WCPay\WooPay\WooPay_Utilities;
@@ -48,6 +47,19 @@
use WCPay\Internal\Payment\State\CompletedState;
use WCPay\Internal\Service\Level3Service;
use WCPay\Internal\Service\OrderService;
+use WCPay\Payment_Methods\Affirm_Payment_Method;
+use WCPay\Payment_Methods\Afterpay_Payment_Method;
+use WCPay\Payment_Methods\Bancontact_Payment_Method;
+use WCPay\Payment_Methods\Becs_Payment_Method;
+use WCPay\Payment_Methods\CC_Payment_Method;
+use WCPay\Payment_Methods\Eps_Payment_Method;
+use WCPay\Payment_Methods\Giropay_Payment_Method;
+use WCPay\Payment_Methods\Ideal_Payment_Method;
+use WCPay\Payment_Methods\Klarna_Payment_Method;
+use WCPay\Payment_Methods\P24_Payment_Method;
+use WCPay\Payment_Methods\Sepa_Payment_Method;
+use WCPay\Payment_Methods\Sofort_Payment_Method;
+use WCPay\Payment_Methods\UPE_Payment_Method;
/**
* Gateway class for WooPayments
@@ -101,6 +113,10 @@ class WC_Payment_Gateway_WCPay extends WC_Payment_Gateway_CC {
const USER_FORMATTED_TOKENS_LIMIT = 100;
+ const PROCESS_REDIRECT_ORDER_MISMATCH_ERROR_CODE = 'upe_process_redirect_order_id_mismatched';
+ const UPE_APPEARANCE_TRANSIENT = 'wcpay_upe_appearance';
+ const WC_BLOCKS_UPE_APPEARANCE_TRANSIENT = 'wcpay_wc_blocks_upe_appearance';
+
/**
* Client for making requests to the WooCommerce Payments API
*
@@ -185,6 +201,27 @@ class WC_Payment_Gateway_WCPay extends WC_Payment_Gateway_CC {
*/
protected $fraud_service;
+ /**
+ * UPE Payment Method for gateway.
+ *
+ * @var UPE_Payment_Method
+ */
+ protected $payment_method;
+
+ /**
+ * Array mapping payment method string IDs to classes
+ *
+ * @var UPE_Payment_Method[]
+ */
+ protected $payment_methods = [];
+
+ /**
+ * Stripe payment method type ID.
+ *
+ * @var string
+ */
+ protected $stripe_id;
+
/**
* WC_Payment_Gateway_WCPay constructor.
*
@@ -193,6 +230,8 @@ class WC_Payment_Gateway_WCPay extends WC_Payment_Gateway_CC {
* @param WC_Payments_Customer_Service $customer_service - Customer class instance.
* @param WC_Payments_Token_Service $token_service - Token class instance.
* @param WC_Payments_Action_Scheduler_Service $action_scheduler_service - Action Scheduler service instance.
+ * @param UPE_Payment_Method $payment_method - Specific UPE_Payment_Method instance for gateway.
+ * @param array $payment_methods - Array of UPE payment methods.
* @param Session_Rate_Limiter|null $failed_transaction_rate_limiter - Rate Limiter for failed transactions.
* @param WC_Payments_Order_Service $order_service - Order class instance.
* @param Duplicate_Payment_Prevention_Service $duplicate_payment_prevention_service - Service for preventing duplicate payments.
@@ -205,12 +244,18 @@ public function __construct(
WC_Payments_Customer_Service $customer_service,
WC_Payments_Token_Service $token_service,
WC_Payments_Action_Scheduler_Service $action_scheduler_service,
+ UPE_Payment_Method $payment_method,
+ array $payment_methods,
Session_Rate_Limiter $failed_transaction_rate_limiter = null,
WC_Payments_Order_Service $order_service,
Duplicate_Payment_Prevention_Service $duplicate_payment_prevention_service,
WC_Payments_Localization_Service $localization_service,
WC_Payments_Fraud_Service $fraud_service
) {
+ $this->payment_methods = $payment_methods;
+ $this->payment_method = $payment_method;
+ $this->stripe_id = $payment_method->get_id();
+
$this->payments_api_client = $payments_api_client;
$this->account = $account;
$this->customer_service = $customer_service;
@@ -223,18 +268,23 @@ public function __construct(
$this->fraud_service = $fraud_service;
$this->id = static::GATEWAY_ID;
- $this->icon = plugins_url( 'assets/images/payment-methods/cc.svg', WCPAY_PLUGIN_FILE );
+ $this->icon = $payment_method->get_icon();
$this->has_fields = true;
$this->method_title = 'WooPayments';
- $this->method_description = $this->get_method_description();
+ $this->method_description = __( 'Payments made simple, with no monthly fees - designed exclusively for WooCommerce stores. Accept credit cards, debit cards, and other popular payment methods.', 'woocommerce-payments' );
- $this->title = __( 'Credit card / debit card', 'woocommerce-payments' );
- $this->description = __( 'Enter your card details', 'woocommerce-payments' );
+ $this->title = $payment_method->get_title();
+ $this->description = '';
$this->supports = [
'products',
'refunds',
];
+ if ( 'card' !== $this->stripe_id ) {
+ $this->id = self::GATEWAY_ID . '_' . $this->stripe_id;
+ $this->method_title = "WooPayments ($this->title)";
+ }
+
// Define setting fields.
$this->form_fields = [
'enabled' => [
@@ -475,6 +525,95 @@ public function init_hooks() {
$this->maybe_init_subscriptions_hooks();
}
+ /**
+ * Displays HTML tags for WC payment gateway radio button content.
+ */
+ public function display_gateway_html() {
+ ?>
+
+ get_selected_stripe_payment_type_id() );
+ do_action( 'wc_payments_add_upe_payment_fields' );
+ }
+
+ /**
+ * Adds a token to current user from a setup intent id.
+ *
+ * @param string $setup_intent_id ID of the setup intent.
+ * @param WP_User $user User to add token to.
+ *
+ * @return WC_Payment_Token_CC|WC_Payment_Token_WCPay_SEPA|null The added token.
+ */
+ public function create_token_from_setup_intent( $setup_intent_id, $user ) {
+ try {
+ $setup_intent_request = Get_Setup_Intention::create( $setup_intent_id );
+ /** @var WC_Payments_API_Setup_Intention $setup_intent */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort
+ $setup_intent = $setup_intent_request->send();
+
+ $payment_method_id = $setup_intent->get_payment_method_id();
+ // TODO: When adding SEPA and Sofort, we will need a new API call to get the payment method and from there get the type.
+ // Leaving 'card' as a hardcoded value for now to avoid the extra API call.
+ // $payment_method = $this->payment_methods['card'];// Maybe this should be enforced.
+ $payment_method = $this->payment_method;
+
+ return $payment_method->get_payment_token_for_user( $user, $payment_method_id );
+ } catch ( Exception $e ) {
+ wc_add_notice( WC_Payments_Utils::get_filtered_error_message( $e ), 'error', [ 'icon' => 'error' ] );
+ Logger::log( 'Error when adding payment method: ' . $e->getMessage() );
+ }
+ }
+
+ /**
+ * Validate order_id received from the request vs value saved in the intent metadata.
+ * Throw an exception if they're not matched.
+ *
+ * @param WC_Order $order The received order to process.
+ * @param array $intent_metadata The metadata of attached intent to the order.
+ *
+ * @return void
+ * @throws Process_Payment_Exception
+ */
+ private function validate_order_id_received_vs_intent_meta_order_id( WC_Order $order, array $intent_metadata ): void {
+ $intent_meta_order_id_raw = $intent_metadata['order_id'] ?? '';
+ $intent_meta_order_id = is_numeric( $intent_meta_order_id_raw ) ? intval( $intent_meta_order_id_raw ) : 0;
+
+ if ( $order->get_id() !== $intent_meta_order_id ) {
+ Logger::error(
+ sprintf(
+ 'UPE Process Redirect Payment - Order ID mismatched. Received: %1$d. Intent Metadata Value: %2$d',
+ $order->get_id(),
+ $intent_meta_order_id
+ )
+ );
+
+ throw new Process_Payment_Exception(
+ __( "We're not able to process this payment due to the order ID mismatch. Please try again later.", 'woocommerce-payments' ),
+ self::PROCESS_REDIRECT_ORDER_MISMATCH_ERROR_CODE
+ );
+ }
+ }
+
+ /**
+ * Gets payment method settings to pass to client scripts
+ *
+ * @deprecated 5.0.0
+ *
+ * @return array
+ */
+ private function get_enabled_payment_method_config() {
+ wc_deprecated_function( __FUNCTION__, '5.0.0', 'WC_Payments_Checkout::get_enabled_payment_method_config' );
+ return WC_Payments::get_wc_payments_checkout()->get_enabled_payment_method_config();
+ }
+
+
/**
* If we're in a WooPay preflight check, remove all the checkout order processed
* actions to prevent reduce available resources quantity.
@@ -575,6 +714,10 @@ public function needs_https_setup() {
* @return bool Whether the gateway is enabled and ready to accept payments.
*/
public function is_available() {
+ $processing_payment_method = $this->payment_methods[ $this->payment_method->get_id() ];
+ if ( ! $processing_payment_method->is_enabled_at_checkout( $this->get_account_country() ) ) {
+ return false;
+ }
// Disable the gateway if using live mode without HTTPS set up or the currency is not
// available in the country of the account.
if ( $this->needs_https_setup() || ! $this->is_available_for_current_currency() ) {
@@ -683,6 +826,59 @@ public function output_payments_settings_screen() {
endif;
}
+ /**
+ * Log payment errors on Checkout.
+ *
+ * @throws Exception If nonce is not present or invalid or charge ID is empty or order not found.
+ */
+ public function log_payment_error_ajax() {
+ try {
+ $is_nonce_valid = check_ajax_referer( 'wcpay_log_payment_error_nonce', false, false );
+ if ( ! $is_nonce_valid ) {
+ throw new Exception( 'Invalid request.' );
+ }
+
+ $charge_id = isset( $_POST['charge_id'] ) ? wc_clean( wp_unslash( $_POST['charge_id'] ) ) : '';
+ if ( empty( $charge_id ) ) {
+ throw new Exception( 'Charge ID cannot be empty.' );
+ }
+
+ // Get charge data from WCPay Server.
+ $request = Get_Charge::create( $charge_id );
+ $request->set_hook_args( $charge_id );
+ $charge_data = $request->send();
+ $order_id = $charge_data['metadata']['order_id'];
+
+ // Validate Order ID and proceed with logging errors and updating order status.
+ $order = wc_get_order( $order_id );
+ if ( ! $order ) {
+ throw new Exception( 'Order not found. Unable to log error.' );
+ }
+
+ $intent_id = $charge_data['payment_intent'] ?? $order->get_meta( '_intent_id' );
+
+ $request = Get_Intention::create( $intent_id );
+ $request->set_hook_args( $order );
+ $intent = $request->send();
+
+ $intent_status = $intent->get_status();
+ $error_message = esc_html( rtrim( $charge_data['failure_message'], '.' ) );
+
+ $this->order_service->mark_payment_failed( $order, $intent_id, $intent_status, $charge_id, $error_message );
+
+ wp_send_json_success();
+ } catch ( Exception $e ) {
+ wp_send_json_error(
+ [
+ 'error' => [
+ 'message' => WC_Payments_Utils::get_filtered_error_message( $e ),
+ ],
+ ],
+ WC_Payments_Utils::get_filtered_error_status_code( $e ),
+ );
+ }
+ }
+
/**
* Displays the save to account checkbox.
*
@@ -709,6 +905,10 @@ public function save_payment_method_checkbox( $force_checked = false ) {
* @return bool
*/
public function should_use_stripe_platform_on_checkout_page() {
+ if ( 'card' !== $this->stripe_id ) {
+ return false;
+ }
+
if (
WC_Payments_Features::is_woopay_eligible() &&
'yes' === $this->get_option( 'platform_checkout', 'no' ) &&
@@ -1527,15 +1727,228 @@ public function process_payment_for_order( $cart, $payment_information, $schedul
];
}
+ /**
+ * Check for a redirect payment method on order received page or setup intent on payment methods page.
+ */
+ public function maybe_process_upe_redirect() {
+ if ( $this->is_payment_methods_page() ) {
+ // If a payment method was added using UPE, we need to clear the cache and notify the user.
+ if ( $this->is_setup_intent_success_creation_redirection() ) {
+ wc_add_notice( __( 'Payment method successfully added.', 'woocommerce-payments' ) );
+ $user = wp_get_current_user();
+ $this->customer_service->clear_cached_payment_methods_for_user( $user->ID );
+ }
+ return;
+ }
+
+ if ( ! is_order_received_page() ) {
+ return;
+ }
+
+ $payment_method = isset( $_GET['wc_payment_method'] ) ? wc_clean( wp_unslash( $_GET['wc_payment_method'] ) ) : '';
+ if ( self::GATEWAY_ID !== $payment_method ) {
+ return;
+ }
+
+ $is_nonce_valid = check_admin_referer( 'wcpay_process_redirect_order_nonce' );
+ if ( ! $is_nonce_valid || empty( $_GET['wc_payment_method'] ) ) {
+ return;
+ }
+
+ if ( ! empty( $_GET['payment_intent_client_secret'] ) ) {
+ $intent_id_from_request = isset( $_GET['payment_intent'] ) ? wc_clean( wp_unslash( $_GET['payment_intent'] ) ) : '';
+ } elseif ( ! empty( $_GET['setup_intent_client_secret'] ) ) {
+ $intent_id_from_request = isset( $_GET['setup_intent'] ) ? wc_clean( wp_unslash( $_GET['setup_intent'] ) ) : '';
+ } else {
+ return;
+ }
+
+ $order_id = absint( get_query_var( 'order-received' ) );
+ $order_key_from_request = isset( $_GET['key'] ) ? wc_clean( wp_unslash( $_GET['key'] ) ) : '';
+ $save_payment_method = isset( $_GET['save_payment_method'] ) ? 'yes' === wc_clean( wp_unslash( $_GET['save_payment_method'] ) ) : false;
+
+ if ( empty( $intent_id_from_request ) || empty( $order_id ) || empty( $order_key_from_request ) ) {
+ return;
+ }
+
+ $order = wc_get_order( $order_id );
+
+ if ( ! is_a( $order, 'WC_Order' ) ) {
+ // the ID of non-existing order was passed in.
+ return;
+ }
+
+ if ( $order->get_order_key() !== $order_key_from_request ) {
+ // Valid return url should have matching order key.
+ return;
+ }
+
+ // Perform additional checks for non-zero-amount. For zero-amount orders, we can't compare intents because they are not attached to the order at this stage.
+ // Once https://github.com/Automattic/woocommerce-payments/issues/6575 is closed, this check can be applied for zero-amount orders as well.
+ if ( $order->get_total() > 0 && ! $this->is_proper_intent_used_with_order( $order, $intent_id_from_request ) ) {
+ return;
+ }
+
+ $this->process_redirect_payment( $order, $intent_id_from_request, $save_payment_method );
+ }
+
/**
- * The parent method which allows to modify the child class implementation, while supporting the current design where the parent process_payment method is called from the child class.
- * Mandate must be shown and acknowledged under certain conditions for Stripe Link and SEPA.
- * Since WC_Payment_Gateway_WCPay represents card payment, which does not require mandate, we return false.
+ * Processes redirect payments.
+ *
+ * @param WC_Order $order The order being processed.
+ * @param string $intent_id The Stripe setup/payment intent ID for the order payment.
+ * @param bool $save_payment_method Boolean representing whether payment method for order should be saved.
*
- * @return boolean False since card payment does not require mandate.
+ * @throws Process_Payment_Exception When the payment intent has an error.
*/
- protected function is_mandate_data_required() {
- return false;
+ public function process_redirect_payment( $order, $intent_id, $save_payment_method ) {
+ try {
+ $order_id = $order->get_id();
+ if ( $order->has_status(
+ [
+ Order_Status::PROCESSING,
+ Order_Status::COMPLETED,
+ Order_Status::ON_HOLD,
+ ]
+ ) ) {
+ return;
+ }
+
+ Logger::log( "Begin processing UPE redirect payment for order {$order_id} for the amount of {$order->get_total()}" );
+
+ // Get user/customer for order.
+ list( $user, $customer_id ) = $this->manage_customer_details_for_order( $order );
+
+ $payment_needed = 0 < $order->get_total();
+
+ // Get payment intent to confirm status.
+ if ( $payment_needed ) {
+ $request = Get_Intention::create( $intent_id );
+ $request->set_hook_args( $order );
+ /** @var WC_Payments_API_Payment_Intention $intent */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort
+ $intent = $request->send();
+ $client_secret = $intent->get_client_secret();
+ $status = $intent->get_status();
+ $charge = $intent->get_charge();
+ $charge_id = $charge ? $charge->get_id() : null;
+ $currency = $intent->get_currency();
+ $payment_method_id = $intent->get_payment_method_id();
+ $payment_method_details = $charge ? $charge->get_payment_method_details() : [];
+ $payment_method_type = $this->get_payment_method_type_from_payment_details( $payment_method_details );
+ $error = $intent->get_last_payment_error();
+
+ // This check applies to payment intents only due to two reasons:
+ // (1) metadata is missed for setup intents. See https://github.com/Automattic/woocommerce-payments/issues/6575.
+ // (2) most issues so far affect only payment intents.
+ $intent_metadata = is_array( $intent->get_metadata() ) ? $intent->get_metadata() : [];
+ $this->validate_order_id_received_vs_intent_meta_order_id( $order, $intent_metadata );
+ } else {
+ $request = Get_Setup_Intention::create( $intent_id );
+ /** @var WC_Payments_API_Setup_Intention $intent */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort
+ $intent = $request->send();
+ $client_secret = $intent->get_client_secret();
+ $status = $intent->get_status();
+ $charge_id = '';
+ $charge = null;
+ $currency = $order->get_currency();
+ $payment_method_id = $intent->get_payment_method_id();
+ $payment_method_details = false;
+ $payment_method_type = $intent->get_payment_method_type();
+ $error = $intent->get_last_setup_error();
+ }
+
+ if ( ! empty( $error ) ) {
+ Logger::log( 'Error when processing payment: ' . $error['message'] );
+ throw new Process_Payment_Exception(
+ __( "We're not able to process this payment. Please try again later.", 'woocommerce-payments' ),
+ 'upe_payment_intent_error'
+ );
+ } else {
+ $payment_method = $this->get_selected_payment_method( $payment_method_type );
+ if ( ! $payment_method ) {
+ return;
+ }
+
+ if ( $save_payment_method && $payment_method->is_reusable() ) {
+ try {
+ $token = $payment_method->get_payment_token_for_user( $user, $payment_method_id );
+ $this->add_token_to_order( $order, $token );
+ } catch ( Exception $e ) {
+ // If saving the token fails, log the error message but catch the error to avoid crashing the checkout flow.
+ Logger::log( 'Error when saving payment method: ' . $e->getMessage() );
+ }
+ }
+
+ $this->order_service->attach_intent_info_to_order( $order, $intent_id, $status, $payment_method_id, $customer_id, $charge_id, $currency );
+ $this->attach_exchange_info_to_order( $order, $charge_id );
+ if ( Intent_Status::SUCCEEDED === $status ) {
+ $this->duplicate_payment_prevention_service->remove_session_processing_order( $order->get_id() );
+ }
+ $this->order_service->update_order_status_from_intent( $order, $intent );
+ $this->set_payment_method_title_for_order( $order, $payment_method_type, $payment_method_details );
+ $this->order_service->attach_transaction_fee_to_order( $order, $charge );
+
+ if ( Intent_Status::REQUIRES_ACTION === $status ) {
+ // I don't think this case should be possible, but just in case...
+ $next_action = $intent->get_next_action();
+ if ( isset( $next_action['type'] ) && 'redirect_to_url' === $next_action['type'] && ! empty( $next_action['redirect_to_url']['url'] ) ) {
+ wp_safe_redirect( $next_action['redirect_to_url']['url'] );
+ exit;
+ } else {
+ $redirect_url = sprintf(
+ '#wcpay-confirm-%s:%s:%s:%s',
+ $payment_needed ? 'pi' : 'si',
+ $order_id,
+ WC_Payments_Utils::encrypt_client_secret( $this->account->get_stripe_account_id(), $client_secret ),
+ wp_create_nonce( 'wcpay_update_order_status_nonce' )
+ );
+ wp_safe_redirect( $redirect_url );
+ exit;
+ }
+ }
+ }
+ } catch ( Exception $e ) {
+ Logger::log( 'Error: ' . $e->getMessage() );
+
+ $is_order_id_mismatched_exception =
+ is_a( $e, Process_Payment_Exception::class )
+ && self::PROCESS_REDIRECT_ORDER_MISMATCH_ERROR_CODE === $e->get_error_code();
+
+ // If the order ID mismatched exception is thrown, do not mark the order as failed.
+ // Because the outcome of the payment intent is for another order, not for the order processed here.
+ if ( ! $is_order_id_mismatched_exception ) {
+ // Confirm our needed variables are set before using them due to there could be a server issue during the get_intent process.
+ $status = $status ?? null;
+ $charge_id = $charge_id ?? null;
+
+ /* translators: localized exception message */
+ $message = sprintf( __( 'UPE payment failed: %s', 'woocommerce-payments' ), $e->getMessage() );
+ $this->order_service->mark_payment_failed( $order, $intent_id, $status, $charge_id, $message );
+ }
+
+ wc_add_notice( WC_Payments_Utils::get_filtered_error_message( $e ), 'error' );
+
+ $redirect_url = wc_get_checkout_url();
+ if ( $is_order_id_mismatched_exception ) {
+ $redirect_url = add_query_arg( self::PROCESS_REDIRECT_ORDER_MISMATCH_ERROR_CODE, 'yes', $redirect_url );
+ }
+ wp_safe_redirect( $redirect_url );
+ exit;
+ }
+ }
+
+ /**
+ * Mandate must be shown and acknowledged by customer before deferred intent UPE payment can be processed.
+ * This applies to SEPA and Link payment methods.
+ * https://stripe.com/docs/payments/finalize-payments-on-the-server
+ *
+ * @return boolean True if mandate must be shown and acknowledged by customer before deferred intent UPE payment can be processed, false otherwise.
+ */
+ public function is_mandate_data_required() {
+ $is_stripe_link_enabled = Payment_Method::CARD === $this->get_selected_stripe_payment_type_id() && in_array( Payment_Method::LINK, $this->get_upe_enabled_payment_method_ids(), true );
+ $is_sepa_debit_payment = Payment_Method::SEPA === $this->get_selected_stripe_payment_type_id();
+
+ return $is_stripe_link_enabled || $is_sepa_debit_payment;
}
/**
@@ -1621,15 +2034,26 @@ private function get_mandate_data() {
}
/**
- * By default this function does not do anything. But it can be overriden by child classes.
- * It is used to set a formatted readable payment method title for order,
+ * Set formatted readable payment method title for order,
* using payment method details from accompanying charge.
*
- * @param WC_Order $order WC Order being processed.
+ * @param \WC_Order $order WC Order being processed.
* @param string $payment_method_type Stripe payment method key.
* @param array|bool $payment_method_details Array of payment method details from charge or false.
*/
public function set_payment_method_title_for_order( $order, $payment_method_type, $payment_method_details ) {
+ $payment_method = $this->get_selected_payment_method( $payment_method_type );
+ if ( ! $payment_method ) {
+ return;
+ }
+
+ $payment_method_title = $payment_method->get_title( $payment_method_details );
+
+ $payment_gateway = in_array( $payment_method->get_id(), [ Payment_Method::CARD, Payment_Method::LINK ], true ) ? self::GATEWAY_ID : self::GATEWAY_ID . '_' . $payment_method_type;
+
+ $order->set_payment_method( $payment_gateway );
+ $order->set_payment_method_title( $payment_method_title );
+ $order->save();
}
/**
@@ -3434,25 +3858,71 @@ public function update_cached_account_data( $property, $data ) {
/**
* Returns the Stripe payment type of the selected payment method.
*
- * @return string[]
+ * @return string
*/
public function get_selected_stripe_payment_type_id() {
- return [
- 'card',
- ];
+ return $this->stripe_id;
}
+
/**
* Returns the list of enabled payment method types that will function with the current checkout.
*
* @param string $order_id optional Order ID.
* @param bool $force_currency_check optional Whether the currency check is required even if is_admin().
+ *
* @return string[]
*/
public function get_payment_method_ids_enabled_at_checkout( $order_id = null, $force_currency_check = false ) {
- return [
- 'card',
- ];
+ $automatic_capture = empty( $this->get_option( 'manual_capture' ) ) || $this->get_option( 'manual_capture' ) === 'no';
+ if ( $automatic_capture ) {
+ $upe_enabled_payment_methods = $this->get_upe_enabled_payment_method_ids();
+ } else {
+ $upe_enabled_payment_methods = array_intersect( $this->get_upe_enabled_payment_method_ids(), [ Payment_Method::CARD, Payment_Method::LINK ] );
+ }
+ if ( is_wc_endpoint_url( 'order-pay' ) ) {
+ $force_currency_check = true;
+ }
+
+ $enabled_payment_methods = [];
+ $active_payment_methods = $this->get_upe_enabled_payment_method_statuses();
+
+ foreach ( $upe_enabled_payment_methods as $payment_method_id ) {
+ $payment_method_capability_key = $this->payment_method_capability_key_map[ $payment_method_id ] ?? 'undefined_capability_key';
+ if ( isset( $this->payment_methods[ $payment_method_id ] ) ) {
+ // When creating a payment intent, we need to ensure the currency is matching
+ // with the payment methods which are sent with the payment intent request, otherwise
+ // Stripe returns an error.
+
+ // force_currency_check = 0 is_admin = 0 currency_is_checked = 1.
+ // force_currency_check = 0 is_admin = 1 currency_is_checked = 0.
+ // force_currency_check = 1 is_admin = 0 currency_is_checked = 1.
+ // force_currency_check = 1 is_admin = 1 currency_is_checked = 1.
+
+ $skip_currency_check = ! $force_currency_check && is_admin();
+ $processing_payment_method = $this->payment_methods[ $payment_method_id ];
+ if ( $processing_payment_method->is_enabled_at_checkout( $this->get_account_country() ) && ( $skip_currency_check || $processing_payment_method->is_currency_valid( $this->get_account_domestic_currency(), $order_id ) ) ) {
+ $status = $active_payment_methods[ $payment_method_capability_key ]['status'] ?? null;
+ if ( 'active' === $status ) {
+ $enabled_payment_methods[] = $payment_method_id;
+ }
+ }
+ }
+ }
+
+ // if credit card payment method is not enabled, we don't use stripe link.
+ if (
+ ! in_array( CC_Payment_Method::PAYMENT_METHOD_STRIPE_ID, $enabled_payment_methods, true ) &&
+ in_array( Link_Payment_Method::PAYMENT_METHOD_STRIPE_ID, $enabled_payment_methods, true ) ) {
+ $enabled_payment_methods = array_filter(
+ $enabled_payment_methods,
+ static function( $method ) {
+ return Link_Payment_Method::PAYMENT_METHOD_STRIPE_ID !== $method;
+ }
+ );
+ }
+
+ return $enabled_payment_methods;
}
/**
@@ -3463,7 +3933,10 @@ public function get_payment_method_ids_enabled_at_checkout( $order_id = null, $f
* @return string[]
*/
public function get_payment_method_ids_enabled_at_checkout_filtered_by_fees( $order_id = null, $force_currency_check = false ) {
- return $this->get_payment_method_ids_enabled_at_checkout( $order_id, $force_currency_check );
+ $enabled_payment_methods = $this->get_payment_method_ids_enabled_at_checkout( $order_id, $force_currency_check );
+ $methods_with_fees = array_keys( $this->account->get_fees() );
+
+ return array_values( array_intersect( $enabled_payment_methods, $methods_with_fees ) );
}
/**
@@ -3473,11 +3946,79 @@ public function get_payment_method_ids_enabled_at_checkout_filtered_by_fees( $or
* @return string[]
*/
public function get_upe_available_payment_methods() {
- return [
- 'card',
- ];
+ $available_methods = [ 'card' ];
+
+ $available_methods[] = Becs_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
+ $available_methods[] = Bancontact_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
+ $available_methods[] = Eps_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
+ $available_methods[] = Giropay_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
+ $available_methods[] = Ideal_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
+ $available_methods[] = Sofort_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
+ $available_methods[] = Sepa_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
+ $available_methods[] = P24_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
+ $available_methods[] = Link_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
+ $available_methods[] = Affirm_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
+ $available_methods[] = Afterpay_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
+ $available_methods[] = Klarna_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
+
+ $available_methods = array_values(
+ apply_filters(
+ 'wcpay_upe_available_payment_methods',
+ $available_methods
+ )
+ );
+
+ $methods_with_fees = array_keys( $this->account->get_fees() );
+
+ return array_values( array_intersect( $available_methods, $methods_with_fees ) );
+ }
+
+ /**
+ * Handle AJAX request for saving UPE appearance value to transient.
+ *
+ * @throws Exception - If nonce or setup intent is invalid.
+ */
+ public function save_upe_appearance_ajax() {
+ try {
+ $is_nonce_valid = check_ajax_referer( 'wcpay_save_upe_appearance_nonce', false, false );
+ if ( ! $is_nonce_valid ) {
+ throw new Exception(
+ __( 'Unable to update UPE appearance values at this time.', 'woocommerce-payments' )
+ );
+ }
+
+ $is_blocks_checkout = isset( $_POST['is_blocks_checkout'] ) ? rest_sanitize_boolean( wc_clean( wp_unslash( $_POST['is_blocks_checkout'] ) ) ) : false;
+ $appearance = isset( $_POST['appearance'] ) ? json_decode( wc_clean( wp_unslash( $_POST['appearance'] ) ) ) : null;
+
+ $appearance_transient = $is_blocks_checkout ? self::WC_BLOCKS_UPE_APPEARANCE_TRANSIENT : self::UPE_APPEARANCE_TRANSIENT;
+
+ if ( null !== $appearance ) {
+ set_transient( $appearance_transient, $appearance, DAY_IN_SECONDS );
+ }
+
+ wp_send_json_success( $appearance, 200 );
+ } catch ( Exception $e ) {
+ // Send back error so it can be displayed to the customer.
+ wp_send_json_error(
+ [
+ 'error' => [
+ 'message' => WC_Payments_Utils::get_filtered_error_message( $e ),
+ ],
+ ],
+ WC_Payments_Utils::get_filtered_error_status_code( $e ),
+ );
+ }
}
+ /**
+ * Clear the saved UPE appearance transient value.
+ */
+ public function clear_upe_appearance_transient() {
+ delete_transient( self::UPE_APPEARANCE_TRANSIENT );
+ delete_transient( self::WC_BLOCKS_UPE_APPEARANCE_TRANSIENT );
+ }
+
+
/**
* Text provided to users during onboarding setup.
*
@@ -3513,6 +4054,81 @@ protected function should_bump_rate_limiter( string $error_code ): bool {
return in_array( $error_code, [ 'card_declined', 'incorrect_number', 'incorrect_cvc' ], true );
}
+ /**
+ * Returns boolean for whether payment gateway supports saved payments.
+ *
+ * @return bool True, if gateway supports saved payments. False, otherwise.
+ */
+ public function should_support_saved_payments() {
+ return $this->is_enabled_for_saved_payments( $this->stripe_id );
+ }
+
+ /**
+ * Returns true when viewing payment methods page.
+ *
+ * @return bool
+ */
+ private function is_payment_methods_page() {
+ global $wp;
+
+ $page_id = wc_get_page_id( 'myaccount' );
+
+ return ( $page_id && is_page( $page_id ) && ( isset( $wp->query_vars['payment-methods'] ) ) );
+ }
+
+ /**
+ * Verifies that the proper intent is used to process the order.
+ *
+ * @param WC_Order $order The order object based on the order_id received from the request.
+ * @param string $intent_id_from_request The intent ID received from the request.
+ *
+ * @return bool True if the proper intent is used to process the order, false otherwise.
+ */
+ public function is_proper_intent_used_with_order( $order, $intent_id_from_request ) {
+ $intent_id_attached_to_order = $this->order_service->get_intent_id_for_order( $order );
+ if ( ! hash_equals( $intent_id_attached_to_order, $intent_id_from_request ) ) {
+ Logger::error(
+ sprintf(
+ 'Intent ID mismatch. Received in request: %1$s. Attached to order: %2$s. Order ID: %3$d',
+ $intent_id_from_request,
+ $intent_id_attached_to_order,
+ $order->get_id()
+ )
+ );
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * True if the request contains the values that indicates a redirection after a successful setup intent creation.
+ *
+ * @return bool
+ */
+ public function is_setup_intent_success_creation_redirection() {
+ return ! empty( $_GET['setup_intent_client_secret'] ) && // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ ! empty( $_GET['setup_intent'] ) && // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ ! empty( $_GET['redirect_status'] ) && // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ 'succeeded' === $_GET['redirect_status']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ }
+
+ /**
+ * Function to be used with array_filter
+ * to filter UPE payment methods that support saved payments
+ *
+ * @param string $payment_method_id Stripe payment method.
+ *
+ * @return bool
+ */
+ public function is_enabled_for_saved_payments( $payment_method_id ) {
+ $payment_method = $this->get_selected_payment_method( $payment_method_id );
+ if ( ! $payment_method ) {
+ return false;
+ }
+ return $payment_method->is_reusable()
+ && ( is_admin() || $payment_method->is_currency_valid( $this->get_account_domestic_currency() ) );
+ }
+
/**
* Move the email field to the top of the Checkout page.
*
@@ -3557,6 +4173,44 @@ public function append_stripelink_button( $field, $key, $args, $value ) {
return $field;
}
+ /**
+ * Get selected UPE payment methods.
+ *
+ * @param string $selected_upe_payment_type Selected payment methods.
+ * @param array $enabled_payment_methods Enabled payment methods.
+ *
+ * @return array
+ */
+ protected function get_selected_upe_payment_methods( string $selected_upe_payment_type, array $enabled_payment_methods ) {
+ $payment_methods = [];
+ if ( '' !== $selected_upe_payment_type ) {
+ // Only update the payment_method_types if we have a reference to the payment type the customer selected.
+ $payment_methods[] = $selected_upe_payment_type;
+
+ if ( CC_Payment_Method::PAYMENT_METHOD_STRIPE_ID === $selected_upe_payment_type ) {
+ $is_link_enabled = in_array(
+ Link_Payment_Method::PAYMENT_METHOD_STRIPE_ID,
+ $enabled_payment_methods,
+ true
+ );
+ if ( $is_link_enabled ) {
+ $payment_methods[] = Link_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
+ }
+ }
+ }
+ return $payment_methods;
+ }
+
+ /**
+ * Gets UPE_Payment_Method instance from ID.
+ *
+ * @param string $payment_method_type Stripe payment method type ID.
+ * @return UPE_Payment_Method|false UPE payment method instance.
+ */
+ public function get_selected_payment_method( $payment_method_type ) {
+ return WC_Payments::get_payment_method_by_id( $payment_method_type );
+ }
+
/**
* Returns the URL of the configuration screen for this gateway, for use in internal links.
*
@@ -3566,6 +4220,73 @@ public static function get_settings_url() {
return WC_Payments_Admin_Settings::get_settings_url();
}
+ /**
+ * Return the payment method type from the payment method details.
+ *
+ * @param array $payment_method_details Payment method details.
+ * @return string|null Payment method type or nothing.
+ */
+ private function get_payment_method_type_from_payment_details( $payment_method_details ) {
+ return $payment_method_details['type'] ?? null;
+ }
+
+
+ /**
+ * This function wraps WC_Payments::get_payment_method_map, useful for unit testing.
+ *
+ * @return array Array of UPE_Payment_Method instances.
+ */
+ public function wc_payments_get_payment_method_map() {
+ return WC_Payments::get_payment_method_map();
+ }
+
+ /**
+ * Returns the payment methods for this gateway.
+ *
+ * @return array|UPE_Payment_Method[]
+ */
+ public function get_payment_methods() {
+ return $this->payment_methods;
+ }
+
+ /**
+ * Returns the UPE payment method for the gateway.
+ *
+ * @return UPE_Payment_Method
+ */
+ public function get_payment_method() {
+ return $this->payment_method;
+ }
+
+ /**
+ * Returns Stripe payment method type ID.
+ *
+ * @return string
+ */
+ public function get_stripe_id() {
+ return $this->stripe_id;
+ }
+
+ /**
+ * This function wraps WC_Payments::get_payment_gateway_by_id, useful for unit testing.
+ *
+ * @param string $payment_method_id Stripe payment method type ID.
+ * @return false|WC_Payment_Gateway_WCPay Matching UPE Payment Gateway instance.
+ */
+ public function wc_payments_get_payment_gateway_by_id( $payment_method_id ) {
+ return WC_Payments::get_payment_gateway_by_id( $payment_method_id );
+ }
+
+ /**
+ * This function wraps WC_Payments::get_payment_method_by_id, useful for unit testing.
+ *
+ * @param string $payment_method_id Stripe payment method type ID.
+ * @return false|UPE_Payment_Method Matching UPE Payment Method instance.
+ */
+ public function wc_payments_get_payment_method_by_id( $payment_method_id ) {
+ return WC_Payments::get_payment_method_by_id( $payment_method_id );
+ }
+
/**
* Get the right method description if WooPay is eligible.
*
@@ -3714,10 +4435,44 @@ private function upe_needs_redirection( $payment_methods ) {
return 1 === count( $payment_methods ) && 'card' !== $payment_methods[0];
}
+ /**
+ * Handles the shipping requirement for Afterpay payments.
+ *
+ * This method extracts the shipping and billing data from the order and sets the appropriate
+ * shipping data for the Afterpay payment request. If neither shipping nor billing data is valid
+ * for shipping, an exception is thrown.
+ *
+ * @param WC_Order $order The order object containing shipping and billing information.
+ * @param Create_And_Confirm_Intention $request The Afterpay payment request object to set shipping data on.
+ *
+ * @throws Invalid_Address_Exception If neither shipping nor billing address is valid for Afterpay payments.
+ * @return void
+ */
+ private function handle_afterpay_shipping_requirement( WC_Order $order, Create_And_Confirm_Intention $request ): void {
+ $check_if_usable = function( array $address ): bool {
+ return $address['country'] && $address['state'] && $address['city'] && $address['postal_code'] && $address['line1'];
+ };
+
+ $shipping_data = $this->order_service->get_shipping_data_from_order( $order );
+ if ( $check_if_usable( $shipping_data['address'] ) ) {
+ $request->set_shipping( $shipping_data );
+ return;
+ }
+
+ $billing_data = $this->order_service->get_billing_data_from_order( $order );
+ if ( $check_if_usable( $billing_data['address'] ) ) {
+ $request->set_shipping( $billing_data );
+ return;
+ }
+
+ throw new Invalid_Address_Exception( __( 'A valid shipping address is required for Afterpay payments.', 'woocommerce-payments' ) );
+ }
+
+
/**
* Modifies the create intent parameters when processing a payment.
*
- * Currently used by child UPE_Payment_Gateway to add required shipping information for Afterpay.
+ * If the selected Stripe payment type is AFTERPAY, it updates the shipping data in the request.
*
* @param Create_And_Confirm_Intention $request The request object for creating and confirming intention.
* @param Payment_Information $payment_information The payment information object.
@@ -3725,7 +4480,9 @@ private function upe_needs_redirection( $payment_methods ) {
*
* @return void
*/
- protected function modify_create_intent_parameters_when_processing_payment( Create_And_Confirm_Intention $request, Payment_Information $payment_information, WC_Order $order ) {
- // Do nothing.
+ protected function modify_create_intent_parameters_when_processing_payment( Create_And_Confirm_Intention $request, Payment_Information $payment_information, WC_Order $order ): void {
+ if ( Payment_Method::AFTERPAY === $this->get_selected_stripe_payment_type_id() ) {
+ $this->handle_afterpay_shipping_requirement( $order, $request );
+ }
}
}
diff --git a/includes/class-wc-payments-checkout.php b/includes/class-wc-payments-checkout.php
index 89f8654f716..4826252e7ec 100644
--- a/includes/class-wc-payments-checkout.php
+++ b/includes/class-wc-payments-checkout.php
@@ -19,7 +19,7 @@
use WC_Payments_Features;
use WCPay\Constants\Payment_Method;
use WCPay\Fraud_Prevention\Fraud_Prevention_Service;
-use WCPay\Payment_Methods\UPE_Payment_Gateway;
+use WC_Payment_Gateway_WCPay;
use WCPay\WooPay\WooPay_Utilities;
use WCPay\Payment_Methods\UPE_Payment_Method;
@@ -32,7 +32,7 @@ class WC_Payments_Checkout {
/**
* WC Payments Gateway.
*
- * @var UPE_Payment_Gateway
+ * @var WC_Payment_Gateway_WCPay
*/
protected $gateway;
@@ -67,14 +67,14 @@ class WC_Payments_Checkout {
/**
* Construct.
*
- * @param UPE_Payment_Gateway $gateway WC Payment Gateway.
+ * @param WC_Payment_Gateway_WCPay $gateway WC Payment Gateway.
* @param WooPay_Utilities $woopay_util WooPay Utilities.
* @param WC_Payments_Account $account WC Payments Account.
* @param WC_Payments_Customer_Service $customer_service WC Payments Customer Service.
* @param WC_Payments_Fraud_Service $fraud_service Fraud service instance.
*/
public function __construct(
- UPE_Payment_Gateway $gateway,
+ WC_Payment_Gateway_WCPay $gateway,
WooPay_Utilities $woopay_util,
WC_Payments_Account $account,
WC_Payments_Customer_Service $customer_service,
@@ -170,7 +170,7 @@ public function get_payment_fields_js_config() {
WC_Checkout::instance();
// The registered card gateway is more reliable than $this->gateway, but if it isn't available for any reason, fall back to the gateway provided to this checkout class.
- $gateway = WC_Payments::get_registered_card_gateway() ?? $this->gateway;
+ $gateway = WC_Payments::get_gateway() ?? $this->gateway;
$js_config = [
'publishableKey' => $this->account->get_publishable_key( WC_Payments::mode()->is_test() ),
@@ -214,12 +214,12 @@ public function get_payment_fields_js_config() {
$payment_fields['accountDescriptor'] = $this->gateway->get_account_statement_descriptor();
$payment_fields['addPaymentReturnURL'] = wc_get_account_endpoint_url( 'payment-methods' );
- $payment_fields['gatewayId'] = UPE_Payment_Gateway::GATEWAY_ID;
+ $payment_fields['gatewayId'] = WC_Payment_Gateway_WCPay::GATEWAY_ID;
$payment_fields['isCheckout'] = is_checkout();
$payment_fields['paymentMethodsConfig'] = $this->get_enabled_payment_method_config();
$payment_fields['testMode'] = WC_Payments::mode()->is_test();
- $payment_fields['upeAppearance'] = get_transient( UPE_Payment_Gateway::UPE_APPEARANCE_TRANSIENT );
- $payment_fields['wcBlocksUPEAppearance'] = get_transient( UPE_Payment_Gateway::WC_BLOCKS_UPE_APPEARANCE_TRANSIENT );
+ $payment_fields['upeAppearance'] = get_transient( WC_Payment_Gateway_WCPay::UPE_APPEARANCE_TRANSIENT );
+ $payment_fields['wcBlocksUPEAppearance'] = get_transient( WC_Payment_Gateway_WCPay::WC_BLOCKS_UPE_APPEARANCE_TRANSIENT );
$payment_fields['cartContainsSubscription'] = $this->gateway->is_subscription_item_in_cart();
$payment_fields['currency'] = get_woocommerce_currency();
$cart_total = ( WC()->cart ? WC()->cart->get_total( '' ) : 0 );
@@ -260,7 +260,7 @@ public function get_payment_fields_js_config() {
$payment_fields['orderReturnURL'] = esc_url_raw(
add_query_arg(
[
- 'wc_payment_method' => UPE_Payment_Gateway::GATEWAY_ID,
+ 'wc_payment_method' => WC_Payment_Gateway_WCPay::GATEWAY_ID,
'_wpnonce' => wp_create_nonce( 'wcpay_process_redirect_order_nonce' ),
],
$this->gateway->get_return_url( $order )
diff --git a/includes/class-wc-payments-payment-method-messaging-element.php b/includes/class-wc-payments-payment-method-messaging-element.php
index 6fe6006188f..3d951d13cc5 100644
--- a/includes/class-wc-payments-payment-method-messaging-element.php
+++ b/includes/class-wc-payments-payment-method-messaging-element.php
@@ -10,7 +10,7 @@
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
-use WCPay\Payment_Methods\UPE_Payment_Gateway;
+use WC_Payment_Gateway_WCPay;
/**
* WC_Payments_Payment_Method_Messaging_Element class.
*/
@@ -24,15 +24,15 @@ class WC_Payments_Payment_Method_Messaging_Element {
/**
* WC_Payments_Gateway instance to get information about the enabled payment methods.
*
- * @var UPE_Payment_Gateway
+ * @var WC_Payment_Gateway_WCPay
*/
private $gateway;
/**
* WC_Payments_Payment_Method_Messaging_Element constructor
*
- * @param WC_Payments_Account $account Account instance.
- * @param UPE_Payment_Gateway $gateway Gateway instance.
+ * @param WC_Payments_Account $account Account instance.
+ * @param WC_Payment_Gateway_WCPay $gateway Gateway instance.
* @return void
*/
public function __construct( WC_Payments_Account $account, $gateway ) {
diff --git a/includes/class-wc-payments.php b/includes/class-wc-payments.php
index f171f9b07d6..0677eaa5a1b 100644
--- a/includes/class-wc-payments.php
+++ b/includes/class-wc-payments.php
@@ -12,7 +12,6 @@
use WCPay\Core\Mode;
use WCPay\Core\Server\Request;
use WCPay\Migrations\Allowed_Payment_Request_Button_Types_Update;
-use WCPay\Payment_Methods\CC_Payment_Gateway;
use WCPay\Payment_Methods\CC_Payment_Method;
use WCPay\Payment_Methods\Bancontact_Payment_Method;
use WCPay\Payment_Methods\Becs_Payment_Method;
@@ -21,7 +20,6 @@
use WCPay\Payment_Methods\P24_Payment_Method;
use WCPay\Payment_Methods\Sepa_Payment_Method;
use WCPay\Payment_Methods\Sofort_Payment_Method;
-use WCPay\Payment_Methods\UPE_Payment_Gateway;
use WCPay\Payment_Methods\Ideal_Payment_Method;
use WCPay\Payment_Methods\Eps_Payment_Method;
use WCPay\Payment_Methods\UPE_Payment_Method;
@@ -51,24 +49,9 @@ class WC_Payments {
/**
* Main payment gateway controller instance, created in init function.
*
- * @var WC_Payment_Gateway_WCPay|UPE_Payment_Gateway
- */
- private static $card_gateway;
-
- /**
- * Instance of WC_Payment_Gateway_WCPay to register as payment gateway.
- *
* @var WC_Payment_Gateway_WCPay
*/
- private static $legacy_card_gateway;
-
- /**
- * Copy of either $card_gateway or $legacy_card_gateway,
- * depending on which gateway is registered as main CC gateway.
- *
- * @var WC_Payment_Gateway_WCPay|UPE_Payment_Gateway
- */
- private static $registered_card_gateway;
+ private static $card_gateway;
/**
* Instance of WC_Payments_API_Client, created in init function.
@@ -211,25 +194,18 @@ class WC_Payments {
private static $webhook_processing_service;
/**
- * Maps all availabled Stripe payment method IDs to UPE Payment Method instances.
+ * Maps all availabled Stripe payment method IDs to Payment Method instances.
*
* @var array
*/
- private static $upe_payment_method_map = [];
+ private static $payment_method_map = [];
/**
- * Maps all availabled Stripe payment method IDs to UPE Payment Gateway instances.
+ * Maps all availabled Stripe payment method IDs to Payment Gateway instances.
*
* @var array
*/
- private static $upe_payment_gateway_map = [];
-
- /**
- * Map to store all the available split upe checkouts
- *
- * @var array
- */
- private static $upe_checkout_map = [];
+ private static $payment_gateway_map = [];
/**
* Instance of WC_Payments_Webhook_Reliability_Service, created in init function
@@ -405,7 +381,6 @@ public static function init() {
include_once __DIR__ . '/class-wc-payment-gateway-wcpay.php';
include_once __DIR__ . '/class-wc-payments-checkout.php';
include_once __DIR__ . '/payment-methods/class-cc-payment-gateway.php';
- include_once __DIR__ . '/payment-methods/class-upe-payment-gateway.php';
include_once __DIR__ . '/payment-methods/class-upe-payment-method.php';
include_once __DIR__ . '/payment-methods/class-cc-payment-method.php';
include_once __DIR__ . '/payment-methods/class-bancontact-payment-method.php';
@@ -523,8 +498,6 @@ public static function init() {
self::$incentives_service->init_hooks();
self::$compatibility_service->init_hooks();
- self::$legacy_card_gateway = new CC_Payment_Gateway( self::$api_client, self::$account, self::$customer_service, self::$token_service, self::$action_scheduler_service, self::$failed_transaction_rate_limiter, self::$order_service, self::$duplicate_payment_prevention_service, self::$localization_service, self::$fraud_service );
-
$payment_method_classes = [
CC_Payment_Method::class,
Bancontact_Payment_Method::class,
@@ -547,16 +520,16 @@ public static function init() {
$payment_methods[ $payment_method->get_id() ] = $payment_method;
}
foreach ( $payment_methods as $payment_method ) {
- self::$upe_payment_method_map[ $payment_method->get_id() ] = $payment_method;
+ self::$payment_method_map[ $payment_method->get_id() ] = $payment_method;
- $split_gateway = new UPE_Payment_Gateway( self::$api_client, self::$account, self::$customer_service, self::$token_service, self::$action_scheduler_service, $payment_method, $payment_methods, self::$failed_transaction_rate_limiter, self::$order_service, self::$duplicate_payment_prevention_service, self::$localization_service, self::$fraud_service );
+ $split_gateway = new WC_Payment_Gateway_WCPay( self::$api_client, self::$account, self::$customer_service, self::$token_service, self::$action_scheduler_service, $payment_method, $payment_methods, self::$failed_transaction_rate_limiter, self::$order_service, self::$duplicate_payment_prevention_service, self::$localization_service, self::$fraud_service );
// Card gateway hooks are registered once below.
if ( 'card' !== $payment_method->get_id() ) {
$split_gateway->init_hooks();
}
- self::$upe_payment_gateway_map[ $payment_method->get_id() ] = $split_gateway;
+ self::$payment_gateway_map[ $payment_method->get_id() ] = $split_gateway;
}
self::$card_gateway = self::get_payment_gateway_by_id( 'card' );
@@ -765,23 +738,21 @@ public static function register_gateway( $gateways ) {
self::get_gateway()->update_option( 'upe_enabled_payment_method_ids', $payment_methods );
}
- self::$registered_card_gateway = self::$card_gateway;
-
- $gateways[] = self::$registered_card_gateway;
- $all_upe_gateways = [];
+ $gateways[] = self::$card_gateway;
+ $all_gateways = [];
$reusable_methods = [];
foreach ( $payment_methods as $payment_method_id ) {
if ( 'card' === $payment_method_id || 'link' === $payment_method_id ) {
continue;
}
- $upe_gateway = self::get_payment_gateway_by_id( $payment_method_id );
- $upe_payment_method = self::get_payment_method_by_id( $payment_method_id );
+ $gateway = self::get_payment_gateway_by_id( $payment_method_id );
+ $payment_method = self::get_payment_method_by_id( $payment_method_id );
- if ( $upe_payment_method->is_reusable() ) {
- $reusable_methods[] = $upe_gateway;
+ if ( $payment_method->is_reusable() ) {
+ $reusable_methods[] = $gateway;
}
- $all_upe_gateways[] = $upe_gateway;
+ $all_gateways[] = $gateway;
}
@@ -789,25 +760,7 @@ public static function register_gateway( $gateways ) {
return array_merge( $gateways, $reusable_methods );
}
- return array_merge( $gateways, $all_upe_gateways );
- }
-
- /**
- * Returns main CC gateway registered for WCPay.
- *
- * @return WC_Payment_Gateway_WCPay|UPE_Payment_Gateway
- */
- public static function get_registered_card_gateway() {
- return self::$registered_card_gateway;
- }
-
- /**
- * Sets registered card gateway instance.
- *
- * @param WC_Payment_Gateway_WCPay|UPE_Payment_Gateway $gateway Gateway instance.
- */
- public static function set_registered_card_gateway( $gateway ) {
- self::$registered_card_gateway = $gateway;
+ return array_merge( $gateways, $all_gateways );
}
/**
@@ -816,7 +769,7 @@ public static function set_registered_card_gateway( $gateway ) {
* Remove all WCPay gateways except CC one.
*/
public static function hide_gateways_on_settings_page() {
- $default_gateway = self::get_registered_card_gateway();
+ $default_gateway = self::get_gateway();
foreach ( WC()->payment_gateways->payment_gateways as $index => $payment_gateway ) {
if ( $payment_gateway instanceof WC_Payment_Gateway_WCPay && $payment_gateway !== $default_gateway ) {
unset( WC()->payment_gateways->payment_gateways[ $index ] );
@@ -1153,26 +1106,26 @@ public static function register_script_with_dependencies( string $handler, strin
* Returns payment method instance by Stripe ID.
*
* @param string $payment_method_id Stripe payment method type ID.
- * @return false|UPE_Payment_Method Matching UPE Payment Method instance.
+ * @return false|UPE_Payment_Method Matching Payment Method instance.
*/
public static function get_payment_method_by_id( $payment_method_id ) {
- if ( ! isset( self::$upe_payment_method_map[ $payment_method_id ] ) ) {
+ if ( ! isset( self::$payment_method_map[ $payment_method_id ] ) ) {
return false;
}
- return self::$upe_payment_method_map[ $payment_method_id ];
+ return self::$payment_method_map[ $payment_method_id ];
}
/**
* Returns payment gateway instance by Stripe ID.
*
* @param string $payment_method_id Stripe payment method type ID.
- * @return false|UPE_Payment_Gateway Matching UPE Payment Gateway instance.
+ * @return false|WC_Payment_Gateway_WCPay Matching Payment Gateway instance.
*/
public static function get_payment_gateway_by_id( $payment_method_id ) {
- if ( ! isset( self::$upe_payment_gateway_map[ $payment_method_id ] ) ) {
+ if ( ! isset( self::$payment_gateway_map[ $payment_method_id ] ) ) {
return false;
}
- return self::$upe_payment_gateway_map[ $payment_method_id ];
+ return self::$payment_gateway_map[ $payment_method_id ];
}
/**
@@ -1181,13 +1134,13 @@ public static function get_payment_gateway_by_id( $payment_method_id ) {
* @return array
*/
public static function get_payment_method_map() {
- return self::$upe_payment_method_map;
+ return self::$payment_method_map;
}
/**
* Returns the WC_Payment_Gateway_WCPay instance
*
- * @return WC_Payment_Gateway_WCPay|UPE_Payment_Gateway gateway instance
+ * @return WC_Payment_Gateway_WCPay gateway instance
*/
public static function get_gateway() {
return self::$card_gateway;
@@ -1223,7 +1176,7 @@ public static function set_database_cache( Database_Cache $database_cache ) {
/**
* Sets the card gateway instance.
*
- * @param WC_Payment_Gateway_WCPay|UPE_Payment_Gateway $gateway The card gateway instance..
+ * @param WC_Payment_Gateway_WCPay $gateway The card gateway instance..
*/
public static function set_gateway( $gateway ) {
self::$card_gateway = $gateway;
diff --git a/includes/payment-methods/class-upe-payment-gateway.php b/includes/payment-methods/class-upe-payment-gateway.php
deleted file mode 100644
index eff6d3ad1d8..00000000000
--- a/includes/payment-methods/class-upe-payment-gateway.php
+++ /dev/null
@@ -1,1138 +0,0 @@
-title = $payment_method->get_title();
- $this->method_description = __( 'Payments made simple, with no monthly fees - designed exclusively for WooCommerce stores. Accept credit cards, debit cards, and other popular payment methods.', 'woocommerce-payments' );
- $this->description = '';
- $this->checkout_title = __( 'Popular payment methods', 'woocommerce-payments' );
- $this->payment_methods = $payment_methods;
-
- $this->stripe_id = $payment_method->get_id();
- $this->payment_method = $payment_method;
- $this->icon = $payment_method->get_icon();
-
- if ( 'card' !== $this->stripe_id ) {
- $this->id = self::GATEWAY_ID . '_' . $this->stripe_id;
- $this->method_title = "WooPayments ($this->title)";
- }
- }
-
- /**
- * Displays HTML tags for WC payment gateway radio button content.
- */
- public function display_gateway_html() {
- ?>
-
- get_selected_stripe_payment_type_id() );
- do_action( 'wc_payments_add_upe_payment_fields' );
- }
-
- /**
- * Update payment intent for completed checkout and return redirect URL for Stripe to confirm payment.
- *
- * @param int $order_id Order ID to process the payment for.
- *
- * @return array|null An array with result of payment and redirect URL, or nothing.
- * @throws Exception Error processing the payment.
- * @throws Order_Not_Found_Exception
- */
- public function process_payment( $order_id ) {
- $order = wc_get_order( $order_id );
-
- if ( 20 < strlen( $order->get_billing_phone() ) ) {
- throw new Process_Payment_Exception(
- __( 'Invalid phone number.', 'woocommerce-payments' ),
- 'invalid_phone_number'
- );
- }
- $payment_intent_id = isset( $_POST['wc_payment_intent_id'] ) ? wc_clean( wp_unslash( $_POST['wc_payment_intent_id'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
- $amount = $order->get_total();
- $currency = $order->get_currency();
- $converted_amount = WC_Payments_Utils::prepare_amount( $amount, $currency );
- $payment_needed = 0 < $converted_amount;
- $payment_type = $this->is_payment_recurring( $order_id ) ? Payment_Type::RECURRING() : Payment_Type::SINGLE();
- $save_payment_method = $payment_type->equals( Payment_Type::RECURRING() ) || ! empty( $_POST[ 'wc-' . $this->id . '-new-payment-method' ] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
- $payment_country = ! empty( $_POST['wcpay_payment_country'] ) ? wc_clean( wp_unslash( $_POST['wcpay_payment_country'] ) ) : null; // phpcs:ignore WordPress.Security.NonceVerification.Missing
-
- if ( $payment_intent_id ) {
- list( $user, $customer_id ) = $this->manage_customer_details_for_order( $order );
-
- if ( $payment_needed ) {
- // Check if session exists before instantiating Fraud_Prevention_Service.
- if ( WC()->session ) {
- $fraud_prevention_service = Fraud_Prevention_Service::get_instance();
- // phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
- if ( $fraud_prevention_service->is_enabled() && ! $fraud_prevention_service->verify_token( $_POST['wcpay-fraud-prevention-token'] ?? null ) ) {
- throw new Process_Payment_Exception(
- __( "We're not able to process this payment. Please refresh the page and try again.", 'woocommerce-payments' ),
- 'fraud_prevention_enabled'
- );
- }
- }
-
- if ( $this->failed_transaction_rate_limiter->is_limited() ) {
- // Throwing an exception instead of adding an error notice
- // makes the error notice show up both in the regular and block checkout.
- throw new Exception( __( 'Your payment was not processed.', 'woocommerce-payments' ) );
- }
-
- // Try catching the error without reaching the API.
- $minimum_amount = WC_Payments_Utils::get_cached_minimum_amount( $currency );
- if ( $minimum_amount > $converted_amount ) {
- $exception = new Amount_Too_Small_Exception( 'Amount too small', $minimum_amount, $currency, 400 );
- throw new Exception( WC_Payments_Utils::get_filtered_error_message( $exception ) );
- }
-
- $check_session_order = $this->duplicate_payment_prevention_service->check_against_session_processing_order( $order );
- if ( is_array( $check_session_order ) ) {
- return $check_session_order;
- }
- $this->duplicate_payment_prevention_service->maybe_update_session_processing_order( $order_id );
-
- $check_existing_intention = $this->duplicate_payment_prevention_service->check_payment_intent_attached_to_order_succeeded( $order );
- if ( is_array( $check_existing_intention ) ) {
- return $check_existing_intention;
- }
-
- // @toDo: This is now not used?
- $additional_api_parameters = $this->get_mandate_params_for_order( $order );
-
- try {
- $payment_methods = $this->get_selected_upe_payment_methods( $this->stripe_id, $this->get_payment_method_ids_enabled_at_checkout( null, true ) ?? [] );
-
- $request = Update_Intention::create( $payment_intent_id );
- $request->set_currency_code( strtolower( $currency ) );
- $request->set_amount( WC_Payments_Utils::prepare_amount( $amount, $currency ) );
- $request->set_metadata( $this->get_metadata_from_order( $order, $payment_type ) );
- $request->set_level3( $this->get_level3_data_from_order( $order ) );
- $request->set_payment_method_types( $payment_methods );
- $request->set_hook_args( $order, $payment_intent_id );
- if ( $payment_country ) {
- $request->set_payment_country( $payment_country );
- }
- if ( true === $save_payment_method ) {
- $request->setup_future_usage();
- }
- if ( $customer_id ) {
- $request->set_customer( $customer_id );
- }
- $payment_method_options = $this->get_mandate_params_for_order( $order );
- if ( $payment_method_options ) {
- $request->setup_future_usage();
- $request->set_payment_method_options( $payment_method_options );
- }
- $updated_payment_intent = $request->send();
- } catch ( Amount_Too_Small_Exception $e ) {
- // This code would only be reached if the cache has already expired.
- throw new Exception( WC_Payments_Utils::get_filtered_error_message( $e ) );
- } catch ( API_Exception $e ) {
- if ( 'wcpay_blocked_by_fraud_rule' === $e->get_error_code() ) {
- $this->order_service->mark_order_blocked_for_fraud( $order, $payment_intent_id, Intent_Status::CANCELED );
- }
- throw $e;
- }
-
- $intent_id = $updated_payment_intent->get_id();
- $intent_status = $updated_payment_intent->get_status();
- $payment_method = $updated_payment_intent->get_payment_method_id();
- $charge = $updated_payment_intent->get_charge();
- $payment_method_details = $charge ? $charge->get_payment_method_details() : [];
- $payment_method_type = $this->get_payment_method_type_from_payment_details( $payment_method_details );
- $charge_id = $charge ? $charge->get_id() : null;
-
- /**
- * Attach the intent and exchange info to the order before doing the redirect, just in case the redirect
- * either does not complete properly, or the Stripe webhook which processes a successful order hits before
- * the redirect completes.
- */
- $this->order_service->attach_intent_info_to_order( $order, $intent_id, $intent_status, $payment_method, $customer_id, $charge_id, $currency );
- $this->attach_exchange_info_to_order( $order, $charge_id );
- $this->set_payment_method_title_for_order( $order, $payment_method_type, $payment_method_details );
- if ( Intent_Status::SUCCEEDED === $intent_status ) {
- $this->duplicate_payment_prevention_service->remove_session_processing_order( $order->get_id() );
- }
- $this->order_service->update_order_status_from_intent( $order, $updated_payment_intent );
-
- $last_payment_error_code = $updated_payment_intent->get_last_payment_error()['code'] ?? '';
- if ( $this->should_bump_rate_limiter( $last_payment_error_code ) ) {
- // UPE method gives us the error of the previous payment attempt, so we use that for the Rate Limiter.
- $this->failed_transaction_rate_limiter->bump();
- }
- }
- } else {
- return $this->parent_process_payment( $order_id );
- }
-
- return [ // nosemgrep: audit.php.wp.security.xss.query-arg -- The output of add_query_arg is being escaped.
- 'result' => 'success',
- 'payment_needed' => $payment_needed,
- 'redirect_url' => wp_sanitize_redirect(
- esc_url_raw(
- add_query_arg(
- [
- 'wc_payment_method' => self::GATEWAY_ID,
- '_wpnonce' => wp_create_nonce( 'wcpay_process_redirect_order_nonce' ),
- 'save_payment_method' => $save_payment_method ? 'yes' : 'no',
- ],
- $this->get_return_url( $order )
- )
- )
- ),
- ];
- }
-
- /**
- * Returns true when viewing payment methods page.
- *
- * @return bool
- */
- private function is_payment_methods_page() {
- global $wp;
-
- $page_id = wc_get_page_id( 'myaccount' );
-
- return ( $page_id && is_page( $page_id ) && ( isset( $wp->query_vars['payment-methods'] ) ) );
- }
-
- /**
- * Get selected UPE payment methods.
- *
- * @param string $selected_upe_payment_type Selected payment methods.
- * @param array $enabled_payment_methods Enabled payment methods.
- *
- * @return array
- */
- protected function get_selected_upe_payment_methods( string $selected_upe_payment_type, array $enabled_payment_methods ) {
- $payment_methods = [];
- if ( '' !== $selected_upe_payment_type ) {
- // Only update the payment_method_types if we have a reference to the payment type the customer selected.
- $payment_methods[] = $selected_upe_payment_type;
-
- if ( CC_Payment_Method::PAYMENT_METHOD_STRIPE_ID === $selected_upe_payment_type ) {
- $is_link_enabled = in_array(
- Link_Payment_Method::PAYMENT_METHOD_STRIPE_ID,
- $enabled_payment_methods,
- true
- );
- if ( $is_link_enabled ) {
- $payment_methods[] = Link_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
- }
- }
- }
- return $payment_methods;
- }
- /**
- * Check for a redirect payment method on order received page or setup intent on payment methods page.
- */
- public function maybe_process_upe_redirect() {
- if ( $this->is_payment_methods_page() ) {
- // If a payment method was added using UPE, we need to clear the cache and notify the user.
- if ( $this->is_setup_intent_success_creation_redirection() ) {
- wc_add_notice( __( 'Payment method successfully added.', 'woocommerce-payments' ) );
- $user = wp_get_current_user();
- $this->customer_service->clear_cached_payment_methods_for_user( $user->ID );
- }
- return;
- }
-
- if ( ! is_order_received_page() ) {
- return;
- }
-
- $payment_method = isset( $_GET['wc_payment_method'] ) ? wc_clean( wp_unslash( $_GET['wc_payment_method'] ) ) : '';
- if ( self::GATEWAY_ID !== $payment_method ) {
- return;
- }
-
- $is_nonce_valid = check_admin_referer( 'wcpay_process_redirect_order_nonce' );
- if ( ! $is_nonce_valid || empty( $_GET['wc_payment_method'] ) ) {
- return;
- }
-
- if ( ! empty( $_GET['payment_intent_client_secret'] ) ) {
- $intent_id_from_request = isset( $_GET['payment_intent'] ) ? wc_clean( wp_unslash( $_GET['payment_intent'] ) ) : '';
- } elseif ( ! empty( $_GET['setup_intent_client_secret'] ) ) {
- $intent_id_from_request = isset( $_GET['setup_intent'] ) ? wc_clean( wp_unslash( $_GET['setup_intent'] ) ) : '';
- } else {
- return;
- }
-
- $order_id = absint( get_query_var( 'order-received' ) );
- $order_key_from_request = isset( $_GET['key'] ) ? wc_clean( wp_unslash( $_GET['key'] ) ) : '';
- $save_payment_method = isset( $_GET['save_payment_method'] ) ? 'yes' === wc_clean( wp_unslash( $_GET['save_payment_method'] ) ) : false;
-
- if ( empty( $intent_id_from_request ) || empty( $order_id ) || empty( $order_key_from_request ) ) {
- return;
- }
-
- $order = wc_get_order( $order_id );
-
- if ( ! is_a( $order, 'WC_Order' ) ) {
- // the ID of non-existing order was passed in.
- return;
- }
-
- if ( $order->get_order_key() !== $order_key_from_request ) {
- // Valid return url should have matching order key.
- return;
- }
-
- // Perform additional checks for non-zero-amount. For zero-amount orders, we can't compare intents because they are not attached to the order at this stage.
- // Once https://github.com/Automattic/woocommerce-payments/issues/6575 is closed, this check can be applied for zero-amount orders as well.
- if ( $order->get_total() > 0 && ! $this->is_proper_intent_used_with_order( $order, $intent_id_from_request ) ) {
- return;
- }
-
- $this->process_redirect_payment( $order, $intent_id_from_request, $save_payment_method );
- }
-
- /**
- * Processes redirect payments.
- *
- * @param WC_Order $order The order being processed.
- * @param string $intent_id The Stripe setup/payment intent ID for the order payment.
- * @param bool $save_payment_method Boolean representing whether payment method for order should be saved.
- *
- * @throws Process_Payment_Exception When the payment intent has an error.
- */
- public function process_redirect_payment( $order, $intent_id, $save_payment_method ) {
- try {
- $order_id = $order->get_id();
- if ( $order->has_status(
- [
- Order_Status::PROCESSING,
- Order_Status::COMPLETED,
- Order_Status::ON_HOLD,
- ]
- ) ) {
- return;
- }
-
- Logger::log( "Begin processing UPE redirect payment for order {$order_id} for the amount of {$order->get_total()}" );
-
- // Get user/customer for order.
- list( $user, $customer_id ) = $this->manage_customer_details_for_order( $order );
-
- $payment_needed = 0 < $order->get_total();
-
- // Get payment intent to confirm status.
- if ( $payment_needed ) {
- $request = Get_Intention::create( $intent_id );
- $request->set_hook_args( $order );
- /** @var WC_Payments_API_Payment_Intention $intent */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort
- $intent = $request->send();
- $client_secret = $intent->get_client_secret();
- $status = $intent->get_status();
- $charge = $intent->get_charge();
- $charge_id = $charge ? $charge->get_id() : null;
- $currency = $intent->get_currency();
- $payment_method_id = $intent->get_payment_method_id();
- $payment_method_details = $charge ? $charge->get_payment_method_details() : [];
- $payment_method_type = $this->get_payment_method_type_from_payment_details( $payment_method_details );
- $error = $intent->get_last_payment_error();
-
- // This check applies to payment intents only due to two reasons:
- // (1) metadata is missed for setup intents. See https://github.com/Automattic/woocommerce-payments/issues/6575.
- // (2) most issues so far affect only payment intents.
- $intent_metadata = is_array( $intent->get_metadata() ) ? $intent->get_metadata() : [];
- $this->validate_order_id_received_vs_intent_meta_order_id( $order, $intent_metadata );
- } else {
- $request = Get_Setup_Intention::create( $intent_id );
- /** @var WC_Payments_API_Setup_Intention $intent */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort
- $intent = $request->send();
- $client_secret = $intent->get_client_secret();
- $status = $intent->get_status();
- $charge_id = '';
- $charge = null;
- $currency = $order->get_currency();
- $payment_method_id = $intent->get_payment_method_id();
- $payment_method_details = false;
- $payment_method_type = $intent->get_payment_method_type();
- $error = $intent->get_last_setup_error();
- }
-
- if ( ! empty( $error ) ) {
- Logger::log( 'Error when processing payment: ' . $error['message'] );
- throw new Process_Payment_Exception(
- __( "We're not able to process this payment. Please try again later.", 'woocommerce-payments' ),
- 'upe_payment_intent_error'
- );
- } else {
- $payment_method = $this->get_selected_payment_method( $payment_method_type );
- if ( ! $payment_method ) {
- return;
- }
-
- if ( $save_payment_method && $payment_method->is_reusable() ) {
- try {
- $token = $payment_method->get_payment_token_for_user( $user, $payment_method_id );
- $this->add_token_to_order( $order, $token );
- } catch ( Exception $e ) {
- // If saving the token fails, log the error message but catch the error to avoid crashing the checkout flow.
- Logger::log( 'Error when saving payment method: ' . $e->getMessage() );
- }
- }
-
- $this->order_service->attach_intent_info_to_order( $order, $intent_id, $status, $payment_method_id, $customer_id, $charge_id, $currency );
- $this->attach_exchange_info_to_order( $order, $charge_id );
- if ( Intent_Status::SUCCEEDED === $status ) {
- $this->duplicate_payment_prevention_service->remove_session_processing_order( $order->get_id() );
- }
- $this->order_service->update_order_status_from_intent( $order, $intent );
- $this->set_payment_method_title_for_order( $order, $payment_method_type, $payment_method_details );
- $this->order_service->attach_transaction_fee_to_order( $order, $charge );
-
- if ( Intent_Status::REQUIRES_ACTION === $status ) {
- // I don't think this case should be possible, but just in case...
- $next_action = $intent->get_next_action();
- if ( isset( $next_action['type'] ) && 'redirect_to_url' === $next_action['type'] && ! empty( $next_action['redirect_to_url']['url'] ) ) {
- wp_safe_redirect( $next_action['redirect_to_url']['url'] );
- exit;
- } else {
- $redirect_url = sprintf(
- '#wcpay-confirm-%s:%s:%s:%s',
- $payment_needed ? 'pi' : 'si',
- $order_id,
- WC_Payments_Utils::encrypt_client_secret( $this->account->get_stripe_account_id(), $client_secret ),
- wp_create_nonce( 'wcpay_update_order_status_nonce' )
- );
- wp_safe_redirect( $redirect_url );
- exit;
- }
- }
- }
- } catch ( Exception $e ) {
- Logger::log( 'Error: ' . $e->getMessage() );
-
- $is_order_id_mismatched_exception =
- is_a( $e, Process_Payment_Exception::class )
- && self::PROCESS_REDIRECT_ORDER_MISMATCH_ERROR_CODE === $e->get_error_code();
-
- // If the order ID mismatched exception is thrown, do not mark the order as failed.
- // Because the outcome of the payment intent is for another order, not for the order processed here.
- if ( ! $is_order_id_mismatched_exception ) {
- // Confirm our needed variables are set before using them due to there could be a server issue during the get_intent process.
- $status = $status ?? null;
- $charge_id = $charge_id ?? null;
-
- /* translators: localized exception message */
- $message = sprintf( __( 'UPE payment failed: %s', 'woocommerce-payments' ), $e->getMessage() );
- $this->order_service->mark_payment_failed( $order, $intent_id, $status, $charge_id, $message );
- }
-
- wc_add_notice( WC_Payments_Utils::get_filtered_error_message( $e ), 'error' );
-
- $redirect_url = wc_get_checkout_url();
- if ( $is_order_id_mismatched_exception ) {
- $redirect_url = add_query_arg( self::PROCESS_REDIRECT_ORDER_MISMATCH_ERROR_CODE, 'yes', $redirect_url );
- }
- wp_safe_redirect( $redirect_url );
- exit;
- }
- }
-
- /**
- * Verifies that the proper intent is used to process the order.
- *
- * @param WC_Order $order The order object based on the order_id received from the request.
- * @param string $intent_id_from_request The intent ID received from the request.
- *
- * @return bool True if the proper intent is used to process the order, false otherwise.
- */
- public function is_proper_intent_used_with_order( $order, $intent_id_from_request ) {
- $intent_id_attached_to_order = $this->order_service->get_intent_id_for_order( $order );
- if ( ! hash_equals( $intent_id_attached_to_order, $intent_id_from_request ) ) {
- Logger::error(
- sprintf(
- 'Intent ID mismatch. Received in request: %1$s. Attached to order: %2$s. Order ID: %3$d',
- $intent_id_from_request,
- $intent_id_attached_to_order,
- $order->get_id()
- )
- );
- return false;
- }
- return true;
- }
-
- /**
- * Generates the configuration values, needed for UPE payment fields.
- *
- * @deprecated 5.0.0
- *
- * @return array
- */
- public function get_payment_fields_js_config() {
- wc_deprecated_function( __FUNCTION__, '5.0.0', 'WC_Payments_Checkout::get_payment_fields_js_config' );
- return WC_Payments::get_wc_payments_checkout()->get_payment_fields_js_config();
- }
-
- /**
- * True if the request contains the values that indicates a redirection after a successful setup intent creation.
- *
- * @return bool
- */
- public function is_setup_intent_success_creation_redirection() {
- return ! empty( $_GET['setup_intent_client_secret'] ) && // phpcs:ignore WordPress.Security.NonceVerification.Recommended
- ! empty( $_GET['setup_intent'] ) && // phpcs:ignore WordPress.Security.NonceVerification.Recommended
- ! empty( $_GET['redirect_status'] ) && // phpcs:ignore WordPress.Security.NonceVerification.Recommended
- 'succeeded' === $_GET['redirect_status']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
- }
-
- /**
- * Adds a token to current user from a setup intent id.
- *
- * @param string $setup_intent_id ID of the setup intent.
- * @param WP_User $user User to add token to.
- *
- * @return WC_Payment_Token_CC|WC_Payment_Token_WCPay_SEPA|null The added token.
- */
- public function create_token_from_setup_intent( $setup_intent_id, $user ) {
- try {
- $setup_intent_request = Get_Setup_Intention::create( $setup_intent_id );
- /** @var WC_Payments_API_Setup_Intention $setup_intent */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort
- $setup_intent = $setup_intent_request->send();
-
- $payment_method_id = $setup_intent->get_payment_method_id();
- // TODO: When adding SEPA and Sofort, we will need a new API call to get the payment method and from there get the type.
- // Leaving 'card' as a hardcoded value for now to avoid the extra API call.
- // $payment_method = $this->payment_methods['card'];// Maybe this should be enforced.
- $payment_method = $this->payment_method;
-
- return $payment_method->get_payment_token_for_user( $user, $payment_method_id );
- } catch ( Exception $e ) {
- wc_add_notice( WC_Payments_Utils::get_filtered_error_message( $e ), 'error', [ 'icon' => 'error' ] );
- Logger::log( 'Error when adding payment method: ' . $e->getMessage() );
- }
- }
-
- /**
- * Mandate must be shown and acknowledged by customer before deferred intent UPE payment can be processed.
- * This applies to SEPA and Link payment methods.
- * https://stripe.com/docs/payments/finalize-payments-on-the-server
- *
- * @return boolean True if mandate must be shown and acknowledged by customer before deferred intent UPE payment can be processed, false otherwise.
- */
- public function is_mandate_data_required() {
- $is_stripe_link_enabled = Payment_Method::CARD === $this->get_selected_stripe_payment_type_id() && in_array( Payment_Method::LINK, $this->get_upe_enabled_payment_method_ids(), true );
- $is_sepa_debit_payment = Payment_Method::SEPA === $this->get_selected_stripe_payment_type_id();
-
- return $is_stripe_link_enabled || $is_sepa_debit_payment;
- }
-
- /**
- * Returns the Stripe payment type of the selected payment method.
- *
- * @return string
- */
- public function get_selected_stripe_payment_type_id() {
- return $this->stripe_id;
- }
-
- /**
- * Set formatted readable payment method title for order,
- * using payment method details from accompanying charge.
- *
- * @param \WC_Order $order WC Order being processed.
- * @param string $payment_method_type Stripe payment method key.
- * @param array|bool $payment_method_details Array of payment method details from charge or false.
- */
- public function set_payment_method_title_for_order( $order, $payment_method_type, $payment_method_details ) {
- $payment_method = $this->get_selected_payment_method( $payment_method_type );
- if ( ! $payment_method ) {
- return;
- }
-
- $payment_method_title = $payment_method->get_title( $payment_method_details );
-
- $payment_gateway = in_array( $payment_method->get_id(), [ Payment_Method::CARD, Payment_Method::LINK ], true ) ? self::GATEWAY_ID : self::GATEWAY_ID . '_' . $payment_method_type;
-
- $order->set_payment_method( $payment_gateway );
- $order->set_payment_method_title( $payment_method_title );
- $order->save();
- }
-
- /**
- * Returns the list of enabled payment method types that will function with the current checkout.
- *
- * @param string $order_id optional Order ID.
- * @param bool $force_currency_check optional Whether the currency check is required even if is_admin().
- *
- * @return string[]
- */
- public function get_payment_method_ids_enabled_at_checkout( $order_id = null, $force_currency_check = false ) {
- $automatic_capture = empty( $this->get_option( 'manual_capture' ) ) || $this->get_option( 'manual_capture' ) === 'no';
- if ( $automatic_capture ) {
- $upe_enabled_payment_methods = $this->get_upe_enabled_payment_method_ids();
- } else {
- $upe_enabled_payment_methods = array_intersect( $this->get_upe_enabled_payment_method_ids(), [ Payment_Method::CARD, Payment_Method::LINK ] );
- }
- if ( is_wc_endpoint_url( 'order-pay' ) ) {
- $force_currency_check = true;
- }
-
- $enabled_payment_methods = [];
- $active_payment_methods = $this->get_upe_enabled_payment_method_statuses();
-
- foreach ( $upe_enabled_payment_methods as $payment_method_id ) {
- $payment_method_capability_key = $this->payment_method_capability_key_map[ $payment_method_id ] ?? 'undefined_capability_key';
- if ( isset( $this->payment_methods[ $payment_method_id ] ) ) {
- // When creating a payment intent, we need to ensure the currency is matching
- // with the payment methods which are sent with the payment intent request, otherwise
- // Stripe returns an error.
-
- // force_currency_check = 0 is_admin = 0 currency_is_checked = 1.
- // force_currency_check = 0 is_admin = 1 currency_is_checked = 0.
- // force_currency_check = 1 is_admin = 0 currency_is_checked = 1.
- // force_currency_check = 1 is_admin = 1 currency_is_checked = 1.
-
- $skip_currency_check = ! $force_currency_check && is_admin();
- $processing_payment_method = $this->payment_methods[ $payment_method_id ];
- if ( $processing_payment_method->is_enabled_at_checkout( $this->get_account_country() ) && ( $skip_currency_check || $processing_payment_method->is_currency_valid( $this->get_account_domestic_currency(), $order_id ) ) ) {
- $status = $active_payment_methods[ $payment_method_capability_key ]['status'] ?? null;
- if ( 'active' === $status ) {
- $enabled_payment_methods[] = $payment_method_id;
- }
- }
- }
- }
-
- // if credit card payment method is not enabled, we don't use stripe link.
- if (
- ! in_array( CC_Payment_Method::PAYMENT_METHOD_STRIPE_ID, $enabled_payment_methods, true ) &&
- in_array( Link_Payment_Method::PAYMENT_METHOD_STRIPE_ID, $enabled_payment_methods, true ) ) {
- $enabled_payment_methods = array_filter(
- $enabled_payment_methods,
- static function( $method ) {
- return Link_Payment_Method::PAYMENT_METHOD_STRIPE_ID !== $method;
- }
- );
- }
-
- return $enabled_payment_methods;
- }
-
- /**
- * Returns the list of enabled payment method types that will function with the current checkout filtered by fees.
- *
- * @param string $order_id optional Order ID.
- * @param bool $force_currency_check optional Whether the currency check is required even if is_admin().
- *
- * @return string[]
- */
- public function get_payment_method_ids_enabled_at_checkout_filtered_by_fees( $order_id = null, $force_currency_check = false ) {
- $enabled_payment_methods = $this->get_payment_method_ids_enabled_at_checkout( $order_id, $force_currency_check );
- $methods_with_fees = array_keys( $this->account->get_fees() );
-
- return array_values( array_intersect( $enabled_payment_methods, $methods_with_fees ) );
- }
-
- /**
- * Returns the list of available payment method types for UPE.
- * Filtering out those without configured fees, this will prevent a payment method not supported by the Stripe account's country from being returned.
- * Note that we are not taking into account capabilities, which are taken into account when managing payment methods in settings.
- * See https://stripe.com/docs/stripe-js/payment-element#web-create-payment-intent for a complete list.
- *
- * @return string[]
- */
- public function get_upe_available_payment_methods() {
- $available_methods = parent::get_upe_available_payment_methods();
-
- $available_methods[] = Becs_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
- $available_methods[] = Bancontact_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
- $available_methods[] = Eps_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
- $available_methods[] = Giropay_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
- $available_methods[] = Ideal_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
- $available_methods[] = Sofort_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
- $available_methods[] = Sepa_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
- $available_methods[] = P24_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
- $available_methods[] = Link_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
- $available_methods[] = Affirm_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
- $available_methods[] = Afterpay_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
- $available_methods[] = Klarna_Payment_Method::PAYMENT_METHOD_STRIPE_ID;
-
- $available_methods = array_values(
- apply_filters(
- 'wcpay_upe_available_payment_methods',
- $available_methods
- )
- );
-
- $methods_with_fees = array_keys( $this->account->get_fees() );
-
- return array_values( array_intersect( $available_methods, $methods_with_fees ) );
- }
-
- /**
- * Handle AJAX request for saving UPE appearance value to transient.
- *
- * @throws Exception - If nonce or setup intent is invalid.
- */
- public function save_upe_appearance_ajax() {
- try {
- $is_nonce_valid = check_ajax_referer( 'wcpay_save_upe_appearance_nonce', false, false );
- if ( ! $is_nonce_valid ) {
- throw new Exception(
- __( 'Unable to update UPE appearance values at this time.', 'woocommerce-payments' )
- );
- }
-
- $is_blocks_checkout = isset( $_POST['is_blocks_checkout'] ) ? rest_sanitize_boolean( wc_clean( wp_unslash( $_POST['is_blocks_checkout'] ) ) ) : false;
- $appearance = isset( $_POST['appearance'] ) ? json_decode( wc_clean( wp_unslash( $_POST['appearance'] ) ) ) : null;
-
- $appearance_transient = $is_blocks_checkout ? self::WC_BLOCKS_UPE_APPEARANCE_TRANSIENT : self::UPE_APPEARANCE_TRANSIENT;
-
- if ( null !== $appearance ) {
- set_transient( $appearance_transient, $appearance, DAY_IN_SECONDS );
- }
-
- wp_send_json_success( $appearance, 200 );
- } catch ( Exception $e ) {
- // Send back error so it can be displayed to the customer.
- wp_send_json_error(
- [
- 'error' => [
- 'message' => WC_Payments_Utils::get_filtered_error_message( $e ),
- ],
- ],
- WC_Payments_Utils::get_filtered_error_status_code( $e ),
- );
- }
- }
-
- /**
- * Clear the saved UPE appearance transient value.
- */
- public function clear_upe_appearance_transient() {
- delete_transient( self::UPE_APPEARANCE_TRANSIENT );
- delete_transient( self::WC_BLOCKS_UPE_APPEARANCE_TRANSIENT );
- }
-
- /**
- * Validate order_id received from the request vs value saved in the intent metadata.
- * Throw an exception if they're not matched.
- *
- * @param WC_Order $order The received order to process.
- * @param array $intent_metadata The metadata of attached intent to the order.
- *
- * @return void
- * @throws Process_Payment_Exception
- */
- private function validate_order_id_received_vs_intent_meta_order_id( WC_Order $order, array $intent_metadata ): void {
- $intent_meta_order_id_raw = $intent_metadata['order_id'] ?? '';
- $intent_meta_order_id = is_numeric( $intent_meta_order_id_raw ) ? intval( $intent_meta_order_id_raw ) : 0;
-
- if ( $order->get_id() !== $intent_meta_order_id ) {
- Logger::error(
- sprintf(
- 'UPE Process Redirect Payment - Order ID mismatched. Received: %1$d. Intent Metadata Value: %2$d',
- $order->get_id(),
- $intent_meta_order_id
- )
- );
-
- throw new Process_Payment_Exception(
- __( "We're not able to process this payment due to the order ID mismatch. Please try again later.", 'woocommerce-payments' ),
- self::PROCESS_REDIRECT_ORDER_MISMATCH_ERROR_CODE
- );
- }
- }
-
- /**
- * Gets payment method settings to pass to client scripts
- *
- * @deprecated 5.0.0
- *
- * @return array
- */
- private function get_enabled_payment_method_config() {
- wc_deprecated_function( __FUNCTION__, '5.0.0', 'WC_Payments_Checkout::get_enabled_payment_method_config' );
- return WC_Payments::get_wc_payments_checkout()->get_enabled_payment_method_config();
- }
-
- /**
- * Function to be used with array_filter
- * to filter UPE payment methods that support saved payments
- *
- * @param string $payment_method_id Stripe payment method.
- *
- * @return bool
- */
- public function is_enabled_for_saved_payments( $payment_method_id ) {
- $payment_method = $this->get_selected_payment_method( $payment_method_id );
- if ( ! $payment_method ) {
- return false;
- }
- return $payment_method->is_reusable()
- && ( is_admin() || $payment_method->is_currency_valid( $this->get_account_domestic_currency() ) );
- }
-
- /**
- * Returns boolean for whether payment gateway supports saved payments.
- *
- * @return bool True, if gateway supports saved payments. False, otherwise.
- */
- public function should_support_saved_payments() {
- return $this->is_enabled_for_saved_payments( $this->stripe_id );
- }
-
- /**
- * Whether we should use the platform account to initialize Stripe on the checkout page.
- *
- * @return bool Result of the WCPay gateway checks if the card payment method is used, false otherwise.
- */
- public function should_use_stripe_platform_on_checkout_page() {
- if ( 'card' === $this->stripe_id ) {
- return parent::should_use_stripe_platform_on_checkout_page();
- }
- return false;
- }
-
- /**
- * This method is used by WooCommerce Core's WC_Payment_Gateways::get_available_payment_gateways() to filter out gateways.
- *
- * The availability decision includes an additional business rule that checks if the payment method is enabled at checkout
- * via the is_enabled_at_checkout method. This method provides crucial information, among others, to determine if the gateway
- * is reusable in case there's a subcription in the cart.
- *
- * @return bool Whether the gateway is enabled and ready to accept payments.
- */
- public function is_available() {
- $processing_payment_method = $this->payment_methods[ $this->payment_method->get_id() ];
- if ( ! $processing_payment_method->is_enabled_at_checkout( $this->get_account_country() ) ) {
- return false;
- }
- return parent::is_available();
- }
-
- /**
- * Log UPE Payment Errors on Checkout.
- *
- * @throws Exception If nonce is not present or invalid or charge ID is empty or order not found.
- */
- public function log_payment_error_ajax() {
- try {
- $is_nonce_valid = check_ajax_referer( 'wcpay_log_payment_error_nonce', false, false );
- if ( ! $is_nonce_valid ) {
- throw new Exception( 'Invalid request.' );
- }
-
- $charge_id = isset( $_POST['charge_id'] ) ? wc_clean( wp_unslash( $_POST['charge_id'] ) ) : '';
- if ( empty( $charge_id ) ) {
- throw new Exception( 'Charge ID cannot be empty.' );
- }
-
- // Get charge data from WCPay Server.
- $request = Get_Charge::create( $charge_id );
- $request->set_hook_args( $charge_id );
- $charge_data = $request->send();
- $order_id = $charge_data['metadata']['order_id'];
-
- // Validate Order ID and proceed with logging errors and updating order status.
- $order = wc_get_order( $order_id );
- if ( ! $order ) {
- throw new Exception( 'Order not found. Unable to log error.' );
- }
-
- $intent_id = $charge_data['payment_intent'] ?? $order->get_meta( '_intent_id' );
-
- $request = Get_Intention::create( $intent_id );
- $request->set_hook_args( $order );
- $intent = $request->send();
-
- $intent_status = $intent->get_status();
- $error_message = esc_html( rtrim( $charge_data['failure_message'], '.' ) );
-
- $this->order_service->mark_payment_failed( $order, $intent_id, $intent_status, $charge_id, $error_message );
-
- wp_send_json_success();
- } catch ( Exception $e ) {
- wp_send_json_error(
- [
- 'error' => [
- 'message' => WC_Payments_Utils::get_filtered_error_message( $e ),
- ],
- ],
- WC_Payments_Utils::get_filtered_error_status_code( $e ),
- );
- }
- }
-
- /**
- * This function wraps WC_Payments::get_payment_method_map, useful for unit testing.
- *
- * @return array Array of UPE_Payment_Method instances.
- */
- public function wc_payments_get_payment_method_map() {
- return WC_Payments::get_payment_method_map();
- }
-
- /**
- * Returns the checkout tile.
- *
- * @return string Checkout title.
- */
- public function get_checkout_title() {
- return $this->checkout_title;
- }
-
- /**
- * Returns the payment methods for this gateway.
- *
- * @return array|UPE_Payment_Method[]
- */
- public function get_payment_methods() {
- return $this->payment_methods;
- }
-
- /**
- * Returns the UPE payment method for the gateway.
- *
- * @return UPE_Payment_Method
- */
- public function get_payment_method() {
- return $this->payment_method;
- }
-
- /**
- * Returns Stripe payment method type ID.
- *
- * @return string
- */
- public function get_stripe_id() {
- return $this->stripe_id;
- }
-
- /**
- * Return the payment method type from the payment method details.
- *
- * @param array $payment_method_details Payment method details.
- * @return string|null Payment method type or nothing.
- */
- private function get_payment_method_type_from_payment_details( $payment_method_details ) {
- return $payment_method_details['type'] ?? null;
- }
-
- /**
- * This function wraps WC_Payments::get_payment_gateway_by_id, useful for unit testing.
- *
- * @param string $payment_method_id Stripe payment method type ID.
- * @return false|UPE_Payment_Gateway Matching UPE Payment Gateway instance.
- */
- public function wc_payments_get_payment_gateway_by_id( $payment_method_id ) {
- return WC_Payments::get_payment_gateway_by_id( $payment_method_id );
- }
-
- /**
- * This function wraps WC_Payments::get_payment_method_by_id, useful for unit testing.
- *
- * @param string $payment_method_id Stripe payment method type ID.
- * @return false|UPE_Payment_Method Matching UPE Payment Method instance.
- */
- public function wc_payments_get_payment_method_by_id( $payment_method_id ) {
- return WC_Payments::get_payment_method_by_id( $payment_method_id );
- }
-
- /**
- * Handles the shipping requirement for Afterpay payments.
- *
- * This method extracts the shipping and billing data from the order and sets the appropriate
- * shipping data for the Afterpay payment request. If neither shipping nor billing data is valid
- * for shipping, an exception is thrown.
- *
- * @param WC_Order $order The order object containing shipping and billing information.
- * @param Create_And_Confirm_Intention $request The Afterpay payment request object to set shipping data on.
- *
- * @throws Invalid_Address_Exception If neither shipping nor billing address is valid for Afterpay payments.
- * @return void
- */
- private function handle_afterpay_shipping_requirement( WC_Order $order, Create_And_Confirm_Intention $request ): void {
- $check_if_usable = function( array $address ): bool {
- return $address['country'] && $address['state'] && $address['city'] && $address['postal_code'] && $address['line1'];
- };
-
- $shipping_data = $this->order_service->get_shipping_data_from_order( $order );
- if ( $check_if_usable( $shipping_data['address'] ) ) {
- $request->set_shipping( $shipping_data );
- return;
- }
-
- $billing_data = $this->order_service->get_billing_data_from_order( $order );
- if ( $check_if_usable( $billing_data['address'] ) ) {
- $request->set_shipping( $billing_data );
- return;
- }
-
- throw new Invalid_Address_Exception( __( 'A valid shipping address is required for Afterpay payments.', 'woocommerce-payments' ) );
- }
-
-
- /**
- * Modifies the create intent parameters when processing a payment.
- *
- * If the selected Stripe payment type is AFTERPAY, it updates the shipping data in the request.
- *
- * @param Create_And_Confirm_Intention $request The request object for creating and confirming intention.
- * @param Payment_Information $payment_information The payment information object.
- * @param WC_Order $order The order object.
- *
- * @return void
- */
- protected function modify_create_intent_parameters_when_processing_payment( Create_And_Confirm_Intention $request, Payment_Information $payment_information, WC_Order $order ): void {
- if ( Payment_Method::AFTERPAY === $this->get_selected_stripe_payment_type_id() ) {
- $this->handle_afterpay_shipping_requirement( $order, $request );
- }
- }
-}
diff --git a/src/Internal/Payment/State/ProcessedState.php b/src/Internal/Payment/State/ProcessedState.php
index 7e8629121eb..5765f96ecbf 100644
--- a/src/Internal/Payment/State/ProcessedState.php
+++ b/src/Internal/Payment/State/ProcessedState.php
@@ -13,7 +13,7 @@
use WCPay\Internal\Service\OrderService;
use WCPay\Vendor\League\Container\Exception\ContainerException;
use WCPay\Internal\Proxy\LegacyProxy;
-use WCPay\Payment_Methods\UPE_Payment_Gateway;
+use WC_Payment_Gateway_WCPay;
/**
* This state is used when payment is completed on the server, and we need to update date on the plugin side.
diff --git a/tests/unit/admin/test-class-wc-rest-payments-settings-controller.php b/tests/unit/admin/test-class-wc-rest-payments-settings-controller.php
index 72d9c1854e3..8c1628a9f91 100644
--- a/tests/unit/admin/test-class-wc-rest-payments-settings-controller.php
+++ b/tests/unit/admin/test-class-wc-rest-payments-settings-controller.php
@@ -12,7 +12,6 @@
use WCPay\Database_Cache;
use WCPay\Duplicate_Payment_Prevention_Service;
use WCPay\Payment_Methods\Eps_Payment_Method;
-use WCPay\Payment_Methods\UPE_Payment_Gateway;
use WCPay\Payment_Methods\CC_Payment_Method;
use WCPay\Payment_Methods\Bancontact_Payment_Method;
use WCPay\Payment_Methods\Becs_Payment_Method;
@@ -65,34 +64,6 @@ class WC_REST_Payments_Settings_Controller_Test extends WCPAY_UnitTestCase {
*/
private $mock_db_cache;
- /**
- * An array of mocked split UPE payment gateways mapped to payment method ID.
- *
- * @var UPE_Payment_Gateway
- */
- private $mock_upe_payment_gateway;
-
- /**
- * An array of mocked split UPE payment gateways mapped to payment method ID.
- *
- * @var UPE_Payment_Gateway
- */
- private $mock_split_upe_payment_gateway;
-
- /**
- * UPE system under test.
- *
- * @var WC_REST_Payments_Settings_Controller
- */
- private $upe_controller;
-
- /**
- * UPE system under test.
- *
- * @var WC_REST_Payments_Settings_Controller
- */
- private $upe_split_controller;
-
/**
* WC_Payments_Localization_Service instance.
*
@@ -144,20 +115,6 @@ public function set_up() {
$this->mock_localization_service = $this->createMock( WC_Payments_Localization_Service::class );
$this->mock_fraud_service = $this->createMock( WC_Payments_Fraud_Service::class );
- $this->gateway = new WC_Payment_Gateway_WCPay(
- $this->mock_api_client,
- $this->mock_wcpay_account,
- $customer_service,
- $token_service,
- $action_scheduler_service,
- $mock_rate_limiter,
- $order_service,
- $mock_dpps,
- $this->mock_localization_service,
- $this->mock_fraud_service
- );
- $this->controller = new WC_REST_Payments_Settings_Controller( $this->mock_api_client, $this->gateway, $this->mock_wcpay_account );
-
$mock_payment_methods = [];
$payment_method_classes = [
Becs_Payment_Method::class,
@@ -184,7 +141,7 @@ public function set_up() {
$mock_payment_methods[ $mock_payment_method->get_id() ] = $mock_payment_method;
}
- $this->mock_upe_payment_gateway = new UPE_Payment_Gateway(
+ $this->gateway = new WC_Payment_Gateway_WCPay(
$this->mock_api_client,
$this->mock_wcpay_account,
$customer_service,
@@ -198,25 +155,7 @@ public function set_up() {
$this->mock_localization_service,
$this->mock_fraud_service
);
-
- $this->upe_controller = new WC_REST_Payments_Settings_Controller( $this->mock_api_client, $this->mock_upe_payment_gateway, $this->mock_wcpay_account );
-
- $this->mock_split_upe_payment_gateway = new UPE_Payment_Gateway(
- $this->mock_api_client,
- $this->mock_wcpay_account,
- $customer_service,
- $token_service,
- $action_scheduler_service,
- $mock_payment_methods['card'],
- $mock_payment_methods,
- $mock_rate_limiter,
- $order_service,
- $mock_dpps,
- $this->mock_localization_service,
- $this->mock_fraud_service
- );
-
- $this->upe_split_controller = new WC_REST_Payments_Settings_Controller( $this->mock_api_client, $this->mock_split_upe_payment_gateway, $this->mock_wcpay_account );
+ $this->controller = new WC_REST_Payments_Settings_Controller( $this->mock_api_client, $this->gateway, $this->mock_wcpay_account );
$this->mock_api_client
->method( 'is_server_connected' )
@@ -267,39 +206,13 @@ public function test_get_settings_returns_enabled_payment_method_ids() {
);
}
- public function test_upe_get_settings_returns_available_payment_method_ids() {
+ public function test_get_settings_returns_available_payment_method_ids() {
$this->mock_localization_service->method( 'get_country_locale_data' )->willReturn(
[
'currency_code' => 'usd',
]
);
- $response = $this->upe_controller->get_settings();
- $enabled_method_ids = $response->get_data()['available_payment_method_ids'];
-
- $this->assertEquals(
- [
- Payment_Method::CARD,
- Payment_Method::BECS,
- Payment_Method::BANCONTACT,
- Payment_Method::EPS,
- Payment_Method::GIROPAY,
- Payment_Method::IDEAL,
- Payment_Method::SOFORT,
- Payment_Method::SEPA,
- Payment_Method::P24,
- Payment_Method::LINK,
- ],
- $enabled_method_ids
- );
- }
-
- public function test_split_upe_get_settings_returns_available_payment_method_ids() {
- $this->mock_localization_service->method( 'get_country_locale_data' )->willReturn(
- [
- 'currency_code' => 'usd',
- ]
- );
- $response = $this->upe_split_controller->get_settings();
+ $response = $this->controller->get_settings();
$enabled_method_ids = $response->get_data()['available_payment_method_ids'];
$this->assertEquals(
@@ -436,26 +349,15 @@ public function test_update_settings_returns_error_on_non_bool_is_wcpay_enabled_
$this->assertEquals( 400, $response->get_status() );
}
- public function test_upe_update_settings_saves_enabled_payment_methods() {
- $this->mock_upe_payment_gateway->update_option( 'upe_enabled_payment_method_ids', [ Payment_Method::CARD ] );
+ public function test_update_settings_saves_enabled_payment_methods() {
+ $this->gateway->update_option( 'upe_enabled_payment_method_ids', [ Payment_Method::CARD ] );
$request = new WP_REST_Request();
$request->set_param( 'enabled_payment_method_ids', [ Payment_Method::CARD, Payment_Method::GIROPAY ] );
- $this->upe_controller->update_settings( $request );
+ $this->controller->update_settings( $request );
- $this->assertEquals( [ Payment_Method::CARD, Payment_Method::GIROPAY ], $this->mock_upe_payment_gateway->get_option( 'upe_enabled_payment_method_ids' ) );
- }
-
- public function test_upe_split_update_settings_saves_enabled_payment_methods() {
- $this->mock_split_upe_payment_gateway->update_option( 'upe_enabled_payment_method_ids', [ Payment_Method::CARD ] );
-
- $request = new WP_REST_Request();
- $request->set_param( 'enabled_payment_method_ids', [ Payment_Method::CARD, Payment_Method::GIROPAY ] );
-
- $this->upe_split_controller->update_settings( $request );
-
- $this->assertEquals( [ Payment_Method::CARD, Payment_Method::GIROPAY ], $this->mock_split_upe_payment_gateway->get_option( 'upe_enabled_payment_method_ids' ) );
+ $this->assertEquals( [ Payment_Method::CARD, Payment_Method::GIROPAY ], $this->gateway->get_option( 'upe_enabled_payment_method_ids' ) );
}
public function test_update_settings_fails_if_user_cannot_manage_woocommerce() {
@@ -769,7 +671,7 @@ public function deregister_wc_blocks_rest_api() {
}
}
- public function test_upe_get_settings_card_eligible_flag(): void {
+ public function test_get_settings_card_eligible_flag(): void {
// Enable Cash on Delivery gateway for the purpose of this test.
$cod_gateway = WC()->payment_gateways()->payment_gateways()['cod'];
$cod_gateway->enabled = 'yes';
@@ -780,26 +682,7 @@ public function test_upe_get_settings_card_eligible_flag(): void {
]
);
- $response = $this->upe_controller->get_settings();
-
- $this->assertArrayHasKey( 'is_card_present_eligible', $response->get_data() );
- $this->assertTrue( $response->get_data()['is_card_present_eligible'] );
-
- // Disable Cash on Delivery gateway.
- $cod_gateway->enabled = 'no';
- }
-
- public function test_upe_split_get_settings_card_eligible_flag(): void {
- // Enable Cash on Delivery gateway for the purpose of this test.
- $cod_gateway = WC()->payment_gateways()->payment_gateways()['cod'];
- $cod_gateway->enabled = 'yes';
-
- $this->mock_localization_service->method( 'get_country_locale_data' )->willReturn(
- [
- 'currency_code' => 'usd',
- ]
- );
- $response = $this->upe_split_controller->get_settings();
+ $response = $this->controller->get_settings();
$this->assertArrayHasKey( 'is_card_present_eligible', $response->get_data() );
$this->assertTrue( $response->get_data()['is_card_present_eligible'] );
@@ -808,7 +691,7 @@ public function test_upe_split_get_settings_card_eligible_flag(): void {
$cod_gateway->enabled = 'no';
}
- public function test_upe_get_settings_domestic_currency(): void {
+ public function test_get_settings_domestic_currency(): void {
$mock_domestic_currency = 'usd';
$this->mock_localization_service->method( 'get_country_locale_data' )->willReturn(
[
@@ -819,49 +702,20 @@ public function test_upe_get_settings_domestic_currency(): void {
->expects( $this->never() )
->method( 'get_account_default_currency' );
- $response = $this->upe_controller->get_settings();
-
- $this->assertArrayHasKey( 'account_domestic_currency', $response->get_data() );
- $this->assertSame( $mock_domestic_currency, $response->get_data()['account_domestic_currency'] );
- }
-
- public function test_upe_get_settings_domestic_currency_fallbacks_to_default_currency(): void {
- $mock_domestic_currency = 'usd';
- $this->mock_localization_service->method( 'get_country_locale_data' )->willReturn( [] );
- $this->mock_wcpay_account
- ->expects( $this->once() )
- ->method( 'get_account_default_currency' )
- ->willReturn( $mock_domestic_currency );
- $response = $this->upe_controller->get_settings();
-
- $this->assertArrayHasKey( 'account_domestic_currency', $response->get_data() );
- $this->assertSame( $mock_domestic_currency, $response->get_data()['account_domestic_currency'] );
- }
-
- public function test_upe_split_get_settings_domestic_currency(): void {
- $mock_domestic_currency = 'usd';
- $this->mock_localization_service->method( 'get_country_locale_data' )->willReturn(
- [
- 'currency_code' => $mock_domestic_currency,
- ]
- );
- $this->mock_wcpay_account
- ->expects( $this->never() )
- ->method( 'get_account_default_currency' );
- $response = $this->upe_split_controller->get_settings();
+ $response = $this->controller->get_settings();
$this->assertArrayHasKey( 'account_domestic_currency', $response->get_data() );
$this->assertSame( $mock_domestic_currency, $response->get_data()['account_domestic_currency'] );
}
- public function test_upe_split_get_settings_domestic_currency_fallbacks_to_default_currency(): void {
+ public function test_get_settings_domestic_currency_fallbacks_to_default_currency(): void {
$mock_domestic_currency = 'usd';
$this->mock_localization_service->method( 'get_country_locale_data' )->willReturn( [] );
$this->mock_wcpay_account
->expects( $this->once() )
->method( 'get_account_default_currency' )
->willReturn( $mock_domestic_currency );
- $response = $this->upe_split_controller->get_settings();
+ $response = $this->controller->get_settings();
$this->assertArrayHasKey( 'account_domestic_currency', $response->get_data() );
$this->assertSame( $mock_domestic_currency, $response->get_data()['account_domestic_currency'] );
diff --git a/tests/unit/admin/test-class-wc-rest-payments-tos-controller.php b/tests/unit/admin/test-class-wc-rest-payments-tos-controller.php
index a7f6ea1a1b9..9597390a9a0 100644
--- a/tests/unit/admin/test-class-wc-rest-payments-tos-controller.php
+++ b/tests/unit/admin/test-class-wc-rest-payments-tos-controller.php
@@ -9,6 +9,7 @@
use WCPay\Core\Server\Request\Add_Account_Tos_Agreement;
use WCPay\Database_Cache;
use WCPay\Duplicate_Payment_Prevention_Service;
+use WCPay\Payment_Methods\CC_Payment_Method;
use WCPay\Session_Rate_Limiter;
/**
@@ -63,6 +64,7 @@ public function set_up() {
$order_service = new WC_Payments_Order_Service( $this->createMock( WC_Payments_API_Client::class ) );
$action_scheduler_service = new WC_Payments_Action_Scheduler_Service( $mock_api_client, $order_service );
$mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class );
+ $mock_payment_method = $this->createMock( CC_Payment_Method::class );
$this->gateway = new WC_Payment_Gateway_WCPay(
$mock_api_client,
@@ -70,6 +72,8 @@ public function set_up() {
$customer_service,
$token_service,
$action_scheduler_service,
+ $mock_payment_method,
+ [ 'card' => $mock_payment_method ],
$mock_rate_limiter,
$order_service,
$mock_dpps,
diff --git a/tests/unit/payment-methods/test-class-upe-payment-gateway.php b/tests/unit/payment-methods/test-class-upe-payment-gateway.php
index cd41a804268..7c013e2b858 100644
--- a/tests/unit/payment-methods/test-class-upe-payment-gateway.php
+++ b/tests/unit/payment-methods/test-class-upe-payment-gateway.php
@@ -1,6 +1,6 @@
mock_api_client = $this->getMockBuilder( 'WC_Payments_API_Client' )
->disableOriginalConstructor()
- ->setMethods(
+ ->onlyMethods(
[
'get_payment_method',
'is_server_connected',
@@ -224,7 +220,7 @@ public function set_up() {
// Arrange: Mock WC_Payments_Customer_Service so its methods aren't called directly.
$this->mock_token_service = $this->getMockBuilder( 'WC_Payments_Token_Service' )
->disableOriginalConstructor()
- ->setMethods( [ 'add_payment_method_to_user' ] )
+ ->onlyMethods( [ 'add_payment_method_to_user' ] )
->getMock();
// Arrange: Mock WC_Payments_Action_Scheduler_Service so its methods aren't called directly.
@@ -257,7 +253,7 @@ public function set_up() {
foreach ( $payment_method_classes as $payment_method_class ) {
$mock_payment_method = $this->getMockBuilder( $payment_method_class )
->setConstructorArgs( [ $this->mock_token_service ] )
- ->setMethods( [ 'is_subscription_item_in_cart', 'get_icon' ] )
+ ->onlyMethods( [ 'is_subscription_item_in_cart', 'get_icon' ] )
->getMock();
$this->mock_payment_methods[ $mock_payment_method->get_id() ] = $mock_payment_method;
}
@@ -268,7 +264,7 @@ public function set_up() {
$this->mock_api_client,
]
)
- ->setMethods(
+ ->onlyMethods(
[
'get_payment_method_id_for_order',
]
@@ -281,9 +277,9 @@ public function set_up() {
->getMock();
$this->mock_payment_methods[ $this->mock_payment_method->get_id() ] = $this->mock_payment_method;
- // Arrange: Mock UPE_Payment_Gateway so that some of its methods can be
+ // Arrange: Mock WC_Payment_Gateway_WCPay so that some of its methods can be
// mocked, and their return values can be used for testing.
- $this->mock_upe_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class )
+ $this->mock_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class )
->setConstructorArgs(
[
$this->mock_api_client,
@@ -312,13 +308,13 @@ public function set_up() {
->getMock();
// Arrange: Set the return value of get_return_url() so it can be used in a test later.
- $this->mock_upe_gateway
+ $this->mock_gateway
->expects( $this->any() )
->method( 'get_return_url' )
->will(
$this->returnValue( $this->return_url )
);
- $this->mock_upe_gateway
+ $this->mock_gateway
->expects( $this->any() )
->method( 'parent_process_payment' )
->will(
@@ -329,7 +325,7 @@ public function set_up() {
// so that get_payment_method_from_request() does not throw error.
$_POST = [
'wcpay-payment-method' => 'pm_mock',
- 'payment_method' => UPE_Payment_Gateway::GATEWAY_ID,
+ 'payment_method' => WC_Payment_Gateway_WCPay::GATEWAY_ID,
];
// Mock the level3 service to always return an empty array.
@@ -358,207 +354,53 @@ public function tear_down() {
wcpay_get_test_container()->reset_all_replacements();
}
- public function test_process_payment_returns_correct_redirect_url() {
- $order = WC_Helper_Order::create_order();
- $_POST['wc_payment_intent_id'] = 'pi_mock';
-
- $payment_intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::PROCESSING ] );
-
- $request = $this->mock_wcpay_request( Update_Intention::class, 1, 'pi_mock' );
-
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $payment_intent );
-
- $this->set_cart_contains_subscription_items( false );
-
- $result = $this->mock_upe_gateway->process_payment( $order->get_id() );
-
- unset( $_POST['wc_payment_intent_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
-
- $this->assertEquals( 'success', $result['result'] );
- $this->assertEquals( true, $result['payment_needed'] );
- $this->assertMatchesRegularExpression( '/wc_payment_method=woocommerce_payments/', $result['redirect_url'] );
- $this->assertMatchesRegularExpression( '/save_payment_method=no/', $result['redirect_url'] );
- }
-
- public function test_process_subscription_payment_passes_save_payment_method() {
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $_POST['wc_payment_intent_id'] = 'pi_mock';
-
- $payment_intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::PROCESSING ] );
-
- $request = $this->mock_wcpay_request( Update_Intention::class, 1, 'pi_mock' );
-
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $payment_intent );
+ public function test_process_payment_returns_correct_redirect_when_using_saved_payment() {
+ $order = WC_Helper_Order::create_order();
+ $_POST = $this->setup_saved_payment_method();
+ $intent = WC_Helper_Intention::create_intention();
- $this->mock_upe_gateway
+ $this->mock_gateway->expects( $this->once() )
+ ->method( 'manage_customer_details_for_order' )
+ ->will(
+ $this->returnValue( [ wp_get_current_user(), 'cus_123' ] )
+ );
+ $this->mock_wcpay_request( Create_And_Confirm_Intention::class, 1, $intent->get_id() )
->expects( $this->once() )
- ->method( 'is_payment_recurring' )
- ->willReturn( true );
-
- $result = $this->mock_upe_gateway->process_payment( $order->get_id() );
-
- unset( $_POST['wc_payment_intent_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
-
- $this->assertEquals( 'success', $result['result'] );
- $this->assertEquals( true, $result['payment_needed'] );
- $this->assertMatchesRegularExpression( '/wc_payment_method=woocommerce_payments/', $result['redirect_url'] );
- $this->assertMatchesRegularExpression( '/save_payment_method=yes/', $result['redirect_url'] );
- }
-
- public function test_process_payment_returns_correct_redirect_when_using_saved_payment() {
- $order = WC_Helper_Order::create_order();
- $_POST = $this->setup_saved_payment_method();
+ ->method( 'format_response' )
+ ->willReturn( $intent );
$this->set_cart_contains_subscription_items( false );
- $this->mock_upe_gateway
- ->expects( $this->never() )
- ->method( 'manage_customer_details_for_order' );
-
- $result = $this->mock_upe_gateway->process_payment( $order->get_id() );
+ $result = $this->mock_gateway->process_payment( $order->get_id() );
$this->assertEquals( 'success', $result['result'] );
- $this->assertMatchesRegularExpression( '/key=mock_order_key/', $result['redirect'] );
+ $this->assertEquals( $this->return_url, $result['redirect'] );
}
public function test_process_payment_returns_correct_redirect_when_using_payment_request() {
$order = WC_Helper_Order::create_order();
+ $intent = WC_Helper_Intention::create_intention();
$_POST['payment_request_type'] = 'google_pay';
- $this->set_cart_contains_subscription_items( false );
-
- $result = $this->mock_upe_gateway->process_payment( $order->get_id() );
-
- $this->mock_upe_gateway
- ->expects( $this->never() )
- ->method( 'manage_customer_details_for_order' );
- $this->assertEquals( 'success', $result['result'] );
- $this->assertMatchesRegularExpression( '/key=mock_order_key/', $result['redirect'] );
- }
-
- public function test_upe_process_payment_check_session_order_redirect_to_previous_order() {
- $_POST['wc_payment_intent_id'] = 'pi_mock';
-
- $response = [
- 'dummy_result' => 'xyz',
- ];
-
- // Arrange the order is being processed.
- $current_order = WC_Helper_Order::create_order();
- $current_order_id = $current_order->get_id();
-
- // Arrange the DPPS to return an order from the session.
- $this->mock_dpps->expects( $this->once() )
- ->method( 'check_against_session_processing_order' )
- ->with( wc_get_order( $current_order ) )
- ->willReturn( $response );
-
- // Assert: no call to the server to confirm the payment.
- $this->mock_wcpay_request( Update_Intention::class, 0, 'pi_XXXXX' );
-
- // Act: process the order but redirect to the previous/session paid order.
- $result = $this->mock_upe_gateway->process_payment( $current_order_id );
-
- // Assert: the result of check_against_session_processing_order.
- $this->assertSame( $response, $result );
- }
-
- public function test_upe_process_payment_check_session_with_failed_intent_then_order_id_saved_to_session() {
- $_POST['wc_payment_intent_id'] = 'pi_mock';
-
- // Arrange the order is being processed.
- $current_order = WC_Helper_Order::create_order();
- $current_order_id = $current_order->get_id();
-
- // Arrange a failed intention.
- $intent = WC_Helper_Intention::create_intention( [ 'status' => 'failed' ] );
-
- // Assert.
- $update_request = $this->mock_wcpay_request( Update_Intention::class, 1, $intent->get_id() );
- $update_request->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- // Arrange the DPPS not to return an order from the session.
- $this->mock_dpps->expects( $this->once() )
- ->method( 'check_against_session_processing_order' )
- ->with( wc_get_order( $current_order ) )
- ->willReturn( null );
-
- // Assert: maybe_update_session_processing_order takes action and its value is kept.
- $this->mock_dpps->expects( $this->once() )
- ->method( 'maybe_update_session_processing_order' )
- ->with( $current_order_id );
-
- // Act: process the order but redirect to the previous/session paid order.
- $this->mock_upe_gateway->process_payment( $current_order_id );
- }
-
- public function test_upe_process_payment_check_session_and_continue_processing() {
- $_POST['wc_payment_intent_id'] = 'pi_mock';
-
- // Arrange the order is being processed.
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
-
- // Arrange a successful intention.
- $intent = WC_Helper_Intention::create_intention();
-
- // Arrange the DPPS not to return an order from the session.
- $this->mock_dpps->expects( $this->once() )
- ->method( 'check_against_session_processing_order' )
- ->with( wc_get_order( $order ) )
- ->willReturn( null );
-
- // Assert: Order is removed from the session.
- $this->mock_dpps->expects( $this->once() )
- ->method( 'remove_session_processing_order' )
- ->with( $order_id );
-
- // Assert: the payment process continues.
- $this->mock_wcpay_request( Update_Intention::class, 1, $intent->get_id() )
+ $this->mock_gateway->expects( $this->once() )
+ ->method( 'manage_customer_details_for_order' )
+ ->will(
+ $this->returnValue( [ wp_get_current_user(), 'cus_123' ] )
+ );
+ $this->mock_wcpay_request( Create_And_Confirm_Intention::class, 1, $intent->get_id() )
->expects( $this->once() )
->method( 'format_response' )
->willReturn( $intent );
+ $this->set_cart_contains_subscription_items( false );
- // Act.
- $this->mock_upe_gateway->process_payment( $order_id );
- }
-
- public function test_upe_check_payment_intent_attached_to_order_succeeded_return_redirection() {
- $_POST['wc_payment_intent_id'] = 'pi_mock';
-
- $response = [
- 'dummy_result' => 'xyz',
- ];
-
- // Arrange order.
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
-
- // Arrange the DPPS to return a prepared response.
- $this->mock_dpps->expects( $this->once() )
- ->method( 'check_payment_intent_attached_to_order_succeeded' )
- ->with( wc_get_order( $order ) )
- ->willReturn( $response );
-
- // Assert: no more call to the server to update the intention.
- $this->mock_wcpay_request( Update_Intention::class, 0 );
-
- // Act: process the order but redirect to the order.
- $result = $this->mock_upe_gateway->process_payment( $order_id );
+ $result = $this->mock_gateway->process_payment( $order->get_id() );
- // Assert: the result of check_intent_attached_to_order_succeeded.
- $this->assertSame( $response, $result );
+ $this->assertEquals( 'success', $result['result'] );
+ $this->assertEquals( $this->return_url, $result['redirect'] );
}
public function is_proper_intent_used_with_order_returns_false() {
- $this->assertFalse( $this->mock_upe_gateway->is_proper_intent_used_with_order( WC_Helper_Order::create_order(), 'wrong_intent_id' ) );
+ $this->assertFalse( $this->mock_gateway->is_proper_intent_used_with_order( WC_Helper_Order::create_order(), 'wrong_intent_id' ) );
}
public function test_process_redirect_payment_intent_processing() {
@@ -584,7 +426,7 @@ public function test_process_redirect_payment_intent_processing() {
]
);
- $this->mock_upe_gateway->expects( $this->once() )
+ $this->mock_gateway->expects( $this->once() )
->method( 'manage_customer_details_for_order' )
->will(
$this->returnValue( [ $user, $customer_id ] )
@@ -598,7 +440,7 @@ public function test_process_redirect_payment_intent_processing() {
$this->set_cart_contains_subscription_items( false );
- $this->mock_upe_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method );
+ $this->mock_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method );
$result_order = wc_get_order( $order_id );
$note = wc_get_order_notes(
@@ -640,7 +482,7 @@ public function test_process_redirect_payment_intent_succeded() {
]
);
- $this->mock_upe_gateway->expects( $this->once() )
+ $this->mock_gateway->expects( $this->once() )
->method( 'manage_customer_details_for_order' )
->will(
$this->returnValue( [ $user, $customer_id ] )
@@ -654,7 +496,7 @@ public function test_process_redirect_payment_intent_succeded() {
$this->set_cart_contains_subscription_items( false );
- $this->mock_upe_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method );
+ $this->mock_gateway->process_redirect_payment( $order, $intent_id, $save_payment_method );
$result_order = wc_get_order( $order_id );
@@ -674,7 +516,7 @@ public function test_validate_order_id_received_vs_intent_meta_order_id_throw_ex
$this->expectExceptionMessage( "We're not able to process this payment due to the order ID mismatch. Please try again later." );
\PHPUnit_Utils::call_method(
- $this->mock_upe_gateway,
+ $this->mock_gateway,
'validate_order_id_received_vs_intent_meta_order_id',
[ $order, $intent_metadata ]
);
@@ -685,7 +527,7 @@ public function test_validate_order_id_received_vs_intent_meta_order_id_returnin
$intent_metadata = [ 'order_id' => (string) ( $order->get_id() ) ];
$res = \PHPUnit_Utils::call_method(
- $this->mock_upe_gateway,
+ $this->mock_gateway,
'validate_order_id_received_vs_intent_meta_order_id',
[ $order, $intent_metadata ]
);
@@ -771,7 +613,7 @@ public function test_correct_payment_method_title_for_order() {
];
foreach ( $charge_payment_method_details as $i => $payment_method_details ) {
- $this->mock_upe_gateway->set_payment_method_title_for_order( $order, $payment_method_details['type'], $payment_method_details );
+ $this->mock_gateway->set_payment_method_title_for_order( $order, $payment_method_details['type'], $payment_method_details );
$this->assertEquals( $expected_payment_method_titles[ $i ], $order->get_payment_method_title() );
}
}
@@ -1069,24 +911,7 @@ public function test_create_token_from_setup_intent_adds_token() {
$this->returnValue( $mock_token )
);
- $this->assertEquals( $mock_token, $this->mock_upe_gateway->create_token_from_setup_intent( $mock_setup_intent_id, $mock_user ) );
- }
-
- public function test_process_payment_rejects_with_cached_minimum_acount() {
- $order = WC_Helper_Order::create_order();
- $order->set_currency( 'USD' );
- $order->set_total( 0.45 );
- $order->save();
-
- set_transient( 'wcpay_minimum_amount_usd', '50', DAY_IN_SECONDS );
- $_POST['wc_payment_intent_id'] = 'pi_mock';
-
- // Make sure that the payment was not actually processed.
- $price = wp_strip_all_tags( html_entity_decode( wc_price( 0.5, [ 'currency' => 'USD' ] ) ) );
- $message = 'The selected payment method requires a total amount of at least ' . $price . '.';
- $this->expectException( Exception::class );
- $this->expectExceptionMessage( $message );
- $this->mock_upe_gateway->process_payment( $order->get_id() );
+ $this->assertEquals( $mock_token, $this->mock_gateway->create_token_from_setup_intent( $mock_setup_intent_id, $mock_user ) );
}
public function test_exception_will_be_thrown_if_phone_number_is_invalid() {
@@ -1095,66 +920,20 @@ public function test_exception_will_be_thrown_if_phone_number_is_invalid() {
$order->save();
$this->expectException( Exception::class );
$this->expectExceptionMessage( 'Invalid phone number.' );
- $this->mock_upe_gateway->process_payment( $order->get_id() );
- }
-
- public function test_process_payment_caches_mimimum_amount_and_displays_error_upon_exception() {
- $amount = 0.45;
- $customer = 'cus_12345';
- $payment_intent_id = 'pi_mock';
-
- $order = WC_Helper_Order::create_order();
- $order->set_total( $amount );
- $order->save();
-
- delete_transient( 'wcpay_minimum_amount_usd' );
-
- $_POST['wc_payment_intent_id'] = $payment_intent_id;
-
- $request = $this->mock_wcpay_request( Update_Intention::class, 1, $payment_intent_id );
-
- $request->expects( $this->once() )
- ->method( 'set_amount' )
- ->with( (int) ( $amount * 100 ) );
-
- $request->expects( $this->once() )
- ->method( 'set_level3' )
- ->with(
- $this->callback(
- function( $argument ) {
- return is_array( $argument );
- }
- )
- );
-
- $request->expects( $this->once() )
- ->method( 'format_response' )
- ->will( $this->throwException( new Amount_Too_Small_Exception( 'Error: Amount must be at least $60 usd', 6000, 'usd', 400 ) ) );
-
- $price = wp_strip_all_tags( html_entity_decode( wc_price( 60, [ 'currency' => 'USD' ] ) ) );
- $message = 'The selected payment method requires a total amount of at least ' . $price . '.';
- $this->expectException( Exception::class );
- $this->expectExceptionMessage( $message );
-
- try {
- $this->mock_upe_gateway->process_payment( $order->get_id() );
- } catch ( Exception $e ) {
- $this->assertEquals( '6000', get_transient( 'wcpay_minimum_amount_usd' ) );
- throw $e;
- }
+ $this->mock_gateway->process_payment( $order->get_id() );
}
public function test_remove_link_payment_method_if_card_disabled() {
- $this->mock_upe_gateway->settings['upe_enabled_payment_method_ids'] = [ 'link' ];
+ $this->mock_gateway->settings['upe_enabled_payment_method_ids'] = [ 'link' ];
- $this->mock_upe_gateway
+ $this->mock_gateway
->expects( $this->once() )
->method( 'get_upe_enabled_payment_method_statuses' )
->will(
$this->returnValue( [ 'link_payments' => [ 'status' => 'active' ] ] )
);
- $this->assertSame( $this->mock_upe_gateway->get_payment_method_ids_enabled_at_checkout(), [] );
+ $this->assertSame( $this->mock_gateway->get_payment_method_ids_enabled_at_checkout(), [] );
}
/**
@@ -1167,7 +946,7 @@ public function test_get_upe_available_payment_methods( $payment_methods, $expec
->method( 'get_fees' )
->willReturn( $payment_methods );
- $gateway = new UPE_Payment_Gateway(
+ $gateway = new WC_Payment_Gateway_WCPay(
$this->mock_api_client,
$mock_wcpay_account,
$this->mock_customer_service,
@@ -1239,7 +1018,7 @@ private function set_get_upe_enabled_payment_method_statuses_return_value( $retu
],
];
}
- $this->mock_upe_gateway
+ $this->mock_gateway
->expects( $this->any() )
->method( 'get_upe_enabled_payment_method_statuses' )
->will( $this->returnValue( $return_value ) );
diff --git a/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php b/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php
index 54ffd9669f0..e788e467a14 100644
--- a/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php
+++ b/tests/unit/payment-methods/test-class-upe-split-payment-gateway.php
@@ -1,6 +1,6 @@
'pm_mock',
- 'payment_method' => UPE_Payment_Gateway::GATEWAY_ID,
+ 'payment_method' => WC_Payment_Gateway_WCPay::GATEWAY_ID,
];
$get_payment_gateway_by_id_return_value_map = [];
@@ -268,7 +266,7 @@ public function set_up() {
->getMock();
$this->mock_payment_methods[ $mock_payment_method->get_id() ] = $mock_payment_method;
- $mock_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class )
+ $mock_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class )
->setConstructorArgs(
[
$this->mock_api_client,
@@ -412,141 +410,36 @@ public function test_non_reusable_payment_method_is_not_available_when_subscript
$this->assertFalse( $payment_gateway->is_available() );
}
- public function test_process_payment_returns_correct_redirect_url() {
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
- $_POST['wc_payment_intent_id'] = 'pi_mock';
-
- $payment_intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::PROCESSING ] );
-
- $this->set_cart_contains_subscription_items( false );
-
- foreach ( $this->mock_payment_gateways as $mock_payment_gateway ) {
- $this->mock_wcpay_request( Update_Intention::class, 1, $payment_intent->get_id() )
- ->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $payment_intent );
-
- $result = $mock_payment_gateway->process_payment( $order->get_id() );
- $this->assertEquals( 'success', $result['result'] );
- $this->assertEquals( true, $result['payment_needed'] );
- $this->assertMatchesRegularExpression( '/wc_payment_method=woocommerce_payments/', $result['redirect_url'] );
- $this->assertMatchesRegularExpression( '/save_payment_method=no/', $result['redirect_url'] );
- }
-
- unset( $_POST['wc_payment_intent_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
- }
-
- public function test_process_payment_passes_save_payment_method_to_store() {
- $mock_sepa_payment_gateway = $this->mock_payment_gateways[ Payment_Method::SEPA ];
-
- $order = WC_Helper_Order::create_order();
- $gateway_id = UPE_Payment_Gateway::GATEWAY_ID . '_' . Payment_Method::SEPA;
- $save_payment_param = "wc-$gateway_id-new-payment-method";
- $_POST[ $save_payment_param ] = 'yes';
- $_POST['wc_payment_intent_id'] = 'pi_mock';
-
- $payment_intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::PROCESSING ] );
-
- $this->mock_wcpay_request( Update_Intention::class, 1, $payment_intent->get_id() )
- ->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn(
- $payment_intent
- );
-
- $this->set_cart_contains_subscription_items( false );
-
- // Test saving with SEPA.
- $result = $mock_sepa_payment_gateway->process_payment( $order->get_id() );
- $this->assertEquals( 'success', $result['result'] );
- $this->assertMatchesRegularExpression( '/wc_payment_method=woocommerce_payments/', $result['redirect_url'] );
- $this->assertMatchesRegularExpression( '/save_payment_method=yes/', $result['redirect_url'] );
-
- unset( $_POST[ $save_payment_param ] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
- unset( $_POST['wc_payment_intent_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
- }
-
- public function test_process_subscription_payment_passes_save_payment_method() {
+ public function test_process_payment_returns_correct_redirect_when_using_saved_payment() {
$mock_card_payment_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ];
- $mock_sepa_payment_gateway = $this->mock_payment_gateways[ Payment_Method::SEPA ];
-
- $order = WC_Helper_Order::create_order();
- $_POST['wc_payment_intent_id'] = 'pi_mock';
-
- $payment_intent = WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::PROCESSING ] );
+ $user = wp_get_current_user();
+ $customer_id = 'cus_mock';
- // Test card.
- $this->mock_wcpay_request( Update_Intention::class, 1, $payment_intent->get_id() )
- ->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn(
- $payment_intent
+ $order = WC_Helper_Order::create_order();
+ $_POST = $this->setup_saved_payment_method();
+ $mock_card_payment_gateway->expects( $this->once() )
+ ->method( 'manage_customer_details_for_order' )
+ ->will(
+ $this->returnValue( [ $user, $customer_id ] )
);
-
- $mock_card_payment_gateway
- ->expects( $this->once() )
- ->method( 'is_payment_recurring' )
- ->willReturn( true );
- $result = $mock_card_payment_gateway->process_payment( $order->get_id() );
- $this->assertEquals( 'success', $result['result'] );
- $this->assertEquals( true, $result['payment_needed'] );
- $this->assertMatchesRegularExpression( '/wc_payment_method=woocommerce_payments/', $result['redirect_url'] );
- $this->assertMatchesRegularExpression( '/save_payment_method=yes/', $result['redirect_url'] );
-
- // Test SEPA.
- $this->mock_wcpay_request( Update_Intention::class, 1, $payment_intent->get_id() )
+ $mock_card_payment_gateway->expects( $this->any() )
+ ->method( 'get_upe_enabled_payment_method_ids' )
+ ->will(
+ $this->returnValue( [ Payment_Method::CARD ] )
+ );
+ $this->mock_wcpay_request( Create_And_Confirm_Intention::class, 1 )
->expects( $this->once() )
->method( 'format_response' )
->willReturn(
- $payment_intent
+ WC_Helper_Intention::create_intention( [ 'status' => Intent_Status::PROCESSING ] )
);
- $mock_sepa_payment_gateway
- ->expects( $this->once() )
- ->method( 'is_payment_recurring' )
- ->willReturn( true );
- $result = $mock_sepa_payment_gateway->process_payment( $order->get_id() );
- $this->assertEquals( 'success', $result['result'] );
- $this->assertEquals( true, $result['payment_needed'] );
- $this->assertMatchesRegularExpression( '/wc_payment_method=woocommerce_payments/', $result['redirect_url'] );
- $this->assertMatchesRegularExpression( '/save_payment_method=yes/', $result['redirect_url'] );
-
- unset( $_POST['wc_payment_intent_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
- }
-
- public function test_process_payment_returns_correct_redirect_when_using_saved_payment() {
- $mock_card_payment_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ];
-
- $order = WC_Helper_Order::create_order();
- $_POST = $this->setup_saved_payment_method();
-
$this->set_cart_contains_subscription_items( false );
$result = $mock_card_payment_gateway->process_payment( $order->get_id() );
- $mock_card_payment_gateway
- ->expects( $this->never() )
- ->method( 'manage_customer_details_for_order' );
$this->assertEquals( 'success', $result['result'] );
- $this->assertMatchesRegularExpression( '/key=mock_order_key/', $result['redirect'] );
- }
-
- public function test_process_payment_returns_correct_redirect_when_using_payment_request() {
- $mock_card_payment_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ];
-
- $order = WC_Helper_Order::create_order();
- $_POST['payment_request_type'] = 'google_pay';
-
- $this->set_cart_contains_subscription_items( false );
-
- $result = $mock_card_payment_gateway->process_payment( $order->get_id() );
-
- $mock_card_payment_gateway
- ->expects( $this->never() )
- ->method( 'manage_customer_details_for_order' );
- $this->assertEquals( 'success', $result['result'] );
- $this->assertMatchesRegularExpression( '/key=mock_order_key/', $result['redirect'] );
+ $this->assertEquals( $this->return_url, $result['redirect'] );
}
public function test_upe_process_payment_check_session_order_redirect_to_previous_order() {
@@ -574,113 +467,6 @@ public function test_upe_process_payment_check_session_order_redirect_to_previou
$this->assertSame( $response, $result );
}
- public function test_upe_process_payment_check_session_with_failed_intent_then_order_id_saved_to_session() {
- $_POST['wc_payment_intent_id'] = 'pi_mock';
-
- // Arrange the order is being processed.
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
-
- // Arrange a failed intention.
- $intent = WC_Helper_Intention::create_intention( [ 'status' => 'failed' ] );
-
- // Assert.
- $this->mock_wcpay_request( Update_Intention::class, 1, $intent->get_id() )
- ->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- // Make sure the DPPS will store the order.
- $this->mock_dpps->expects( $this->once() )
- ->method( 'maybe_update_session_processing_order' )
- ->with( $order_id );
-
- // Act: process the order but redirect to the previous/session paid order.
- $this->mock_payment_gateways[ Payment_Method::SEPA ]->process_payment( $order_id );
- }
-
- public function test_upe_process_payment_check_session_and_continue_processing() {
- $_POST['wc_payment_intent_id'] = 'pi_mock';
- $mock_upe_gateway = $this->mock_payment_gateways[ Payment_Method::SEPA ];
-
- // Arrange the order is being processed.
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
-
- // Arrange a successful intention.
- $intent = WC_Helper_Intention::create_intention();
-
- $mock_upe_gateway
- ->expects( $this->once() )
- ->method( 'get_payment_method_ids_enabled_at_checkout' )
- ->willReturn( [] );
-
- // Arrange the DPPs not to return anything.
- $this->mock_dpps->expects( $this->once() )
- ->method( 'check_against_session_processing_order' )
- ->with( wc_get_order( $order ) )
- ->willReturn( null );
-
- $this->mock_wcpay_request( Update_Intention::class, 1, $intent->get_id() )
- ->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- // Act.
- $mock_upe_gateway->process_payment( $order_id );
- }
-
- public function test_upe_check_payment_intent_attached_to_order_succeeded_with_invalid_intent_id_continue_process_payment() {
- $_POST['wc_payment_intent_id'] = 'pi_mock';
-
- // Arrange order.
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
-
- // Arrange the DPPS not to return a redirect.
- $this->mock_dpps->expects( $this->once() )
- ->method( 'check_payment_intent_attached_to_order_succeeded' )
- ->with( wc_get_order( $order ) )
- ->willReturn( null );
-
- // Assert: the payment process continues.
- $intent = WC_Helper_Intention::create_intention();
- $this->mock_wcpay_request( Update_Intention::class, 1, $intent->get_id() )
- ->expects( $this->once() )
- ->method( 'format_response' )
- ->willReturn( $intent );
-
- // Act: process the order.
- $this->mock_payment_gateways[ Payment_Method::SEPA ]->process_payment( $order_id );
- }
-
- public function test_upe_check_payment_intent_attached_to_order_succeeded_return_redirection() {
- $_POST['wc_payment_intent_id'] = 'pi_mock';
-
- $response = [
- 'dummy_result' => 'xyz',
- ];
-
- // Arrange order.
- $order = WC_Helper_Order::create_order();
- $order_id = $order->get_id();
-
- // Arrange the DPPS to return a redirect based on a redirect.
- $this->mock_dpps->expects( $this->once() )
- ->method( 'check_payment_intent_attached_to_order_succeeded' )
- ->with( wc_get_order( $order ) )
- ->willReturn( $response );
-
- // Assert: no more call to the server to update the intention.
- $this->mock_wcpay_request( Update_Intention::class, 0 );
-
- // Act: process the order but redirect to the order.
- $result = $this->mock_payment_gateways[ Payment_Method::SEPA ]->process_payment( $order_id );
-
- // Assert: the result of check_intent_attached_to_order_succeeded.
- $this->assertSame( $response, $result );
- }
-
public function test_process_redirect_payment_intent_processing() {
$mock_upe_gateway = $this->mock_payment_gateways[ Payment_Method::CARD ];
@@ -1263,64 +1049,13 @@ public function test_create_token_from_setup_intent_adds_token() {
}
}
- public function test_process_payment_rejects_with_cached_minimum_acount() {
-
- $order = WC_Helper_Order::create_order();
- $order->set_currency( 'USD' );
- $order->set_total( 0.45 );
- $order->save();
-
- set_transient( 'wcpay_minimum_amount_usd', '50', DAY_IN_SECONDS );
- $_POST['wc_payment_intent_id'] = 'pi_mock';
-
- // Make sure that the payment was not actually processed.
- $price = wp_strip_all_tags( html_entity_decode( wc_price( 0.5, [ 'currency' => 'USD' ] ) ) );
- $message = 'The selected payment method requires a total amount of at least ' . $price . '.';
-
- foreach ( $this->mock_payment_gateways as $mock_payment_gateway ) {
- $this->expectException( Exception::class );
- $this->expectExceptionMessage( $message );
- $mock_payment_gateway->process_payment( $order->get_id() );
- }
- }
-
- public function test_process_payment_caches_mimimum_amount_and_displays_error_upon_exception() {
- $order = WC_Helper_Order::create_order();
- $order->set_total( 0.45 );
- $order->save();
-
- delete_transient( 'wcpay_minimum_amount_usd' );
- $_POST['wc_payment_intent_id'] = 'pi_mock';
-
- $price = wp_strip_all_tags( html_entity_decode( wc_price( 60, [ 'currency' => 'USD' ] ) ) );
- $message = 'The selected payment method requires a total amount of at least ' . $price . '.';
- $this->expectException( Exception::class );
- $this->expectExceptionMessage( $message );
-
- try {
- foreach ( $this->mock_payment_gateways as $mock_payment_gateway ) {
- $this->mock_wcpay_request( Update_Intention::class, 1, 'pi_mock' )
- ->expects( $this->once() )
- ->method( 'format_response' )
- ->will( $this->throwException( new Amount_Too_Small_Exception( 'Error: Amount must be at least $60 usd', 6000, 'usd', 400 ) ) );
-
- $mock_payment_gateway->process_payment( $order->get_id() );
-
- break;
- }
- } catch ( Exception $e ) {
- $this->assertEquals( '6000', get_transient( 'wcpay_minimum_amount_usd' ) );
- throw $e;
- }
- }
-
/**
* Test get_payment_method_types with regular checkout post request context.
*
* @return void
*/
public function test_get_payment_methods_with_request_context() {
- $mock_upe_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class )
+ $mock_upe_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class )
->setConstructorArgs(
[
$this->mock_api_client,
@@ -1365,7 +1100,7 @@ public function test_get_payment_methods_with_request_context() {
* @return void
*/
public function test_get_payment_methods_without_request_context() {
- $mock_upe_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class )
+ $mock_upe_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class )
->setConstructorArgs(
[
$this->mock_api_client,
@@ -1409,7 +1144,7 @@ public function test_get_payment_methods_without_request_context() {
* @return void
*/
public function test_get_payment_methods_without_request_context_or_token() {
- $mock_upe_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class )
+ $mock_upe_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class )
->setConstructorArgs(
[
$this->mock_api_client,
@@ -1462,7 +1197,7 @@ public function test_get_payment_methods_without_request_context_or_token() {
*/
public function test_get_payment_methods_from_gateway_id_upe() {
WC_Helper_Order::create_order();
- $mock_upe_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class )
+ $mock_upe_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class )
->setConstructorArgs(
[
$this->mock_api_client,
@@ -1496,7 +1231,7 @@ public function test_get_payment_methods_from_gateway_id_upe() {
$this->returnValue( [ Payment_Method::CARD, Payment_Method::LINK ] )
);
- $payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( UPE_Payment_Gateway::GATEWAY_ID . '_' . Payment_Method::BANCONTACT );
+ $payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( WC_Payment_Gateway_WCPay::GATEWAY_ID . '_' . Payment_Method::BANCONTACT );
$this->assertSame( [ Payment_Method::BANCONTACT ], $payment_methods );
$mock_upe_gateway->expects( $this->any() )
@@ -1508,10 +1243,10 @@ public function test_get_payment_methods_from_gateway_id_upe() {
)
);
- $payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( UPE_Payment_Gateway::GATEWAY_ID );
+ $payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( WC_Payment_Gateway_WCPay::GATEWAY_ID );
$this->assertSame( [ Payment_Method::CARD, Payment_Method::LINK ], $payment_methods );
- $payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( UPE_Payment_Gateway::GATEWAY_ID );
+ $payment_methods = $mock_upe_gateway->get_payment_methods_from_gateway_id( WC_Payment_Gateway_WCPay::GATEWAY_ID );
$this->assertSame( [ Payment_Method::CARD ], $payment_methods );
WC_Payments::set_gateway( $gateway );
diff --git a/tests/unit/src/Internal/Payment/State/ProcessedStateTest.php b/tests/unit/src/Internal/Payment/State/ProcessedStateTest.php
index 94273521a05..aca6138622e 100644
--- a/tests/unit/src/Internal/Payment/State/ProcessedStateTest.php
+++ b/tests/unit/src/Internal/Payment/State/ProcessedStateTest.php
@@ -16,7 +16,7 @@
use WCPay\Internal\Service\DuplicatePaymentPreventionService;
use WCPay\Internal\Service\OrderService;
use WCPay\Internal\Proxy\LegacyProxy;
-use WCPay\Payment_Methods\UPE_Payment_Gateway;
+use WC_Payment_Gateway_WCPay;
use WCPAY_UnitTestCase;
/**
diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay-payment-types.php b/tests/unit/test-class-wc-payment-gateway-wcpay-payment-types.php
index e80c97b1834..8cd1668986d 100644
--- a/tests/unit/test-class-wc-payment-gateway-wcpay-payment-types.php
+++ b/tests/unit/test-class-wc-payment-gateway-wcpay-payment-types.php
@@ -11,7 +11,7 @@
use WCPay\Duplicate_Payment_Prevention_Service;
use WCPay\Session_Rate_Limiter;
use WCPay\Fraud_Prevention\Fraud_Prevention_Service;
-use WCPay\Internal\Service\OrderService;
+use WCPay\Payment_Methods\CC_Payment_Method;
/**
* WC_Payment_Gateway_WCPay unit tests.
@@ -133,7 +133,8 @@ public function set_up() {
$this->mock_order_service = $this->createMock( WC_Payments_Order_Service::class );
- $mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class );
+ $mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class );
+ $mock_payment_method = $this->createMock( CC_Payment_Method::class );
// Arrange: Mock WC_Payment_Gateway_WCPay so that some of its methods can be
// mocked, and their return values can be used for testing.
@@ -145,6 +146,8 @@ public function set_up() {
$this->mock_customer_service,
$this->mock_token_service,
$this->mock_action_scheduler_service,
+ $mock_payment_method,
+ [ 'card' => $mock_payment_method ],
$this->mock_rate_limiter,
$this->mock_order_service,
$mock_dpps,
diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay-process-payment.php b/tests/unit/test-class-wc-payment-gateway-wcpay-process-payment.php
index da7ed2798db..1ce7132f420 100644
--- a/tests/unit/test-class-wc-payment-gateway-wcpay-process-payment.php
+++ b/tests/unit/test-class-wc-payment-gateway-wcpay-process-payment.php
@@ -6,19 +6,17 @@
*/
use WCPay\Core\Server\Request\Create_And_Confirm_Intention;
-use WCPay\Core\Server\Request\WooPay_Create_And_Confirm_Intention;
use WCPay\Core\Server\Request\Create_And_Confirm_Setup_Intention;
use WCPay\Core\Server\Request\Get_Charge;
-use WCPay\Core\Server\Response;
use WCPay\Constants\Order_Status;
use WCPay\Constants\Intent_Status;
-use WCPay\Core\Server\Request\Get_Intention;
-use WCPay\Core\Server\Request\Update_Intention;
use WCPay\Duplicate_Payment_Prevention_Service;
use WCPay\Exceptions\API_Exception;
use WCPay\Exceptions\Connection_Exception;
use WCPay\Session_Rate_Limiter;
use WCPay\Constants\Payment_Method;
+use WCPay\Payment_Methods\CC_Payment_Method;
+
// Need to use WC_Mock_Data_Store.
require_once dirname( __FILE__ ) . '/helpers/class-wc-mock-wc-data-store.php';
@@ -149,7 +147,8 @@ public function set_up() {
$this->mock_order_service = $this->createMock( WC_Payments_Order_Service::class );
- $this->mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class );
+ $this->mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class );
+ $mock_payment_method = $this->createMock( CC_Payment_Method::class );
// Arrange: Mock WC_Payment_Gateway_WCPay so that some of its methods can be
// mocked, and their return values can be used for testing.
@@ -161,6 +160,8 @@ public function set_up() {
$this->mock_customer_service,
$this->mock_token_service,
$this->mock_action_scheduler_service,
+ $mock_payment_method,
+ [ 'card' => $mock_payment_method ],
$this->mock_rate_limiter,
$this->mock_order_service,
$this->mock_dpps,
diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay-process-refund.php b/tests/unit/test-class-wc-payment-gateway-wcpay-process-refund.php
index 79c11b5fe1b..7350621aedc 100644
--- a/tests/unit/test-class-wc-payment-gateway-wcpay-process-refund.php
+++ b/tests/unit/test-class-wc-payment-gateway-wcpay-process-refund.php
@@ -13,6 +13,7 @@
use WCPay\Core\Server\Response;
use WCPay\Duplicate_Payment_Prevention_Service;
use WCPay\Exceptions\API_Exception;
+use WCPay\Payment_Methods\CC_Payment_Method;
use WCPay\Session_Rate_Limiter;
// Need to use WC_Mock_Data_Store.
@@ -89,6 +90,7 @@ public function set_up() {
$this->mock_rate_limiter = $this->createMock( Session_Rate_Limiter::class );
$this->mock_order_service = $this->createMock( WC_Payments_Order_Service::class );
$mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class );
+ $mock_payment_method = $this->createMock( CC_Payment_Method::class );
$this->wcpay_gateway = new WC_Payment_Gateway_WCPay(
$this->mock_api_client,
@@ -96,6 +98,8 @@ public function set_up() {
$this->mock_customer_service,
$this->mock_token_service,
$this->mock_action_scheduler_service,
+ $mock_payment_method,
+ [ 'card' => $mock_payment_method ],
$this->mock_rate_limiter,
$this->mock_order_service,
$mock_dpps,
diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions-payment-method-order-note.php b/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions-payment-method-order-note.php
index 73be48c5cbc..9715d61a193 100644
--- a/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions-payment-method-order-note.php
+++ b/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions-payment-method-order-note.php
@@ -6,7 +6,7 @@
*/
use WCPay\Duplicate_Payment_Prevention_Service;
-use WCPay\Exceptions\API_Exception;
+use WCPay\Payment_Methods\CC_Payment_Method;
use WCPay\Session_Rate_Limiter;
/**
@@ -96,6 +96,9 @@ public function set_up() {
->getMock();
$this->mock_wcpay_account = $this->createMock( WC_Payments_Account::class );
+ $this->mock_wcpay_account
+ ->method( 'get_account_default_currency' )
+ ->willReturn( 'USD' );
$this->mock_customer_service = $this->getMockBuilder( 'WC_Payments_Customer_Service' )
->disableOriginalConstructor()
@@ -119,12 +122,19 @@ public function set_up() {
$mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class );
+ $mock_payment_method = $this->getMockBuilder( CC_Payment_Method::class )
+ ->setConstructorArgs( [ $this->mock_token_service ] )
+ ->onlyMethods( [ 'is_subscription_item_in_cart' ] )
+ ->getMock();
+
$this->wcpay_gateway = new \WC_Payment_Gateway_WCPay(
$this->mock_api_client,
$this->mock_wcpay_account,
$this->mock_customer_service,
$this->mock_token_service,
$this->mock_action_scheduler_service,
+ $mock_payment_method,
+ [ 'card' => $mock_payment_method ],
$this->mock_session_rate_limiter,
$this->mock_order_service,
$mock_dpps,
diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions-process-payment.php b/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions-process-payment.php
index 0db2ec88933..168349f902d 100644
--- a/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions-process-payment.php
+++ b/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions-process-payment.php
@@ -7,10 +7,10 @@
use WCPay\Core\Server\Request\Create_And_Confirm_Intention;
use WCPay\Core\Server\Request\Create_And_Confirm_Setup_Intention;
-use WCPay\Core\Server\Response;
use WCPay\Constants\Order_Status;
use WCPay\Constants\Intent_Status;
use WCPay\Duplicate_Payment_Prevention_Service;
+use WCPay\Payment_Methods\CC_Payment_Method;
use WCPay\Session_Rate_Limiter;
/**
@@ -122,6 +122,9 @@ public function set_up() {
->getMock();
$this->mock_wcpay_account = $this->createMock( WC_Payments_Account::class );
+ $this->mock_wcpay_account
+ ->method( 'get_account_default_currency' )
+ ->willReturn( 'usd' );
$this->mock_customer_service = $this->getMockBuilder( 'WC_Payments_Customer_Service' )
->disableOriginalConstructor()
@@ -139,7 +142,8 @@ public function set_up() {
$this->order_service = new WC_Payments_Order_Service( $this->mock_api_client );
- $mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class );
+ $mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class );
+ $mock_payment_method = $this->createMock( CC_Payment_Method::class );
$this->mock_wcpay_gateway = $this->getMockBuilder( '\WC_Payment_Gateway_WCPay' )
->setConstructorArgs(
@@ -149,6 +153,8 @@ public function set_up() {
$this->mock_customer_service,
$this->mock_token_service,
$this->mock_action_scheduler_service,
+ $mock_payment_method,
+ [ 'card' => $mock_payment_method ],
$this->mock_rate_limiter,
$this->order_service,
$mock_dpps,
diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions.php b/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions.php
index 9c27fda1b2d..a5b33c1581c 100644
--- a/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions.php
+++ b/tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions.php
@@ -11,6 +11,7 @@
use WCPay\Exceptions\API_Exception;
use WCPay\Internal\Service\Level3Service;
use WCPay\Internal\Service\OrderService;
+use WCPay\Payment_Methods\CC_Payment_Method;
use WCPay\Session_Rate_Limiter;
/**
@@ -111,6 +112,9 @@ public function set_up() {
->getMock();
$this->mock_wcpay_account = $this->createMock( WC_Payments_Account::class );
+ $this->mock_wcpay_account
+ ->method( 'get_account_default_currency' )
+ ->willReturn( 'usd' );
$this->mock_customer_service = $this->getMockBuilder( 'WC_Payments_Customer_Service' )
->disableOriginalConstructor()
@@ -135,12 +139,19 @@ public function set_up() {
$this->mock_localization_service = $this->createMock( WC_Payments_Localization_Service::class );
$this->mock_fraud_service = $this->createMock( WC_Payments_Fraud_Service::class );
+ $mock_payment_method = $this->getMockBuilder( CC_Payment_Method::class )
+ ->setConstructorArgs( [ $this->mock_token_service ] )
+ ->onlyMethods( [ 'is_subscription_item_in_cart' ] )
+ ->getMock();
+
$this->wcpay_gateway = new \WC_Payment_Gateway_WCPay(
$this->mock_api_client,
$this->mock_wcpay_account,
$this->mock_customer_service,
$this->mock_token_service,
$this->mock_action_scheduler_service,
+ $mock_payment_method,
+ [ 'card' => $mock_payment_method ],
$this->mock_session_rate_limiter,
$this->order_service,
$this->mock_dpps,
@@ -148,6 +159,7 @@ public function set_up() {
$this->mock_fraud_service
);
$this->wcpay_gateway->init_hooks();
+ WC_Payments::set_gateway( $this->wcpay_gateway );
// Mock the level3 service to always return an empty array.
$mock_level3_service = $this->createMock( Level3Service::class );
@@ -801,12 +813,19 @@ public function test_adds_custom_payment_meta_input_fallback_until_subs_3_0_7()
WC_Subscriptions::$version = '3.0.7';
+ $mock_payment_method = $this->getMockBuilder( CC_Payment_Method::class )
+ ->setConstructorArgs( [ $this->mock_token_service ] )
+ ->onlyMethods( [ 'is_subscription_item_in_cart' ] )
+ ->getMock();
+
$payment_gateway = new \WC_Payment_Gateway_WCPay(
$this->mock_api_client,
$this->mock_wcpay_account,
$this->mock_customer_service,
$this->mock_token_service,
$this->mock_action_scheduler_service,
+ $mock_payment_method,
+ [ 'card' => $mock_payment_method ],
$this->mock_session_rate_limiter,
$this->order_service,
$this->mock_dpps,
@@ -827,6 +846,11 @@ public function test_adds_custom_payment_meta_input_fallback_until_subs_3_0_7()
public function test_does_not_add_custom_payment_meta_input_fallback_for_subs_3_0_8() {
remove_all_actions( 'woocommerce_admin_order_data_after_billing_address' );
+ $mock_payment_method = $this->getMockBuilder( CC_Payment_Method::class )
+ ->setConstructorArgs( [ $this->mock_token_service ] )
+ ->onlyMethods( [ 'is_subscription_item_in_cart' ] )
+ ->getMock();
+
WC_Subscriptions::$version = '3.0.8';
new \WC_Payment_Gateway_WCPay(
$this->mock_api_client,
@@ -834,6 +858,8 @@ public function test_does_not_add_custom_payment_meta_input_fallback_for_subs_3_
$this->mock_customer_service,
$this->mock_token_service,
$this->mock_action_scheduler_service,
+ $mock_payment_method,
+ [ 'card' => $mock_payment_method ],
$this->mock_session_rate_limiter,
$this->order_service,
$this->mock_dpps,
diff --git a/tests/unit/test-class-wc-payment-gateway-wcpay.php b/tests/unit/test-class-wc-payment-gateway-wcpay.php
index 3eb69d5cfb5..02505f94d51 100644
--- a/tests/unit/test-class-wc-payment-gateway-wcpay.php
+++ b/tests/unit/test-class-wc-payment-gateway-wcpay.php
@@ -13,9 +13,7 @@
use WCPay\Core\Server\Request\Get_Charge;
use WCPay\Core\Server\Request\Get_Intention;
use WCPay\Core\Server\Request\Get_Setup_Intention;
-use WCPay\Core\Server\Request\Update_Intention;
use WCPay\Constants\Order_Status;
-use WCPay\Constants\Payment_Type;
use WCPay\Constants\Intent_Status;
use WCPay\Duplicate_Payment_Prevention_Service;
use WCPay\Exceptions\Amount_Too_Small_Exception;
@@ -30,7 +28,6 @@
use WCPay\Payment_Information;
use WCPay\Payment_Methods\CC_Payment_Method;
use WCPay\Payment_Methods\Sepa_Payment_Method;
-use WCPay\Payment_Methods\UPE_Payment_Gateway;
use WCPay\WooPay\WooPay_Utilities;
use WCPay\Session_Rate_Limiter;
@@ -48,7 +45,7 @@ class WC_Payment_Gateway_WCPay_Test extends WCPAY_UnitTestCase {
/**
* System under test.
*
- * @var UPE_Payment_Gateway
+ * @var WC_Payment_Gateway_WCPay
*/
private $wcpay_gateway;
@@ -214,7 +211,7 @@ public function set_up() {
->setMethods( [ 'is_subscription_item_in_cart' ] )
->getMock();
- $this->wcpay_gateway = new UPE_Payment_Gateway(
+ $this->wcpay_gateway = new WC_Payment_Gateway_WCPay(
$this->mock_api_client,
$this->mock_wcpay_account,
$this->mock_customer_service,
@@ -2006,7 +2003,7 @@ public function test_is_in_test_mode() {
* @return MockObject|WC_Payment_Gateway_WCPay
*/
private function get_partial_mock_for_gateway( array $methods = [] ) {
- return $this->getMockBuilder( UPE_Payment_Gateway::class )
+ return $this->getMockBuilder( WC_Payment_Gateway_WCPay::class )
->setConstructorArgs(
[
$this->mock_api_client,
@@ -2363,7 +2360,7 @@ private function create_charge_object() {
}
private function create_gateway_with( $payment_method ) {
- return new UPE_Payment_Gateway(
+ return new WC_Payment_Gateway_WCPay(
$this->mock_api_client,
$this->mock_wcpay_account,
$this->mock_customer_service,
diff --git a/tests/unit/test-class-wc-payments-checkout.php b/tests/unit/test-class-wc-payments-checkout.php
index b187c4f51ce..d6273a1fcd2 100644
--- a/tests/unit/test-class-wc-payments-checkout.php
+++ b/tests/unit/test-class-wc-payments-checkout.php
@@ -8,7 +8,6 @@
use WCPay\WC_Payments_Checkout;
use PHPUnit\Framework\MockObject\MockObject;
use WCPay\Constants\Payment_Method;
-use WCPay\Payment_Methods\UPE_Payment_Gateway;
use WCPay\WooPay\WooPay_Utilities;
use WCPay\Fraud_Prevention\Fraud_Prevention_Service;
use WCPay\Payment_Methods\Bancontact_Payment_Method;
@@ -36,9 +35,9 @@ class WC_Payments_Checkout_Test extends WP_UnitTestCase {
private $system_under_test;
/**
- * UPE_Payment_Gateway instance.
+ * WC_Payment_Gateway_WCPay instance.
*
- * @var UPE_Payment_Gateway|MockObject
+ * @var WC_Payment_Gateway_WCPay|MockObject
*/
private $mock_wcpay_gateway;
@@ -81,7 +80,7 @@ class WC_Payments_Checkout_Test extends WP_UnitTestCase {
/**
* Default gateway.
*
- * @var UPE_Payment_Gateway
+ * @var WC_Payment_Gateway_WCPay
*/
private $default_gateway;
@@ -89,7 +88,7 @@ public function set_up() {
parent::set_up();
// Setup the gateway mock.
- $this->mock_wcpay_gateway = $this->getMockBuilder( UPE_Payment_Gateway::class )
+ $this->mock_wcpay_gateway = $this->getMockBuilder( WC_Payment_Gateway_WCPay::class )
->onlyMethods( [ 'get_account_domestic_currency', 'get_payment_method_ids_enabled_at_checkout', 'should_use_stripe_platform_on_checkout_page', 'should_support_saved_payments', 'is_saved_cards_enabled', 'save_payment_method_checkbox', 'get_account_statement_descriptor', 'get_icon_url', 'get_payment_method_ids_enabled_at_checkout_filtered_by_fees', 'is_subscription_item_in_cart', 'wc_payments_get_payment_method_by_id', 'display_gateway_html' ] )
->disableOriginalConstructor()
->getMock();
@@ -119,8 +118,7 @@ public function set_up() {
$this->mock_token_service = $this->createMock( WC_Payments_Token_Service::class );
// This is needed to ensure that only the mocked gateway is always used by the checkout class.
- $this->default_gateway = WC_Payments::get_registered_card_gateway();
- WC_Payments::set_registered_card_gateway( $this->mock_wcpay_gateway );
+ $this->default_gateway = WC_Payments::get_gateway();
WC_Payments::set_gateway( $this->mock_wcpay_gateway );
// Use a callback to suppresses the output buffering being printed to the CLI.
@@ -135,7 +133,6 @@ function ( $output ) {
public function tear_down() {
parent::tear_down();
- WC_Payments::set_registered_card_gateway( $this->default_gateway );
WC_Payments::set_gateway( $this->default_gateway );
}
diff --git a/tests/unit/test-class-wc-payments-express-checkout-button-display-handler.php b/tests/unit/test-class-wc-payments-express-checkout-button-display-handler.php
index dfb059ba7b4..899e530aa67 100644
--- a/tests/unit/test-class-wc-payments-express-checkout-button-display-handler.php
+++ b/tests/unit/test-class-wc-payments-express-checkout-button-display-handler.php
@@ -7,6 +7,7 @@
use PHPUnit\Framework\MockObject\MockObject;
use WCPay\Duplicate_Payment_Prevention_Service;
+use WCPay\Payment_Methods\CC_Payment_Method;
use WCPay\Session_Rate_Limiter;
use WCPay\WooPay\WooPay_Utilities;
@@ -148,6 +149,7 @@ private function make_wcpay_gateway() {
$mock_rate_limiter = $this->createMock( Session_Rate_Limiter::class );
$mock_order_service = $this->createMock( WC_Payments_Order_Service::class );
$mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class );
+ $mock_payment_method = $this->createMock( CC_Payment_Method::class );
return new WC_Payment_Gateway_WCPay(
$this->mock_api_client,
@@ -155,6 +157,8 @@ private function make_wcpay_gateway() {
$mock_customer_service,
$mock_token_service,
$mock_action_scheduler_service,
+ $mock_payment_method,
+ [ 'card' => $mock_payment_method ],
$mock_rate_limiter,
$mock_order_service,
$mock_dpps,
diff --git a/tests/unit/test-class-wc-payments-payment-request-button-handler.php b/tests/unit/test-class-wc-payments-payment-request-button-handler.php
index ce1283265b4..e4d7412bf15 100644
--- a/tests/unit/test-class-wc-payments-payment-request-button-handler.php
+++ b/tests/unit/test-class-wc-payments-payment-request-button-handler.php
@@ -6,6 +6,7 @@
*/
use WCPay\Duplicate_Payment_Prevention_Service;
+use WCPay\Payment_Methods\CC_Payment_Method;
use WCPay\Session_Rate_Limiter;
/**
@@ -198,6 +199,7 @@ private function make_wcpay_gateway() {
$mock_rate_limiter = $this->createMock( Session_Rate_Limiter::class );
$mock_order_service = $this->createMock( WC_Payments_Order_Service::class );
$mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class );
+ $mock_payment_method = $this->createMock( CC_Payment_Method::class );
return new WC_Payment_Gateway_WCPay(
$this->mock_api_client,
@@ -205,6 +207,8 @@ private function make_wcpay_gateway() {
$mock_customer_service,
$mock_token_service,
$mock_action_scheduler_service,
+ $mock_payment_method,
+ [ 'card' => $mock_payment_method ],
$mock_rate_limiter,
$mock_order_service,
$mock_dpps,
diff --git a/tests/unit/test-class-wc-payments-woopay-button-handler.php b/tests/unit/test-class-wc-payments-woopay-button-handler.php
index 78f464cadf2..161c5796101 100644
--- a/tests/unit/test-class-wc-payments-woopay-button-handler.php
+++ b/tests/unit/test-class-wc-payments-woopay-button-handler.php
@@ -6,6 +6,7 @@
*/
use WCPay\Duplicate_Payment_Prevention_Service;
+use WCPay\Payment_Methods\CC_Payment_Method;
use WCPay\Session_Rate_Limiter;
use WCPay\WooPay\WooPay_Utilities;
@@ -127,6 +128,7 @@ private function make_wcpay_gateway() {
$mock_rate_limiter = $this->createMock( Session_Rate_Limiter::class );
$mock_order_service = $this->createMock( WC_Payments_Order_Service::class );
$mock_dpps = $this->createMock( Duplicate_Payment_Prevention_Service::class );
+ $mock_payment_method = $this->createMock( CC_Payment_Method::class );
return new WC_Payment_Gateway_WCPay(
$this->mock_api_client,
@@ -134,6 +136,8 @@ private function make_wcpay_gateway() {
$mock_customer_service,
$mock_token_service,
$mock_action_scheduler_service,
+ $mock_payment_method,
+ [ 'card' => $mock_payment_method ],
$mock_rate_limiter,
$mock_order_service,
$mock_dpps,
diff --git a/tests/unit/test-class-wc-payments.php b/tests/unit/test-class-wc-payments.php
index ce6aa216a1d..d5e7da12239 100644
--- a/tests/unit/test-class-wc-payments.php
+++ b/tests/unit/test-class-wc-payments.php
@@ -5,7 +5,6 @@
* @package WooCommerce\Payments\Tests
*/
-use WCPay\Payment_Methods\UPE_Payment_Gateway;
use WCPay\WooPay\WooPay_Session;
/**
@@ -81,7 +80,7 @@ public function test_it_does_not_register_woopay_hooks_if_feature_flag_is_disabl
public function test_it_skips_stripe_link_gateway_registration() {
$this->mock_cache->method( 'get' )->willReturn( [ 'is_deferred_intent_creation_upe_enabled' => true ] );
- $card_gateway_mock = $this->createMock( UPE_Payment_Gateway::class );
+ $card_gateway_mock = $this->createMock( WC_Payment_Gateway_WCPay::class );
$card_gateway_mock
->expects( $this->once() )
->method( 'get_payment_method_ids_enabled_at_checkout' )
@@ -100,7 +99,7 @@ public function test_it_skips_stripe_link_gateway_registration() {
$registered_gateways = WC_Payments::register_gateway( [] );
$this->assertCount( 1, $registered_gateways );
- $this->assertInstanceOf( UPE_Payment_Gateway::class, $registered_gateways[0] );
+ $this->assertInstanceOf( WC_Payment_Gateway_WCPay::class, $registered_gateways[0] );
$this->assertEquals( $registered_gateways[0]->get_stripe_id(), 'card' );
}
From 0af42f558c730ee97a461931c06360026241f657 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Sun, 31 Dec 2023 12:07:35 +0000
Subject: [PATCH 54/56] Update version and add changelog entries for release
7.0.0
---
changelog.txt | 56 ++++++++++++++++++
changelog/7588-express-checkout-utilities | 4 --
.../add-334-test-mode-notice-order-details | 4 --
...ancel-authorizations-if-order-is-cancelled | 4 --
...-7248-refund-transaction-from-details-page | 4 --
changelog/add-7591-missing-columns-export-csv | 4 --
changelog/add-7846-test-mode-confirm-modal | 4 --
changelog/add-thank-you-page-tracks | 4 --
changelog/cleanup-devtools-flags | 4 --
changelog/cleanup-is-upe-enabled-logic | 4 --
changelog/cleanup-redundant-script-enqueueing | 4 --
changelog/cleanup-upe-checkout-class | 4 --
changelog/cleanup-upe-gateways-II | 4 --
changelog/cleanup-upe-gateways-part-1 | 4 --
changelog/deferred-intent | 4 --
.../dev-3468-allow-reset-account-management | 4 --
changelog/dev-bump-wc-version-8-4-0 | 4 --
changelog/dev-fix-e2e-tests-on-wc-7-7 | 5 --
changelog/dev-fix-multi-currency-e2e-tests | 5 --
changelog/dev-test-ci-without-3ds1 | 4 --
changelog/e2e-7349-currency-switcher-widget | 4 --
...2e-7382-spec-merchant-multi-currency-setup | 4 --
changelog/fix-3693-qualitative-feedback-note | 4 --
...700-remove-currency-sign-modification-code | 4 --
changelog/fix-6782-support-phone-dev-mode | 4 --
...ror-while-trying-to-capture-partial-amount | 4 --
...01-descriptive-error-message-on-invalid-pm | 4 --
.../fix-7588-woopay-subscription-variation | 5 --
.../fix-7592-update-transaction-order-id | 4 --
changelog/fix-7595-reports-customers | 4 --
...748-capture-notification-styles-are-broken | 4 --
.../fix-7750-include-discount-in-tooltip | 4 --
changelog/fix-7834-zero-decimals-csv-export | 4 --
.../fix-7838-fraud-filters-html-encode-bug | 4 --
changelog/fix-7839-deposits-rest-api-docs | 4 --
...3-woopay-automatewoo-referrals-integration | 4 --
...ect-account-overview-account-type-nullable | 5 --
changelog/fix-account-currency-hook | 4 --
changelog/fix-apple-pay-including-tax | 4 --
changelog/fix-jstest-regression-pr-7851 | 5 --
.../fix-jsx-account-status-error-messages | 4 --
...r-order-and-first-party-auth-compatibility | 4 --
...erview-account-balances-on-instant-deposit | 4 --
changelog/fix-test-support-phone | 5 --
changelog/fix-update-payment-assets | 4 --
.../partially-ccleanup-legacy-upe-and-card | 4 --
changelog/remove-flag-usage | 4 --
.../revert-file-needed-for-plugin-update | 5 --
changelog/revert-prefetch-session-for-button | 4 --
changelog/subscriptions-6.6.0-1 | 4 --
changelog/subscriptions-6.6.0-2 | 4 --
changelog/subscriptions-core-6.6.0 | 4 --
changelog/subscriptions-core-6.6.0-3 | 4 --
changelog/subscriptions-core-6.6.0-4 | 4 --
changelog/subscriptions-core-6.6.0-5 | 4 --
changelog/subscriptions-core-6.6.0-6 | 4 --
changelog/subscriptions-core-6.6.0-7 | 4 --
changelog/subscriptions-core-6.6.0-8 | 4 --
changelog/update-4163-compatibility-service | 4 --
...-card-behavior-if-affected-by-other-config | 4 --
...date-6325-fraud-risk-link-text-in-settings | 4 --
...-change-setup-refund-policy-note-into-task | 4 --
package-lock.json | 4 +-
package.json | 2 +-
readme.txt | 58 ++++++++++++++++++-
woocommerce-payments.php | 2 +-
66 files changed, 117 insertions(+), 256 deletions(-)
delete mode 100644 changelog/7588-express-checkout-utilities
delete mode 100644 changelog/add-334-test-mode-notice-order-details
delete mode 100644 changelog/add-5605-cancel-authorizations-if-order-is-cancelled
delete mode 100644 changelog/add-7248-refund-transaction-from-details-page
delete mode 100644 changelog/add-7591-missing-columns-export-csv
delete mode 100644 changelog/add-7846-test-mode-confirm-modal
delete mode 100644 changelog/add-thank-you-page-tracks
delete mode 100644 changelog/cleanup-devtools-flags
delete mode 100644 changelog/cleanup-is-upe-enabled-logic
delete mode 100644 changelog/cleanup-redundant-script-enqueueing
delete mode 100644 changelog/cleanup-upe-checkout-class
delete mode 100644 changelog/cleanup-upe-gateways-II
delete mode 100644 changelog/cleanup-upe-gateways-part-1
delete mode 100644 changelog/deferred-intent
delete mode 100644 changelog/dev-3468-allow-reset-account-management
delete mode 100644 changelog/dev-bump-wc-version-8-4-0
delete mode 100644 changelog/dev-fix-e2e-tests-on-wc-7-7
delete mode 100644 changelog/dev-fix-multi-currency-e2e-tests
delete mode 100644 changelog/dev-test-ci-without-3ds1
delete mode 100644 changelog/e2e-7349-currency-switcher-widget
delete mode 100644 changelog/e2e-7382-spec-merchant-multi-currency-setup
delete mode 100644 changelog/fix-3693-qualitative-feedback-note
delete mode 100644 changelog/fix-6700-remove-currency-sign-modification-code
delete mode 100644 changelog/fix-6782-support-phone-dev-mode
delete mode 100644 changelog/fix-6806-authorizations-level-3-data-error-while-trying-to-capture-partial-amount
delete mode 100644 changelog/fix-7301-descriptive-error-message-on-invalid-pm
delete mode 100644 changelog/fix-7588-woopay-subscription-variation
delete mode 100644 changelog/fix-7592-update-transaction-order-id
delete mode 100644 changelog/fix-7595-reports-customers
delete mode 100644 changelog/fix-7748-capture-notification-styles-are-broken
delete mode 100644 changelog/fix-7750-include-discount-in-tooltip
delete mode 100644 changelog/fix-7834-zero-decimals-csv-export
delete mode 100644 changelog/fix-7838-fraud-filters-html-encode-bug
delete mode 100644 changelog/fix-7839-deposits-rest-api-docs
delete mode 100644 changelog/fix-7913-woopay-automatewoo-referrals-integration
delete mode 100644 changelog/fix-7920-correct-account-overview-account-type-nullable
delete mode 100644 changelog/fix-account-currency-hook
delete mode 100644 changelog/fix-apple-pay-including-tax
delete mode 100644 changelog/fix-jstest-regression-pr-7851
delete mode 100644 changelog/fix-jsx-account-status-error-messages
delete mode 100644 changelog/fix-pay-for-order-and-first-party-auth-compatibility
delete mode 100644 changelog/fix-refresh-payments-overview-account-balances-on-instant-deposit
delete mode 100644 changelog/fix-test-support-phone
delete mode 100644 changelog/fix-update-payment-assets
delete mode 100644 changelog/partially-ccleanup-legacy-upe-and-card
delete mode 100644 changelog/remove-flag-usage
delete mode 100644 changelog/revert-file-needed-for-plugin-update
delete mode 100644 changelog/revert-prefetch-session-for-button
delete mode 100644 changelog/subscriptions-6.6.0-1
delete mode 100644 changelog/subscriptions-6.6.0-2
delete mode 100644 changelog/subscriptions-core-6.6.0
delete mode 100644 changelog/subscriptions-core-6.6.0-3
delete mode 100644 changelog/subscriptions-core-6.6.0-4
delete mode 100644 changelog/subscriptions-core-6.6.0-5
delete mode 100644 changelog/subscriptions-core-6.6.0-6
delete mode 100644 changelog/subscriptions-core-6.6.0-7
delete mode 100644 changelog/subscriptions-core-6.6.0-8
delete mode 100644 changelog/update-4163-compatibility-service
delete mode 100644 changelog/update-6320-rule-card-behavior-if-affected-by-other-config
delete mode 100644 changelog/update-6325-fraud-risk-link-text-in-settings
delete mode 100644 changelog/update-change-setup-refund-policy-note-into-task
diff --git a/changelog.txt b/changelog.txt
index 73e649d188e..68da1290131 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,5 +1,61 @@
*** WooPayments Changelog ***
+= 7.0.0 - 2024-01-03 =
+* Add - Add Account Management tools with reset account functionality for partially onboarded accounts.
+* Add - Adding Compatibility Service to assist with flagging possible compatibility issues in the future.
+* Add - Add refund controls to transaction details view
+* Add - Add test mode notice in page order detail.
+* Add - Display a Confirmaton Modal on enabling Test Mode
+* Add - Introduce Customer currency, Deposit currency, Amount in Customer Currency and Deposit ID columns to the Transaction list UI and CSV export
+* Fix - Allow test phone number as Support Phone in Dev mode
+* Fix - Avoid using the removed deferred UPE flag
+* Fix - Ensure proper backfilling of subscription metadata (i.e. dates and cache) to the postmeta table when HPOS is enabled and compatibility mode (data syncing) is turned on.
+* Fix - Fetch and update the `_cancelled_email_sent` meta in a HPOS compatibile way.
+* Fix - fix: account currency hook return value
+* Fix - Fix account status error messages with links.
+* Fix - Fix country names with accents not showing correctly on international country fraud filter
+* Fix - Fix currency negative sign position on JS rendered amounts
+* Fix - Fixed a Level 3 error occurring during the capture of an authorization for amounts lower than the initial authorization amount.
+* Fix - Fixed Apple Pay Double Tax Calculation Issue
+* Fix - Fixed broken styles in authorization capture notifications
+* Fix - Fix incorrect amounts caused by zero-decimal currencies on Transactions, Deposits and Deposits CSV export
+* Fix - Fix missing customer data from transactions report
+* Fix - Fix missing order number in transaction reports CSV
+* Fix - Fix WooPay integration with AutomateWoo - Refer a Friend extension.
+* Fix - Improved error message for invalid payment method
+* Fix - Include discount fee in fees tooltip
+* Fix - Introduce WC_Payments_Express_Checkout_Button_Utils class.
+* Fix - Pass the pay-for-order params to get the pre-fetch session data
+* Fix - Prevents a PHP fatal error that occurs when the cart contains a renewal order item that no longer exists.
+* Fix - Resolved an issue that would cause undefined $current_page, $max_num_pages, and $paginate variable errors when viewing a page with the subscriptions-shortcode.
+* Fix - Revemoved pre-fretch session for button to prevent draft order creation
+* Fix - Update account balances on the Payments Overview screen when an instant deposit is requested
+* Fix - Update Qualitative Feedback note to have more efficient sql query.
+* Fix - When HPOS is enabled and data compatibility mode is turned on, make sure subscription date changes made to postmeta are synced to orders_meta table.
+* Fix - When using the checkout block to pay for renewal orders, ensure the order's cart hash is updated to make sure the existing order can be used.
+* Update - Actualized cards-related assets for settings and transactions pages.
+* Update - Cleanup the deprecated payment gateway processing - part II
+* Update - Cleanup the deprecated payment gateway processing - part III
+* Update - Confirmation when cancelling order with pending authorization. Automatic order changes submission if confirmed.
+* Update - Updates the anchor text for the fraud and risk tools documentation link on the Payments Settings page.
+* Update - Updates the behavior and display of the international IP address rule card if the rule is being affected by the WooCommerce core selling locations general option.
+* Dev - Add e2e tests for the currency switcher widget.
+* Dev - Added documentation for deposits REST API endpoints.
+* Dev - Bump WC tested up to version to 8.4.0.
+* Dev - Cleanup enqueueing of the scripts which were removed
+* Dev - Cleanup the deprecated payment gateway processing - part IV
+* Dev - Cleanup the deprecated payment gateway processing - part V
+* Dev - Cleanup the deprecated payment gateway processing - part VI
+* Dev - Comment: Fix declined 3DS card E2E test.
+* Dev - Deprecate the WC_Subscriptions_Synchroniser::add_to_recurring_cart_key(). Use WC_Subscriptions_Synchroniser::add_to_recurring_product_grouping_key() instead.
+* Dev - E2E test - Merchant facing: Multi-currency setup
+* Dev - Improve E2E checkout tests
+* Dev - Introduce a new wcs_get_subscription_grouping_key() function to generate a unique key for a subscription based on its billing schedule. This function uses the existing recurring cart key concept.
+* Dev - Remove "Set-up refund policy" Inbox note as superfluous.
+* Dev - remove unused factor flag for deferred UPE
+* Dev - Thank you page Tracks event
+* Dev - Updated subscriptions-core to version 6.6.0
+
= 6.9.2 - 2023-12-14 =
* Add - Notice is added when merchant has funds that are not yet available for deposit.
* Add - Show a deposit schedule notice on the deposits list page to indicate that future deposits can be expected.
diff --git a/changelog/7588-express-checkout-utilities b/changelog/7588-express-checkout-utilities
deleted file mode 100644
index 143b670d60c..00000000000
--- a/changelog/7588-express-checkout-utilities
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: fix
-
-Introduce WC_Payments_Express_Checkout_Button_Utils class.
diff --git a/changelog/add-334-test-mode-notice-order-details b/changelog/add-334-test-mode-notice-order-details
deleted file mode 100644
index de22a34c323..00000000000
--- a/changelog/add-334-test-mode-notice-order-details
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: add
-
-Add test mode notice in page order detail.
diff --git a/changelog/add-5605-cancel-authorizations-if-order-is-cancelled b/changelog/add-5605-cancel-authorizations-if-order-is-cancelled
deleted file mode 100644
index 879ed83d30f..00000000000
--- a/changelog/add-5605-cancel-authorizations-if-order-is-cancelled
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: update
-
-Confirmation when cancelling order with pending authorization. Automatic order changes submission if confirmed.
diff --git a/changelog/add-7248-refund-transaction-from-details-page b/changelog/add-7248-refund-transaction-from-details-page
deleted file mode 100644
index bfd753860e8..00000000000
--- a/changelog/add-7248-refund-transaction-from-details-page
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: add
-
-Add refund controls to transaction details view
diff --git a/changelog/add-7591-missing-columns-export-csv b/changelog/add-7591-missing-columns-export-csv
deleted file mode 100644
index 668644d2cfc..00000000000
--- a/changelog/add-7591-missing-columns-export-csv
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: add
-
-Introduce Customer currency, Deposit currency, Amount in Customer Currency and Deposit ID columns to the Transaction list UI and CSV export
diff --git a/changelog/add-7846-test-mode-confirm-modal b/changelog/add-7846-test-mode-confirm-modal
deleted file mode 100644
index 0725c55b1aa..00000000000
--- a/changelog/add-7846-test-mode-confirm-modal
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: add
-
-Display a Confirmaton Modal on enabling Test Mode
diff --git a/changelog/add-thank-you-page-tracks b/changelog/add-thank-you-page-tracks
deleted file mode 100644
index 31888d5d917..00000000000
--- a/changelog/add-thank-you-page-tracks
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: dev
-
-Thank you page Tracks event
diff --git a/changelog/cleanup-devtools-flags b/changelog/cleanup-devtools-flags
deleted file mode 100644
index adbf7f71958..00000000000
--- a/changelog/cleanup-devtools-flags
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: dev
-
-remove unused factor flag for deferred UPE
diff --git a/changelog/cleanup-is-upe-enabled-logic b/changelog/cleanup-is-upe-enabled-logic
deleted file mode 100644
index 79bae6fa471..00000000000
--- a/changelog/cleanup-is-upe-enabled-logic
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: update
-
-Cleanup the deprecated payment gateway processing - part III
diff --git a/changelog/cleanup-redundant-script-enqueueing b/changelog/cleanup-redundant-script-enqueueing
deleted file mode 100644
index 20c952d459e..00000000000
--- a/changelog/cleanup-redundant-script-enqueueing
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: dev
-
-Cleanup enqueueing of the scripts which were removed
diff --git a/changelog/cleanup-upe-checkout-class b/changelog/cleanup-upe-checkout-class
deleted file mode 100644
index 95cfa040bf5..00000000000
--- a/changelog/cleanup-upe-checkout-class
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: dev
-
-Cleanup the deprecated payment gateway processing - part IV
diff --git a/changelog/cleanup-upe-gateways-II b/changelog/cleanup-upe-gateways-II
deleted file mode 100644
index 16f3e3cd17f..00000000000
--- a/changelog/cleanup-upe-gateways-II
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: dev
-
-Cleanup the deprecated payment gateway processing - part VI
diff --git a/changelog/cleanup-upe-gateways-part-1 b/changelog/cleanup-upe-gateways-part-1
deleted file mode 100644
index d449f2047df..00000000000
--- a/changelog/cleanup-upe-gateways-part-1
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: dev
-
-Cleanup the deprecated payment gateway processing - part V
diff --git a/changelog/deferred-intent b/changelog/deferred-intent
deleted file mode 100644
index ef5442b5f17..00000000000
--- a/changelog/deferred-intent
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: dev
-
-Improve E2E checkout tests
diff --git a/changelog/dev-3468-allow-reset-account-management b/changelog/dev-3468-allow-reset-account-management
deleted file mode 100644
index ed030674f95..00000000000
--- a/changelog/dev-3468-allow-reset-account-management
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: add
-
-Add Account Management tools with reset account functionality for partially onboarded accounts.
diff --git a/changelog/dev-bump-wc-version-8-4-0 b/changelog/dev-bump-wc-version-8-4-0
deleted file mode 100644
index 5c00289cc5b..00000000000
--- a/changelog/dev-bump-wc-version-8-4-0
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: dev
-
-Bump WC tested up to version to 8.4.0.
\ No newline at end of file
diff --git a/changelog/dev-fix-e2e-tests-on-wc-7-7 b/changelog/dev-fix-e2e-tests-on-wc-7-7
deleted file mode 100644
index 15b4d3b72e9..00000000000
--- a/changelog/dev-fix-e2e-tests-on-wc-7-7
+++ /dev/null
@@ -1,5 +0,0 @@
-Significance: patch
-Type: dev
-Comment: Fix e2e tests on WC 7.7.
-
-
diff --git a/changelog/dev-fix-multi-currency-e2e-tests b/changelog/dev-fix-multi-currency-e2e-tests
deleted file mode 100644
index 45ac7deccc1..00000000000
--- a/changelog/dev-fix-multi-currency-e2e-tests
+++ /dev/null
@@ -1,5 +0,0 @@
-Significance: patch
-Type: dev
-Comment: Fix multi-currency e2e tests.
-
-
diff --git a/changelog/dev-test-ci-without-3ds1 b/changelog/dev-test-ci-without-3ds1
deleted file mode 100644
index f2d4b778788..00000000000
--- a/changelog/dev-test-ci-without-3ds1
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: dev
-
-Comment: Fix declined 3DS card E2E test.
diff --git a/changelog/e2e-7349-currency-switcher-widget b/changelog/e2e-7349-currency-switcher-widget
deleted file mode 100644
index 1bf9af1d6c3..00000000000
--- a/changelog/e2e-7349-currency-switcher-widget
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: dev
-
-Add e2e tests for the currency switcher widget.
diff --git a/changelog/e2e-7382-spec-merchant-multi-currency-setup b/changelog/e2e-7382-spec-merchant-multi-currency-setup
deleted file mode 100644
index b079e3e6e8e..00000000000
--- a/changelog/e2e-7382-spec-merchant-multi-currency-setup
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: dev
-
-E2E test - Merchant facing: Multi-currency setup
diff --git a/changelog/fix-3693-qualitative-feedback-note b/changelog/fix-3693-qualitative-feedback-note
deleted file mode 100644
index 8862cc0c961..00000000000
--- a/changelog/fix-3693-qualitative-feedback-note
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: fix
-
-Update Qualitative Feedback note to have more efficient sql query.
diff --git a/changelog/fix-6700-remove-currency-sign-modification-code b/changelog/fix-6700-remove-currency-sign-modification-code
deleted file mode 100644
index 74634338357..00000000000
--- a/changelog/fix-6700-remove-currency-sign-modification-code
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: fix
-
-Fix currency negative sign position on JS rendered amounts
diff --git a/changelog/fix-6782-support-phone-dev-mode b/changelog/fix-6782-support-phone-dev-mode
deleted file mode 100644
index 42166e6419d..00000000000
--- a/changelog/fix-6782-support-phone-dev-mode
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: fix
-
-Allow test phone number as Support Phone in Dev mode
diff --git a/changelog/fix-6806-authorizations-level-3-data-error-while-trying-to-capture-partial-amount b/changelog/fix-6806-authorizations-level-3-data-error-while-trying-to-capture-partial-amount
deleted file mode 100644
index 870c1de09f2..00000000000
--- a/changelog/fix-6806-authorizations-level-3-data-error-while-trying-to-capture-partial-amount
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: fix
-
-Fixed a Level 3 error occurring during the capture of an authorization for amounts lower than the initial authorization amount.
diff --git a/changelog/fix-7301-descriptive-error-message-on-invalid-pm b/changelog/fix-7301-descriptive-error-message-on-invalid-pm
deleted file mode 100644
index 798235980af..00000000000
--- a/changelog/fix-7301-descriptive-error-message-on-invalid-pm
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: fix
-
-Improved error message for invalid payment method
diff --git a/changelog/fix-7588-woopay-subscription-variation b/changelog/fix-7588-woopay-subscription-variation
deleted file mode 100644
index 06f44dc9845..00000000000
--- a/changelog/fix-7588-woopay-subscription-variation
+++ /dev/null
@@ -1,5 +0,0 @@
-Significance: patch
-Type: fix
-Comment: Edge case adding subscription_variation to WooPay button supported types
-
-
diff --git a/changelog/fix-7592-update-transaction-order-id b/changelog/fix-7592-update-transaction-order-id
deleted file mode 100644
index 0ef8cffd17f..00000000000
--- a/changelog/fix-7592-update-transaction-order-id
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: fix
-
-Fix missing order number in transaction reports CSV
diff --git a/changelog/fix-7595-reports-customers b/changelog/fix-7595-reports-customers
deleted file mode 100644
index e4ab131cb21..00000000000
--- a/changelog/fix-7595-reports-customers
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: fix
-
-Fix missing customer data from transactions report
diff --git a/changelog/fix-7748-capture-notification-styles-are-broken b/changelog/fix-7748-capture-notification-styles-are-broken
deleted file mode 100644
index 348106f98f8..00000000000
--- a/changelog/fix-7748-capture-notification-styles-are-broken
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: fix
-
-Fixed broken styles in authorization capture notifications
diff --git a/changelog/fix-7750-include-discount-in-tooltip b/changelog/fix-7750-include-discount-in-tooltip
deleted file mode 100644
index b600a611e92..00000000000
--- a/changelog/fix-7750-include-discount-in-tooltip
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: fix
-
-Include discount fee in fees tooltip
diff --git a/changelog/fix-7834-zero-decimals-csv-export b/changelog/fix-7834-zero-decimals-csv-export
deleted file mode 100644
index 1e5b2a1cf87..00000000000
--- a/changelog/fix-7834-zero-decimals-csv-export
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: fix
-
-Fix incorrect amounts caused by zero-decimal currencies on Transactions, Deposits and Deposits CSV export
diff --git a/changelog/fix-7838-fraud-filters-html-encode-bug b/changelog/fix-7838-fraud-filters-html-encode-bug
deleted file mode 100644
index 1b358176fe8..00000000000
--- a/changelog/fix-7838-fraud-filters-html-encode-bug
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: fix
-
-Fix country names with accents not showing correctly on international country fraud filter
diff --git a/changelog/fix-7839-deposits-rest-api-docs b/changelog/fix-7839-deposits-rest-api-docs
deleted file mode 100644
index b50f1644a81..00000000000
--- a/changelog/fix-7839-deposits-rest-api-docs
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: dev
-
-Added documentation for deposits REST API endpoints.
diff --git a/changelog/fix-7913-woopay-automatewoo-referrals-integration b/changelog/fix-7913-woopay-automatewoo-referrals-integration
deleted file mode 100644
index bace9a2cc9b..00000000000
--- a/changelog/fix-7913-woopay-automatewoo-referrals-integration
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: fix
-
-Fix WooPay integration with AutomateWoo - Refer a Friend extension.
diff --git a/changelog/fix-7920-correct-account-overview-account-type-nullable b/changelog/fix-7920-correct-account-overview-account-type-nullable
deleted file mode 100644
index 5db6d1382f4..00000000000
--- a/changelog/fix-7920-correct-account-overview-account-type-nullable
+++ /dev/null
@@ -1,5 +0,0 @@
-Significance: patch
-Type: dev
-Comment: No changelog entry required – minor TS interface fix with no user-facing changes
-
-
diff --git a/changelog/fix-account-currency-hook b/changelog/fix-account-currency-hook
deleted file mode 100644
index 23d9628b19f..00000000000
--- a/changelog/fix-account-currency-hook
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: fix
-
-fix: account currency hook return value
diff --git a/changelog/fix-apple-pay-including-tax b/changelog/fix-apple-pay-including-tax
deleted file mode 100644
index 59afc2bef4f..00000000000
--- a/changelog/fix-apple-pay-including-tax
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: fix
-
-Fixed Apple Pay Double Tax Calculation Issue
diff --git a/changelog/fix-jstest-regression-pr-7851 b/changelog/fix-jstest-regression-pr-7851
deleted file mode 100644
index 4308b603c02..00000000000
--- a/changelog/fix-jstest-regression-pr-7851
+++ /dev/null
@@ -1,5 +0,0 @@
-Significance: patch
-Type: dev
-Comment: Fix JS regression test in PR 7851
-
-
diff --git a/changelog/fix-jsx-account-status-error-messages b/changelog/fix-jsx-account-status-error-messages
deleted file mode 100644
index a45adc8b5ab..00000000000
--- a/changelog/fix-jsx-account-status-error-messages
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: fix
-
-Fix account status error messages with links.
diff --git a/changelog/fix-pay-for-order-and-first-party-auth-compatibility b/changelog/fix-pay-for-order-and-first-party-auth-compatibility
deleted file mode 100644
index 26182c064d4..00000000000
--- a/changelog/fix-pay-for-order-and-first-party-auth-compatibility
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: fix
-
-Pass the pay-for-order params to get the pre-fetch session data
diff --git a/changelog/fix-refresh-payments-overview-account-balances-on-instant-deposit b/changelog/fix-refresh-payments-overview-account-balances-on-instant-deposit
deleted file mode 100644
index 59ba1fb0bdd..00000000000
--- a/changelog/fix-refresh-payments-overview-account-balances-on-instant-deposit
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: fix
-
-Update account balances on the Payments Overview screen when an instant deposit is requested
diff --git a/changelog/fix-test-support-phone b/changelog/fix-test-support-phone
deleted file mode 100644
index 97abae072f7..00000000000
--- a/changelog/fix-test-support-phone
+++ /dev/null
@@ -1,5 +0,0 @@
-Significance: patch
-Type: fix
-Comment: Modified the test phone numbers supported by Stripe.
-
-
diff --git a/changelog/fix-update-payment-assets b/changelog/fix-update-payment-assets
deleted file mode 100644
index 0b45545b774..00000000000
--- a/changelog/fix-update-payment-assets
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: update
-
-Actualized cards-related assets for settings and transactions pages.
diff --git a/changelog/partially-ccleanup-legacy-upe-and-card b/changelog/partially-ccleanup-legacy-upe-and-card
deleted file mode 100644
index 9e5386f594e..00000000000
--- a/changelog/partially-ccleanup-legacy-upe-and-card
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: update
-
-Cleanup the deprecated payment gateway processing - part II
diff --git a/changelog/remove-flag-usage b/changelog/remove-flag-usage
deleted file mode 100644
index cab11239829..00000000000
--- a/changelog/remove-flag-usage
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: fix
-
-Avoid using the removed deferred UPE flag
diff --git a/changelog/revert-file-needed-for-plugin-update b/changelog/revert-file-needed-for-plugin-update
deleted file mode 100644
index f4e5d1e3224..00000000000
--- a/changelog/revert-file-needed-for-plugin-update
+++ /dev/null
@@ -1,5 +0,0 @@
-Significance: patch
-Type: dev
-Comment: This is the file revert to avoid failures on plugin update. This is a temporary solution. Both removal & revert happen on develop meaning there is no change to the outside world.
-
-
diff --git a/changelog/revert-prefetch-session-for-button b/changelog/revert-prefetch-session-for-button
deleted file mode 100644
index bcb2e97e61e..00000000000
--- a/changelog/revert-prefetch-session-for-button
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: fix
-
-Revemoved pre-fretch session for button to prevent draft order creation
diff --git a/changelog/subscriptions-6.6.0-1 b/changelog/subscriptions-6.6.0-1
deleted file mode 100644
index 9c70ea3d4ce..00000000000
--- a/changelog/subscriptions-6.6.0-1
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: dev
-
-Deprecate the WC_Subscriptions_Synchroniser::add_to_recurring_cart_key(). Use WC_Subscriptions_Synchroniser::add_to_recurring_product_grouping_key() instead.
diff --git a/changelog/subscriptions-6.6.0-2 b/changelog/subscriptions-6.6.0-2
deleted file mode 100644
index 98a24e2a8d8..00000000000
--- a/changelog/subscriptions-6.6.0-2
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: dev
-
-Introduce a new wcs_get_subscription_grouping_key() function to generate a unique key for a subscription based on its billing schedule. This function uses the existing recurring cart key concept.
diff --git a/changelog/subscriptions-core-6.6.0 b/changelog/subscriptions-core-6.6.0
deleted file mode 100644
index 192de7697f3..00000000000
--- a/changelog/subscriptions-core-6.6.0
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: dev
-
-Updated subscriptions-core to version 6.6.0
diff --git a/changelog/subscriptions-core-6.6.0-3 b/changelog/subscriptions-core-6.6.0-3
deleted file mode 100644
index 39e3728713e..00000000000
--- a/changelog/subscriptions-core-6.6.0-3
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: fix
-
-Fetch and update the `_cancelled_email_sent` meta in a HPOS compatibile way.
diff --git a/changelog/subscriptions-core-6.6.0-4 b/changelog/subscriptions-core-6.6.0-4
deleted file mode 100644
index adf5488ac54..00000000000
--- a/changelog/subscriptions-core-6.6.0-4
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: fix
-
-Ensure proper backfilling of subscription metadata (i.e. dates and cache) to the postmeta table when HPOS is enabled and compatibility mode (data syncing) is turned on.
diff --git a/changelog/subscriptions-core-6.6.0-5 b/changelog/subscriptions-core-6.6.0-5
deleted file mode 100644
index fc15acdb576..00000000000
--- a/changelog/subscriptions-core-6.6.0-5
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: fix
-
-Resolved an issue that would cause undefined $current_page, $max_num_pages, and $paginate variable errors when viewing a page with the subscriptions-shortcode.
diff --git a/changelog/subscriptions-core-6.6.0-6 b/changelog/subscriptions-core-6.6.0-6
deleted file mode 100644
index df965094736..00000000000
--- a/changelog/subscriptions-core-6.6.0-6
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: fix
-
-When HPOS is enabled and data compatibility mode is turned on, make sure subscription date changes made to postmeta are synced to orders_meta table.
diff --git a/changelog/subscriptions-core-6.6.0-7 b/changelog/subscriptions-core-6.6.0-7
deleted file mode 100644
index 96c2cae1f2c..00000000000
--- a/changelog/subscriptions-core-6.6.0-7
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: fix
-
-Prevents a PHP fatal error that occurs when the cart contains a renewal order item that no longer exists.
diff --git a/changelog/subscriptions-core-6.6.0-8 b/changelog/subscriptions-core-6.6.0-8
deleted file mode 100644
index a2ffa0feb0c..00000000000
--- a/changelog/subscriptions-core-6.6.0-8
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: fix
-
-When using the checkout block to pay for renewal orders, ensure the order's cart hash is updated to make sure the existing order can be used.
diff --git a/changelog/update-4163-compatibility-service b/changelog/update-4163-compatibility-service
deleted file mode 100644
index 3a524da05ae..00000000000
--- a/changelog/update-4163-compatibility-service
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: minor
-Type: add
-
-Adding Compatibility Service to assist with flagging possible compatibility issues in the future.
diff --git a/changelog/update-6320-rule-card-behavior-if-affected-by-other-config b/changelog/update-6320-rule-card-behavior-if-affected-by-other-config
deleted file mode 100644
index 3755be13f4f..00000000000
--- a/changelog/update-6320-rule-card-behavior-if-affected-by-other-config
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: update
-
-Updates the behavior and display of the international IP address rule card if the rule is being affected by the WooCommerce core selling locations general option.
diff --git a/changelog/update-6325-fraud-risk-link-text-in-settings b/changelog/update-6325-fraud-risk-link-text-in-settings
deleted file mode 100644
index 3f37d6371ca..00000000000
--- a/changelog/update-6325-fraud-risk-link-text-in-settings
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: update
-
-Updates the anchor text for the fraud and risk tools documentation link on the Payments Settings page.
diff --git a/changelog/update-change-setup-refund-policy-note-into-task b/changelog/update-change-setup-refund-policy-note-into-task
deleted file mode 100644
index 08cf0d142a9..00000000000
--- a/changelog/update-change-setup-refund-policy-note-into-task
+++ /dev/null
@@ -1,4 +0,0 @@
-Significance: patch
-Type: dev
-
-Remove "Set-up refund policy" Inbox note as superfluous.
diff --git a/package-lock.json b/package-lock.json
index 7e7375967b4..056a7547a52 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "woocommerce-payments",
- "version": "6.9.2",
+ "version": "7.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "woocommerce-payments",
- "version": "6.9.2",
+ "version": "7.0.0",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
diff --git a/package.json b/package.json
index d80cfbe4bd0..32b6a95a35f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "woocommerce-payments",
- "version": "6.9.2",
+ "version": "7.0.0",
"main": "webpack.config.js",
"author": "Automattic",
"license": "GPL-3.0-or-later",
diff --git a/readme.txt b/readme.txt
index 8a57aead24b..0c4dc6d82e0 100644
--- a/readme.txt
+++ b/readme.txt
@@ -4,7 +4,7 @@ Tags: woocommerce payments, apple pay, credit card, google pay, payment, payment
Requires at least: 6.0
Tested up to: 6.4
Requires PHP: 7.3
-Stable tag: 6.9.2
+Stable tag: 7.0.0
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
@@ -94,6 +94,62 @@ Please note that our support for the checkout block is still experimental and th
== Changelog ==
+= 7.0.0 - 2024-01-03 =
+* Add - Add Account Management tools with reset account functionality for partially onboarded accounts.
+* Add - Adding Compatibility Service to assist with flagging possible compatibility issues in the future.
+* Add - Add refund controls to transaction details view
+* Add - Add test mode notice in page order detail.
+* Add - Display a Confirmaton Modal on enabling Test Mode
+* Add - Introduce Customer currency, Deposit currency, Amount in Customer Currency and Deposit ID columns to the Transaction list UI and CSV export
+* Fix - Allow test phone number as Support Phone in Dev mode
+* Fix - Avoid using the removed deferred UPE flag
+* Fix - Ensure proper backfilling of subscription metadata (i.e. dates and cache) to the postmeta table when HPOS is enabled and compatibility mode (data syncing) is turned on.
+* Fix - Fetch and update the `_cancelled_email_sent` meta in a HPOS compatibile way.
+* Fix - fix: account currency hook return value
+* Fix - Fix account status error messages with links.
+* Fix - Fix country names with accents not showing correctly on international country fraud filter
+* Fix - Fix currency negative sign position on JS rendered amounts
+* Fix - Fixed a Level 3 error occurring during the capture of an authorization for amounts lower than the initial authorization amount.
+* Fix - Fixed Apple Pay Double Tax Calculation Issue
+* Fix - Fixed broken styles in authorization capture notifications
+* Fix - Fix incorrect amounts caused by zero-decimal currencies on Transactions, Deposits and Deposits CSV export
+* Fix - Fix missing customer data from transactions report
+* Fix - Fix missing order number in transaction reports CSV
+* Fix - Fix WooPay integration with AutomateWoo - Refer a Friend extension.
+* Fix - Improved error message for invalid payment method
+* Fix - Include discount fee in fees tooltip
+* Fix - Introduce WC_Payments_Express_Checkout_Button_Utils class.
+* Fix - Pass the pay-for-order params to get the pre-fetch session data
+* Fix - Prevents a PHP fatal error that occurs when the cart contains a renewal order item that no longer exists.
+* Fix - Resolved an issue that would cause undefined $current_page, $max_num_pages, and $paginate variable errors when viewing a page with the subscriptions-shortcode.
+* Fix - Revemoved pre-fretch session for button to prevent draft order creation
+* Fix - Update account balances on the Payments Overview screen when an instant deposit is requested
+* Fix - Update Qualitative Feedback note to have more efficient sql query.
+* Fix - When HPOS is enabled and data compatibility mode is turned on, make sure subscription date changes made to postmeta are synced to orders_meta table.
+* Fix - When using the checkout block to pay for renewal orders, ensure the order's cart hash is updated to make sure the existing order can be used.
+* Update - Actualized cards-related assets for settings and transactions pages.
+* Update - Cleanup the deprecated payment gateway processing - part II
+* Update - Cleanup the deprecated payment gateway processing - part III
+* Update - Confirmation when cancelling order with pending authorization. Automatic order changes submission if confirmed.
+* Update - Updates the anchor text for the fraud and risk tools documentation link on the Payments Settings page.
+* Update - Updates the behavior and display of the international IP address rule card if the rule is being affected by the WooCommerce core selling locations general option.
+* Dev - Add e2e tests for the currency switcher widget.
+* Dev - Added documentation for deposits REST API endpoints.
+* Dev - Bump WC tested up to version to 8.4.0.
+* Dev - Cleanup enqueueing of the scripts which were removed
+* Dev - Cleanup the deprecated payment gateway processing - part IV
+* Dev - Cleanup the deprecated payment gateway processing - part V
+* Dev - Cleanup the deprecated payment gateway processing - part VI
+* Dev - Comment: Fix declined 3DS card E2E test.
+* Dev - Deprecate the WC_Subscriptions_Synchroniser::add_to_recurring_cart_key(). Use WC_Subscriptions_Synchroniser::add_to_recurring_product_grouping_key() instead.
+* Dev - E2E test - Merchant facing: Multi-currency setup
+* Dev - Improve E2E checkout tests
+* Dev - Introduce a new wcs_get_subscription_grouping_key() function to generate a unique key for a subscription based on its billing schedule. This function uses the existing recurring cart key concept.
+* Dev - Remove "Set-up refund policy" Inbox note as superfluous.
+* Dev - remove unused factor flag for deferred UPE
+* Dev - Thank you page Tracks event
+* Dev - Updated subscriptions-core to version 6.6.0
+
= 6.9.2 - 2023-12-14 =
* Add - Notice is added when merchant has funds that are not yet available for deposit.
* Add - Show a deposit schedule notice on the deposits list page to indicate that future deposits can be expected.
diff --git a/woocommerce-payments.php b/woocommerce-payments.php
index df7afe47766..7f453eb5c35 100644
--- a/woocommerce-payments.php
+++ b/woocommerce-payments.php
@@ -12,7 +12,7 @@
* WC tested up to: 8.4.0
* Requires at least: 6.0
* Requires PHP: 7.3
- * Version: 6.9.2
+ * Version: 7.0.0
*
* @package WooCommerce\Payments
*/
From 3c9c94d72056eabbe2e93906aed5d212dcb7741f Mon Sep 17 00:00:00 2001
From: Eric Jinks <3147296+Jinksi@users.noreply.github.com>
Date: Tue, 2 Jan 2024 16:40:26 +1000
Subject: [PATCH 55/56] Fix broken dispute details UI (#7959)
---
...nsaction-details-dispute-details-broken-ui | 5 +
.../test/__snapshots__/index.test.tsx.snap | 78 +-
client/payment-details/summary/index.tsx | 535 ++++----
client/payment-details/summary/style.scss | 6 +-
.../test/__snapshots__/index.test.tsx.snap | 1208 +++++++++--------
.../test/__snapshots__/index.test.tsx.snap | 224 +--
6 files changed, 1074 insertions(+), 982 deletions(-)
create mode 100644 changelog/fix-7958-transaction-details-dispute-details-broken-ui
diff --git a/changelog/fix-7958-transaction-details-dispute-details-broken-ui b/changelog/fix-7958-transaction-details-dispute-details-broken-ui
new file mode 100644
index 00000000000..b196bc9910c
--- /dev/null
+++ b/changelog/fix-7958-transaction-details-dispute-details-broken-ui
@@ -0,0 +1,5 @@
+Significance: patch
+Type: fix
+Comment: Not user-facing: fixes styling bug introduced in develop branch
+
+
diff --git a/client/payment-details/order-details/test/__snapshots__/index.test.tsx.snap b/client/payment-details/order-details/test/__snapshots__/index.test.tsx.snap
index f28176053a7..ea41fb13ccb 100644
--- a/client/payment-details/order-details/test/__snapshots__/index.test.tsx.snap
+++ b/client/payment-details/order-details/test/__snapshots__/index.test.tsx.snap
@@ -20,55 +20,61 @@ exports[`Order details page should match the snapshot - Charge without payment i
data-wp-component="CardBody"
>
-
- $15.00
-
- USD
-
-
- Pending
-
-
-
-
- Fees:
- -$0.00
-
-
-
- Net:
+
$15.00
+
+ USD
+
+
+ Pending
+
+
+
+
+ Fees:
+ -$0.00
+
+
+
+ Net:
+ $15.00
+
+
-
-
- Payment ID:
- 776
+
+ Payment ID:
+ 776
+
+
-
= ( {
return (
-
-
-
-
- { formattedAmount }
-
- { charge.currency || 'USD' }
-
- { charge.dispute ? (
-
- ) : (
-
- ) }
-
-
-
- { renderStorePrice ? (
-
- { formatExplicitCurrency(
- balance.amount,
- balance.currency
- ) }
-
- ) : null }
- { balance.refunded ? (
-
- { `${
- disputeFee
- ? __(
- 'Deducted',
- 'woocommerce-payments'
- )
- : __(
- 'Refunded',
- 'woocommerce-payments'
- )
- }: ` }
- { formatExplicitCurrency(
- -balance.refunded,
- balance.currency
- ) }
-
- ) : (
- ''
- ) }
-
+
+
+
+
- { `${ __(
- 'Fees',
- 'woocommerce-payments'
- ) }: ` }
- { formatCurrency(
- -balance.fee,
- balance.currency
- ) }
- { disputeFee && (
- }
- buttonLabel={ __(
- 'Fee breakdown',
- 'woocommerce-payments'
- ) }
- content={
- <>
-
-
- { __(
- 'Transaction fee',
- 'woocommerce-payments'
- ) }
-
-
- { formatCurrency(
- transactionFee.fee,
- transactionFee.currency
- ) }
-
-
-
-
- { __(
- 'Dispute fee',
- 'woocommerce-payments'
- ) }
-
-
- { disputeFee }
-
-
-
-
- { __(
- 'Total fees',
- 'woocommerce-payments'
- ) }
-
-
- { formatCurrency(
- balance.fee,
- balance.currency
- ) }
-
-
- >
+ { formattedAmount }
+
+ { charge.currency || 'USD' }
+
+ { charge.dispute ? (
+
+ ) : (
+
) }
- { charge.paydown ? (
+
+ { renderStorePrice ? (
+
+ { formatExplicitCurrency(
+ balance.amount,
+ balance.currency
+ ) }
+
+ ) : null }
+ { balance.refunded ? (
+
+ { `${
+ disputeFee
+ ? __(
+ 'Deducted',
+ 'woocommerce-payments'
+ )
+ : __(
+ 'Refunded',
+ 'woocommerce-payments'
+ )
+ }: ` }
+ { formatExplicitCurrency(
+ -balance.refunded,
+ balance.currency
+ ) }
+
+ ) : (
+ ''
+ ) }
- { `${ __(
- 'Loan repayment',
- 'woocommerce-payments'
- ) }: ` }
- { formatExplicitCurrency(
- charge.paydown.amount,
- balance.currency
- ) }
+
+ { `${ __(
+ 'Fees',
+ 'woocommerce-payments'
+ ) }: ` }
+ { formatCurrency(
+ -balance.fee,
+ balance.currency
+ ) }
+ { disputeFee && (
+
+ }
+ buttonLabel={ __(
+ 'Fee breakdown',
+ 'woocommerce-payments'
+ ) }
+ content={
+ <>
+
+
+ { __(
+ 'Transaction fee',
+ 'woocommerce-payments'
+ ) }
+
+
+ { formatCurrency(
+ transactionFee.fee,
+ transactionFee.currency
+ ) }
+
+
+
+
+ { __(
+ 'Dispute fee',
+ 'woocommerce-payments'
+ ) }
+
+
+ { disputeFee }
+
+
+
+
+ { __(
+ 'Total fees',
+ 'woocommerce-payments'
+ ) }
+
+
+ { formatCurrency(
+ balance.fee,
+ balance.currency
+ ) }
+
+
+ >
+ }
+ />
+ ) }
+
+
+ { charge.paydown ? (
+
+ { `${ __(
+ 'Loan repayment',
+ 'woocommerce-payments'
+ ) }: ` }
+ { formatExplicitCurrency(
+ charge.paydown.amount,
+ balance.currency
+ ) }
+
+ ) : (
+ ''
+ ) }
+
+
+ { `${ __(
+ 'Net',
+ 'woocommerce-payments'
+ ) }: ` }
+ { formatExplicitCurrency(
+ charge.paydown
+ ? balance.net -
+ Math.abs(
+ charge.paydown
+ .amount
+ )
+ : balance.net,
+ balance.currency
+ ) }
+
- ) : (
- ''
+
+
+
+ { ! isLoading && isFraudOutcomeReview && (
+
+ {
+ wcpayTracks.recordEvent(
+ 'wcpay_fraud_protection_transaction_reviewed_merchant_blocked',
+ {
+ payment_intent_id:
+ charge.payment_intent,
+ }
+ );
+ wcpayTracks.recordEvent(
+ 'payments_transactions_details_cancel_charge_button_click',
+ {
+ payment_intent_id:
+ charge.payment_intent,
+ }
+ );
+ } }
+ >
+ { __( 'Block transaction' ) }
+
+
+ {
+ wcpayTracks.recordEvent(
+ 'wcpay_fraud_protection_transaction_reviewed_merchant_approved',
+ {
+ payment_intent_id:
+ charge.payment_intent,
+ }
+ );
+ wcpayTracks.recordEvent(
+ 'payments_transactions_details_capture_charge_button_click',
+ {
+ payment_intent_id:
+ charge.payment_intent,
+ }
+ );
+ } }
+ >
+ { __( 'Approve Transaction' ) }
+
+
) }
-
+
{ `${ __(
- 'Net',
+ 'Payment ID',
'woocommerce-payments'
) }: ` }
- { formatExplicitCurrency(
- charge.paydown
- ? balance.net -
- Math.abs(
- charge.paydown.amount
- )
- : balance.net,
- balance.currency
- ) }
+ { charge.payment_intent
+ ? charge.payment_intent
+ : charge.id }
-
+
-
- { ! isLoading && isFraudOutcomeReview && (
-
- {
- wcpayTracks.recordEvent(
- 'wcpay_fraud_protection_transaction_reviewed_merchant_blocked',
- {
- payment_intent_id:
- charge.payment_intent,
- }
- );
- wcpayTracks.recordEvent(
- 'payments_transactions_details_cancel_charge_button_click',
- {
- payment_intent_id:
- charge.payment_intent,
- }
- );
- } }
- >
- { __( 'Block transaction' ) }
-
-
- {
- wcpayTracks.recordEvent(
- 'wcpay_fraud_protection_transaction_reviewed_merchant_approved',
- {
- payment_intent_id:
- charge.payment_intent,
- }
- );
- wcpayTracks.recordEvent(
- 'payments_transactions_details_capture_charge_button_click',
- {
- payment_intent_id:
- charge.payment_intent,
- }
- );
- } }
- >
- { __( 'Approve Transaction' ) }
-
-
- ) }
-
+
+ { ! charge?.refunded && charge?.captured && (
- { `${ __(
- 'Payment ID',
- 'woocommerce-payments'
- ) }: ` }
- { charge.payment_intent
- ? charge.payment_intent
- : charge.id }
-
-
-
-
-
- { ! charge?.refunded && charge?.captured && (
-
-
- { ( { onClose } ) => (
-
- {
- setIsRefundModalOpen( true );
- wcpayTracks.recordEvent(
- 'payments_transactions_details_refund_modal_open',
- {
- payment_intent_id:
- charge.payment_intent,
- }
- );
- onClose();
- } }
- >
- { __(
- 'Refund in full',
- 'woocommerce-payments'
- ) }
-
- { charge.order && (
+
+ { ( { onClose } ) => (
+
{
+ setIsRefundModalOpen(
+ true
+ );
wcpayTracks.recordEvent(
- 'payments_transactions_details_partial_refund',
+ 'payments_transactions_details_refund_modal_open',
{
payment_intent_id:
charge.payment_intent,
- order_id:
- charge.order
- ?.number,
}
);
- window.location =
- charge.order?.url;
+ onClose();
} }
>
{ __(
- 'Partial refund',
+ 'Refund in full',
'woocommerce-payments'
) }
- ) }
-
- ) }
-
-
- ) }
-
+ { charge.order && (
+ {
+ wcpayTracks.recordEvent(
+ 'payments_transactions_details_partial_refund',
+ {
+ payment_intent_id:
+ charge.payment_intent,
+ order_id:
+ charge.order
+ ?.number,
+ }
+ );
+ window.location =
+ charge.order?.url;
+ } }
+ >
+ { __(
+ 'Partial refund',
+ 'woocommerce-payments'
+ ) }
+
+ ) }
+
+ ) }
+
+
+ ) }
+
+
diff --git a/client/payment-details/summary/style.scss b/client/payment-details/summary/style.scss
index 95df0d33edd..0ee051834fb 100755
--- a/client/payment-details/summary/style.scss
+++ b/client/payment-details/summary/style.scss
@@ -8,11 +8,6 @@
margin-bottom: 24px;
}
-.components-card__body:first-of-type {
- display: flex;
- flex-direction: row;
-}
-
.payment-details-summary {
display: flex;
flex: 1;
@@ -30,6 +25,7 @@
padding: 0;
margin: 0;
display: flex;
+ flex-wrap: wrap;
align-items: center;
.payment-details-summary__amount-currency {
diff --git a/client/payment-details/summary/test/__snapshots__/index.test.tsx.snap b/client/payment-details/summary/test/__snapshots__/index.test.tsx.snap
index b719e25c342..4d582a000c7 100644
--- a/client/payment-details/summary/test/__snapshots__/index.test.tsx.snap
+++ b/client/payment-details/summary/test/__snapshots__/index.test.tsx.snap
@@ -16,55 +16,61 @@ exports[`PaymentDetailsSummary capture notification and fraud buttons renders ca
data-wp-component="CardBody"
>
-
- $20.00
-
- usd
-
-
- Payment authorized
-
-
-
-
- Fees:
- -$0.70
-
-
-
- Net:
- $19.30
+
+ $20.00
+
+ usd
+
+
+ Payment authorized
+
+
+
+
+ Fees:
+ -$0.70
+
+
+
+ Net:
+ $19.30
+
+
-
-
- Payment ID:
- ch_38jdHA39KKA
+
+ Payment ID:
+ ch_38jdHA39KKA
+
+
-
-
- $20.00
-
- usd
-
-
- Needs review
-
-
-
-
- Fees:
- -$0.70
-
-
-
- Net:
- $19.30
+
+ $20.00
+
+ usd
+
+
+ Needs review
+
+
+
+
+ Fees:
+ -$0.70
+
+
+
+ Net:
+ $19.30
+
+
-
-
-
- Block transaction
-
-
+ Block transaction
+
+
+ Approve Transaction
+
+
+
- Approve Transaction
-
-
-
- Payment ID:
- ch_38jdHA39KKA
+ Payment ID:
+ ch_38jdHA39KKA
+
+
-
-
- $20.00
-
- usd
-
-
- Paid
-
-
-
-
- Fees:
- -$0.70
-
-
-
- Net:
- $19.30
+
+ $20.00
+
+ usd
+
+
+ Paid
+
+
+
+
+ Fees:
+ -$0.70
+
+
+
+ Net:
+ $19.30
+
+
-
-
- Payment ID:
- ch_38jdHA39KKA
+
+ Payment ID:
+ ch_38jdHA39KKA
+
-
-
@@ -923,79 +941,85 @@ exports[`PaymentDetailsSummary order missing notice does not render notice if or
data-wp-component="CardBody"
>
-
- $20.00
-
- usd
-
-
- Paid
-
-
-
-
- Fees:
- -$0.70
-
-
-
- Net:
- $19.30
+
+ $20.00
+
+ usd
+
+
+ Paid
+
+
+
+
+ Fees:
+ -$0.70
+
+
+
+ Net:
+ $19.30
+
+
-
-
- Payment ID:
- ch_38jdHA39KKA
+
+ Payment ID:
+ ch_38jdHA39KKA
+
-
-
@@ -1212,79 +1236,85 @@ exports[`PaymentDetailsSummary order missing notice renders notice if order miss
data-wp-component="CardBody"
>
-
- $20.00
-
- usd
-
-
- Paid
-
-
-
-
- Fees:
- -$0.70
-
-
-
- Net:
- $19.30
+
+ $20.00
+
+ usd
+
+
+ Paid
+
+
+
+
+ Fees:
+ -$0.70
+
+
+
+ Net:
+ $19.30
+
+
-
-
- Payment ID:
- ch_38jdHA39KKA
+
+ Payment ID:
+ ch_38jdHA39KKA
+
-
-
@@ -1524,79 +1554,85 @@ exports[`PaymentDetailsSummary renders a charge with subscriptions 1`] = `
data-wp-component="CardBody"
>
-
- $20.00
-
- usd
-
-
- Paid
-
-
-
-
- Fees:
- -$0.70
-
-
-
- Net:
- $19.30
+
+ $20.00
+
+ usd
+
+
+ Paid
+
+
+
+
+ Fees:
+ -$0.70
+
+
+
+ Net:
+ $19.30
+
+
-
-
- Payment ID:
- ch_38jdHA39KKA
+
+ Payment ID:
+ ch_38jdHA39KKA
+
-
-
@@ -1840,58 +1876,64 @@ exports[`PaymentDetailsSummary renders fully refunded information for a charge 1
data-wp-component="CardBody"
>
-
- $20.00
-
- usd
-
-
- Refunded
-
-
-
- Refunded:
- -$20.00
-
-
- Fees:
- -$0.70
-
-
-
- Net:
- -$0.70
+
+ $20.00
+
+ usd
+
+
+ Refunded
+
+
+
+ Refunded:
+ -$20.00
+
+
+ Fees:
+ -$0.70
+
+
+
+ Net:
+ -$0.70
+
+
-
-
- Payment ID:
- ch_38jdHA39KKA
+
+ Payment ID:
+ ch_38jdHA39KKA
+
+
-
-
-
-
- USD
-
-
-
-
-
- Fees:
- $0.00
-
-
-
- Net:
- $0.00
+
+
+
+ USD
+
+
+
+
+
+ Fees:
+ $0.00
+
+
+
+ Net:
+ $0.00
+
+
-
-
- Payment ID:
+
+ Payment ID:
+
+
-
-
- $20.00
-
- usd
-
-
- Partial refund
-
-
-
- Refunded:
- -$12.00
-
-
- Fees:
- -$0.70
-
-
-
- Net:
- $7.30
+
+ $20.00
+
+ usd
+
+
+ Partial refund
+
+
+
+ Refunded:
+ -$12.00
+
+
+ Fees:
+ -$0.70
+
+
+
+ Net:
+ $7.30
+
+
-
-
- Payment ID:
- ch_38jdHA39KKA
+
+ Payment ID:
+ ch_38jdHA39KKA
+
-
-
@@ -2634,79 +2688,85 @@ exports[`PaymentDetailsSummary renders the Tap to Pay channel from metadata 1`]
data-wp-component="CardBody"
>
-
- $20.00
-
- usd
-
-
- Paid
-
-
-
-
- Fees:
- -$0.70
-
-
-
- Net:
- $19.30
+
+ $20.00
+
+ usd
+
+
+ Paid
+
+
+
+
+ Fees:
+ -$0.70
+
+
+
+ Net:
+ $19.30
+
+
-
-
- Payment ID:
- ch_38jdHA39KKA
+
+ Payment ID:
+ ch_38jdHA39KKA
+
-
-
@@ -2923,79 +2983,85 @@ exports[`PaymentDetailsSummary renders the information of a dispute-reversal cha
data-wp-component="CardBody"
>
-
- $20.00
-
- usd
-
-
- Disputed: Won
-
-
-
-
- Fees:
- -$0.70
-
-
-
- Net:
- $19.30
+
+ $20.00
+
+ usd
+
+
+ Disputed: Won
+
+
+
+
+ Fees:
+ -$0.70
+
+
+
+ Net:
+ $19.30
+
+
-
-
- Payment ID:
- ch_38jdHA39KKA
+
+ Payment ID:
+ ch_38jdHA39KKA
+
-
-
diff --git a/client/payment-details/test/__snapshots__/index.test.tsx.snap b/client/payment-details/test/__snapshots__/index.test.tsx.snap
index 7a3274751bf..ebe9d418a92 100644
--- a/client/payment-details/test/__snapshots__/index.test.tsx.snap
+++ b/client/payment-details/test/__snapshots__/index.test.tsx.snap
@@ -20,78 +20,84 @@ exports[`Payment details page should match the snapshot - Charge query param 1`]
data-wp-component="CardBody"
>
-
-
- Amount placeholder
-
-
-
-
+
- Fee amount
+ Amount placeholder
-
-
+
+
+
+
+ Fee amount
+
+
+
+
+
+ Net amount
+
+
+
+
+
+
- Net amount
+ Payment ID: pi_xxxxxxxxxxxxxxxxxxxxxxxx
-
+
-
-
- Payment ID: pi_xxxxxxxxxxxxxxxxxxxxxxxx
-
-
+
+
+
-
-
- $1,500.00
-
- usd
-
-
- Paid
-
-
-
-
- Fees:
- -$74.00
-
-
-
- Net:
- $1,426.00
+
+ $1,500.00
+
+ usd
+
+
+ Paid
+
+
+
+
+ Fees:
+ -$74.00
+
+
+
+ Net:
+ $1,426.00
+
+
-
-
- Payment ID:
- pi_mock
+
+ Payment ID:
+ pi_mock
+
-
-
From 5ee80a640b2360292e55e37e1331316b89f1d30e Mon Sep 17 00:00:00 2001
From: botwoo
Date: Tue, 2 Jan 2024 08:44:39 +0000
Subject: [PATCH 56/56] Amend changelog entries for release 7.0.0
---
.../fix-7958-transaction-details-dispute-details-broken-ui | 5 -----
1 file changed, 5 deletions(-)
delete mode 100644 changelog/fix-7958-transaction-details-dispute-details-broken-ui
diff --git a/changelog/fix-7958-transaction-details-dispute-details-broken-ui b/changelog/fix-7958-transaction-details-dispute-details-broken-ui
deleted file mode 100644
index b196bc9910c..00000000000
--- a/changelog/fix-7958-transaction-details-dispute-details-broken-ui
+++ /dev/null
@@ -1,5 +0,0 @@
-Significance: patch
-Type: fix
-Comment: Not user-facing: fixes styling bug introduced in develop branch
-
-